public ServerPlayer AddPlayer(ServerPlayer player) { if (Players.Contains(player)) { return(player); } player.Player.Id = Game.AvailablePlayerId; Game.AddPlayer(player.Player); _players.Add(player); //Queue the game state for them, delaying 1sec for connect messages to be processed fully Timers.CreateTimer(a => { MessageProcessor.SendPrivateMessage(player, new GameCreatedAction()); MessageProcessor.SendPrivateMessage(player, new FullGameStateSentAction(Game)); }, TimeSpan.FromSeconds(1)); //Announce that they joined ChatHandler.SendMessage($"{player.Player.Username} joined the server"); player.LastSentState = PseudoFullGameWorldState.Create(Game); player.Player.OnPropertyChanged -= Player_PropertyChanged; player.Player.OnPropertyChanged += Player_PropertyChanged; MessageProcessor.SendMessage(new PlayerUpdateAction(player.Player, Game)); //Create a state sync loop Timers.CreateReccuringTimer(t => { if (Players.Contains(player)) { var message = new PartialGameStateUpdateAction(Game, player.LastSentState); player.LastSentState = message.StatePartial; //do state sync MessageProcessor.SendPrivateMessage(player, message); } else { //Disconnect Timers.RemoveTimer(t); } }, Configuration.StateSyncRate); //Special case for hotjoin if (Game.HasStarted && Game.Gamemode.HotJoinEnabled) { var time = ServerSettings.Instance.TimeToWaitForPlayersReady.Value; Timers.CreateReccuringTimer((t) => { if (!Game.Running || !Game.Gamemode.HotJoinEnabled) { t.Remove(); } MessageProcessor.SendPrivateMessage(player, new CountdownStartedAction(time)); time -= TimeSpan.FromMilliseconds(16.666); if (time < TimeSpan.Zero) { t.Remove(); } if (player.IsReady) { t.Remove(); MessageProcessor.SendPrivateMessage(player, new CountdownStartedAction(TimeSpan.FromSeconds(-1))); } }, TimeSpan.FromSeconds(0.01)); } return(player); }