3030using GameFrameX . NetWork . Messages ;
3131using GameFrameX . Proto . Proto ;
3232using GameFrameX . Foundation . Logger ;
33+ using System . Collections . Concurrent ;
3334using ErrorEventArgs = GameFrameX . SuperSocket . ClientEngine . ErrorEventArgs ;
3435
3536namespace GameFrameX . Client . Bot ;
@@ -39,17 +40,34 @@ namespace GameFrameX.Client.Bot;
3940/// </summary>
4041public sealed class BotClient
4142{
43+ private static readonly ConcurrentDictionary < string , long > OnlinePlayerIds = new ( StringComparer . Ordinal ) ;
44+
45+ private enum FriendScenarioStage
46+ {
47+ None = 0 ,
48+ WaitAdd = 1 ,
49+ WaitListAfterAdd = 2 ,
50+ WaitDelete = 3 ,
51+ WaitListAfterDelete = 4 ,
52+ Completed = 5 ,
53+ }
54+
4255 private readonly BotTcpClient m_TcpClient ;
4356 private readonly string m_BotName ;
4457 private readonly BotTcpClientEvent m_BotTcpClientEvent ;
4558 private readonly BotRunOptions _options ;
4659 private int _disconnectScheduled ;
4760 private long _accountId ;
61+ private long _playerId ;
62+ private long _friendTargetPlayerId ;
63+ private int _friendTargetResolveAttempts ;
64+ private FriendScenarioStage _friendScenarioStage ;
4865
4966 /// <summary>
5067 /// 初始化机器人客户端
5168 /// </summary>
5269 /// <param name="botName">机器人名称</param>
70+ /// <param name="options">运行参数</param>
5371 public BotClient ( string botName , BotRunOptions options )
5472 {
5573 m_BotName = botName ;
@@ -97,6 +115,15 @@ private void OnReceiveMsg(MessageObject messageObject)
97115 case RespPlayerLogin msg :
98116 OnPlayerLoginSuccess ( msg ) ;
99117 break ;
118+ case RespFriendByAdd msg :
119+ OnFriendAddSuccess ( msg ) ;
120+ break ;
121+ case RespDeleteFriend msg :
122+ OnDeleteFriendSuccess ( msg ) ;
123+ break ;
124+ case RespFriendList msg :
125+ OnFriendListSuccess ( msg ) ;
126+ break ;
100127 }
101128 }
102129
@@ -115,6 +142,10 @@ private void ClientConnectedCallback()
115142 /// </summary>
116143 private void ClientClosedCallback ( )
117144 {
145+ if ( ! string . IsNullOrWhiteSpace ( m_BotName ) )
146+ {
147+ OnlinePlayerIds . TryRemove ( m_BotName , out _ ) ;
148+ }
118149 }
119150
120151 /// <summary>
@@ -220,10 +251,135 @@ private void OnPlayerCreateSuccess(RespPlayerCreate msg)
220251 /// <param name="msg">登录成功的响应消息</param>
221252 private void OnPlayerLoginSuccess ( RespPlayerLogin msg )
222253 {
223- LogHelper . Info ( $ "机器人-{ m_BotName } 登录成功,id:{ msg . PlayerInfo . Id } ") ;
254+ _playerId = msg . PlayerInfo . Id ;
255+ OnlinePlayerIds [ m_BotName ] = _playerId ;
256+ LogHelper . Info ( $ "机器人-{ m_BotName } 登录成功,id:{ _playerId } ") ;
257+ if ( _options . HasScenario ( "friend" ) )
258+ {
259+ StartFriendScenario ( ) ;
260+ return ;
261+ }
262+
224263 ScheduleDisconnectIfNeeded ( ) ;
225264 }
226265
266+ private void StartFriendScenario ( )
267+ {
268+ if ( _playerId <= 0 )
269+ {
270+ LogHelper . Error ( $ "机器人-{ m_BotName } 好友场景启动失败,玩家ID非法:{ _playerId } ") ;
271+ ScheduleDisconnectIfNeeded ( ) ;
272+ return ;
273+ }
274+
275+ if ( ! TryResolveFriendTargetPlayerId ( ) )
276+ {
277+ _friendTargetResolveAttempts ++ ;
278+ if ( _friendTargetResolveAttempts > 5 )
279+ {
280+ LogHelper . Error ( $ "机器人-{ m_BotName } 好友场景启动失败,未找到可用好友目标。") ;
281+ ScheduleDisconnectIfNeeded ( ) ;
282+ return ;
283+ }
284+
285+ _ = Task . Run ( async ( ) =>
286+ {
287+ await Task . Delay ( 1000 ) ;
288+ StartFriendScenario ( ) ;
289+ } ) ;
290+ return ;
291+ }
292+
293+ _friendScenarioStage = FriendScenarioStage . WaitAdd ;
294+ LogHelper . Info ( $ "机器人-{ m_BotName } 开始执行好友场景,目标玩家:{ _friendTargetPlayerId } ") ;
295+ m_TcpClient . SendToServer ( new ReqFriendByAdd { PlayerId = _friendTargetPlayerId } ) ;
296+ }
297+
298+ private void OnFriendAddSuccess ( RespFriendByAdd msg )
299+ {
300+ if ( _friendScenarioStage != FriendScenarioStage . WaitAdd )
301+ {
302+ return ;
303+ }
304+
305+ if ( ! msg . Success || msg . ErrorCode != 0 )
306+ {
307+ LogHelper . Error ( $ "机器人-{ m_BotName } 好友场景-加好友失败,Success:{ msg . Success } , ErrorCode:{ msg . ErrorCode } ") ;
308+ ScheduleDisconnectIfNeeded ( ) ;
309+ return ;
310+ }
311+
312+ _friendScenarioStage = FriendScenarioStage . WaitListAfterAdd ;
313+ LogHelper . Info ( $ "机器人-{ m_BotName } 好友场景-加好友成功,开始拉取好友列表。") ;
314+ m_TcpClient . SendToServer ( new ReqFriendList ( ) ) ;
315+ }
316+
317+ private void OnDeleteFriendSuccess ( RespDeleteFriend msg )
318+ {
319+ if ( _friendScenarioStage != FriendScenarioStage . WaitDelete )
320+ {
321+ return ;
322+ }
323+
324+ if ( ! msg . Success || msg . ErrorCode != 0 )
325+ {
326+ LogHelper . Error ( $ "机器人-{ m_BotName } 好友场景-删好友失败,Success:{ msg . Success } , ErrorCode:{ msg . ErrorCode } ") ;
327+ ScheduleDisconnectIfNeeded ( ) ;
328+ return ;
329+ }
330+
331+ _friendScenarioStage = FriendScenarioStage . WaitListAfterDelete ;
332+ LogHelper . Info ( $ "机器人-{ m_BotName } 好友场景-删好友成功,开始二次拉取好友列表。") ;
333+ m_TcpClient . SendToServer ( new ReqFriendList ( ) ) ;
334+ }
335+
336+ private void OnFriendListSuccess ( RespFriendList msg )
337+ {
338+ if ( _friendScenarioStage != FriendScenarioStage . WaitListAfterAdd
339+ && _friendScenarioStage != FriendScenarioStage . WaitListAfterDelete )
340+ {
341+ return ;
342+ }
343+
344+ if ( msg . ErrorCode != 0 )
345+ {
346+ LogHelper . Error ( $ "机器人-{ m_BotName } 好友场景-拉取列表失败,ErrorCode:{ msg . ErrorCode } ") ;
347+ ScheduleDisconnectIfNeeded ( ) ;
348+ return ;
349+ }
350+
351+ if ( _friendScenarioStage == FriendScenarioStage . WaitListAfterAdd )
352+ {
353+ _friendScenarioStage = FriendScenarioStage . WaitDelete ;
354+ LogHelper . Info ( $ "机器人-{ m_BotName } 好友场景-首次列表成功,数量:{ msg . Friends ? . Count ?? 0 } ,开始删好友。") ;
355+ m_TcpClient . SendToServer ( new ReqDeleteFriend { PlayerId = _friendTargetPlayerId } ) ;
356+ return ;
357+ }
358+
359+ _friendScenarioStage = FriendScenarioStage . Completed ;
360+ LogHelper . Info ( $ "机器人-{ m_BotName } 好友场景执行完成,二次列表数量:{ msg . Friends ? . Count ?? 0 } 。") ;
361+ ScheduleDisconnectIfNeeded ( ) ;
362+ }
363+
364+ private bool TryResolveFriendTargetPlayerId ( )
365+ {
366+ foreach ( var entry in OnlinePlayerIds )
367+ {
368+ if ( entry . Key == m_BotName )
369+ {
370+ continue ;
371+ }
372+
373+ if ( entry . Value > 0 && entry . Value != _playerId )
374+ {
375+ _friendTargetPlayerId = entry . Value ;
376+ return true ;
377+ }
378+ }
379+
380+ return false ;
381+ }
382+
227383 private void ScheduleDisconnectIfNeeded ( )
228384 {
229385 if ( ! _options . EnableDisconnectLoop || _options . DisconnectAfterLoginSeconds <= 0 )
0 commit comments