示例#1
0
        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++;
            }
        }
示例#2
0
        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);
        }
示例#3
0
        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();
            }
        }