外观
完整示例
这里提供几个可以直接使用的完整插件代码,覆盖欢迎提示、传送命令、区域保护和每日签到。
构建与目标版本
示例以发行 DLL 构建为准:using Game.Server.EssentialCmd;、net8.0、引用 Engine.dll 等发行程序集。若你基于 sc2.2network 源码构建,把命令的 using 改为 Game.Server,目标框架改为 net10.0,并改用项目引用即可。
示例 1:欢迎插件
玩家进入时发送欢迎消息。
csharp
using System;
using Game.Server;
using Game.Server.PlayerEvent;
using Game.NetWork;
using Game.NetWork.Packages;
public class WelcomePlugin : ServerPlugin, IPlayerEnterGameEventHandle
{
public override string Name => "Welcome";
public override int Version => 1;
public byte FirstLevel => 0;
public override void Initialize()
{
PlayerEnterGameEventManager.AddObject(this);
Console.WriteLine("[Welcome] 插件已加载");
}
void IPlayerEnterGameEventHandle.PlayerEnter(PlayerData player)
{
SendMessage(player, "欢迎来到服务器!");
SendMessage(player, "输入 /help 查看命令列表");
}
void IPlayerEnterGameEventHandle.PlayerLeave(PlayerData player) { }
void SendMessage(PlayerData player, string message)
{
var pkg = new MessagePackage(null, message, 0, null);
pkg.To = player.Client;
CommonLib.Net.QueuePackage(pkg);
}
public override void Load() { }
public override void Save() { }
}示例 2:传送命令
/tp <玩家名> 传送到指定玩家。
csharp
using System;
using Engine;
using Game.Server.EssentialCmd;
using Game.NetWork;
using Game.NetWork.Packages;
public class TpCommand : AbstractProcessCmd
{
public override string Cmd => "tp";
public override string Introduce => "/tp <玩家名> - 传送到玩家";
public override int AuthLevel => 0;
public override DisplayType Display => DisplayType.Private;
public override void ProcessCmd()
{
if (GameManager.Project == null)
{
SendMessage("系统", "请先进入游戏");
return;
}
if (m_isTerminal)
{
SendMessage("系统", "控制台不能传送");
return;
}
if (m_messageDatas.Length < 2)
{
SendMessage("系统", "用法: /tp <玩家名>");
return;
}
string targetName = m_messageDatas[1];
ComponentPlayer target = FindPlayer(targetName);
if (target == null)
{
SendMessage("系统", $"玩家 {targetName} 不在线");
return;
}
ComponentPlayer me = m_client.PlayerData.ComponentPlayer;
Vector3 pos = target.ComponentBody.Position;
me.ComponentBody.Position = pos;
CommonLib.Net.QueuePackage(new ComponentPlayerPackage(me, (PlayerAction)12));
SendMessage("系统", $"已传送到 {targetName}");
}
ComponentPlayer FindPlayer(string name)
{
var players = GameManager.Project.FindSubsystem<SubsystemPlayers>();
foreach (var p in players.ComponentPlayers)
{
if (p.PlayerData.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
return p;
}
return null;
}
}示例 3:区域保护
保护指定区域不被破坏。
csharp
using System;
using System.Collections.Generic;
using Engine;
using Game.Server;
using Game.Server.PlayerEvent;
using Game.NetWork;
using Game.NetWork.Packages;
public class ProtectPlugin : ServerPlugin, IPlayerBreakAndPlaceHandle
{
public override string Name => "Protect";
public override int Version => 1;
public byte FirstLevel => 0;
private List<Zone> zones = new List<Zone>();
public override void Initialize()
{
PlayerBreakAndPlaceBlockEventManager.AddObject(this);
zones.Add(new Zone {
Name = "主城",
X1 = -50, X2 = 50,
Y1 = 0, Y2 = 100,
Z1 = -50, Z2 = 50
});
}
bool IPlayerBreakAndPlaceHandle.PlayerBreakEvent(
ComponentPlayer player, Point3 point, int blockValue, int toolLevel)
{
foreach (var z in zones)
{
if (z.Contains(point))
{
SendMsg(player, $"[{z.Name}] 不能破坏方块");
return false;
}
}
return true;
}
bool IPlayerBreakAndPlaceHandle.PlayerPlaceEvent(
ComponentPlayer player, Point3 point, int blockValue)
{
foreach (var z in zones)
{
if (z.Contains(point))
{
SendMsg(player, $"[{z.Name}] 不能放置方块");
return false;
}
}
return true;
}
void SendMsg(ComponentPlayer player, string msg)
{
var pkg = new MessagePackage(null, msg, 0, null);
pkg.To = player.PlayerData.Client;
CommonLib.Net.QueuePackage(pkg);
}
public override void Load() { }
public override void Save() { }
}
class Zone
{
public string Name;
public int X1, X2, Y1, Y2, Z1, Z2;
public bool Contains(Point3 p)
{
return p.X >= X1 && p.X <= X2 && p.Y >= Y1 && p.Y <= Y2 && p.Z >= Z1 && p.Z <= Z2;
}
}示例 4:签到命令
csharp
using System;
using System.Collections.Generic;
using System.IO;
using Game.Server.EssentialCmd;
using Game.NetWork;
using Game.NetWork.Packages;
using Newtonsoft.Json;
public class SignCommand : AbstractProcessCmd
{
public override string Cmd => "sign";
public override string Introduce => "每日签到";
public override int AuthLevel => 0;
public override DisplayType Display => DisplayType.Private;
private static Dictionary<string, SignData> data = new Dictionary<string, SignData>();
private static string path = "Plugins/Sign/data.json";
static SignCommand()
{
Directory.CreateDirectory("Plugins/Sign");
Load();
}
public override void ProcessCmd()
{
if (m_isTerminal)
{
SendMessage("系统", "控制台不能签到");
return;
}
string name = m_client.PlayerData.Name;
if (!data.ContainsKey(name))
data[name] = new SignData();
var d = data[name];
if (d.Last.Date == DateTime.Today)
{
SendMessage("系统", "今天已签到");
return;
}
if (d.Last.Date == DateTime.Today.AddDays(-1))
d.Continuous++;
else
d.Continuous = 1;
d.Total++;
d.Last = DateTime.Now;
Save();
SendMessage("系统", $"签到成功!连续{d.Continuous}天,累计{d.Total}天");
}
static void Load()
{
if (File.Exists(path))
{
string json = File.ReadAllText(path);
data = JsonConvert.DeserializeObject<Dictionary<string, SignData>>(json);
}
}
static void Save()
{
string json = JsonConvert.SerializeObject(data, Formatting.Indented);
File.WriteAllText(path, json);
}
}
class SignData
{
public int Total;
public int Continuous;
public DateTime Last;
}项目配置文件
创建 MyPlugin.csproj:
xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<Reference Include="Engine">
<HintPath>游戏目录\Engine.dll</HintPath>
</Reference>
<Reference Include="GameEntitySystem">
<HintPath>游戏目录\GameEntitySystem.dll</HintPath>
</Reference>
<Reference Include="LiteNetLib">
<HintPath>游戏目录\LiteNetLib.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>游戏目录\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
</Project>编译和安装
- 用 Visual Studio 或
dotnet build编译; - 将
.dll复制到服务器的Plugins文件夹; - 重启服务器。
小贴士
- 从简单开始:先写欢迎插件测试。
- 逐步添加:确认基础功能正常再加功能。
- 本地测试:测试没问题再放正式服。
- 保留日志:用
Console.WriteLine或Log.Information调试。
IyDlrozmlbTnpLrkvosKCui/memHjOaPkOS+m+WHoOS4quWPr+S7peebtOaOpeS9v+eUqOeahOWujOaVtOaPkuS7tuS7o+egge+8jOimhuebluasoui/juaPkOekuuOAgeS8oOmAgeWRveS7pOOAgeWMuuWfn+S/neaKpOWSjOavj+aXpeetvuWIsOOAggoKOjo6IHdhcm5pbmcg5p6E5bu65LiO55uu5qCH54mI5pysCuekuuS+i+S7pSoq5Y+R6KGMIERMTCDmnoTlu7oqKuS4uuWHhu+8mmB1c2luZyBHYW1lLlNlcnZlci5Fc3NlbnRpYWxDbWQ7YOOAgWBuZXQ4LjBg44CB5byV55SoIGBFbmdpbmUuZGxsYCDnrYnlj5HooYznqIvluo/pm4bjgILoi6XkvaDln7rkuo4gYHNjMi4ybmV0d29ya2Ag5rqQ56CB5p6E5bu677yM5oqK5ZG95Luk55qEIGB1c2luZ2Ag5pS55Li6IGBHYW1lLlNlcnZlcmDvvIznm67moIfmoYbmnrbmlLnkuLogYG5ldDEwLjBg77yM5bm25pS555So6aG555uu5byV55So5Y2z5Y+v44CCCjo6OgoKIyMg56S65L6LIDHvvJrmrKLov47mj5Lku7YKCueOqeWutui/m+WFpeaXtuWPkemAgeasoui/jua2iOaBr+OAggoKYGBgY3NoYXJwCnVzaW5nIFN5c3RlbTsKdXNpbmcgR2FtZS5TZXJ2ZXI7CnVzaW5nIEdhbWUuU2VydmVyLlBsYXllckV2ZW50Owp1c2luZyBHYW1lLk5ldFdvcms7CnVzaW5nIEdhbWUuTmV0V29yay5QYWNrYWdlczsKCnB1YmxpYyBjbGFzcyBXZWxjb21lUGx1Z2luIDogU2VydmVyUGx1Z2luLCBJUGxheWVyRW50ZXJHYW1lRXZlbnRIYW5kbGUKewogICAgcHVibGljIG92ZXJyaWRlIHN0cmluZyBOYW1lID0+ICJXZWxjb21lIjsKICAgIHB1YmxpYyBvdmVycmlkZSBpbnQgVmVyc2lvbiA9PiAxOwogICAgcHVibGljIGJ5dGUgRmlyc3RMZXZlbCA9PiAwOwoKICAgIHB1YmxpYyBvdmVycmlkZSB2b2lkIEluaXRpYWxpemUoKQogICAgewogICAgICAgIFBsYXllckVudGVyR2FtZUV2ZW50TWFuYWdlci5BZGRPYmplY3QodGhpcyk7CiAgICAgICAgQ29uc29sZS5Xcml0ZUxpbmUoIltXZWxjb21lXSDmj5Lku7blt7LliqDovb0iKTsKICAgIH0KCiAgICB2b2lkIElQbGF5ZXJFbnRlckdhbWVFdmVudEhhbmRsZS5QbGF5ZXJFbnRlcihQbGF5ZXJEYXRhIHBsYXllcikKICAgIHsKICAgICAgICBTZW5kTWVzc2FnZShwbGF5ZXIsICLmrKLov47mnaXliLDmnI3liqHlmajvvIEiKTsKICAgICAgICBTZW5kTWVzc2FnZShwbGF5ZXIsICLovpPlhaUgL2hlbHAg5p+l55yL5ZG95Luk5YiX6KGoIik7CiAgICB9CgogICAgdm9pZCBJUGxheWVyRW50ZXJHYW1lRXZlbnRIYW5kbGUuUGxheWVyTGVhdmUoUGxheWVyRGF0YSBwbGF5ZXIpIHsgfQoKICAgIHZvaWQgU2VuZE1lc3NhZ2UoUGxheWVyRGF0YSBwbGF5ZXIsIHN0cmluZyBtZXNzYWdlKQogICAgewogICAgICAgIHZhciBwa2cgPSBuZXcgTWVzc2FnZVBhY2thZ2UobnVsbCwgbWVzc2FnZSwgMCwgbnVsbCk7CiAgICAgICAgcGtnLlRvID0gcGxheWVyLkNsaWVudDsKICAgICAgICBDb21tb25MaWIuTmV0LlF1ZXVlUGFja2FnZShwa2cpOwogICAgfQoKICAgIHB1YmxpYyBvdmVycmlkZSB2b2lkIExvYWQoKSB7IH0KICAgIHB1YmxpYyBvdmVycmlkZSB2b2lkIFNhdmUoKSB7IH0KfQpgYGAKCiMjIOekuuS+iyAy77ya5Lyg6YCB5ZG95LukCgpgL3RwIDznjqnlrrblkI0+YCDkvKDpgIHliLDmjIflrprnjqnlrrbjgIIKCmBgYGNzaGFycAp1c2luZyBTeXN0ZW07CnVzaW5nIEVuZ2luZTsKdXNpbmcgR2FtZS5TZXJ2ZXIuRXNzZW50aWFsQ21kOwp1c2luZyBHYW1lLk5ldFdvcms7CnVzaW5nIEdhbWUuTmV0V29yay5QYWNrYWdlczsKCnB1YmxpYyBjbGFzcyBUcENvbW1hbmQgOiBBYnN0cmFjdFByb2Nlc3NDbWQKewogICAgcHVibGljIG92ZXJyaWRlIHN0cmluZyBDbWQgPT4gInRwIjsKICAgIHB1YmxpYyBvdmVycmlkZSBzdHJpbmcgSW50cm9kdWNlID0+ICIvdHAgPOeOqeWutuWQjT4gLSDkvKDpgIHliLDnjqnlrrYiOwogICAgcHVibGljIG92ZXJyaWRlIGludCBBdXRoTGV2ZWwgPT4gMDsKICAgIHB1YmxpYyBvdmVycmlkZSBEaXNwbGF5VHlwZSBEaXNwbGF5ID0+IERpc3BsYXlUeXBlLlByaXZhdGU7CgogICAgcHVibGljIG92ZXJyaWRlIHZvaWQgUHJvY2Vzc0NtZCgpCiAgICB7CiAgICAgICAgaWYgKEdhbWVNYW5hZ2VyLlByb2plY3QgPT0gbnVsbCkKICAgICAgICB7CiAgICAgICAgICAgIFNlbmRNZXNzYWdlKCLns7vnu58iLCAi6K+35YWI6L+b5YWl5ri45oiPIik7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CgogICAgICAgIGlmIChtX2lzVGVybWluYWwpCiAgICAgICAgewogICAgICAgICAgICBTZW5kTWVzc2FnZSgi57O757ufIiwgIuaOp+WItuWPsOS4jeiDveS8oOmAgSIpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQoKICAgICAgICBpZiAobV9tZXNzYWdlRGF0YXMuTGVuZ3RoIDwgMikKICAgICAgICB7CiAgICAgICAgICAgIFNlbmRNZXNzYWdlKCLns7vnu58iLCAi55So5rOVOiAvdHAgPOeOqeWutuWQjT4iKTsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KCiAgICAgICAgc3RyaW5nIHRhcmdldE5hbWUgPSBtX21lc3NhZ2VEYXRhc1sxXTsKICAgICAgICBDb21wb25lbnRQbGF5ZXIgdGFyZ2V0ID0gRmluZFBsYXllcih0YXJnZXROYW1lKTsKCiAgICAgICAgaWYgKHRhcmdldCA9PSBudWxsKQogICAgICAgIHsKICAgICAgICAgICAgU2VuZE1lc3NhZ2UoIuezu+e7nyIsICQi546p5a62IHt0YXJnZXROYW1lfSDkuI3lnKjnur8iKTsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KCiAgICAgICAgQ29tcG9uZW50UGxheWVyIG1lID0gbV9jbGllbnQuUGxheWVyRGF0YS5Db21wb25lbnRQbGF5ZXI7CiAgICAgICAgVmVjdG9yMyBwb3MgPSB0YXJnZXQuQ29tcG9uZW50Qm9keS5Qb3NpdGlvbjsKCiAgICAgICAgbWUuQ29tcG9uZW50Qm9keS5Qb3NpdGlvbiA9IHBvczsKICAgICAgICBDb21tb25MaWIuTmV0LlF1ZXVlUGFja2FnZShuZXcgQ29tcG9uZW50UGxheWVyUGFja2FnZShtZSwgKFBsYXllckFjdGlvbikxMikpOwoKICAgICAgICBTZW5kTWVzc2FnZSgi57O757ufIiwgJCLlt7LkvKDpgIHliLAge3RhcmdldE5hbWV9Iik7CiAgICB9CgogICAgQ29tcG9uZW50UGxheWVyIEZpbmRQbGF5ZXIoc3RyaW5nIG5hbWUpCiAgICB7CiAgICAgICAgdmFyIHBsYXllcnMgPSBHYW1lTWFuYWdlci5Qcm9qZWN0LkZpbmRTdWJzeXN0ZW08U3Vic3lzdGVtUGxheWVycz4oKTsKICAgICAgICBmb3JlYWNoICh2YXIgcCBpbiBwbGF5ZXJzLkNvbXBvbmVudFBsYXllcnMpCiAgICAgICAgewogICAgICAgICAgICBpZiAocC5QbGF5ZXJEYXRhLk5hbWUuRXF1YWxzKG5hbWUsIFN0cmluZ0NvbXBhcmlzb24uT3JkaW5hbElnbm9yZUNhc2UpKQogICAgICAgICAgICAgICAgcmV0dXJuIHA7CiAgICAgICAgfQogICAgICAgIHJldHVybiBudWxsOwogICAgfQp9CmBgYAoKIyMg56S65L6LIDPvvJrljLrln5/kv53miqQKCuS/neaKpOaMh+WumuWMuuWfn+S4jeiiq+egtOWdj+OAggoKYGBgY3NoYXJwCnVzaW5nIFN5c3RlbTsKdXNpbmcgU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWM7CnVzaW5nIEVuZ2luZTsKdXNpbmcgR2FtZS5TZXJ2ZXI7CnVzaW5nIEdhbWUuU2VydmVyLlBsYXllckV2ZW50Owp1c2luZyBHYW1lLk5ldFdvcms7CnVzaW5nIEdhbWUuTmV0V29yay5QYWNrYWdlczsKCnB1YmxpYyBjbGFzcyBQcm90ZWN0UGx1Z2luIDogU2VydmVyUGx1Z2luLCBJUGxheWVyQnJlYWtBbmRQbGFjZUhhbmRsZQp7CiAgICBwdWJsaWMgb3ZlcnJpZGUgc3RyaW5nIE5hbWUgPT4gIlByb3RlY3QiOwogICAgcHVibGljIG92ZXJyaWRlIGludCBWZXJzaW9uID0+IDE7CiAgICBwdWJsaWMgYnl0ZSBGaXJzdExldmVsID0+IDA7CgogICAgcHJpdmF0ZSBMaXN0PFpvbmU+IHpvbmVzID0gbmV3IExpc3Q8Wm9uZT4oKTsKCiAgICBwdWJsaWMgb3ZlcnJpZGUgdm9pZCBJbml0aWFsaXplKCkKICAgIHsKICAgICAgICBQbGF5ZXJCcmVha0FuZFBsYWNlQmxvY2tFdmVudE1hbmFnZXIuQWRkT2JqZWN0KHRoaXMpOwoKICAgICAgICB6b25lcy5BZGQobmV3IFpvbmUgewogICAgICAgICAgICBOYW1lID0gIuS4u+WfjiIsCiAgICAgICAgICAgIFgxID0gLTUwLCBYMiA9IDUwLAogICAgICAgICAgICBZMSA9IDAsIFkyID0gMTAwLAogICAgICAgICAgICBaMSA9IC01MCwgWjIgPSA1MAogICAgICAgIH0pOwogICAgfQoKICAgIGJvb2wgSVBsYXllckJyZWFrQW5kUGxhY2VIYW5kbGUuUGxheWVyQnJlYWtFdmVudCgKICAgICAgICBDb21wb25lbnRQbGF5ZXIgcGxheWVyLCBQb2ludDMgcG9pbnQsIGludCBibG9ja1ZhbHVlLCBpbnQgdG9vbExldmVsKQogICAgewogICAgICAgIGZvcmVhY2ggKHZhciB6IGluIHpvbmVzKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHouQ29udGFpbnMocG9pbnQpKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBTZW5kTXNnKHBsYXllciwgJCJbe3ouTmFtZX1dIOS4jeiDveegtOWdj+aWueWdlyIpOwogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiB0cnVlOwogICAgfQoKICAgIGJvb2wgSVBsYXllckJyZWFrQW5kUGxhY2VIYW5kbGUuUGxheWVyUGxhY2VFdmVudCgKICAgICAgICBDb21wb25lbnRQbGF5ZXIgcGxheWVyLCBQb2ludDMgcG9pbnQsIGludCBibG9ja1ZhbHVlKQogICAgewogICAgICAgIGZvcmVhY2ggKHZhciB6IGluIHpvbmVzKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHouQ29udGFpbnMocG9pbnQpKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBTZW5kTXNnKHBsYXllciwgJCJbe3ouTmFtZX1dIOS4jeiDveaUvue9ruaWueWdlyIpOwogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybiB0cnVlOwogICAgfQoKICAgIHZvaWQgU2VuZE1zZyhDb21wb25lbnRQbGF5ZXIgcGxheWVyLCBzdHJpbmcgbXNnKQogICAgewogICAgICAgIHZhciBwa2cgPSBuZXcgTWVzc2FnZVBhY2thZ2UobnVsbCwgbXNnLCAwLCBudWxsKTsKICAgICAgICBwa2cuVG8gPSBwbGF5ZXIuUGxheWVyRGF0YS5DbGllbnQ7CiAgICAgICAgQ29tbW9uTGliLk5ldC5RdWV1ZVBhY2thZ2UocGtnKTsKICAgIH0KCiAgICBwdWJsaWMgb3ZlcnJpZGUgdm9pZCBMb2FkKCkgeyB9CiAgICBwdWJsaWMgb3ZlcnJpZGUgdm9pZCBTYXZlKCkgeyB9Cn0KCmNsYXNzIFpvbmUKewogICAgcHVibGljIHN0cmluZyBOYW1lOwogICAgcHVibGljIGludCBYMSwgWDIsIFkxLCBZMiwgWjEsIFoyOwoKICAgIHB1YmxpYyBib29sIENvbnRhaW5zKFBvaW50MyBwKQogICAgewogICAgICAgIHJldHVybiBwLlggPj0gWDEgJiYgcC5YIDw9IFgyICYmIHAuWSA+PSBZMSAmJiBwLlkgPD0gWTIgJiYgcC5aID49IFoxICYmIHAuWiA8PSBaMjsKICAgIH0KfQpgYGAKCiMjIOekuuS+iyA077ya562+5Yiw5ZG95LukCgpgYGBjc2hhcnAKdXNpbmcgU3lzdGVtOwp1c2luZyBTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYzsKdXNpbmcgU3lzdGVtLklPOwp1c2luZyBHYW1lLlNlcnZlci5Fc3NlbnRpYWxDbWQ7CnVzaW5nIEdhbWUuTmV0V29yazsKdXNpbmcgR2FtZS5OZXRXb3JrLlBhY2thZ2VzOwp1c2luZyBOZXd0b25zb2Z0Lkpzb247CgpwdWJsaWMgY2xhc3MgU2lnbkNvbW1hbmQgOiBBYnN0cmFjdFByb2Nlc3NDbWQKewogICAgcHVibGljIG92ZXJyaWRlIHN0cmluZyBDbWQgPT4gInNpZ24iOwogICAgcHVibGljIG92ZXJyaWRlIHN0cmluZyBJbnRyb2R1Y2UgPT4gIuavj+aXpeetvuWIsCI7CiAgICBwdWJsaWMgb3ZlcnJpZGUgaW50IEF1dGhMZXZlbCA9PiAwOwogICAgcHVibGljIG92ZXJyaWRlIERpc3BsYXlUeXBlIERpc3BsYXkgPT4gRGlzcGxheVR5cGUuUHJpdmF0ZTsKCiAgICBwcml2YXRlIHN0YXRpYyBEaWN0aW9uYXJ5PHN0cmluZywgU2lnbkRhdGE+IGRhdGEgPSBuZXcgRGljdGlvbmFyeTxzdHJpbmcsIFNpZ25EYXRhPigpOwogICAgcHJpdmF0ZSBzdGF0aWMgc3RyaW5nIHBhdGggPSAiUGx1Z2lucy9TaWduL2RhdGEuanNvbiI7CgogICAgc3RhdGljIFNpZ25Db21tYW5kKCkKICAgIHsKICAgICAgICBEaXJlY3RvcnkuQ3JlYXRlRGlyZWN0b3J5KCJQbHVnaW5zL1NpZ24iKTsKICAgICAgICBMb2FkKCk7CiAgICB9CgogICAgcHVibGljIG92ZXJyaWRlIHZvaWQgUHJvY2Vzc0NtZCgpCiAgICB7CiAgICAgICAgaWYgKG1faXNUZXJtaW5hbCkKICAgICAgICB7CiAgICAgICAgICAgIFNlbmRNZXNzYWdlKCLns7vnu58iLCAi5o6n5Yi25Y+w5LiN6IO9562+5YiwIik7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CgogICAgICAgIHN0cmluZyBuYW1lID0gbV9jbGllbnQuUGxheWVyRGF0YS5OYW1lOwoKICAgICAgICBpZiAoIWRhdGEuQ29udGFpbnNLZXkobmFtZSkpCiAgICAgICAgICAgIGRhdGFbbmFtZV0gPSBuZXcgU2lnbkRhdGEoKTsKCiAgICAgICAgdmFyIGQgPSBkYXRhW25hbWVdOwoKICAgICAgICBpZiAoZC5MYXN0LkRhdGUgPT0gRGF0ZVRpbWUuVG9kYXkpCiAgICAgICAgewogICAgICAgICAgICBTZW5kTWVzc2FnZSgi57O757ufIiwgIuS7iuWkqeW3suetvuWIsCIpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQoKICAgICAgICBpZiAoZC5MYXN0LkRhdGUgPT0gRGF0ZVRpbWUuVG9kYXkuQWRkRGF5cygtMSkpCiAgICAgICAgICAgIGQuQ29udGludW91cysrOwogICAgICAgIGVsc2UKICAgICAgICAgICAgZC5Db250aW51b3VzID0gMTsKCiAgICAgICAgZC5Ub3RhbCsrOwogICAgICAgIGQuTGFzdCA9IERhdGVUaW1lLk5vdzsKICAgICAgICBTYXZlKCk7CgogICAgICAgIFNlbmRNZXNzYWdlKCLns7vnu58iLCAkIuetvuWIsOaIkOWKn++8gei/nue7rXtkLkNvbnRpbnVvdXN95aSp77yM57Sv6K6he2QuVG90YWx95aSpIik7CiAgICB9CgogICAgc3RhdGljIHZvaWQgTG9hZCgpCiAgICB7CiAgICAgICAgaWYgKEZpbGUuRXhpc3RzKHBhdGgpKQogICAgICAgIHsKICAgICAgICAgICAgc3RyaW5nIGpzb24gPSBGaWxlLlJlYWRBbGxUZXh0KHBhdGgpOwogICAgICAgICAgICBkYXRhID0gSnNvbkNvbnZlcnQuRGVzZXJpYWxpemVPYmplY3Q8RGljdGlvbmFyeTxzdHJpbmcsIFNpZ25EYXRhPj4oanNvbik7CiAgICAgICAgfQogICAgfQoKICAgIHN0YXRpYyB2b2lkIFNhdmUoKQogICAgewogICAgICAgIHN0cmluZyBqc29uID0gSnNvbkNvbnZlcnQuU2VyaWFsaXplT2JqZWN0KGRhdGEsIEZvcm1hdHRpbmcuSW5kZW50ZWQpOwogICAgICAgIEZpbGUuV3JpdGVBbGxUZXh0KHBhdGgsIGpzb24pOwogICAgfQp9CgpjbGFzcyBTaWduRGF0YQp7CiAgICBwdWJsaWMgaW50IFRvdGFsOwogICAgcHVibGljIGludCBDb250aW51b3VzOwogICAgcHVibGljIERhdGVUaW1lIExhc3Q7Cn0KYGBgCgojIyDpobnnm67phY3nva7mlofku7YKCuWIm+W7uiBgTXlQbHVnaW4uY3Nwcm9qYO+8mgoKYGBgeG1sCjxQcm9qZWN0IFNkaz0iTWljcm9zb2Z0Lk5FVC5TZGsiPgogIDxQcm9wZXJ0eUdyb3VwPgogICAgPFRhcmdldEZyYW1ld29yaz5uZXQ4LjA8L1RhcmdldEZyYW1ld29yaz4KICAgIDxPdXRwdXRUeXBlPkxpYnJhcnk8L091dHB1dFR5cGU+CiAgPC9Qcm9wZXJ0eUdyb3VwPgogIDxJdGVtR3JvdXA+CiAgICA8UmVmZXJlbmNlIEluY2x1ZGU9IkVuZ2luZSI+CiAgICAgIDxIaW50UGF0aD7muLjmiI/nm67lvZVcRW5naW5lLmRsbDwvSGludFBhdGg+CiAgICA8L1JlZmVyZW5jZT4KICAgIDxSZWZlcmVuY2UgSW5jbHVkZT0iR2FtZUVudGl0eVN5c3RlbSI+CiAgICAgIDxIaW50UGF0aD7muLjmiI/nm67lvZVcR2FtZUVudGl0eVN5c3RlbS5kbGw8L0hpbnRQYXRoPgogICAgPC9SZWZlcmVuY2U+CiAgICA8UmVmZXJlbmNlIEluY2x1ZGU9IkxpdGVOZXRMaWIiPgogICAgICA8SGludFBhdGg+5ri45oiP55uu5b2VXExpdGVOZXRMaWIuZGxsPC9IaW50UGF0aD4KICAgIDwvUmVmZXJlbmNlPgogICAgPFJlZmVyZW5jZSBJbmNsdWRlPSJOZXd0b25zb2Z0Lkpzb24iPgogICAgICA8SGludFBhdGg+5ri45oiP55uu5b2VXE5ld3RvbnNvZnQuSnNvbi5kbGw8L0hpbnRQYXRoPgogICAgPC9SZWZlcmVuY2U+CiAgPC9JdGVtR3JvdXA+CjwvUHJvamVjdD4KYGBgCgojIyDnvJbor5Hlkozlronoo4UKCjEuIOeUqCBWaXN1YWwgU3R1ZGlvIOaIliBgZG90bmV0IGJ1aWxkYCDnvJbor5HvvJsKMi4g5bCGIGAuZGxsYCDlpI3liLbliLDmnI3liqHlmajnmoQgYFBsdWdpbnNgIOaWh+S7tuWkue+8mwozLiDph43lkK/mnI3liqHlmajjgIIKCiMjIOWwj+i0tOWjqwoKMS4gKirku47nroDljZXlvIDlp4sqKu+8muWFiOWGmeasoui/juaPkuS7tua1i+ivleOAggoyLiAqKumAkOatpea3u+WKoCoq77ya56Gu6K6k5Z+656GA5Yqf6IO95q2j5bi45YaN5Yqg5Yqf6IO944CCCjMuICoq5pys5Zyw5rWL6K+VKirvvJrmtYvor5XmsqHpl67popjlho3mlL7mraPlvI/mnI3jgIIKNC4gKirkv53nlZnml6Xlv5cqKu+8mueUqCBgQ29uc29sZS5Xcml0ZUxpbmVgIOaIliBgTG9nLkluZm9ybWF0aW9uYCDosIPor5XjgIIK
