From 894ee79ebc812c52d195adee3c2e432250bc2acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BE=BD=E5=AD=A6?= <1242509682@qq.com> Date: Sun, 14 Apr 2024 08:18:21 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=EF=BC=9A?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=8C=85=E6=8B=A6=E6=88=AA=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PacketsStop/Configuration.cs | 73 ++++++++++++ PacketsStop/PacketsStop.cs | 210 +++++++++++++++++++++++++++++++++ PacketsStop/PacketsStop.csproj | 3 + PacketsStop/README.md | 54 +++++++++ README.md | 1 + 5 files changed, 341 insertions(+) create mode 100644 PacketsStop/Configuration.cs create mode 100644 PacketsStop/PacketsStop.cs create mode 100644 PacketsStop/PacketsStop.csproj create mode 100644 PacketsStop/README.md diff --git a/PacketsStop/Configuration.cs b/PacketsStop/Configuration.cs new file mode 100644 index 000000000..ae91dc0d4 --- /dev/null +++ b/PacketsStop/Configuration.cs @@ -0,0 +1,73 @@ +using Newtonsoft.Json; +using TShockAPI; + +namespace PacketsStop +{ + public class Configuration + { + [JsonProperty("数据包名可查看")] + public string README = "https://github.com/Pryaxis/TSAPI/blob/general-devel/TerrariaServerAPI/TerrariaApi.Server/PacketTypes.cs"; + + [JsonProperty("插件指令与权限名")] + public string README2 = "拦截"; + + [JsonProperty("第一次使用输这个")] + public string README3 = "/group addperm default 免拦截"; + + [JsonProperty("拦截的数据包名")] + public HashSet Packets { get; set; } = new HashSet(); + + public static readonly string FilePath = Path.Combine(TShock.SavePath, "数据包拦截.json"); + + + public Configuration() + { + Packets = new HashSet + { + "ConnectRequest", + "Disconnect", + "ContinueConnecting", + "ContinueConnecting2", + "PlayerInfo", + "PlayerSlot", + "TileGetSection", + "PlayerSpawn", + "ProjectileNew", + "ProjectileDestroy", + "SyncProjectileTrackers", + }; + } + + public void Write(string path) + { + using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write)) + { + var str = JsonConvert.SerializeObject(this, Formatting.Indented); + using (var sw = new StreamWriter(fs)) + { + sw.Write(str); + } + } + } + + public static Configuration Read(string path) + { + if (!File.Exists(path)) + { + var defaultConfig = new Configuration(); + defaultConfig.Write(path); + return defaultConfig; + } + else + { + using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var sr = new StreamReader(fs)) + { + var json = sr.ReadToEnd(); + var cf = JsonConvert.DeserializeObject(json); + return cf; + } + } + } + } +} diff --git a/PacketsStop/PacketsStop.cs b/PacketsStop/PacketsStop.cs new file mode 100644 index 000000000..02a648bcf --- /dev/null +++ b/PacketsStop/PacketsStop.cs @@ -0,0 +1,210 @@ +using Terraria; +using TerrariaApi.Server; +using TShockAPI; +using TShockAPI.Hooks; + +namespace PacketsStop +{ + [ApiVersion(2, 1)] + public class PacketsStop : TerrariaPlugin + { + + public override string Name => "数据包拦截 PacketsStop"; + public override Version Version => new Version(1, 0, 0); + public override string Author => "羽学 感谢少司命"; + public override string Description => "拦截没有指定权限的用户组数据包"; + + #region 配置方法的工具 + private readonly Dictionary> countDictionary = new Dictionary>(); + private readonly object lockObject = new object(); + private const double PacketInterval = 1000.0; + private bool _Enabled = false; + internal static Configuration Config; + private HashSet Packets; + #endregion + + public PacketsStop(Main game) : base(game) + { + Config = new Configuration(); + } + + public override void Initialize() + { + LoadConfig(); + Packets = GetPackets(); + ServerApi.Hooks.NetGetData.Register(this, OnGetData, int.MaxValue); + Commands.ChatCommands.Add(new Command("拦截", Command, "拦截")); + GeneralHooks.ReloadEvent += LoadConfig; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + ServerApi.Hooks.NetGetData.Deregister(this, OnGetData); + } + base.Dispose(disposing); + } + + #region 配置文件创建与重读加载方法 + private static void LoadConfig(ReloadEventArgs args = null) + { + if (!File.Exists(Configuration.FilePath)) + { + var defaultConfig = new Configuration(); + defaultConfig.Write(Configuration.FilePath); + } + else + { + Config = Configuration.Read(Configuration.FilePath); + } + + if (args != null && args.Player != null) + { + args.Player.SendSuccessMessage("[数据包拦截]重新加载配置完毕。"); + } + } + #endregion + + #region 指令 + + + private void Command(CommandArgs args) + { + // 确保玩家不为null且具有相应权限 + if (args.Player != null && !args.Player.HasPermission("拦截")) + { + args.Player.SendErrorMessage("你没有使用数据包拦截的权限"); + return; + } + + _Enabled = !_Enabled; + args.Player.SendSuccessMessage($"数据包处理已{(_Enabled ? "启用" : "禁用")}"); + + if (args.Parameters.Count != 2) + { + args.Player.SendInfoMessage("/拦截 add 玩家名 - 将玩家添加到LJ组(不存在自动创建)。\n/拦截 del 玩家名 - 将玩家从LJ组移除并设为default组。"); + return; + } + + string Action = args.Parameters[0]; + string Name = args.Parameters[1]; + var Account = TShock.UserAccounts.GetUserAccountByName(Name); + + if (Account == null) + { + args.Player.SendInfoMessage($"无法找到名为'{Name}'的在线玩家。"); + return; + } + + switch (Action.ToLower()) + { + case "add": + if (!TShock.Groups.GroupExists("LJ")) + { + TShock.Groups.AddGroup("LJ", "", "tshock.canchat,tshock,tshock.partychat,tshock.sendemoji", "045,235,203"); + args.Player.SendSuccessMessage("LJ组已创建。"); + } + + try + { + TShock.UserAccounts.SetUserGroup(Account, "LJ"); + args.Player.SendSuccessMessage($"{Name}已被设为LJ组成员。"); + } + catch (Exception ex) + { + args.Player.SendErrorMessage($"无法将{Name}设为LJ组成员。错误信息: \n{ex.Message}"); + } + break; + case "del": + try + { + TShock.UserAccounts.SetUserGroup(Account, "default"); + args.Player.SendSuccessMessage($"{Name}已从LJ组移除,并被设为default组。"); + } + catch (Exception ex) + { + args.Player.SendErrorMessage($"无法将{Name}从LJ组移除或设为default组。错误信息: \n{ex.Message}"); + } + break; + default: + args.Player.SendInfoMessage("无效的子命令。使用 'add' 或 'del'。"); + break; + } + } + #endregion + + #region 获取数据包方法 + private void OnGetData(GetDataEventArgs args) + { + TSPlayer player = TShock.Players[args.Msg.whoAmI]; + + if (!_Enabled) + { + return; + } + + if (!player.HasPermission("免拦截")) + { + if (!Packets.Contains(args.MsgID)) + { + args.Handled = true; + } + else + { + HandlePacket(player, args.MsgID); + } + } + } + + private HashSet GetPackets() + { + HashSet Packets = new HashSet(); + foreach (string packetName in Config.Packets) + { + if (Enum.TryParse(packetName, out PacketTypes packetType)) + { + Packets.Add(packetType); + } + else + { + TShock.Log.Error($"无法识别的数据包类型名称: {packetName}"); + } + } + return Packets; + } + #endregion + + #region 处理数据包方法 + private void HandlePacket(TSPlayer tsplayer, PacketTypes packetType) + { + if (_Enabled) + { + lock (lockObject) + { + DateTime now = DateTime.Now; + if (tsplayer.Name != null) + { + if (!countDictionary.TryGetValue(tsplayer.Name, out var packetDictionary)) + { + packetDictionary = new Dictionary(); + countDictionary[tsplayer.Name] = packetDictionary; + } + if (packetDictionary.TryGetValue(packetType, out DateTime lastPacketTime)) + { + if ((now - lastPacketTime).TotalMilliseconds >= PacketInterval) + { + packetDictionary[packetType] = now; + } + } + else + { + packetDictionary[packetType] = now; + } + } + } + } + } + #endregion + } +} \ No newline at end of file diff --git a/PacketsStop/PacketsStop.csproj b/PacketsStop/PacketsStop.csproj new file mode 100644 index 000000000..91316f375 --- /dev/null +++ b/PacketsStop/PacketsStop.csproj @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/PacketsStop/README.md b/PacketsStop/README.md new file mode 100644 index 000000000..41e39fb7e --- /dev/null +++ b/PacketsStop/README.md @@ -0,0 +1,54 @@ +# PacketsStop 数据包拦截 + +- 作者: 羽学 +- 出处: [github](https://github.com/1242509682/PacketsStop/) +- 插件源码来于少司命的游客限制插件,将其处理数据包方法做成了一个独立的功能插件 +- 这是一个Tshock服务器插件主要用于: +- 使用指令开启拦截玩家数据包 +- 使用前必须先给default组一个权限【免拦截】 +- 接着通过修改配置文件添加数据包名使用/reload重载 +- 输入【/拦截 add 名字】将玩家分配到一个新建的【LJ组】 +- 封锁了大部分可用权限并对其数据包拦截。 +## 更新日志 + +``` +- 0.5 +- 修复未释放钩子导致关闭服务器时的报错 +- 0.4 +- 适配.net 6.0 +- 加了中文命令,并添加了一个权限名 +``` +## 指令 + +| 语法 | 权限 | 说明 | +| -------------- | :-----------------: | :------: | +| /拦截 | 拦截 | 开启功能 | +| /拦截 add 玩家名 | 拦截 |添加拦截指定玩家并分配到一个自动创建的LJ组| +| /拦截 del 玩家名 | 拦截 |移除拦截指定玩家并分配回default组| +| 无 | 免拦截 | 不受插件数据包拦截影响 | + +## 配置 + +```json +{ + "数据包名可查看": "https://github.com/Pryaxis/TSAPI/blob/general-devel/TerrariaServerAPI/TerrariaApi.Server/PacketTypes.cs", + "插件指令与权限名": "拦截", + "第一次使用输这个": "/group addperm default 免拦截", + "拦截的数据包名": [ + "ConnectRequest", + "Disconnect", + "ContinueConnecting", + "ContinueConnecting2", + "PlayerInfo", + "PlayerSlot", + "TileGetSection", + "PlayerSpawn", + "ProjectileNew", + "ProjectileDestroy", + "SyncProjectileTrackers" + ] +} +``` +## 反馈 +- 共同维护的插件库:https://github.com/THEXN/TShockPlugin/ +- 国内社区trhub.cn 或 TShock官方群等 \ No newline at end of file diff --git a/README.md b/README.md index 88b5da066..855548a30 100644 --- a/README.md +++ b/README.md @@ -53,3 +53,4 @@ | [RegionView](https://github.com/Controllerdestiny/TShockPlugin/tree/master/RegionView) | 显示区域边界 | 无 | | [Noagent](https://github.com/Controllerdestiny/TShockPlugin/tree/master/Noagent) | 禁止代理ip进入 | 无 | | [SwitchCommands](https://github.com/Controllerdestiny/TShockPlugin/tree/master/SwitchCommands) | 区域执行指令 | 无 | +| [PacketsStop](https://github.com/Controllerdestiny/TShockPlugin/tree/master/PacketsStop) | 数据包拦截 | 无 | From 19fcf6484828e20c5c06e305c799d905e355fad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BE=BD=E5=AD=A6?= <1242509682@qq.com> Date: Sun, 14 Apr 2024 18:11:16 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=8C=85=E6=8B=A6=E6=88=AA=E6=8F=92=E4=BB=B6=E7=9A=84GetPacket?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=9A=E5=8E=9F=E5=AF=B9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=86=85=E7=9A=84=E6=95=B0=E6=8D=AE=E5=8C=85?= =?UTF-8?q?=E5=90=8D=E4=BB=A5=E5=A4=96=E7=9A=84=E5=85=A8=E9=83=A8=E6=8B=A6?= =?UTF-8?q?=E6=88=AA=E9=97=AE=E9=A2=98=E5=B7=B2=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PacketsStop/PacketsStop.cs | 52 ++++++++++++++++---------------------- PacketsStop/README.md | 9 +++---- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/PacketsStop/PacketsStop.cs b/PacketsStop/PacketsStop.cs index 02a648bcf..0335f35ba 100644 --- a/PacketsStop/PacketsStop.cs +++ b/PacketsStop/PacketsStop.cs @@ -16,7 +16,6 @@ public class PacketsStop : TerrariaPlugin #region 配置方法的工具 private readonly Dictionary> countDictionary = new Dictionary>(); - private readonly object lockObject = new object(); private const double PacketInterval = 1000.0; private bool _Enabled = false; internal static Configuration Config; @@ -71,15 +70,17 @@ private static void LoadConfig(ReloadEventArgs args = null) private void Command(CommandArgs args) { - // 确保玩家不为null且具有相应权限 if (args.Player != null && !args.Player.HasPermission("拦截")) { args.Player.SendErrorMessage("你没有使用数据包拦截的权限"); return; } + else + { + _Enabled = !_Enabled; + TSPlayer.All.SendInfoMessage($"[数据包拦截]已{(_Enabled ? "启用" : "禁用")}"); + } - _Enabled = !_Enabled; - args.Player.SendSuccessMessage($"数据包处理已{(_Enabled ? "启用" : "禁用")}"); if (args.Parameters.Count != 2) { @@ -139,21 +140,15 @@ private void OnGetData(GetDataEventArgs args) { TSPlayer player = TShock.Players[args.Msg.whoAmI]; - if (!_Enabled) + if (!_Enabled ||! Packets.Contains(args.MsgID)) { return; } if (!player.HasPermission("免拦截")) { - if (!Packets.Contains(args.MsgID)) - { - args.Handled = true; - } - else - { - HandlePacket(player, args.MsgID); - } + + HandlePacket(player, args.MsgID); } } @@ -176,32 +171,29 @@ private HashSet GetPackets() #endregion #region 处理数据包方法 - private void HandlePacket(TSPlayer tsplayer, PacketTypes packetType) + private void HandlePacket(TSPlayer args, PacketTypes packetType) { if (_Enabled) { - lock (lockObject) + DateTime now = DateTime.Now; + if (args.Name != null) { - DateTime now = DateTime.Now; - if (tsplayer.Name != null) + if (!countDictionary.TryGetValue(args.Name, out var packetDictionary)) { - if (!countDictionary.TryGetValue(tsplayer.Name, out var packetDictionary)) - { - packetDictionary = new Dictionary(); - countDictionary[tsplayer.Name] = packetDictionary; - } - if (packetDictionary.TryGetValue(packetType, out DateTime lastPacketTime)) - { - if ((now - lastPacketTime).TotalMilliseconds >= PacketInterval) - { - packetDictionary[packetType] = now; - } - } - else + packetDictionary = new Dictionary(); + countDictionary[args.Name] = packetDictionary; + } + if (packetDictionary.TryGetValue(packetType, out DateTime lastPacketTime)) + { + if ((now - lastPacketTime).TotalMilliseconds >= PacketInterval) { packetDictionary[packetType] = now; } } + else + { + packetDictionary[packetType] = now; + } } } } diff --git a/PacketsStop/README.md b/PacketsStop/README.md index 41e39fb7e..9bd01cd0b 100644 --- a/PacketsStop/README.md +++ b/PacketsStop/README.md @@ -12,11 +12,10 @@ ## 更新日志 ``` -- 0.5 -- 修复未释放钩子导致关闭服务器时的报错 -- 0.4 -- 适配.net 6.0 -- 加了中文命令,并添加了一个权限名 +- 2.0 +- 修复数据包拦截插件的GetPacket逻辑:原对配置文件内的数据包名以外的全部拦截问题已修复 +- 1.0 +- 将少司命的游客限制插件处理数据包方法,做成了一个独立的功能插件。 ``` ## 指令