/// <summary> /// Fired when client fails to join game /// </summary> /// <param name="sender">DriverClient that caused this event</param> /// <param name="e">Failure information</param> void newClient_OnFailure(object sender, FailureArgs e) { ClientDriver source = sender as ClientDriver; FailedClientCounts[source.ClientIndex]++; if (FailedClientCounts[source.ClientIndex] <= 3) { if (!RecycleClient(source)) { return; } Output("Client failure #" + FailedClientCounts[source.ClientIndex]); } else { Output("Client failed too many times, ignoring it from now on"); } if (e.Type == FailureArgs.FailureTypes.GameserverDeniedConnection) { TemporaryJoinDelay += 5000; Output("Adding a 5second temporary join delay"); } else if (e.Type == FailureArgs.FailureTypes.FailedToJoinGame) { Output("Failed to join game, giving up"); return; } Output("Attempting next client"); PushBot(); }
/// <summary> /// Fired when client successfully enteres game /// </summary> /// <param name="sender">DriverClient that caused this event</param> /// <param name="e">Unused</param> void newClient_OnEnterGame(object sender, EventArgs e) { if (isShuttindDown) { PopBot(); return; } ClientDriver source = sender as ClientDriver; Output("Client entered game"); if (settings.IsSinglePlayerMode) { if (source.PlayerNames.Count + 1 < source.MaxPlayers) { Output("Room for another bot, adding..."); PushBot(); } } else { // PlayerNames doesn't include our bot's name yet if (source.PlayerNames.Count + 1 < source.MaxPlayers - 1) { Output("Room for another bot, adding..."); PushBot(); } else if (source.PlayerNames.Count + 1 == source.MaxPlayers && clients.Count > 0) { Output("oops, this bot wasn't needed, removing..."); PopBot(); } } }
/// <summary> /// Fired when client disconnects from game /// </summary> /// <param name="sender">DriverClient that caused this event</param> /// <param name="e">Unused</param> void newClient_OnClientDisconnect(object sender, EventArgs e) { ClientDriver source = sender as ClientDriver; Output("Client disconnected"); RecycleClient(source); }
/// <summary> /// Starts and new bot /// </summary> private void PushBot() { ClientDriver newClient = null; lock (availableClients) { if (availableClients.Count == 0) { Output("PushBot(): No bots available!"); return; } newClient = availableClients.Dequeue(); } Output("Waiting " + (settings.JoinDelay + TemporaryJoinDelay) + "ms..."); for (int i = 0; i < (settings.JoinDelay + TemporaryJoinDelay) / 100; i++) { System.Threading.Thread.Sleep(100); if (isShuttindDown) { TemporaryJoinDelay = 0; Output("Canceling PushBot()"); FireOnCompletion(); return; } } TemporaryJoinDelay = 0; newClient.OnClientDisconnect += new EventHandler(newClient_OnClientDisconnect); newClient.OnEnterGame += new EventHandler(newClient_OnEnterGame); newClient.OnFailure += new EventHandler <FailureArgs>(newClient_OnFailure); newClient.OnShutdown += new EventHandler(newClient_OnShutdown); lock (clients) { if (clients.Count == 0) { // Only one client should handle player count change events since this is where we handle adding/removing bots newClient.OnPlayerCountChanged += new EventHandler <PlayerCountArgs>(newClient_OnPlayerCountChanged); // We only want to read game chat from one client Logger.Instance.GameMessageFilter.Add(newClient.CharacterName); // TODO: Why only one client for driver messages...? Logger.Instance.DriverMessageFilter.Add(newClient.CharacterName); } clients.Add(newClient); } newClient.Start(); }
/// <summary> /// Moves specified client from pool of running clients to pool of available clients. Client itself /// isn't moved, but it's recreated using the same clientIndex so any values from deadClient will be /// lost. /// </summary> /// <param name="deadClient"></param> /// <returns> /// True if client was successfully recycled, false if this is the only active client and the /// driver needs to shut down. OnCompletion has been fired /// </returns> bool RecycleClient(ClientDriver deadClient) { lock (clients) { clients.Remove(deadClient); if (clients.Count == 0) { // If the last client failed or disconnected then we can no longer operate FireOnCompletion(); return(false); } } AddBotAsAvailable(deadClient); return(true); }
/// <summary> /// Moves specified client from pool of running clients to pool of available clients. Client itself /// isn't moved, but it's recreated using the same clientIndex so any values from deadClient will be /// lost. /// </summary> /// <param name="deadClient"></param> /// <returns> /// True if client was successfully recycled, false if this is the only active client and the /// driver needs to shut down. OnCompletion has been fired /// </returns> bool RecycleClient(ClientDriver deadClient) { lock (clients) { clients.Remove(deadClient); if (clients.Count == 0) { // If the last client failed or disconnected then we can no longer operate FireOnCompletion(); return false; } } AddBotAsAvailable(deadClient); return true; }
/// <summary> /// Adds client to list of available clients if it's not already present /// </summary> /// <param name="client">Bot to add</param> private void AddBotAsAvailable(ClientDriver client) { AddBotAsAvailable(client.ClientIndex); }