forked from Celestine-Lux/SL_qqban
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOneBotIntegration.cs
More file actions
388 lines (339 loc) · 15.7 KB
/
Copy pathOneBotIntegration.cs
File metadata and controls
388 lines (339 loc) · 15.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
using Exiled.API.Features;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace OneBotIntegration
{
public class OneBotIntegration : Plugin<Config>
{
private ClientWebSocket _webSocket;
private CancellationTokenSource _cancellationTokenSource;
public override void OnEnabled()
{
base.OnEnabled();
Log.Info("插件已启用,正在启动反向 WebSocket 连接...");
// 启动反向 WebSocket 连接
_cancellationTokenSource = new CancellationTokenSource();
Task.Run(() => ConnectToOneBot(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
}
public override void OnDisabled()
{
Log.Info("插件已禁用,正在关闭 WebSocket 连接...");
_cancellationTokenSource?.Cancel();
_webSocket?.Dispose();
base.OnDisabled();
}
private async Task ConnectToOneBot(CancellationToken cancellationToken)
{
_webSocket = new ClientWebSocket();
try
{
Log.Info($"正在尝试连接到 OneBot WebSocket 服务器: {Config.OneBotWsUrl}");
await _webSocket.ConnectAsync(new Uri(Config.OneBotWsUrl), cancellationToken);
Log.Info("成功连接到 OneBot WebSocket 服务器。");
while (_webSocket.State == WebSocketState.Open)
{
var buffer = new ArraySegment<byte>(new byte[1024]);
var result = await _webSocket.ReceiveAsync(buffer, cancellationToken);
var message = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
Log.Info($"收到来自 OneBot 的消息: {message}");
HandleMessage(message);
}
}
catch (Exception ex)
{
Log.Error($"WebSocket 连接失败: {ex.Message}");
}
}
private void HandleMessage(string jsonMessage)
{
try
{
Log.Info("正在处理收到的消息...");
// 解析 JSON 消息
var messageEvent = JsonConvert.DeserializeObject<MessageEvent>(jsonMessage);
// 检查消息类型(私聊或群聊)
if (messageEvent.PostType == "message" &&
(messageEvent.MessageType == "private" || messageEvent.MessageType == "group"))
{
string rawMessage = messageEvent.RawMessage; // 原始消息内容
// 如果 rawMessage 为空,尝试从 message 字段中提取
if (string.IsNullOrEmpty(rawMessage))
{
if (messageEvent.Message is string messageText)
{
rawMessage = messageText; // 如果 message 是字符串,直接使用
}
else if (messageEvent.Message is List<MessageSegment> messageSegments)
{
// 如果 message 是数组,提取文本内容
rawMessage = string.Join("", messageSegments
.Where(segment => segment.Type == "text")
.Select(segment => segment.Data["text"]));
}
}
if (string.IsNullOrEmpty(rawMessage))
{
Log.Info("消息内容为空,无法处理。");
return;
}
string[] parts = rawMessage.Split(' ');
string command = parts[0]; // 命令部分
switch (command)
{
case "/ban_player":
Log.Info("收到封禁玩家命令...");
if (parts.Length >= 4)
{
string steam64id = parts[1];
int duration = int.Parse(parts[2]);
string reason = string.Join(" ", parts.Skip(3));
string qqNumber = messageEvent.UserId.ToString();
BanPlayer(steam64id, duration, reason, qqNumber).GetAwaiter().GetResult();
}
else
{
Log.Info("封禁命令参数不足,请检查格式。");
SendQQMessageAsync("封禁命令格式错误,正确格式:/ban_player <steam64id> <时间> <原因>").GetAwaiter().GetResult();
}
break;
case "/unban_player":
Log.Info("收到解封玩家命令...");
if (parts.Length >= 2)
{
string steam64id = parts[1];
string qqNumber = messageEvent.UserId.ToString();
UnbanPlayer(steam64id, qqNumber).GetAwaiter().GetResult();
}
else
{
Log.Info("解封命令参数不足,请检查格式。");
SendQQMessageAsync("解封命令格式错误,正确格式:/unban_player <steam64id>").GetAwaiter().GetResult();
}
break;
case "/kick_player":
Log.Info("收到踢出玩家命令...");
if (parts.Length >= 2)
{
string steam64id = parts[1];
KickPlayer(steam64id).GetAwaiter().GetResult();
}
else
{
Log.Info("踢出命令参数不足,请检查格式。");
SendQQMessageAsync("踢出命令格式错误,正确格式:/kick_player <steam64id>").GetAwaiter().GetResult();
}
break;
case "/cx":
Log.Info("收到查询在线人数命令...");
QueryOnlinePlayers().GetAwaiter().GetResult();
break;
case "/verify_qq":
Log.Info("收到 QQ 号验证命令...");
if (parts.Length >= 2)
{
string qqNumber = parts[1];
VerifyQQ(qqNumber).GetAwaiter().GetResult();
}
else
{
Log.Info("验证命令参数不足,请检查格式。");
SendQQMessageAsync("验证命令格式错误,正确格式:/verify_qq <qq号>").GetAwaiter().GetResult();
}
break;
case "/help":
Log.Info("收到帮助命令...");
SendHelpMessage().GetAwaiter().GetResult();
break;
default:
if (command.StartsWith("/"))
{
Log.Info($"未知命令: {command}");
SendQQMessageAsync($"未知命令: {command},请输入 /help 查看可用命令。").GetAwaiter().GetResult();
}
break;
}
}
}
catch (Exception ex)
{
Log.Error($"处理消息时出错: {ex.Message}");
}
}
private async Task BanPlayer(string steam64id, int duration, string reason, string qqNumber)
{
Log.Info($"正在验证 QQ 号: {qqNumber}");
if (!Config.AllowedQQs.Contains(qqNumber))
{
Log.Info($"QQ {qqNumber} 不在允许的列表中,无法封禁玩家 {steam64id}。");
await SendQQMessageAsync($"QQ {qqNumber} 不在允许的列表中,无法封禁玩家 {steam64id}。");
return;
}
Log.Info($"正在查找玩家: {steam64id}");
Player player = Player.Get(steam64id);
if (player != null)
{
Log.Info($"封禁玩家: {player.Nickname} ({steam64id})");
player.Ban(duration, reason);
await SendQQMessageAsync($"玩家 {steam64id} 已被封禁,封禁时长:{duration} 分钟,原因:{reason}");
}
else
{
Log.Info($"玩家 {steam64id} 不在线,尝试离线封禁...");
bool isBanned = BanManager.OfflineBanPlayer(BanHandler.BanType.UserId, steam64id, reason, TimeSpan.FromMinutes(duration), qqNumber);
if (isBanned)
{
await SendQQMessageAsync($"玩家 {steam64id} 已被离线封禁,封禁时长:{duration} 分钟,原因:{reason}");
}
else
{
await SendQQMessageAsync($"无法封禁玩家 {steam64id},请检查参数是否正确。");
}
}
}
private async Task UnbanPlayer(string steam64id, string qqNumber)
{
Log.Info($"正在验证 QQ 号: {qqNumber}");
if (!Config.AllowedQQs.Contains(qqNumber))
{
Log.Info($"QQ {qqNumber} 不在允许的列表中,无法解封玩家 {steam64id}。");
await SendQQMessageAsync($"QQ {qqNumber} 不在允许的列表中,无法解封玩家 {steam64id}。");
return;
}
Log.Info($"正在解封玩家: {steam64id}");
BanManager.UnbanPlayer(BanHandler.BanType.UserId, steam64id);
await SendQQMessageAsync($"玩家 {steam64id} 已被解封。");
}
private async Task KickPlayer(string steam64id)
{
Log.Info($"正在查找玩家: {steam64id}");
Player player = Player.Get(steam64id);
if (player != null)
{
Log.Info($"踢出玩家: {player.Nickname} ({steam64id})");
player.Kick("你由于违反服务器规则被踢出,详情联系服务器管理员");
await SendQQMessageAsync($"玩家 {steam64id} 已被踢出。");
}
else
{
Log.Info($"未找到玩家: {steam64id}");
await SendQQMessageAsync($"未找到玩家 {steam64id}。");
}
}
private async Task QueryOnlinePlayers()
{
try
{
// 获取当前在线玩家
var onlinePlayers = Player.List;
// 构造消息内容
string message = $"当前服务器在线人数: {onlinePlayers.Count()}\n";
message += "在线玩家列表:\n";
foreach (var player in onlinePlayers)
{
message += $"- {player.Nickname} ({player.UserId})\n";
}
// 发送消息到 QQ
await SendQQMessageAsync(message);
}
catch (Exception ex)
{
Log.Error($"查询在线人数时出错: {ex.Message}");
await SendQQMessageAsync("查询在线人数时出错,请稍后重试。");
}
}
private async Task VerifyQQ(string qqNumber)
{
Log.Info($"正在验证 QQ 号: {qqNumber}");
if (Config.AllowedQQs.Contains(qqNumber))
{
Log.Info($"QQ {qqNumber} 已通过验证。");
await SendQQMessageAsync($"QQ {qqNumber} 已通过验证,可以使用封禁系统。");
}
else
{
Log.Info($"QQ {qqNumber} 不在允许的列表中。");
await SendQQMessageAsync($"QQ {qqNumber} 不在允许的列表中,无法使用封禁系统。");
}
}
private async Task SendHelpMessage()
{
string helpMessage = "可用命令:\n" +
"/ban_player <steam64id> <时间> <原因> - 封禁玩家\n" +
"/unban_player <steam64id> - 解封玩家\n" +
"/kick_player <steam64id> - 踢出玩家\n" +
"/verify_qq <qq号> - 验证 QQ 号\n" +
"/cx - 查询当前服务器在线人数\n" +
"/help - 显示帮助信息";
await SendQQMessageAsync(helpMessage);
}
private async Task SendQQMessageAsync(string message)
{
if (_webSocket == null || _webSocket.State != WebSocketState.Open)
{
Log.Error("WebSocket 未连接,无法发送消息。");
return;
}
try
{
// 构造消息对象
var request = new
{
action = "send_group_msg",
@params = new
{
group_id = Config.GroupId.ToString(), // 确保 group_id 是字符串
message = message
}
};
// 将对象序列化为 JSON 字符串
string jsonMessage = JsonConvert.SerializeObject(request);
Log.Info($"正在发送消息到 QQ: {jsonMessage}");
// 发送消息
byte[] messageBytes = Encoding.UTF8.GetBytes(jsonMessage);
await _webSocket.SendAsync(new ArraySegment<byte>(messageBytes), WebSocketMessageType.Text, true, CancellationToken.None);
Log.Info("消息已成功发送。");
}
catch (Exception ex)
{
Log.Error($"发送消息时出错: {ex.Message}");
}
}
}
public class MessageEvent
{
[JsonProperty("post_type")]
public string PostType { get; set; } // 消息类型
[JsonProperty("message_type")]
public string MessageType { get; set; } // 消息子类型(私聊或群聊)
[JsonProperty("user_id")]
public string UserId { get; set; } // 发送者 QQ 号
[JsonProperty("raw_message")]
public string RawMessage { get; set; } // 原始消息内容
[JsonProperty("message")]
public object Message { get; set; } // 消息内容(可能是字符串或数组)
[JsonProperty("sender")]
public SenderInfo Sender { get; set; } // 发送者信息
}
public class MessageSegment
{
[JsonProperty("type")]
public string Type { get; set; } // 消息段类型(如 text)
[JsonProperty("data")]
public Dictionary<string, string> Data { get; set; } // 消息段数据
}
public class SenderInfo
{
[JsonProperty("user_id")]
public string UserId { get; set; } // 发送者 QQ 号
[JsonProperty("nickname")]
public string Nickname { get; set; } // 发送者昵称
[JsonProperty("card")]
public string Card { get; set; } // 发送者群名片
}
}