From 4fbb83e2e7149cfc7fcc03f9068ec9c392813dcb Mon Sep 17 00:00:00 2001 From: Regalis Date: Fri, 9 Sep 2016 19:49:13 +0300 Subject: [PATCH] The server can start the game --- Subsurface/Source/DebugConsole.cs | 14 -- Subsurface/Source/Networking/GameClient.cs | 75 ++++++++ Subsurface/Source/Networking/GameServer.cs | 179 ++++++++++++++---- Subsurface/Source/Networking/NetworkMember.cs | 27 +-- 4 files changed, 235 insertions(+), 60 deletions(-) diff --git a/Subsurface/Source/DebugConsole.cs b/Subsurface/Source/DebugConsole.cs index d8aaab928..c8e5a00b2 100644 --- a/Subsurface/Source/DebugConsole.cs +++ b/Subsurface/Source/DebugConsole.cs @@ -637,20 +637,6 @@ namespace Barotrauma if (!(c.AIController is EnemyAIController)) continue; c.AddDamage(CauseOfDeath.Damage, 10000.0f, null); } - break; - case "sendrandomdata": - int messageCount = 1; - - if (commands.Length > 1) int.TryParse(commands[1], out messageCount); - - for (int i = 0; i < messageCount; i++) - { - if (GameMain.Server != null) - { - GameMain.Server.SendRandomData(); - } - } - break; case "netstats": if (GameMain.Server == null) return; diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 2bd8693d8..6a9888cd4 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -513,12 +513,87 @@ namespace Barotrauma.Networking case ServerPacketHeader.UPDATE_LOBBY: ReadLobbyUpdate(inc); break; + case ServerPacketHeader.QUERY_STARTGAME: + string subName = inc.ReadString(); + string subHash = inc.ReadString(); + + string shuttleName = inc.ReadString(); + string shuttleHash = inc.ReadString(); + + NetOutgoingMessage readyToStartMsg = client.CreateMessage(); + readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME); + + readyToStartMsg.Write( + GameMain.NetLobbyScreen.TrySelectSub(subName, subHash, GameMain.NetLobbyScreen.SubList) && + GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox)); + + client.SendMessage(readyToStartMsg, NetDeliveryMethod.ReliableUnordered); + + break; + case ServerPacketHeader.STARTGAME: + startGameCoroutine = GameMain.ShowLoading(StartGame(inc), false); + break; } break; } } } + private IEnumerable StartGame(NetIncomingMessage inc) + { + if (Character != null) Character.Remove(); + + endVoteTickBox.Selected = false; + + int seed = inc.ReadInt32(); + string levelSeed = inc.ReadString(); + + int missionTypeIndex = inc.ReadByte(); + + string subName = inc.ReadString(); + string subHash = inc.ReadString(); + + string shuttleName = inc.ReadString(); + string shuttleHash = inc.ReadString(); + + string modeName = inc.ReadString(); + + bool respawnAllowed = inc.ReadBoolean(); + + GameModePreset gameMode = GameModePreset.list.Find(gm => gm.Name == modeName); + + if (gameMode == null) + { + DebugConsole.ThrowError("Game mode ''" + modeName + "'' not found!"); + yield return CoroutineStatus.Success; + } + + if (!GameMain.NetLobbyScreen.TrySelectSub(subName, subHash, GameMain.NetLobbyScreen.SubList)) + { + yield return CoroutineStatus.Success; + } + + if (!GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox)) + { + yield return CoroutineStatus.Success; + } + + Rand.SetSyncedSeed(seed); + + GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, Mission.MissionTypes[missionTypeIndex]); + GameMain.GameSession.StartShift(levelSeed); + + if (respawnAllowed) respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.SelectedShuttle); + + gameStarted = true; + + endVoteTickBox.Visible = Voting.AllowEndVoting && myCharacter != null; + + GameMain.GameScreen.Select(); + + yield return CoroutineStatus.Success; + } + private void ReadLobbyUpdate(NetIncomingMessage inc) { ServerNetObject objHeader; diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 54bfbbf73..3b74f5881 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -368,29 +368,7 @@ namespace Barotrauma.Networking switch (inc.MessageType) { case NetIncomingMessageType.Data: - if (banList.IsBanned(inc.SenderEndPoint.Address.ToString())) - { - KickClient(inc.SenderConnection,true); - } - else - { - ClientPacketHeader header = (ClientPacketHeader)inc.ReadByte(); - switch (header) - { - case ClientPacketHeader.REQUEST_AUTH: - ClientAuthRequest(inc.SenderConnection); - break; - case ClientPacketHeader.REQUEST_INIT: - ClientInitRequest(inc); - break; - case ClientPacketHeader.UPDATE_LOBBY: - ClientReadLobby(inc); - break; - case ClientPacketHeader.UPDATE_INGAME: - //TODO - break; - } - } + ReadDataMessage(inc); break; case NetIncomingMessageType.StatusChanged: switch (inc.SenderConnection.Status) @@ -426,9 +404,9 @@ namespace Barotrauma.Networking } } break; - } - + } } + catch (Exception e) { #if DEBUG @@ -498,6 +476,40 @@ namespace Barotrauma.Networking refreshMasterTimer = DateTime.Now + refreshMasterInterval; } + private void ReadDataMessage(NetIncomingMessage inc) + { + if (banList.IsBanned(inc.SenderEndPoint.Address.ToString())) + { + KickClient(inc.SenderConnection, true); + return; + } + + ClientPacketHeader header = (ClientPacketHeader)inc.ReadByte(); + switch (header) + { + case ClientPacketHeader.REQUEST_AUTH: + ClientAuthRequest(inc.SenderConnection); + break; + case ClientPacketHeader.REQUEST_INIT: + ClientInitRequest(inc); + break; + + case ClientPacketHeader.RESPONSE_STARTGAME: + var connectedClient = connectedClients.Find(c => c.Connection == inc.SenderConnection); + if (connectedClient != null) + { + connectedClient.ReadyToStart = inc.ReadBoolean(); + } + break; + case ClientPacketHeader.UPDATE_LOBBY: + ClientReadLobby(inc); + break; + case ClientPacketHeader.UPDATE_INGAME: + //TODO + break; + } + } + private void SparseUpdate() { //if (gameStarted) @@ -703,11 +715,117 @@ namespace Barotrauma.Networking return false; } - //CoroutineManager.StartCoroutine(WaitForPlayersReady(selectedSub, selectedShuttle, selectedMode), "WaitForPlayersReady"); + CoroutineManager.StartCoroutine(InitiateStartGame(selectedSub, selectedShuttle, selectedMode), "InitiateStartGame"); return true; } + private IEnumerable InitiateStartGame(Submarine selectedSub, Submarine selectedShuttle, GameModePreset selectedMode) + { + GameMain.NetLobbyScreen.StartButton.Enabled = false; + + NetOutgoingMessage msg = server.CreateMessage(); + msg.Write((byte)ServerPacketHeader.QUERY_STARTGAME); + + msg.Write(selectedSub.Name); + msg.Write(selectedSub.MD5Hash.Hash); + + msg.Write(selectedShuttle.Name); + msg.Write(selectedShuttle.MD5Hash.Hash); + + connectedClients.ForEach(c => c.ReadyToStart = false); + + server.SendMessage(msg, connectedClients.Select(c => c.Connection).ToList(), NetDeliveryMethod.ReliableUnordered, 0); + + //give the clients a few seconds to request missing sub/shuttle files before starting the round + float waitForResponseTimer = 3.0f; + while (connectedClients.Any(c => !c.ReadyToStart) && waitForResponseTimer > 0.0f) + { + waitForResponseTimer -= CoroutineManager.UnscaledDeltaTime; + yield return CoroutineStatus.Running; + } + + //todo: wait until file transfers are finished/cancelled + + GameMain.ShowLoading(StartGame(selectedSub, selectedShuttle, selectedMode), false); + + yield return CoroutineStatus.Success; + } + + private IEnumerable StartGame(Submarine selectedSub, Submarine selectedShuttle, GameModePreset selectedMode) + { + Item.Spawner.Clear(); + Item.Remover.Clear(); + + GameMain.NetLobbyScreen.StartButton.Enabled = false; + + GUIMessageBox.CloseAll(); + + //AssignJobs(connectedClients); + + roundStartSeed = DateTime.Now.Millisecond; + Rand.SetSyncedSeed(roundStartSeed); + + GameMain.GameSession = new GameSession(selectedSub, "", selectedMode, Mission.MissionTypes[GameMain.NetLobbyScreen.MissionTypeIndex]); + GameMain.GameSession.StartShift(GameMain.NetLobbyScreen.LevelSeed); + + GameServer.Log("Starting a new round...", Color.Cyan); + GameServer.Log("Submarine: " + selectedSub.Name, Color.Cyan); + GameServer.Log("Game mode: " + selectedMode.Name, Color.Cyan); + GameServer.Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed, Color.Cyan); + + if (AllowRespawn) respawnManager = new RespawnManager(this, selectedShuttle); + + var startMessage = CreateStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.gameMode.Preset); + server.SendMessage(startMessage, connectedClients.Select(c => c.Connection).ToList(), NetDeliveryMethod.ReliableUnordered, 0); + + yield return CoroutineStatus.Running; + + //UpdateCrewFrame(); + + //TraitorManager = null; + //if (TraitorsEnabled == YesNoMaybe.Yes || + // (TraitorsEnabled == YesNoMaybe.Maybe && Rand.Range(0.0f, 1.0f) < 0.5f)) + //{ + // TraitorManager = new TraitorManager(this); + //} + + GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; + GameMain.GameScreen.Select(); + + AddChatMessage("Press TAB to chat. Use ''r;'' to talk through the radio.", ChatMessageType.Server); + + GameMain.NetLobbyScreen.StartButton.Enabled = true; + + gameStarted = true; + + yield return CoroutineStatus.Success; + } + + private NetOutgoingMessage CreateStartMessage(int seed, Submarine selectedSub, GameModePreset selectedMode) + { + NetOutgoingMessage msg = server.CreateMessage(); + msg.Write((byte)ServerPacketHeader.STARTGAME); + + msg.Write(seed); + + msg.Write(GameMain.NetLobbyScreen.LevelSeed); + + msg.Write((byte)GameMain.NetLobbyScreen.MissionTypeIndex); + + msg.Write(selectedSub.Name); + msg.Write(selectedSub.MD5Hash.Hash); + + msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.Name); + msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash.Hash); + + msg.Write(selectedMode.Name); + + msg.Write(AllowRespawn); + + return msg; + } + public void EndGame() { if (!gameStarted) return; @@ -1135,15 +1253,6 @@ namespace Barotrauma.Networking GameMain.Server.log.WriteLine(line, color); } - /// - /// sends some random data to the clients - /// use for debugging purposes - /// - public void SendRandomData() - { - //NO DON'T DO THIS WHY - } - public override void Disconnect() { banList.Save(); diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index a0dfc2c65..26db014d9 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -11,27 +11,32 @@ namespace Barotrauma.Networking { enum ClientPacketHeader { - REQUEST_AUTH, //ask the server if a password is needed, if so we'll get nonce for encryption - REQUEST_INIT, //ask the server to give you initialization - UPDATE_LOBBY, //update state in lobby - UPDATE_INGAME, //update state ingame while alive + REQUEST_AUTH, //ask the server if a password is needed, if so we'll get nonce for encryption + REQUEST_INIT, //ask the server to give you initialization + UPDATE_LOBBY, //update state in lobby + UPDATE_INGAME, //update state ingame while alive + + RESPONSE_STARTGAME //tell the server whether you're ready to start } enum ClientNetObject { END_OF_MESSAGE, //self-explanatory - SYNC_IDS, //ids of the last changes the client knows about - CHAT_MESSAGE, //also self-explanatory - VOTE, //you get the idea + SYNC_IDS, //ids of the last changes the client knows about + CHAT_MESSAGE, //also self-explanatory + VOTE, //you get the idea CHARACTER_INPUT, ITEM_INTERACTION } enum ServerPacketHeader { - AUTH_RESPONSE, //tell the player if they require a password to log in - AUTH_FAILURE, //the server won't authorize player yet, however connection is still alive - UPDATE_LOBBY, //update state in lobby (votes and chat messages) - UPDATE_INGAME, //update state ingame while alive (character input and chat messages) + AUTH_RESPONSE, //tell the player if they require a password to log in + AUTH_FAILURE, //the server won't authorize player yet, however connection is still alive + UPDATE_LOBBY, //update state in lobby (votes and chat messages) + UPDATE_INGAME, //update state ingame while alive (character input and chat messages) + + QUERY_STARTGAME, //ask the clients whether they're ready to start + STARTGAME //start a new round } enum ServerNetObject {