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..0335f35ba --- /dev/null +++ b/PacketsStop/PacketsStop.cs @@ -0,0 +1,202 @@ +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 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) + { + if (args.Player != null && !args.Player.HasPermission("拦截")) + { + args.Player.SendErrorMessage("你没有使用数据包拦截的权限"); + return; + } + else + { + _Enabled = !_Enabled; + TSPlayer.All.SendInfoMessage($"[数据包拦截]已{(_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 ||! Packets.Contains(args.MsgID)) + { + return; + } + + if (!player.HasPermission("免拦截")) + { + + 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 args, PacketTypes packetType) + { + if (_Enabled) + { + DateTime now = DateTime.Now; + if (args.Name != null) + { + if (!countDictionary.TryGetValue(args.Name, out var packetDictionary)) + { + 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; + } + } + } + } + #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..9bd01cd0b --- /dev/null +++ b/PacketsStop/README.md @@ -0,0 +1,53 @@ +# PacketsStop 数据包拦截 + +- 作者: 羽学 +- 出处: [github](https://github.com/1242509682/PacketsStop/) +- 插件源码来于少司命的游客限制插件,将其处理数据包方法做成了一个独立的功能插件 +- 这是一个Tshock服务器插件主要用于: +- 使用指令开启拦截玩家数据包 +- 使用前必须先给default组一个权限【免拦截】 +- 接着通过修改配置文件添加数据包名使用/reload重载 +- 输入【/拦截 add 名字】将玩家分配到一个新建的【LJ组】 +- 封锁了大部分可用权限并对其数据包拦截。 +## 更新日志 + +``` +- 2.0 +- 修复数据包拦截插件的GetPacket逻辑:原对配置文件内的数据包名以外的全部拦截问题已修复 +- 1.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 f86c380f1..790b7b060 100644 --- a/README.md +++ b/README.md @@ -18,40 +18,40 @@ ### 已收集插件 -| 名称 | 插件说明 | 前置 | -| ---------------------------------------------------------------- | :----------------: | :---------------------------: | -| [ChattyBridge](ChattyBridge/README.md) | 用于跨服聊天 | 无 | -| [EconomicsAPI](EconomicsAPI/README.md) | 经济插件前置 | 无 | -| [Economics.RPG](Economics.RPG/README.md) | RPG | EconomicsAPI | -| [Economics.Deal](Economics.RPG/README.md) | 交易插件 | EconomicsAPI | -| [Economics.Shop](Economics.Shop/README.md) | 商店插件 | EconomicsAPI
Economics.RPG | -| [Economics.Skill](Economics.Skill/README.md) | 技能插件(未完成) | EconomicsAPI
Economics.RPG | -| [CreateSpawn](CreateSpawn/README.md) | 出生点建筑生成 | 无 | -| [AutoBroadcast](AutoBroadcast/README.md) | 自动广播 | 无 | -| [AutoTeam](AutoTeam/README.md) | 自动队伍 | 无 | -| [BridgeBuilder](BridgeBuilder/README.md) | 快速铺桥 | 无 | -| [OnlineGiftPackage](OnlineGiftPackage/README.md) | 在线礼包 | 无 | -| [LifemaxExtra](LifemaxExtra/README.md) | 吃更多生命果/水晶 | 无 | -| [DisableMonsCoin](DisableMonsCoin/README.md) | 怪物不掉钱 | 无 | -| [PermaBuff](PermaBuff/README.md) | 永久 Buff | 无 | -| [ShortCommand](ShortCommand/README.md) | 简短指令 | 无 | -| [ProgressBag](ProgressBag/README.md) | 进度礼包 | 无 | -| [CriticalHit](CriticalHit/README.md) | 击打提示 | 无 | -| [DisableMonsCoin](DisableMonsCoin/README.md) | 怪物不掉钱 | 无 | -| [Back](Back/RETUEN) | 死亡回溯 | 无 | -| [BanNpc](BanNpc/README.md) | 阻止怪物生成 | 无 | -| [MapTeleport](MapTp/README.md) | 双击大地图传送 | 无 | -| [RandReSpawn](RandRespawn/README.md) | 随机出生点 | 无 | -| [CGive](CGive/README.md) | 离线命令 | 无 | -| [RainbowChat](RainbowChat/README.md) | 每次说话颜色不一样 | 无 | -| [NormalDropsBags](NormalDropsBags/README.md) | 普通难度宝藏袋 | 无 | -| [DisableSurfaceProjectiles](DisableSurfaceProjectiles/README.md) | 禁地表弹幕 | 无 | -| [RecipesBrowser](RecipesBrowser/README.md) | 合成表 | 无 | -| [DisableGodMod](DisableGodMod/README.md) | 阻止玩家无敌 | 无 | -| [TownNPCHomes](TownNPCHomes/README.md) | NPC 快速回家 | 无 | -| [RegionView](RegionView/README.md) | 显示区域边界 | 无 | -| [Noagent](Noagent/README.md) | 禁止代理 ip 进入 | 无 | -| [SwitchCommands](SwitchCommands/README.md) | 区域执行指令 | 无 | -| [GolfRewards](GolfRewards/README.md) | 高尔夫奖励 | 无 | -| [DataSync](DataSync/README.md) | 进度同步 | 无 | -| [ProgressRestrict](ProgressRestrict/README.md) | 超进度检测 | DataSync | + +| 名称 | 插件说明 | 前置 | +| ---------------------------------------------------------------------------------------------------- | :----------------: | :---------------------------: | +| [ChattyBridge](ChattyBridge/README.md) | 用于跨服聊天 | 无 | +| [EconomicsAPI](https://github.com/Controllerdestiny/TShockPlugin/tree/master/EconomicsAPI) | 经济插件前置 | 无 | +| [Economics.RPG](https://github.com/Controllerdestiny/TShockPlugin/tree/master/Economics.RPG) | RPG | EconomicsAPI | +| [Economics.Deal](https://github.com/Controllerdestiny/TShockPlugin/tree/master/Economics.RPG) | 交易插件 | EconomicsAPI | +| [Economics.Shop](https://github.com/Controllerdestiny/TShockPlugin/tree/master/Economics.Shop) | 商店插件 | EconomicsAPI
Economics.RPG | +| [Economics.Skill](https://github.com/Controllerdestiny/TShockPlugin/tree/master/Economics.Skill) | 技能插件(未完成) | EconomicsAPI
Economics.RPG | +| [CreateSpawn](https://github.com/Controllerdestiny/TShockPlugin/tree/master/CreateSpawn) | 出生点建筑生成 | 无 | +| [AutoBroadcast](https://github.com/Controllerdestiny/TShockPlugin/tree/master/AutoBroadcast) | 自动广播 | 无 | +| [AutoTeam](https://github.com/Controllerdestiny/TShockPlugin/tree/master/AutoTeam) | 自动队伍 | 无 | +| [BridgeBuilder](https://github.com/Controllerdestiny/TShockPlugin/tree/master/BridgeBuilder) | 快速铺桥 | 无 | +| [OnlineGiftPackage](https://github.com/Controllerdestiny/TShockPlugin/tree/master/OnlineGiftPackage) | 在线礼包 | 无 | +| [LifemaxExtra](https://github.com/Controllerdestiny/TShockPlugin/tree/master/LifemaxExtra) | 吃更多生命果/水晶 | 无 | +| [DisableMonsCoin](https://github.com/Controllerdestiny/TShockPlugin/tree/master/DisableMonsCoin) | 怪物不掉钱 | 无 | +| [PermaBuff](https://github.com/Controllerdestiny/TShockPlugin/tree/master/PermaBuff) | 永久 Buff | 无 | +| [ShortCommand](https://github.com/Controllerdestiny/TShockPlugin/tree/master/ShortCommand) | 简短指令 | 无 | +| [ProgressBag](https://github.com/Controllerdestiny/TShockPlugin/tree/master/ProgressBag) | 进度礼包 | 无 | +| [CriticalHit](https://github.com/Controllerdestiny/TShockPlugin/tree/master/CriticalHit) | 击打提示 | 无 | +| [DisableMonsCoin](https://github.com/Controllerdestiny/TShockPlugin/tree/master/DisableMonsCoin) | 怪物不掉钱 | 无 | +| [Back](https://github.com/Controllerdestiny/TShockPlugin/tree/master/Back) | 死亡回溯 | 无 | +| [BanNpc](https://github.com/Controllerdestiny/TShockPlugin/tree/master/BanNpc) | 阻止怪物生成 | 无 | +| [MapTeleport](https://github.com/Controllerdestiny/TShockPlugin/tree/master/MapTp) | 双击大地图传送 | 无 | +| [RandReSpawn](https://github.com/Controllerdestiny/TShockPlugin/tree/master/RandRespawn) | 随机出生点 | 无 | +| [CGive](https://github.com/Controllerdestiny/TShockPlugin/tree/master/CGive) | 离线命令 | 无 | +| [RainbowChat](https://github.com/Controllerdestiny/TShockPlugin/tree/master/RainbowChat) | 每次说话颜色不一样 | 无 | +| [NormalDropsBags](https://github.com/Controllerdestiny/TShockPlugin/tree/master/NormalDropsBags) | 普通难度宝藏袋 | 无 | +| [CheckBag](https://github.com/Controllerdestiny/TShockPlugin/tree/master/CheckBag) | 检查背包(超进度物品检测) | 无 | +| [DisableSurfaceProjectiles](https://github.com/Controllerdestiny/TShockPlugin/tree/master/DisableSurfaceProjectiles) | 禁地表弹幕 | 无 | +| [RecipesBrowser](https://github.com/Controllerdestiny/TShockPlugin/tree/master/RecipesBrowser) | 合成表 | 无 | +| [DisableGodMod](https://github.com/Controllerdestiny/TShockPlugin/tree/master/DisableGodMod) | 阻止玩家无敌 | 无 | +| [TownNPCHomes](https://github.com/Controllerdestiny/TShockPlugin/tree/master/TownNPCHomes) | NPC快速回家 | 无 | +| [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) | 数据包拦截 | 无 |