Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

添加插件:数据包拦截插件 #18

Merged
merged 3 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions PacketsStop/Configuration.cs
Original file line number Diff line number Diff line change
@@ -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<string> Packets { get; set; } = new HashSet<string>();

public static readonly string FilePath = Path.Combine(TShock.SavePath, "数据包拦截.json");


public Configuration()
{
Packets = new HashSet<string>
{
"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<Configuration>(json);
return cf;
}
}
}
}
}
202 changes: 202 additions & 0 deletions PacketsStop/PacketsStop.cs
Original file line number Diff line number Diff line change
@@ -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<string, Dictionary<PacketTypes, DateTime>> countDictionary = new Dictionary<string, Dictionary<PacketTypes, DateTime>>();
private const double PacketInterval = 1000.0;
private bool _Enabled = false;
internal static Configuration Config;
private HashSet<PacketTypes> 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<PacketTypes> GetPackets()
{
HashSet<PacketTypes> Packets = new HashSet<PacketTypes>();
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<PacketTypes, DateTime>();
countDictionary[args.Name] = packetDictionary;
}
if (packetDictionary.TryGetValue(packetType, out DateTime lastPacketTime))
{
if ((now - lastPacketTime).TotalMilliseconds >= PacketInterval)
{
packetDictionary[packetType] = now;
}
}
else
{
packetDictionary[packetType] = now;
}
}
}
}
#endregion
}
}
3 changes: 3 additions & 0 deletions PacketsStop/PacketsStop.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\template.targets"/>
</Project>
53 changes: 53 additions & 0 deletions PacketsStop/README.md
Original file line number Diff line number Diff line change
@@ -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官方群等
Loading
Loading