コード例 #1
0
ファイル: Client.cs プロジェクト: GraionDilach/freeserf.net
        void ProcessData(IRemoteServer server, INetworkData networkData, ResponseHandler responseHandler)
        {
            switch (networkData.Type)
            {
            case NetworkDataType.Request:
                HandleRequest(networkData as RequestData, responseHandler);
                break;

            case NetworkDataType.Heartbeat:
            {
                var heartbeat = networkData as Heartbeat;
                // Last heartbeat time was set before.
                if (PlayerIndex == 0u)
                {
                    PlayerIndex = heartbeat.PlayerId;
                }
                foreach (var registeredHeartbeatHandler in registeredHeartbeatHandlers.ToArray())
                {
                    registeredHeartbeatHandler?.Invoke(heartbeat);
                }
                responseHandler?.Invoke(ResponseType.Ok);
                break;
            }

            case NetworkDataType.LobbyData:
                if (serverState != ServerState.Lobby)
                {
                    responseHandler?.Invoke(ResponseType.BadState);
                }
                else
                {
                    responseHandler?.Invoke(ResponseType.Ok);
                    UpdateLobbyData(networkData as LobbyData);
                }
                break;

            case NetworkDataType.Response:
            {
                var responseData = networkData as ResponseData;
                foreach (var registeredResponseHandler in registeredResponseHandlers.ToArray())
                {
                    registeredResponseHandler?.Invoke(responseData);
                }
                break;
            }

            case NetworkDataType.InSync:
            {
                if (serverState != ServerState.Game &&
                    serverState != ServerState.Loading)
                {
                    responseHandler?.Invoke(ResponseType.BadState);
                }
                else
                {
                    if (Game == null)
                    {
                        serverState = ServerState.Offline;
                        responseHandler?.Invoke(ResponseType.BadState);
                        return;
                    }

                    try
                    {
                        var insyncData = networkData as InSyncData;

                        Log.Verbose.Write(ErrorSystemType.Network, $"Processing in-sync message with game time {Misc.SecondsToTime(insyncData.GameTime)}.");

                        if (!lastSavedGameStates.ContainsKey(insyncData.GameTime))         // We don't have the saved state anymore -> need full update
                        {
                            Log.Verbose.Write(ErrorSystemType.Network, $"Last saved game state with game time {Misc.SecondsToTime(insyncData.GameTime)} not available. Requesting re-sync.");
                            RequestGameStateUpdate();
                            return;
                        }

                        Log.Verbose.Write(ErrorSystemType.Network, $"Updating last synced saved state to game time {Misc.SecondsToTime(insyncData.GameTime)} and discarding outdated saved game states.");
                        lastVerifiedSavedGameState = lastSavedGameStates[insyncData.GameTime];
                        // Remove all outdated (timestamp before in-sync game time) saved states.
                        foreach (var outdatedSavedGameState in lastSavedGameStates.Where(s => s.Key <= insyncData.GameTime).ToList())
                        {
                            lastSavedGameStates.Remove(outdatedSavedGameState.Key);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error.Write(ErrorSystemType.Network, "Failed to update game state: " + ex.Message);
                        Disconnect();
                        throw ex;         // TODO: Close game instead of crash?
                    }
                }
                break;
            }

            case NetworkDataType.SyncData:
            {
                if (serverState != ServerState.Game &&
                    serverState != ServerState.Loading)
                {
                    responseHandler?.Invoke(ResponseType.BadState);
                }
                else
                {
                    if (Game == null)
                    {
                        serverState = ServerState.Offline;
                        responseHandler?.Invoke(ResponseType.BadState);
                        return;
                    }

                    try
                    {
                        var syncData = networkData as SyncData;

#if DEBUG
                        var stopWatch = System.Diagnostics.Stopwatch.StartNew();
                        Log.Verbose.Write(ErrorSystemType.Network, "Processing sync ... ");
#endif
                        lock (Game)
                        {
                            lastSavedGameStates.Clear();
                            if (lastVerifiedSavedGameState == null)
                            {
                                lastVerifiedSavedGameState = SavedGameState.FromGame(Game);
                            }
                            lastVerifiedSavedGameState = SavedGameState.UpdateGameAndLastState(Game, lastVerifiedSavedGameState, syncData.SerializedData, syncData.Full);
                        }

#if DEBUG
                        Log.Verbose.Write(ErrorSystemType.Network, $"Processing sync done in {stopWatch.ElapsedMilliseconds / 1000.0} seconds");
#endif
                    }
                    catch (Exception ex)
                    {
                        Log.Error.Write(ErrorSystemType.Network, "Failed to update game state: " + ex.Message);
                        Disconnect();
                        throw ex;         // TODO: Close game instead of crash?
                    }
                }
                break;
            }

            default:
                // Should have been handled by Server_DataReceived already.
                break;
            }
        }