public async Task Run() { _csconfig.Validate(); var clients = new List <Tuple <AccountCharacter, Client> >(); foreach (var account in _csconfig.Accounts) { var client = new Client(); var accountAndClient = Tuple.Create(account, client); client.OnReceivedPacketEvent(InComingPacket.EventMessage, (packet) => HandleEventMessage(client, new EventNotifyPacket(packet))); if (GetIsLeadClient(accountAndClient)) { client.OnReceivedPacketEvent(InComingPacket.PlayerInGame, (packet) => NewPlayerJoinGame(client, new PlayerInGamePacket(packet))); } _externalMessagingClient.RegisterClient(client); clients.Add(accountAndClient); } int gameCount = 1; while (true) { ; var leaveTasks = clients.Select(async(c, i) => { return(await LeaveGameAndRejoinMCPWithRetry(c.Item2, c.Item1)); }).ToList(); var leaveResults = await Task.WhenAll(leaveTasks); if (leaveResults.Any(r => !r)) { Log.Warning($"One or more characters failed to leave and rejoin"); continue; } await Task.Delay(TimeSpan.FromSeconds(2)); var leadClient = clients.First(c => GetIsLeadClient(c)); var result = await RealmConnectHelpers.CreateGameWithRetry(gameCount, leadClient.Item2, _config, leadClient.Item1); gameCount = result.Item2; if (!result.Item1) { continue; } await GameLoop(clients, gameCount); gameCount++; } }
private async Task <bool> LeaveGameAndRejoinMCPWithRetry(Client client, AccountCharacter cowAccount) { if (!client.Chat.IsConnected()) { if (!await RealmConnectHelpers.ConnectToRealmWithRetry(client, _config, cowAccount, 10)) { return(false); } } if (client.Game.IsInGame()) { Log.Information($"Leaving game with {client.LoggedInUserName()}"); client.Game.LeaveGame(); } if (!client.RejoinMCP()) { Log.Warning($"Disconnecting client {cowAccount.Username} since reconnecting to MCP failed, reconnecting to realm"); return(await RealmConnectHelpers.ConnectToRealmWithRetry(client, _config, cowAccount, 10)); } return(true); }
public async Task GameLoop(List <Tuple <AccountCharacter, Client> > clients, int gameCount) { var leadClient = clients.Single(c => GetIsLeadClient(c)); var csManager = new CSManager(new List <Client> { leadClient.Item2 }); uint currentTeleportId = 0; var nextGameCancellation = new CancellationTokenSource(); var gameTasks = clients.Select(async(c, i) => { bool isLeadClient = leadClient == c; if (!isLeadClient) { await Task.Delay(TimeSpan.FromSeconds(2 * i)); if (!await RealmConnectHelpers.JoinGameWithRetry(gameCount, c.Item2, _config, c.Item1)) { return(false); } } Log.Information("In game"); var client = c.Item2; client.Game.RequestUpdate(client.Game.Me.Id); if (!GeneralHelpers.TryWithTimeout( (_) => client.Game.Me.Location.X != 0 && client.Game.Me.Location.Y != 0, TimeSpan.FromSeconds(10))) { return(false); } var townManagementOptions = new TownManagementOptions() { Act = Act.Act4 }; if (!await _townManagementService.PerformTownTasks(c.Item2, townManagementOptions)) { return(false); } Func <uint> getTeleportId = () => currentTeleportId; if (c.Item1.Character.Equals(_csconfig.TeleportCharacterName, StringComparison.CurrentCultureIgnoreCase)) { var result = await TaxiCs(c.Item2, csManager, t => currentTeleportId = t); nextGameCancellation.Cancel(); return(result); } else { var movementMode = client.Game.Me.HasSkill(Skill.Teleport) ? MovementMode.Teleport : MovementMode.Walking; var pathToTpLocation = await _pathingService.GetPathToLocation(client.Game, new Point(5042, 5036), movementMode); if (!await MovementHelpers.TakePathOfLocations(client.Game, pathToTpLocation, movementMode)) { Log.Warning($"Client {client.Game.Me.Name} {movementMode} to portal area failed at {client.Game.Me.Location}"); return(false); } await BaseCsBot(csManager, getTeleportId, nextGameCancellation, client, GetKillActionForClass(client)); } return(true); } ).ToList(); var firstCompletedResult = await Task.WhenAny(gameTasks); if (!await firstCompletedResult) { Log.Warning($"One or more characters failed there town task"); nextGameCancellation.Cancel(); await Task.WhenAll(gameTasks); return; } var townResults = await Task.WhenAll(gameTasks); if (townResults.Any(r => !r)) { Log.Warning($"One or more characters failed there town task"); nextGameCancellation.Cancel(); return; } }
public async Task <bool> MuleItemsForClient(Client client) { var muleGameName = $"{_botConfig.GameNamePrefix}m{GameCount++}"; if (!client.CreateGame(Difficulty.Normal, muleGameName, _botConfig.GamePassword, _botConfig.GameDescriptions?.ElementAtOrDefault(0))) { await Task.Delay(TimeSpan.FromSeconds(10)); return(false); } var failedToJoinCount = 0; foreach (var account in _muleConfig.Accounts) { List <Item> muleItems = GetMuleItems(client, account); if (!muleItems.Any()) { continue; } var accountCharacters = GetAccountCharactersForMule(account); foreach (var character in accountCharacters) { InventoryHelpers.CleanupCursorItem(client.Game); if (!HasAnyItemsToMule(client)) { break; } var muleClient = new Client(); var accountCharacter = new AccountCharacter() { Username = account.Username, Password = account.Password, Character = character }; if (!RealmConnectHelpers.ConnectToRealm( muleClient, _botConfig, accountCharacter)) { Log.Error($"Fail to connect to realm with {account.Username} with character {character}"); return(false); } if (!muleClient.JoinGame(muleGameName, _botConfig.GamePassword)) { Log.Error($"Fail to join game with {account.Username} with character {character}"); failedToJoinCount++; await Task.Delay(TimeSpan.FromSeconds(5) *failedToJoinCount); if (failedToJoinCount > 5) { client.Game.LeaveGame(); await Task.Delay(TimeSpan.FromSeconds(2)); client.RejoinMCP(); return(false); } continue; } await Task.Delay(TimeSpan.FromSeconds(2)); InventoryHelpers.CleanupCursorItem(muleClient.Game); MoveItemResult moveItemResult = MoveItemResult.Succes; do { var movableInventoryItems = muleClient.Game.Inventory.Items.Where(i => Pickit.Pickit.CanTouchInventoryItem(muleClient.Game, i)).ToList(); moveItemResult = InventoryHelpers.StashItemsAndGold(muleClient.Game, movableInventoryItems, 0); if (moveItemResult == MoveItemResult.Failed) { break; } var itemsToTrade = GetItemsToTrade(muleClient.Game.Inventory, muleItems); if (!itemsToTrade.Any()) { break; } var stashItemsToTrade = itemsToTrade.Where(i => i.Container == ContainerType.Stash || i.Container == ContainerType.Stash2).ToList(); if (stashItemsToTrade.Count > 0) { moveItemResult = InventoryHelpers.MoveStashItemsToInventory(client.Game, stashItemsToTrade); InventoryHelpers.CleanupCursorItem(client.Game); } else { moveItemResult = MoveItemResult.Succes; } var itemIdsToTrade = itemsToTrade.Select(i => i.Id).ToHashSet(); itemsToTrade = client.Game.Inventory.Items.Where(i => itemIdsToTrade.Contains(i.Id)).ToList(); if (!itemsToTrade.Any()) { break; } if (moveItemResult != MoveItemResult.Failed) { moveItemResult = await TradeInventoryItems(client, muleClient, itemsToTrade); await Task.Delay(TimeSpan.FromSeconds(5)); } muleItems = GetMuleItems(client, account); if (!muleItems.Any()) { break; } } while (moveItemResult == MoveItemResult.Succes); await Task.Delay(TimeSpan.FromSeconds(2)); muleClient.Game.LeaveGame(); await Task.Delay(TimeSpan.FromSeconds(1)); muleClient.Disconnect(); if (moveItemResult == MoveItemResult.Failed) { client.Game.LeaveGame(); await Task.Delay(TimeSpan.FromSeconds(2)); client.RejoinMCP(); return(false); } } } var stashInventoryItems = client.Game.Inventory.Items.Where(i => i.IsIdentified && Pickit.Pickit.ShouldKeepItem(client.Game, i) && Pickit.Pickit.CanTouchInventoryItem(client.Game, i)).ToList(); InventoryHelpers.StashItemsAndGold(client.Game, stashInventoryItems, 0); client.Game.LeaveGame(); await Task.Delay(TimeSpan.FromSeconds(2)); if (!client.RejoinMCP()) { return(false); } return(true); }
protected async Task CreateGameLoop(Client client) { _accountCharacter.Validate(); try { if (!RealmConnectHelpers.ConnectToRealm(client, _config, _accountCharacter)) { throw new Exception("Could not connect to realm"); } int totalCount = 0; int gameCount = 0; int successiveFailures = 0; int gameDescriptionIndex = 0; while (true) { if (successiveFailures > 0 && successiveFailures % 10 == 0) { gameDescriptionIndex++; if (gameDescriptionIndex == _config.GameDescriptions?.Count) { gameDescriptionIndex = 0; } var reconnectMessage = $"Many successive failures, swithing GS to {_config.GameDescriptions?.ElementAtOrDefault(gameDescriptionIndex)}"; Log.Warning(reconnectMessage); bool reconnectResult = await RealmConnectHelpers.ConnectToRealmWithRetry(client, _config, _accountCharacter, 10); if (!reconnectResult) { await _externalMessagingClient.SendMessage($"Reconnect tries of 10 reached, restarting bot"); return; } } if (gameCount >= 100) { gameCount = 1; } if (NeedsMule) { await _externalMessagingClient.SendMessage($"{client.LoggedInUserName()}: needs mule, starting mule"); if (await _muleService.MuleItemsForClient(client)) { NeedsMule = false; await _externalMessagingClient.SendMessage($"{client.LoggedInUserName()}: finished mule"); } else { await Task.Delay(Math.Pow(successiveFailures, 1.3) *TimeSpan.FromSeconds(5)); await _externalMessagingClient.SendMessage($"{client.LoggedInUserName()}: failed to mule all items, trying again"); if (!await RealmConnectHelpers.ConnectToRealmWithRetry(client, _config, _accountCharacter, 10)) { throw new Exception("Could not connect to realm"); } successiveFailures++; continue; } } try { gameCount++; totalCount++; if (client.CreateGame(_config.Difficulty, $"{_config.GameNamePrefix}{gameCount}", _config.GamePassword, _config.GameDescriptions?.ElementAtOrDefault(gameDescriptionIndex))) { if (!await RunSingleGame(client)) { successiveFailures += 1; } else { successiveFailures = 0; } } else { successiveFailures += 1; await Task.Delay(Math.Pow(successiveFailures, 1.3) *TimeSpan.FromSeconds(5)); } if (client.Game.IsInGame()) { client.Game.LeaveGame(); await Task.Delay(TimeSpan.FromSeconds(3)); } if (!client.RejoinMCP()) { var reconnectMessage = $"Reconnecting to MCP failed, reconnecting to realm instead"; Log.Warning(reconnectMessage); if (!await RealmConnectHelpers.ConnectToRealmWithRetry(client, _config, _accountCharacter, 10)) { throw new Exception("Could not connect to realm"); } } } catch (HttpRequestException) { await _externalMessagingClient.SendMessage($"{client.LoggedInUserName() } Received http exception, map server is probably down, restarting bot"); return; } catch (Exception e) { gameDescriptionIndex++; if (gameDescriptionIndex == _config.GameDescriptions?.Count) { gameDescriptionIndex = 0; } successiveFailures += 1; Log.Warning($"Disconnecting client due to exception {e}, reconnecting to realm, game description is now: {_config.GameDescriptions?.ElementAtOrDefault(gameDescriptionIndex)}"); bool reconnectResult = await RealmConnectHelpers.ConnectToRealmWithRetry(client, _config, _accountCharacter, 10); if (!reconnectResult) { await _externalMessagingClient.SendMessage($"Reconnect tries of 10 reached, restarting bot"); return; } } } } catch (Exception e) { Log.Error(e, $"Unhandled Exception: {e}"); await _externalMessagingClient.SendMessage($"bot crashed with exception: {e}"); throw e; } finally { if (client.Game.IsInGame()) { client.Game.LeaveGame(); } client.Disconnect(); } }