From 08053bec852184cd8bb1054484ab2ee3e70b0d69 Mon Sep 17 00:00:00 2001 From: Regalis Date: Thu, 12 Jan 2017 20:41:21 +0200 Subject: [PATCH] Clients can join the game mid-round --- Subsurface/Source/Networking/GameClient.cs | 106 ++++++++++-------- Subsurface/Source/Networking/GameServer.cs | 37 ++++-- .../Source/Networking/RespawnManager.cs | 10 +- 3 files changed, 97 insertions(+), 56 deletions(-) diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 058f544d1..659e7c8dd 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -463,33 +463,20 @@ namespace Barotrauma.Networking #endif } - if (gameStarted && respawnManager != null) - { - respawnManager.Update(deltaTime); - } if (updateTimer > DateTime.Now) return; - - if (myCharacter != null) + + if (gameStarted && Screen.Selected == GameMain.GameScreen) { - if (myCharacter.IsDead) + if (respawnManager != null) { - //Character.Controlled = null; - //GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; + respawnManager.Update(deltaTime); } - else if (gameStarted) - { - - } - } - - if (!gameStarted) - { - SendLobbyUpdate(); + SendIngameUpdate(); } else { - SendIngameUpdate(); + SendLobbyUpdate(); } // Update current time @@ -665,6 +652,49 @@ namespace Barotrauma.Networking yield return CoroutineStatus.Success; } + private void ReadInitialUpdate(NetIncomingMessage inc, bool isDuplicate) + { + myID = inc.ReadByte(); + + UInt16 subListCount = inc.ReadUInt16(); + List submarines = new List(); + for (int i = 0; i < subListCount; i++) + { + + string subName = inc.ReadString(); + string subHash = inc.ReadString(); + + var matchingSub = Submarine.SavedSubmarines.Find(s => s.Name == subName); + if (matchingSub != null) + { + submarines.Add(matchingSub); + } + else + { + submarines.Add(new Submarine(Path.Combine(Submarine.SavePath, subName), subHash, false)); + } + } + + if (!isDuplicate) + { + GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.SubList, submarines); + GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.ShuttleList.ListBox, submarines); + } + + gameStarted = inc.ReadBoolean(); + bool allowSpectating = inc.ReadBoolean(); + + if (gameStarted && !isDuplicate) + { + new GUIMessageBox("Please wait", + (allowSpectating) ? + "A round is already running, but you can spectate the game while waiting for a respawn shuttle or a new round." : + "A round is already running and the admin has disabled spectating. You will have to wait for a new round to start."); + + GameMain.NetLobbyScreen.Select(); + } + } + private void ReadLobbyUpdate(NetIncomingMessage inc) { ServerNetObject objHeader; @@ -684,32 +714,7 @@ namespace Barotrauma.Networking if (inc.ReadBoolean()) { - myID = inc.ReadByte(); - - UInt16 subListCount = inc.ReadUInt16(); - List submarines = new List(); - for (int i = 0; i < subListCount; i++) - { - - string subName = inc.ReadString(); - string subHash = inc.ReadString(); - - var matchingSub = Submarine.SavedSubmarines.Find(s => s.Name == subName); - if (matchingSub != null) - { - submarines.Add(matchingSub); - } - else - { - submarines.Add(new Submarine(Path.Combine(Submarine.SavePath, subName), subHash, false)); - } - } - - if (updateID > GameMain.NetLobbyScreen.LastUpdateID) - { - GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.SubList, submarines); - GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.ShuttleList.ListBox, submarines); - } + ReadInitialUpdate(inc, updateID <= GameMain.NetLobbyScreen.LastUpdateID); } string selectSubName = inc.ReadString(); @@ -999,6 +1004,17 @@ namespace Barotrauma.Networking { if (button != null) button.Enabled = false; + NetOutgoingMessage readyToStartMsg = client.CreateMessage(); + readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME); + + //correct sub & shuttle files found + //TODO: check if they're actually found + readyToStartMsg.Write(true); + + WriteCharacterInfo(readyToStartMsg); + + client.SendMessage(readyToStartMsg, NetDeliveryMethod.ReliableUnordered); + return false; } diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index a21066a47..aaf4ef17c 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -518,6 +518,12 @@ namespace Barotrauma.Networking { connectedClient.ReadyToStart = inc.ReadBoolean(); UpdateCharacterInfo(inc, connectedClient); + + //game already started -> send start message immediately + if (gameStarted) + { + SendStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.gameMode.Preset, connectedClients); + } } break; case ClientPacketHeader.UPDATE_LOBBY: @@ -647,6 +653,25 @@ namespace Barotrauma.Networking } } + /// + /// Write info that the client needs when joining the server + /// + private void ClientWriteInitial(Client c, NetBuffer outmsg) + { + outmsg.Write(c.ID); + + var subList = GameMain.NetLobbyScreen.GetSubList(); + outmsg.Write((UInt16)subList.Count); + for (int i = 0; i < subList.Count; i++) + { + outmsg.Write(subList[i].Name); + outmsg.Write(subList[i].MD5Hash.ToString()); + } + + outmsg.Write(GameStarted); + outmsg.Write(AllowSpectating); + } + private void ClientWriteIngame(Client c) { NetOutgoingMessage outmsg = server.CreateMessage(); @@ -721,19 +746,11 @@ namespace Barotrauma.Networking outmsg.Write(GameMain.NetLobbyScreen.LastUpdateID); outmsg.Write(GameMain.NetLobbyScreen.GetServerName()); outmsg.Write(GameMain.NetLobbyScreen.ServerMessage.Text); - var subList = GameMain.NetLobbyScreen.GetSubList(); - + outmsg.Write(c.lastRecvGeneralUpdate < 1); if (c.lastRecvGeneralUpdate < 1) { - outmsg.Write(c.ID); - - outmsg.Write((UInt16)subList.Count); - for (int i = 0; i < subList.Count; i++) - { - outmsg.Write(subList[i].Name); - outmsg.Write(subList[i].MD5Hash.ToString()); - } + ClientWriteInitial(c, outmsg); } outmsg.Write((GameMain.NetLobbyScreen.SubList.SelectedData as Submarine).Name); outmsg.Write((GameMain.NetLobbyScreen.SubList.SelectedData as Submarine).MD5Hash.ToString()); diff --git a/Subsurface/Source/Networking/RespawnManager.cs b/Subsurface/Source/Networking/RespawnManager.cs index 0ee0fdf61..c60194ee5 100644 --- a/Subsurface/Source/Networking/RespawnManager.cs +++ b/Subsurface/Source/Networking/RespawnManager.cs @@ -388,11 +388,19 @@ namespace Barotrauma.Networking var clients = GetClientsToRespawn(); + foreach (Client c in clients) + { + if (c.characterInfo == null) c.characterInfo = new CharacterInfo(Character.HumanConfigFile, c.name); + } + List characterInfos = clients.Select(c => c.characterInfo).ToList(); if (server.Character != null && server.Character.IsDead) characterInfos.Add(server.CharacterInfo); server.AssignJobs(clients, server.Character != null && server.Character.IsDead); - clients.ForEach(c => c.characterInfo.Job = new Job(c.assignedJob)); + foreach (Client c in clients) + { + c.characterInfo.Job = new Job(c.assignedJob); + } //the spawnpoints where the characters will spawn var shuttleSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, respawnShuttle);