1
+ using Terraria ;
2
+ using TerrariaApi . Server ;
3
+ using TShockAPI ;
4
+ using TShockAPI . Hooks ;
5
+
6
+ namespace PacketsStop
7
+ {
8
+ [ ApiVersion ( 2 , 1 ) ]
9
+ public class PacketsStop : TerrariaPlugin
10
+ {
11
+
12
+ public override string Name => "数据包拦截 PacketsStop" ;
13
+ public override Version Version => new Version ( 1 , 0 , 0 ) ;
14
+ public override string Author => "羽学 感谢少司命" ;
15
+ public override string Description => "拦截没有指定权限的用户组数据包" ;
16
+
17
+ #region 配置方法的工具
18
+ private readonly Dictionary < string , Dictionary < PacketTypes , DateTime > > countDictionary = new Dictionary < string , Dictionary < PacketTypes , DateTime > > ( ) ;
19
+ private const double PacketInterval = 1000.0 ;
20
+ private bool _Enabled = false ;
21
+ internal static Configuration Config ;
22
+ private HashSet < PacketTypes > Packets ;
23
+ #endregion
24
+
25
+ public PacketsStop ( Main game ) : base ( game )
26
+ {
27
+ Config = new Configuration ( ) ;
28
+ }
29
+
30
+ public override void Initialize ( )
31
+ {
32
+ LoadConfig ( ) ;
33
+ Packets = GetPackets ( ) ;
34
+ ServerApi . Hooks . NetGetData . Register ( this , OnGetData , int . MaxValue ) ;
35
+ Commands . ChatCommands . Add ( new Command ( "拦截" , Command , "拦截" ) ) ;
36
+ GeneralHooks . ReloadEvent += LoadConfig ;
37
+ }
38
+
39
+ protected override void Dispose ( bool disposing )
40
+ {
41
+ if ( disposing )
42
+ {
43
+ ServerApi . Hooks . NetGetData . Deregister ( this , OnGetData ) ;
44
+ }
45
+ base . Dispose ( disposing ) ;
46
+ }
47
+
48
+ #region 配置文件创建与重读加载方法
49
+ private static void LoadConfig ( ReloadEventArgs args = null )
50
+ {
51
+ if ( ! File . Exists ( Configuration . FilePath ) )
52
+ {
53
+ var defaultConfig = new Configuration ( ) ;
54
+ defaultConfig . Write ( Configuration . FilePath ) ;
55
+ }
56
+ else
57
+ {
58
+ Config = Configuration . Read ( Configuration . FilePath ) ;
59
+ }
60
+
61
+ if ( args != null && args . Player != null )
62
+ {
63
+ args . Player . SendSuccessMessage ( "[数据包拦截]重新加载配置完毕。" ) ;
64
+ }
65
+ }
66
+ #endregion
67
+
68
+ #region 指令
69
+
70
+
71
+ private void Command ( CommandArgs args )
72
+ {
73
+ if ( args . Player != null && ! args . Player . HasPermission ( "拦截" ) )
74
+ {
75
+ args . Player . SendErrorMessage ( "你没有使用数据包拦截的权限" ) ;
76
+ return ;
77
+ }
78
+ else
79
+ {
80
+ _Enabled = ! _Enabled ;
81
+ TSPlayer . All . SendInfoMessage ( $ "[数据包拦截]已{ ( _Enabled ? "启用" : "禁用" ) } ") ;
82
+ }
83
+
84
+
85
+ if ( args . Parameters . Count != 2 )
86
+ {
87
+ args . Player . SendInfoMessage ( "/拦截 add 玩家名 - 将玩家添加到LJ组(不存在自动创建)。\n /拦截 del 玩家名 - 将玩家从LJ组移除并设为default组。" ) ;
88
+ return ;
89
+ }
90
+
91
+ string Action = args . Parameters [ 0 ] ;
92
+ string Name = args . Parameters [ 1 ] ;
93
+ var Account = TShock . UserAccounts . GetUserAccountByName ( Name ) ;
94
+
95
+ if ( Account == null )
96
+ {
97
+ args . Player . SendInfoMessage ( $ "无法找到名为'{ Name } '的在线玩家。") ;
98
+ return ;
99
+ }
100
+
101
+ switch ( Action . ToLower ( ) )
102
+ {
103
+ case "add" :
104
+ if ( ! TShock . Groups . GroupExists ( "LJ" ) )
105
+ {
106
+ TShock . Groups . AddGroup ( "LJ" , "" , "tshock.canchat,tshock,tshock.partychat,tshock.sendemoji" , "045,235,203" ) ;
107
+ args . Player . SendSuccessMessage ( "LJ组已创建。" ) ;
108
+ }
109
+
110
+ try
111
+ {
112
+ TShock . UserAccounts . SetUserGroup ( Account , "LJ" ) ;
113
+ args . Player . SendSuccessMessage ( $ "{ Name } 已被设为LJ组成员。") ;
114
+ }
115
+ catch ( Exception ex )
116
+ {
117
+ args . Player . SendErrorMessage ( $ "无法将{ Name } 设为LJ组成员。错误信息: \n { ex . Message } ") ;
118
+ }
119
+ break ;
120
+ case "del" :
121
+ try
122
+ {
123
+ TShock . UserAccounts . SetUserGroup ( Account , "default" ) ;
124
+ args . Player . SendSuccessMessage ( $ "{ Name } 已从LJ组移除,并被设为default组。") ;
125
+ }
126
+ catch ( Exception ex )
127
+ {
128
+ args . Player . SendErrorMessage ( $ "无法将{ Name } 从LJ组移除或设为default组。错误信息: \n { ex . Message } ") ;
129
+ }
130
+ break ;
131
+ default :
132
+ args . Player . SendInfoMessage ( "无效的子命令。使用 'add' 或 'del'。" ) ;
133
+ break ;
134
+ }
135
+ }
136
+ #endregion
137
+
138
+ #region 获取数据包方法
139
+ private void OnGetData ( GetDataEventArgs args )
140
+ {
141
+ TSPlayer player = TShock . Players [ args . Msg . whoAmI ] ;
142
+
143
+ if ( ! _Enabled || ! Packets . Contains ( args . MsgID ) )
144
+ {
145
+ return ;
146
+ }
147
+
148
+ if ( ! player . HasPermission ( "免拦截" ) )
149
+ {
150
+
151
+ HandlePacket ( player , args . MsgID ) ;
152
+ }
153
+ }
154
+
155
+ private HashSet < PacketTypes > GetPackets ( )
156
+ {
157
+ HashSet < PacketTypes > Packets = new HashSet < PacketTypes > ( ) ;
158
+ foreach ( string packetName in Config . Packets )
159
+ {
160
+ if ( Enum . TryParse ( packetName , out PacketTypes packetType ) )
161
+ {
162
+ Packets . Add ( packetType ) ;
163
+ }
164
+ else
165
+ {
166
+ TShock . Log . Error ( $ "无法识别的数据包类型名称: { packetName } ") ;
167
+ }
168
+ }
169
+ return Packets ;
170
+ }
171
+ #endregion
172
+
173
+ #region 处理数据包方法
174
+ private void HandlePacket ( TSPlayer args , PacketTypes packetType )
175
+ {
176
+ if ( _Enabled )
177
+ {
178
+ DateTime now = DateTime . Now ;
179
+ if ( args . Name != null )
180
+ {
181
+ if ( ! countDictionary . TryGetValue ( args . Name , out var packetDictionary ) )
182
+ {
183
+ packetDictionary = new Dictionary < PacketTypes , DateTime > ( ) ;
184
+ countDictionary [ args . Name ] = packetDictionary ;
185
+ }
186
+ if ( packetDictionary . TryGetValue ( packetType , out DateTime lastPacketTime ) )
187
+ {
188
+ if ( ( now - lastPacketTime ) . TotalMilliseconds >= PacketInterval )
189
+ {
190
+ packetDictionary [ packetType ] = now ;
191
+ }
192
+ }
193
+ else
194
+ {
195
+ packetDictionary [ packetType ] = now ;
196
+ }
197
+ }
198
+ }
199
+ }
200
+ #endregion
201
+ }
202
+ }
0 commit comments