外观
命令系统
继承 AbstractProcessCmd 创建自定义命令。服务端会自动扫描并注册 DLL 中所有非抽象的 AbstractProcessCmd 子类。
命名空间差异
- 社区源码构建(
sc2.2network):using Game.Server;中的AbstractProcessCmd。 - 发行 DLL 构建(插件站):
using Game.Server.EssentialCmd;中的AbstractProcessCmd。
下文示例以发行构建写法为例,使用 Game.Server.EssentialCmd;若你用源码构建,把该 using 改为 Game.Server 即可,其余代码一致。
创建一个命令
csharp
using Game.Server.EssentialCmd;
public class HelloCommand : AbstractProcessCmd
{
public override string Cmd => "hello"; // 命令名(玩家输入 /hello)
public override string Introduce => "打招呼"; // 命令介绍
public override int AuthLevel => 0; // 0=所有人可用,1=管理员
public override DisplayType Display => DisplayType.Private;
public override void ProcessCmd()
{
SendMessage("系统", "你好!");
}
}命令属性说明
| 属性 | 类型 | 说明 |
|---|---|---|
Cmd | string | 命令名称,不含 / |
Introduce | string | 命令帮助说明 |
AuthLevel | int | 权限等级:0=所有人,1=管理员 |
Display | DisplayType | 帮助中是否可见(All/Authority/NoDisplay) |
获取命令参数
csharp
public override void ProcessCmd()
{
// m_messageDatas 是参数数组
// m_messageDatas[0] 是命令本身
// m_messageDatas[1] 是第一个参数
if (m_messageDatas.Length < 2)
{
SendMessage("系统", "用法: /hello <名字>");
return;
}
string name = m_messageDatas[1];
SendMessage("系统", $"你好,{name}!");
}判断是否为控制台
csharp
public override void ProcessCmd()
{
if (m_isTerminal)
{
SendMessage("系统", "控制台不能使用此命令");
return;
}
// 获取发送命令的玩家
ComponentPlayer player = m_client.PlayerData.ComponentPlayer;
}m_isTerminal:是否为服务端终端触发。m_client:触发命令的客户端对象,从中可取PlayerData与ComponentPlayer。SendMessage(title, message):向触发者发消息,标题通常填"系统"。它是AbstractProcessCmd提供的便捷方法,对应底层MessagePackage。
完整示例:传送命令
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 targetPos = target.ComponentBody.Position;
// 传送
me.ComponentBody.Position = targetPos;
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;
}
}多参数命令
csharp
public override void ProcessCmd()
{
if (m_messageDatas.Length < 3)
{
SendMessage("系统", "用法: /give <玩家> <物品ID> [数量]");
return;
}
string playerName = m_messageDatas[1];
if (!int.TryParse(m_messageDatas[2], out int itemId))
{
SendMessage("系统", "物品ID必须是数字");
return;
}
int count = 1;
if (m_messageDatas.Length > 3)
{
int.TryParse(m_messageDatas[3], out count);
}
// 执行给予物品逻辑...
SendMessage("系统", $"已给予 {playerName} {count} 个物品({itemId})");
}管理员命令
设置 AuthLevel = 1 限制只有管理员能用:
csharp
public class KickCommand : AbstractProcessCmd
{
public override string Cmd => "kick";
public override string Introduce => "/kick <玩家> [原因] - 踢出玩家";
public override int AuthLevel => 1; // 只有管理员能用
public override DisplayType Display => DisplayType.Private;
public override void ProcessCmd()
{
if (m_messageDatas.Length < 2)
{
SendMessage("系统", "用法: /kick <玩家> [原因]");
return;
}
string playerName = m_messageDatas[1];
string reason = m_messageDatas.Length > 2
? string.Join(" ", m_messageDatas.Skip(2))
: "被管理员踢出";
// 踢人逻辑...
}
}常用代码片段
检查游戏状态
csharp
if (GameManager.Project == null)
{
SendMessage("系统", "请先进入游戏");
return;
}获取在线玩家列表
csharp
var players = GameManager.Project.FindSubsystem<SubsystemPlayers>();
foreach (var p in players.ComponentPlayers)
{
string name = p.PlayerData.Name;
// 处理每个玩家...
}解析数字参数
csharp
if (!int.TryParse(m_messageDatas[1], out int number))
{
SendMessage("系统", "请输入有效的数字");
return;
}设计建议
命令类继承 AbstractProcessCmd,设计时至少考虑:
AuthLevel权限等级;DisplayType是否在帮助中可见;- 参数缺失和非法输入;
- 玩家上下文与控制台上下文(
m_isTerminal); - 是否支持
GetSuggestions自动补全; - 长耗时任务不能阻塞主循环。
更多事件与命令的"需求→接口"映射见 事件与命令路线图。
IyDlkb3ku6Tns7vnu58KCue7p+aJvyBgQWJzdHJhY3RQcm9jZXNzQ21kYCDliJvlu7roh6rlrprkuYnlkb3ku6TjgILmnI3liqHnq6/kvJroh6rliqjmiavmj4/lubbms6jlhowgRExMIOS4reaJgOaciemdnuaKveixoeeahCBgQWJzdHJhY3RQcm9jZXNzQ21kYCDlrZDnsbvjgIIKCjo6OiB3YXJuaW5nIOWRveWQjeepuumXtOW3ruW8ggotIOekvuWMuua6kOeggeaehOW7uu+8iGBzYzIuMm5ldHdvcmtg77yJ77yaYHVzaW5nIEdhbWUuU2VydmVyO2Ag5Lit55qEIGBBYnN0cmFjdFByb2Nlc3NDbWRg44CCCi0g5Y+R6KGMIERMTCDmnoTlu7rvvIjmj5Lku7bnq5nvvInvvJpgdXNpbmcgR2FtZS5TZXJ2ZXIuRXNzZW50aWFsQ21kO2Ag5Lit55qEIGBBYnN0cmFjdFByb2Nlc3NDbWRg44CCCgrkuIvmlofnpLrkvovku6Xlj5HooYzmnoTlu7rlhpnms5XkuLrkvovvvIzkvb/nlKggYEdhbWUuU2VydmVyLkVzc2VudGlhbENtZGDvvJvoi6XkvaDnlKjmupDnoIHmnoTlu7rvvIzmioror6UgYHVzaW5nYCDmlLnkuLogYEdhbWUuU2VydmVyYCDljbPlj6/vvIzlhbbkvZnku6PnoIHkuIDoh7TjgIIKOjo6CgojIyDliJvlu7rkuIDkuKrlkb3ku6QKCmBgYGNzaGFycAp1c2luZyBHYW1lLlNlcnZlci5Fc3NlbnRpYWxDbWQ7CgpwdWJsaWMgY2xhc3MgSGVsbG9Db21tYW5kIDogQWJzdHJhY3RQcm9jZXNzQ21kCnsKICAgIHB1YmxpYyBvdmVycmlkZSBzdHJpbmcgQ21kID0+ICJoZWxsbyI7ICAgICAgICAgICAvLyDlkb3ku6TlkI3vvIjnjqnlrrbovpPlhaUgL2hlbGxv77yJCiAgICBwdWJsaWMgb3ZlcnJpZGUgc3RyaW5nIEludHJvZHVjZSA9PiAi5omT5oub5ZG8IjsgICAgIC8vIOWRveS7pOS7i+e7jQogICAgcHVibGljIG92ZXJyaWRlIGludCBBdXRoTGV2ZWwgPT4gMDsgICAgICAgICAgICAgIC8vIDA95omA5pyJ5Lq65Y+v55So77yMMT3nrqHnkIblkZgKICAgIHB1YmxpYyBvdmVycmlkZSBEaXNwbGF5VHlwZSBEaXNwbGF5ID0+IERpc3BsYXlUeXBlLlByaXZhdGU7CgogICAgcHVibGljIG92ZXJyaWRlIHZvaWQgUHJvY2Vzc0NtZCgpCiAgICB7CiAgICAgICAgU2VuZE1lc3NhZ2UoIuezu+e7nyIsICLkvaDlpb3vvIEiKTsKICAgIH0KfQpgYGAKCiMjIOWRveS7pOWxnuaAp+ivtOaYjgoKfCDlsZ7mgKcgfCDnsbvlnosgfCDor7TmmI4gfAp8IC0tLSB8IC0tLSB8IC0tLSB8CnwgYENtZGAgfCBgc3RyaW5nYCB8IOWRveS7pOWQjeensO+8jOS4jeWQqyBgL2AgfAp8IGBJbnRyb2R1Y2VgIHwgYHN0cmluZ2AgfCDlkb3ku6TluK7liqnor7TmmI4gfAp8IGBBdXRoTGV2ZWxgIHwgYGludGAgfCDmnYPpmZDnrYnnuqfvvJpgMGA95omA5pyJ5Lq677yMYDFgPeeuoeeQhuWRmCB8CnwgYERpc3BsYXlgIHwgYERpc3BsYXlUeXBlYCB8IOW4ruWKqeS4reaYr+WQpuWPr+inge+8iGBBbGxgL2BBdXRob3JpdHlgL2BOb0Rpc3BsYXlg77yJIHwKCiMjIOiOt+WPluWRveS7pOWPguaVsAoKYGBgY3NoYXJwCnB1YmxpYyBvdmVycmlkZSB2b2lkIFByb2Nlc3NDbWQoKQp7CiAgICAvLyBtX21lc3NhZ2VEYXRhcyDmmK/lj4LmlbDmlbDnu4QKICAgIC8vIG1fbWVzc2FnZURhdGFzWzBdIOaYr+WRveS7pOacrOi6qwogICAgLy8gbV9tZXNzYWdlRGF0YXNbMV0g5piv56ys5LiA5Liq5Y+C5pWwCgogICAgaWYgKG1fbWVzc2FnZURhdGFzLkxlbmd0aCA8IDIpCiAgICB7CiAgICAgICAgU2VuZE1lc3NhZ2UoIuezu+e7nyIsICLnlKjms5U6IC9oZWxsbyA85ZCN5a2XPiIpOwogICAgICAgIHJldHVybjsKICAgIH0KCiAgICBzdHJpbmcgbmFtZSA9IG1fbWVzc2FnZURhdGFzWzFdOwogICAgU2VuZE1lc3NhZ2UoIuezu+e7nyIsICQi5L2g5aW977yMe25hbWV977yBIik7Cn0KYGBgCgojIyDliKTmlq3mmK/lkKbkuLrmjqfliLblj7AKCmBgYGNzaGFycApwdWJsaWMgb3ZlcnJpZGUgdm9pZCBQcm9jZXNzQ21kKCkKewogICAgaWYgKG1faXNUZXJtaW5hbCkKICAgIHsKICAgICAgICBTZW5kTWVzc2FnZSgi57O757ufIiwgIuaOp+WItuWPsOS4jeiDveS9v+eUqOatpOWRveS7pCIpOwogICAgICAgIHJldHVybjsKICAgIH0KCiAgICAvLyDojrflj5blj5HpgIHlkb3ku6TnmoTnjqnlrrYKICAgIENvbXBvbmVudFBsYXllciBwbGF5ZXIgPSBtX2NsaWVudC5QbGF5ZXJEYXRhLkNvbXBvbmVudFBsYXllcjsKfQpgYGAKCi0gYG1faXNUZXJtaW5hbGDvvJrmmK/lkKbkuLrmnI3liqHnq6/nu4jnq6/op6blj5HjgIIKLSBgbV9jbGllbnRg77ya6Kem5Y+R5ZG95Luk55qE5a6i5oi356uv5a+56LGh77yM5LuO5Lit5Y+v5Y+WIGBQbGF5ZXJEYXRhYCDkuI4gYENvbXBvbmVudFBsYXllcmDjgIIKLSBgU2VuZE1lc3NhZ2UodGl0bGUsIG1lc3NhZ2UpYO+8muWQkeinpuWPkeiAheWPkea2iOaBr++8jOagh+mimOmAmuW4uOWhqyBgIuezu+e7nyJg44CC5a6D5pivIGBBYnN0cmFjdFByb2Nlc3NDbWRgIOaPkOS+m+eahOS+v+aNt+aWueazle+8jOWvueW6lOW6leWxgiBgTWVzc2FnZVBhY2thZ2Vg44CCCgojIyDlrozmlbTnpLrkvovvvJrkvKDpgIHlkb3ku6QKCmBgYGNzaGFycAp1c2luZyBTeXN0ZW07CnVzaW5nIEVuZ2luZTsKdXNpbmcgR2FtZS5TZXJ2ZXIuRXNzZW50aWFsQ21kOwp1c2luZyBHYW1lLk5ldFdvcms7CnVzaW5nIEdhbWUuTmV0V29yay5QYWNrYWdlczsKCnB1YmxpYyBjbGFzcyBUcENvbW1hbmQgOiBBYnN0cmFjdFByb2Nlc3NDbWQKewogICAgcHVibGljIG92ZXJyaWRlIHN0cmluZyBDbWQgPT4gInRwIjsKICAgIHB1YmxpYyBvdmVycmlkZSBzdHJpbmcgSW50cm9kdWNlID0+ICIvdHAgPOeOqeWutuWQjT4gLSDkvKDpgIHliLDnjqnlrrbouqvovrkiOwogICAgcHVibGljIG92ZXJyaWRlIGludCBBdXRoTGV2ZWwgPT4gMDsKICAgIHB1YmxpYyBvdmVycmlkZSBEaXNwbGF5VHlwZSBEaXNwbGF5ID0+IERpc3BsYXlUeXBlLlByaXZhdGU7CgogICAgcHVibGljIG92ZXJyaWRlIHZvaWQgUHJvY2Vzc0NtZCgpCiAgICB7CiAgICAgICAgLy8g5qOA5p+l5ri45oiP5piv5ZCm5Yqg6L29CiAgICAgICAgaWYgKEdhbWVNYW5hZ2VyLlByb2plY3QgPT0gbnVsbCkKICAgICAgICB7CiAgICAgICAgICAgIFNlbmRNZXNzYWdlKCLns7vnu58iLCAi6K+35YWI6L+b5YWl5ri45oiPIik7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CgogICAgICAgIC8vIOaOp+WItuWPsOajgOafpQogICAgICAgIGlmIChtX2lzVGVybWluYWwpCiAgICAgICAgewogICAgICAgICAgICBTZW5kTWVzc2FnZSgi57O757ufIiwgIuaOp+WItuWPsOS4jeiDveS8oOmAgSIpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQoKICAgICAgICAvLyDlj4LmlbDmo4Dmn6UKICAgICAgICBpZiAobV9tZXNzYWdlRGF0YXMuTGVuZ3RoIDwgMikKICAgICAgICB7CiAgICAgICAgICAgIFNlbmRNZXNzYWdlKCLns7vnu58iLCAi55So5rOVOiAvdHAgPOeOqeWutuWQjT4iKTsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KCiAgICAgICAgc3RyaW5nIHRhcmdldE5hbWUgPSBtX21lc3NhZ2VEYXRhc1sxXTsKCiAgICAgICAgLy8g5p+l5om+55uu5qCH546p5a62CiAgICAgICAgQ29tcG9uZW50UGxheWVyIHRhcmdldCA9IEZpbmRQbGF5ZXIodGFyZ2V0TmFtZSk7CiAgICAgICAgaWYgKHRhcmdldCA9PSBudWxsKQogICAgICAgIHsKICAgICAgICAgICAgU2VuZE1lc3NhZ2UoIuezu+e7nyIsICQi546p5a62IHt0YXJnZXROYW1lfSDkuI3lnKjnur8iKTsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KCiAgICAgICAgLy8g6I635Y+W6Ieq5bex55qE546p5a625a+56LGhCiAgICAgICAgQ29tcG9uZW50UGxheWVyIG1lID0gbV9jbGllbnQuUGxheWVyRGF0YS5Db21wb25lbnRQbGF5ZXI7CgogICAgICAgIC8vIOiOt+WPluebruagh+S9jee9rgogICAgICAgIFZlY3RvcjMgdGFyZ2V0UG9zID0gdGFyZ2V0LkNvbXBvbmVudEJvZHkuUG9zaXRpb247CgogICAgICAgIC8vIOS8oOmAgQogICAgICAgIG1lLkNvbXBvbmVudEJvZHkuUG9zaXRpb24gPSB0YXJnZXRQb3M7CiAgICAgICAgQ29tbW9uTGliLk5ldC5RdWV1ZVBhY2thZ2UobmV3IENvbXBvbmVudFBsYXllclBhY2thZ2UobWUsIChQbGF5ZXJBY3Rpb24pMTIpKTsKCiAgICAgICAgU2VuZE1lc3NhZ2UoIuezu+e7nyIsICQi5bey5Lyg6YCB5YiwIHt0YXJnZXROYW1lfSIpOwogICAgfQoKICAgIC8vIOafpeaJvueOqeWutueahOi+heWKqeaWueazlQogICAgQ29tcG9uZW50UGxheWVyIEZpbmRQbGF5ZXIoc3RyaW5nIG5hbWUpCiAgICB7CiAgICAgICAgdmFyIHBsYXllcnMgPSBHYW1lTWFuYWdlci5Qcm9qZWN0LkZpbmRTdWJzeXN0ZW08U3Vic3lzdGVtUGxheWVycz4oKTsKICAgICAgICBmb3JlYWNoICh2YXIgcCBpbiBwbGF5ZXJzLkNvbXBvbmVudFBsYXllcnMpCiAgICAgICAgewogICAgICAgICAgICBpZiAocC5QbGF5ZXJEYXRhLk5hbWUuRXF1YWxzKG5hbWUsIFN0cmluZ0NvbXBhcmlzb24uT3JkaW5hbElnbm9yZUNhc2UpKQogICAgICAgICAgICAgICAgcmV0dXJuIHA7CiAgICAgICAgfQogICAgICAgIHJldHVybiBudWxsOwogICAgfQp9CmBgYAoKIyMg5aSa5Y+C5pWw5ZG95LukCgpgYGBjc2hhcnAKcHVibGljIG92ZXJyaWRlIHZvaWQgUHJvY2Vzc0NtZCgpCnsKICAgIGlmIChtX21lc3NhZ2VEYXRhcy5MZW5ndGggPCAzKQogICAgewogICAgICAgIFNlbmRNZXNzYWdlKCLns7vnu58iLCAi55So5rOVOiAvZ2l2ZSA8546p5a62PiA854mp5ZOBSUQ+IFvmlbDph49dIik7CiAgICAgICAgcmV0dXJuOwogICAgfQoKICAgIHN0cmluZyBwbGF5ZXJOYW1lID0gbV9tZXNzYWdlRGF0YXNbMV07CgogICAgaWYgKCFpbnQuVHJ5UGFyc2UobV9tZXNzYWdlRGF0YXNbMl0sIG91dCBpbnQgaXRlbUlkKSkKICAgIHsKICAgICAgICBTZW5kTWVzc2FnZSgi57O757ufIiwgIueJqeWTgUlE5b+F6aG75piv5pWw5a2XIik7CiAgICAgICAgcmV0dXJuOwogICAgfQoKICAgIGludCBjb3VudCA9IDE7CiAgICBpZiAobV9tZXNzYWdlRGF0YXMuTGVuZ3RoID4gMykKICAgIHsKICAgICAgICBpbnQuVHJ5UGFyc2UobV9tZXNzYWdlRGF0YXNbM10sIG91dCBjb3VudCk7CiAgICB9CgogICAgLy8g5omn6KGM57uZ5LqI54mp5ZOB6YC76L6RLi4uCiAgICBTZW5kTWVzc2FnZSgi57O757ufIiwgJCLlt7Lnu5nkuogge3BsYXllck5hbWV9IHtjb3VudH0g5Liq54mp5ZOBKHtpdGVtSWR9KSIpOwp9CmBgYAoKIyMg566h55CG5ZGY5ZG95LukCgrorr7nva4gYEF1dGhMZXZlbCA9IDFgIOmZkOWItuWPquacieeuoeeQhuWRmOiDveeUqO+8mgoKYGBgY3NoYXJwCnB1YmxpYyBjbGFzcyBLaWNrQ29tbWFuZCA6IEFic3RyYWN0UHJvY2Vzc0NtZAp7CiAgICBwdWJsaWMgb3ZlcnJpZGUgc3RyaW5nIENtZCA9PiAia2ljayI7CiAgICBwdWJsaWMgb3ZlcnJpZGUgc3RyaW5nIEludHJvZHVjZSA9PiAiL2tpY2sgPOeOqeWutj4gW+WOn+WboF0gLSDouKLlh7rnjqnlrrYiOwogICAgcHVibGljIG92ZXJyaWRlIGludCBBdXRoTGV2ZWwgPT4gMTsgIC8vIOWPquacieeuoeeQhuWRmOiDveeUqAogICAgcHVibGljIG92ZXJyaWRlIERpc3BsYXlUeXBlIERpc3BsYXkgPT4gRGlzcGxheVR5cGUuUHJpdmF0ZTsKCiAgICBwdWJsaWMgb3ZlcnJpZGUgdm9pZCBQcm9jZXNzQ21kKCkKICAgIHsKICAgICAgICBpZiAobV9tZXNzYWdlRGF0YXMuTGVuZ3RoIDwgMikKICAgICAgICB7CiAgICAgICAgICAgIFNlbmRNZXNzYWdlKCLns7vnu58iLCAi55So5rOVOiAva2ljayA8546p5a62PiBb5Y6f5ZugXSIpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQoKICAgICAgICBzdHJpbmcgcGxheWVyTmFtZSA9IG1fbWVzc2FnZURhdGFzWzFdOwogICAgICAgIHN0cmluZyByZWFzb24gPSBtX21lc3NhZ2VEYXRhcy5MZW5ndGggPiAyCiAgICAgICAgICAgID8gc3RyaW5nLkpvaW4oIiAiLCBtX21lc3NhZ2VEYXRhcy5Ta2lwKDIpKQogICAgICAgICAgICA6ICLooqvnrqHnkIblkZjouKLlh7oiOwoKICAgICAgICAvLyDouKLkurrpgLvovpEuLi4KICAgIH0KfQpgYGAKCiMjIOW4uOeUqOS7o+eggeeJh+autQoKIyMjIOajgOafpea4uOaIj+eKtuaAgQoKYGBgY3NoYXJwCmlmIChHYW1lTWFuYWdlci5Qcm9qZWN0ID09IG51bGwpCnsKICAgIFNlbmRNZXNzYWdlKCLns7vnu58iLCAi6K+35YWI6L+b5YWl5ri45oiPIik7CiAgICByZXR1cm47Cn0KYGBgCgojIyMg6I635Y+W5Zyo57q/546p5a625YiX6KGoCgpgYGBjc2hhcnAKdmFyIHBsYXllcnMgPSBHYW1lTWFuYWdlci5Qcm9qZWN0LkZpbmRTdWJzeXN0ZW08U3Vic3lzdGVtUGxheWVycz4oKTsKZm9yZWFjaCAodmFyIHAgaW4gcGxheWVycy5Db21wb25lbnRQbGF5ZXJzKQp7CiAgICBzdHJpbmcgbmFtZSA9IHAuUGxheWVyRGF0YS5OYW1lOwogICAgLy8g5aSE55CG5q+P5Liq546p5a62Li4uCn0KYGBgCgojIyMg6Kej5p6Q5pWw5a2X5Y+C5pWwCgpgYGBjc2hhcnAKaWYgKCFpbnQuVHJ5UGFyc2UobV9tZXNzYWdlRGF0YXNbMV0sIG91dCBpbnQgbnVtYmVyKSkKewogICAgU2VuZE1lc3NhZ2UoIuezu+e7nyIsICLor7fovpPlhaXmnInmlYjnmoTmlbDlrZciKTsKICAgIHJldHVybjsKfQpgYGAKCiMjIOiuvuiuoeW7uuiurgoK5ZG95Luk57G757un5om/IGBBYnN0cmFjdFByb2Nlc3NDbWRg77yM6K6+6K6h5pe26Iez5bCR6ICD6JmR77yaCgotIGBBdXRoTGV2ZWxgIOadg+mZkOetiee6p++8mwotIGBEaXNwbGF5VHlwZWAg5piv5ZCm5Zyo5biu5Yqp5Lit5Y+v6KeB77ybCi0g5Y+C5pWw57y65aSx5ZKM6Z2e5rOV6L6T5YWl77ybCi0g546p5a625LiK5LiL5paH5LiO5o6n5Yi25Y+w5LiK5LiL5paH77yIYG1faXNUZXJtaW5hbGDvvInvvJsKLSDmmK/lkKbmlK/mjIEgYEdldFN1Z2dlc3Rpb25zYCDoh6rliqjooaXlhajvvJsKLSDplb/ogJfml7bku7vliqHkuI3og73pmLvloZ7kuLvlvqrnjq/jgIIKCuabtOWkmuS6i+S7tuS4juWRveS7pOeahCLpnIDmsYLihpLmjqXlj6Mi5pig5bCE6KeBIFvkuovku7bkuI7lkb3ku6Tot6/nur/lm75dKC9kZXZlbG9wZXIvc2VydmVyLXBsdWdpbnMvZXZlbnRzLWNvbW1hbmRzKeOAggo=
