private void ApplyUpdates() { List <ServerPlayerState> currentTickStates = Server.WorldState.FindAll(state => state.tick == (Server.tick - Server.tickDelay)); for (int i = 1; i < Server.clients.Count; i++) { Client client = Server.clients[i]; if (client != null) { Player player = client.player; if (player != null) // Not disconnected { Debug.Log($"tick {Server.tick} and delayedTick {Server.tick - Server.tickDelay}"); ServerPlayerState stateForCurrentTick = currentTickStates.Find(state => state.clientId == client.id); if (stateForCurrentTick == null) // Client didn't send a packet for this tick (in time) { // EMPTY State, assume no action has been taken ServerPlayerState emptyState = new ServerPlayerState(Server.tick - Server.tickDelay, client.id, new bool[] { false, false, false, false, false, }, player.transform.rotation, 0f, -1f); Server.clients[emptyState.clientId].player.SetInput(emptyState.inputs, emptyState.rotation, emptyState.tick, emptyState.packetClientSendTime, emptyState.serverPacketWriteTime); //FIXME Update clients tick, if this happens more often? } else { // Apply this state player.SetInput(stateForCurrentTick.inputs, stateForCurrentTick.rotation, stateForCurrentTick.tick, stateForCurrentTick.packetClientSendTime, stateForCurrentTick.serverPacketWriteTime); } } } } Server.WorldState.RemoveAll(state => state.tick == (Server.tick - Server.tickDelay)); // Remove when inputs applied (fixme can still states be added while running the loop above?) }
public ServerPlayerState Initialize(PlayerInitializer playerInitializer) { var state = new ServerPlayerState() { OriginalDeck = playerInitializer.Deck, Deck = playerInitializer.Deck.Init(), Hand = new List <CardBase>(), Minions = new List <Minion>(), Player = new Player(playerInitializer.Name, playerInitializer.Class, ruleSet.PlayerStartingHealth), Mana = new ManaStorage(ruleSet.ManaStorageCrystalsAtStart), MinionOrderNumber = 0, Triggers = new TriggerStorage(), Events = new Dictionary <int, List <EventBase> >() }; return(state); }
private static void TryFlow(PacketContext <PlayerFlowPacket> packetContext, ServerPlayer player, ServerPlayerState originState, ServerPlayerState targetState, ServerFlowType serverFlow) { if (!packetContext.Server.AllPlayersInState(originState, false)) { packetContext.Logger.LogWarning($"Player sent disallowed flow-packet: {packetContext.Packet}\nPlayer: {player}"); return; } player.Finished = true; packetContext.Server.BroadcastWithoutSecret(packetContext.Packet); if (!packetContext.Server.AllPlayersInState(originState, true)) { return; } packetContext.Server.Players.ForEach(p => p.MoveToState(targetState)); packetContext.Server.GameServer.Broadcast(new ServerFlowPacket { Type = serverFlow }); }
public GameResult HostTheGame( PlayerInitializer playerInitializer1, PlayerInitializer playerInitializer2, IUserInteractor playerInteractor1, IUserInteractor playerInteractor2) { logger.Log(LogType.Arbiter, LogSeverity.Info, "Game started"); this.playerInteractor1 = playerInteractor1; this.playerInteractor2 = playerInteractor2; var deckValidation1 = deckValidator.ValidateDeck(playerInitializer1.Deck, playerInitializer1.Class); var deckValidation2 = deckValidator.ValidateDeck(playerInitializer2.Deck, playerInitializer2.Class); if (!deckValidation1.IsOk || !deckValidation2.IsOk) { //TODO: figure out where to log the validator messages return(new GameResult() { IsOk = false }); } player1State = gameStatePreparator.Initialize(playerInitializer1); player2State = gameStatePreparator.Initialize(playerInitializer2); //TODO: gamble the right of first turn. //TODO: implement mulligan and initial draw here //TODO: add service for draws and fatigue for (int i = 0; i < ruleSet.HandStartingSize; i++) { var randomCardIndex = new Random().Next(0, player1State.Deck.Count); var card = player1State.Deck[randomCardIndex]; player1State.Deck.RemoveAt(randomCardIndex); player1State.Hand.Add(card); var randomCardIndex2 = new Random().Next(0, player2State.Deck.Count); var card2 = player2State.Deck[randomCardIndex2]; player2State.Deck.RemoveAt(randomCardIndex2); player2State.Hand.Add(card); } isPlayerOneActive = true; var internalTurnNumber = 1; while (internalTurnNumber++ < ruleSet.TurnMaxCountPerGame) { var state = new ServerGameState() { Me = ActivePlayerState, Opp = PassivePlayerState }; state.Me.Events.Add(internalTurnNumber, new List <EventBase>()); logger.Log(LogType.Arbiter, LogSeverity.Info, $"Turn {internalTurnNumber / 2} started for {state.Me.Player.Name}"); // Add new non-empty mana crystal if (state.Me.Mana.PermanentManaCrystals < ruleSet.ManaStorageMaxCrystals) { state.Me.Mana.AddManaCrystals(1, false); } // Refresh Permanent Mana Crystals state.Me.Mana.RefreshPermanentManaCrystals(); //TODO: draw the card from the deck var randomCardIndex = new Random().Next(0, state.Me.Deck.Count); var card = state.Me.Deck[randomCardIndex]; state.Me.Deck.RemoveAt(randomCardIndex); state.Me.Hand.Add(card); //TODO: start of turn events here //TODO: update the state to both users //TODO: send the events var stateForActiveUser = gameStatePreparator.PrepareGameState(state); ActivePlayerInteractor.Update(stateForActiveUser); //TODO: add time limit for a user to interact while (true) { var interaction = ActivePlayerInteractor.Interact(); var interactionValidation = userInteractionProcessor.ValidateInteraction(stateForActiveUser, interaction); if (!interactionValidation.IsOk) { //TODO: figure out where to log the validator messages return(new GameResult() { IsOk = false }); } if (interaction is InteractionEndTurn) { break; } //TODO: send the events to other user userInteractionProcessor.ProcessInteraction(state, interaction); if (state.Me.LastTurnEvents.Any(x => x is EventCharacterDied && (x as EventCharacterDied).DiedCharacter == state.Opp.Player.Id)) { logger.Log(LogType.Arbiter, LogSeverity.Info, $"{state.Me.Player.Name} Won"); logger.Log(LogType.Arbiter, LogSeverity.Info, $"After Game State: {JsonConvert.SerializeObject(state)}"); // TODO: find a more approriate way to stop the game return(new GameResult() { IsOk = true, IsFirstPlayerWon = isPlayerOneActive, FinalState = state }); } stateForActiveUser = gameStatePreparator.PrepareGameState(state); ActivePlayerInteractor.Update(stateForActiveUser); } // Burn Unused Mana state.Me.Mana.BurnTemporaryCrystals(); //TODO: end of turn events here isPlayerOneActive = !isPlayerOneActive; } return(null); }
public bool AllPlayersInState(ServerPlayerState state, bool finished) => Players.TrueForAll(p => p.State == state && (p.Finished || !finished));
public void MoveToState(ServerPlayerState state) { State = state; Finished = false; }