From 89e881cb57cb688be2a35c06e8c4e9fdd0d7c01d Mon Sep 17 00:00:00 2001 From: Regalis Date: Sat, 4 Feb 2017 16:44:46 +0200 Subject: [PATCH] Readded voting (submarine, mode, end round & kick) --- Subsurface/Barotrauma.csproj | 2 +- Subsurface/Source/Characters/Character.cs | 9 +- Subsurface/Source/GUI/GUIListBox.cs | 10 +- Subsurface/Source/Networking/GameClient.cs | 59 ++++- Subsurface/Source/Networking/GameServer.cs | 59 +++-- .../Source/Networking/GameServerLogin.cs | 2 +- .../Source/Networking/GameServerSettings.cs | 2 +- .../Voting.cs} | 236 +++++++++++++----- Subsurface/Source/Screens/NetLobbyScreen.cs | 10 +- 9 files changed, 281 insertions(+), 108 deletions(-) rename Subsurface/Source/{Screens/NetLobbyVoting.cs => Networking/Voting.cs} (55%) diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj index 50fdf4c58..149dcc032 100644 --- a/Subsurface/Barotrauma.csproj +++ b/Subsurface/Barotrauma.csproj @@ -169,7 +169,7 @@ - + diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index 02d27b668..d92441529 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -2486,7 +2486,6 @@ namespace Barotrauma { if (GameMain.Server != null) return null; - bool noInfo = inc.ReadBoolean(); ushort id = inc.ReadUInt16(); string configPath = inc.ReadString(); @@ -2540,6 +2539,14 @@ namespace Barotrauma character.memPos.Clear(); character.memLocalPos.Clear(); } + else + { + var ownerClient = GameMain.Client.ConnectedClients.Find(c => c.ID == ownerId); + if (ownerClient != null) + { + ownerClient.Character = character; + } + } if (configPath == Character.HumanConfigFile) { diff --git a/Subsurface/Source/GUI/GUIListBox.cs b/Subsurface/Source/GUI/GUIListBox.cs index 6c6cb3ee2..684f48e92 100644 --- a/Subsurface/Source/GUI/GUIListBox.cs +++ b/Subsurface/Source/GUI/GUIListBox.cs @@ -239,14 +239,7 @@ namespace Barotrauma child.State = ComponentState.Hover; if (PlayerInput.LeftButtonClicked()) { - Debug.WriteLine("clicked"); Select(i); - //selected = child; - //if (OnSelected != null) - //{ - // if (!OnSelected(selected, child.UserData)) selected = null; - //} - } } else if (selected.Contains(child)) @@ -301,8 +294,7 @@ namespace Barotrauma bool wasSelected = true; if (OnSelected != null) wasSelected = OnSelected(children[childIndex], children[childIndex].UserData) || force; - - + if (!wasSelected) return; if (SelectMultiple) diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index fb3106632..4aafe6211 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -465,6 +465,8 @@ namespace Barotrauma.Networking if (gameStarted && Screen.Selected == GameMain.GameScreen) { + endVoteTickBox.Visible = Voting.AllowEndVoting && myCharacter != null; + if (respawnManager != null) { respawnManager.Update(deltaTime); @@ -632,8 +634,6 @@ namespace Barotrauma.Networking gameStarted = true; - endVoteTickBox.Visible = Voting.AllowEndVoting && myCharacter != null; - GameMain.GameScreen.Select(); yield return CoroutineStatus.Success; @@ -744,6 +744,9 @@ namespace Barotrauma.Networking string selectShuttleName = inc.ReadString(); string selectShuttleHash = inc.ReadString(); + bool allowSubVoting = inc.ReadBoolean(); + bool allowModeVoting = inc.ReadBoolean(); + YesNoMaybe traitorsEnabled = (YesNoMaybe)inc.ReadRangedInteger(0, 2); int missionTypeIndex = inc.ReadRangedInteger(0, Mission.MissionTypes.Count - 1); int modeIndex = inc.ReadByte(); @@ -754,10 +757,14 @@ namespace Barotrauma.Networking float autoRestartTimer = autoRestartEnabled ? inc.ReadFloat() : 0.0f; int clientCount = inc.ReadByte(); - List clientNames = new List(); + List clientNames = new List(); + List clientIDs = new List(); + List characterIDs = new List(); for (int i = 0; i < clientCount; i++) { + clientIDs.Add(inc.ReadByte()); clientNames.Add(inc.ReadString()); + characterIDs.Add(inc.ReadUInt16()); } //ignore the message if we already a more up-to-date one @@ -768,22 +775,40 @@ namespace Barotrauma.Networking GameMain.NetLobbyScreen.ServerName = serverName; GameMain.NetLobbyScreen.ServerMessage.Text = serverText; - GameMain.NetLobbyScreen.TrySelectSub(selectSubName, selectSubHash, GameMain.NetLobbyScreen.SubList); + if (!allowSubVoting) + { + GameMain.NetLobbyScreen.TrySelectSub(selectSubName, selectSubHash, GameMain.NetLobbyScreen.SubList); + } GameMain.NetLobbyScreen.TrySelectSub(selectShuttleName, selectShuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox); GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled); GameMain.NetLobbyScreen.SetMissionType(missionTypeIndex); - GameMain.NetLobbyScreen.SelectMode(modeIndex); + + if (!allowModeVoting) + { + GameMain.NetLobbyScreen.SelectMode(modeIndex); + } GameMain.NetLobbyScreen.LevelSeed = levelSeed; GameMain.NetLobbyScreen.SetAutoRestart(autoRestartEnabled, autoRestartTimer); - + + ConnectedClients.Clear(); GameMain.NetLobbyScreen.ClearPlayers(); - foreach (string clientName in clientNames) + for (int i = 0; i < clientNames.Count; i++) { - GameMain.NetLobbyScreen.AddPlayer(clientName); + var newClient = new Client(clientNames[i], clientIDs[i]); + if (characterIDs[i] > 0) + { + newClient.Character = Entity.FindEntityByID(characterIDs[i]) as Character; + } + + ConnectedClients.Add(newClient); + GameMain.NetLobbyScreen.AddPlayer(newClient.name); } + + Voting.AllowSubVoting = allowSubVoting; + Voting.AllowModeVoting = allowModeVoting; } } lastSentChatMsgID = inc.ReadUInt32(); @@ -791,6 +816,9 @@ namespace Barotrauma.Networking case ServerNetObject.CHAT_MESSAGE: ChatMessage.ClientRead(inc); break; + case ServerNetObject.VOTE: + Voting.ClientRead(inc); + break; } } } @@ -1018,6 +1046,17 @@ namespace Barotrauma.Networking return true; } + public void Vote(VoteType voteType, object data) + { + NetOutgoingMessage msg = client.CreateMessage(); + msg.Write((byte)ClientPacketHeader.UPDATE_LOBBY); + msg.Write((byte)ClientNetObject.VOTE); + Voting.ClientWrite(msg, voteType, data); + msg.Write((byte)ServerNetObject.END_OF_MESSAGE); + + client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); + } + public bool VoteForKick(GUIButton button, object userdata) { var votedClient = otherClients.Find(c => c.Character == userdata); @@ -1027,7 +1066,7 @@ namespace Barotrauma.Networking if (votedClient == null) return false; - //Vote(VoteType.Kick, votedClient); + Vote(VoteType.Kick, votedClient); button.Enabled = false; @@ -1062,7 +1101,7 @@ namespace Barotrauma.Networking return false; } - //Vote(VoteType.EndRound, tickBox.Selected); + Vote(VoteType.EndRound, tickBox.Selected); return false; } diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 965385ff2..01b0fb638 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -370,8 +370,7 @@ namespace Barotrauma.Networking Log("Ending round (submarine reached the end of the level)", Color.Cyan); } - EndGame(); - UpdateNetLobby(null,null); + EndGame(); return; } } @@ -629,6 +628,9 @@ namespace Barotrauma.Networking case ClientNetObject.CHAT_MESSAGE: ChatMessage.ServerRead(inc, c); break; + case ClientNetObject.VOTE: + Voting.ServerRead(inc, c); + break; default: return; //break; @@ -694,7 +696,7 @@ namespace Barotrauma.Networking entityEventManager.Read(inc, c); break; case ClientNetObject.VOTE: - Voting.RegisterVote(inc, c); + Voting.ServerRead(inc, c); break; default: return; @@ -815,6 +817,9 @@ namespace Barotrauma.Networking outmsg.Write((GameMain.NetLobbyScreen.ShuttleList.SelectedData as Submarine).Name); outmsg.Write((GameMain.NetLobbyScreen.ShuttleList.SelectedData as Submarine).MD5Hash.ToString()); + outmsg.Write(Voting.AllowSubVoting); + outmsg.Write(Voting.AllowModeVoting); + outmsg.WriteRangedInteger(0, 2, (int)TraitorsEnabled); outmsg.WriteRangedInteger(0, Mission.MissionTypes.Count - 1, (GameMain.NetLobbyScreen.MissionTypeIndex)); @@ -831,7 +836,9 @@ namespace Barotrauma.Networking outmsg.Write((byte)connectedClients.Count); foreach (Client client in connectedClients) { + outmsg.Write(client.ID); outmsg.Write(client.name); + outmsg.Write(client.Character == null || !gameStarted ? (ushort)0 : client.Character.ID); } } else @@ -965,8 +972,7 @@ namespace Barotrauma.Networking //try again in >5 seconds if (autoRestart) AutoRestartTimer = Math.Max(AutoRestartInterval, 5.0f); GameMain.NetLobbyScreen.StartButton.Enabled = true; - - UpdateNetLobby(null, null); + GameMain.NetLobbyScreen.LastUpdateID++; couldNotStart = true; } @@ -1294,6 +1300,8 @@ namespace Barotrauma.Networking GameMain.NetLobbyScreen.RemovePlayer(client.name); connectedClients.Remove(client); + UpdateVoteStatus(); + AddChatMessage(msg, ChatMessageType.Server); UpdateCrewFrame(); @@ -1457,6 +1465,11 @@ namespace Barotrauma.Networking break; } + if (type == ChatMessageType.Server) + { + senderName = null; + } + var chatMsg = ChatMessage.Create( senderName, modifiedMessage, @@ -1598,21 +1611,29 @@ namespace Barotrauma.Networking { if (server.Connections.Count == 0) return; - var clientsToKick = connectedClients.FindAll(c => c.KickVoteCount > connectedClients.Count * KickVoteRequiredRatio); - //clientsToKick.ForEach(c => KickClient(c)); - - } + var clientsToKick = connectedClients.FindAll(c => c.KickVoteCount >= connectedClients.Count * KickVoteRequiredRatio); + foreach (Client c in clientsToKick) + { + SendChatMessage(c.name+" has been kicked from the server.", ChatMessageType.Server, null); + KickClient(c); + } + + GameMain.NetLobbyScreen.LastUpdateID++; - public bool UpdateNetLobby(object obj) - { - return UpdateNetLobby(null, obj); - } + NetOutgoingMessage msg = server.CreateMessage(); + msg.Write((byte)ServerPacketHeader.UPDATE_LOBBY); + msg.Write((byte)ServerNetObject.VOTE); + Voting.ServerWrite(msg); + msg.Write((byte)ServerNetObject.END_OF_MESSAGE); - public bool UpdateNetLobby(GUIComponent component, object obj) - { - if (server.Connections.Count == 0) return true; - - return true; + server.SendMessage(msg, connectedClients.Select(c => c.Connection).ToList(), NetDeliveryMethod.ReliableUnordered, 0); + + if (Voting.AllowEndVoting && EndVoteMax > 0 && + ((float)EndVoteCount / (float)EndVoteMax) >= EndVoteRequiredRatio) + { + Log("Ending round by votes (" + EndVoteCount + "/" + (EndVoteMax - EndVoteCount) + ")", Color.Cyan); + EndGame(); + } } public void UpdateClientPermissions(Client client) @@ -1757,8 +1778,6 @@ namespace Barotrauma.Networking break; } } - - UpdateNetLobby(null); } private Client FindClientWithJobPreference(List clients, JobPrefab job, bool forceAssign = false) diff --git a/Subsurface/Source/Networking/GameServerLogin.cs b/Subsurface/Source/Networking/GameServerLogin.cs index ef460f968..d3ab37f45 100644 --- a/Subsurface/Source/Networking/GameServerLogin.cs +++ b/Subsurface/Source/Networking/GameServerLogin.cs @@ -204,7 +204,7 @@ namespace Barotrauma.Networking GameMain.NetLobbyScreen.AddPlayer(newClient.name); - AddChatMessage(clName+" has joined the server.", ChatMessageType.Server); + GameMain.Server.SendChatMessage(clName + " has joined the server.", ChatMessageType.Server, null); } } } diff --git a/Subsurface/Source/Networking/GameServerSettings.cs b/Subsurface/Source/Networking/GameServerSettings.cs index 5bc147018..68b4c4515 100644 --- a/Subsurface/Source/Networking/GameServerSettings.cs +++ b/Subsurface/Source/Networking/GameServerSettings.cs @@ -774,7 +774,7 @@ namespace Barotrauma.Networking Voting.AllowSubVoting = subSelectionMode == SelectionMode.Vote; - if (subSelectionMode==SelectionMode.Random) + if (subSelectionMode == SelectionMode.Random) { GameMain.NetLobbyScreen.SubList.Select(Rand.Range(0, GameMain.NetLobbyScreen.SubList.CountChildren)); } diff --git a/Subsurface/Source/Screens/NetLobbyVoting.cs b/Subsurface/Source/Networking/Voting.cs similarity index 55% rename from Subsurface/Source/Screens/NetLobbyVoting.cs rename to Subsurface/Source/Networking/Voting.cs index ce23342c4..871b6c550 100644 --- a/Subsurface/Source/Screens/NetLobbyVoting.cs +++ b/Subsurface/Source/Networking/Voting.cs @@ -58,66 +58,6 @@ namespace Barotrauma } } - public void RegisterVote(NetIncomingMessage inc, List connectedClients) - { - /*byte voteTypeByte = inc.ReadByte(); - VoteType voteType = VoteType.Unknown; - try - { - voteType = (VoteType)voteTypeByte; - } - catch (Exception e) - { - DebugConsole.ThrowError("Failed to cast vote type \""+voteTypeByte+"\"", e); - return; - } - - Client sender = connectedClients.Find(x => x.Connection == inc.SenderConnection); - switch (voteType) - { - case VoteType.Sub: - string subName = inc.ReadString(); - Submarine sub = Submarine.SavedSubmarines.Find(s => s.Name == subName); - sender.SetVote(voteType, sub); - UpdateVoteTexts(connectedClients, voteType); - break; - - case VoteType.Mode: - string modeName = inc.ReadString(); - GameModePreset mode = GameModePreset.list.Find(gm => gm.Name == modeName); - sender.SetVote(voteType, mode); - UpdateVoteTexts(connectedClients, voteType); - break; - case VoteType.EndRound: - if (sender.Character == null) return; - sender.SetVote(voteType, inc.ReadBoolean()); - - GameMain.NetworkMember.EndVoteCount = connectedClients.Count(c => c.Character != null && c.GetVote(VoteType.EndRound)); - GameMain.NetworkMember.EndVoteMax = connectedClients.Count(c => c.Character != null); - - break; - case VoteType.Kick: - - byte kickedClientID = inc.ReadByte(); - - Client kicked = connectedClients.Find(x => x.ID == kickedClientID); - if (kicked == null) return; - - kicked.AddKickVote(sender); - - if (GameMain.Server != null) - { - GameMain.Server.SendChatMessage( - ChatMessage.Create("", sender.name + " has voted to kick " + kicked.name, ChatMessageType.Server, null), - GameMain.Server.ConnectedClients); - } - - break; - } - - GameMain.Server.UpdateVoteStatus();*/ - } - public void UpdateVoteTexts(List clients, VoteType voteType) { GUIListBox listBox = (voteType == VoteType.Sub) ? @@ -162,7 +102,7 @@ namespace Barotrauma object vote = voter.GetVote(voteType); if (vote == null) continue; - var existingVotable = voteList.Find(v => v.First == vote); + var existingVotable = voteList.Find(v => v.First == vote || v.First.Equals(vote)); if (existingVotable == null) { voteList.Add(Pair.Create(vote, 1)); @@ -209,6 +149,180 @@ namespace Barotrauma UpdateVoteTexts(connectedClients, VoteType.Mode); UpdateVoteTexts(connectedClients, VoteType.Sub); } + + public void ClientWrite(NetBuffer msg, VoteType voteType, object data) + { + if (GameMain.Server != null) return; + + msg.Write((byte)voteType); + + switch (voteType) + { + case VoteType.Sub: + Submarine sub = data as Submarine; + if (sub == null) return; + + msg.Write(sub.Name); + break; + case VoteType.Mode: + GameModePreset gameMode = data as GameModePreset; + if (gameMode == null) return; + + msg.Write(gameMode.Name); + break; + case VoteType.EndRound: + if (!(data is bool)) return; + + msg.Write((bool)data); + break; + case VoteType.Kick: + Client votedClient = data as Client; + if (votedClient == null) return; + + msg.Write(votedClient.ID); + break; + } + + msg.WritePadBits(); + } + + public void ServerRead(NetIncomingMessage inc, Client sender) + { + if (GameMain.Server == null || sender == null) return; + + byte voteTypeByte = inc.ReadByte(); + VoteType voteType = VoteType.Unknown; + try + { + voteType = (VoteType)voteTypeByte; + } + catch (Exception e) + { + DebugConsole.ThrowError("Failed to cast vote type \"" + voteTypeByte + "\"", e); + return; + } + + switch (voteType) + { + case VoteType.Sub: + string subName = inc.ReadString(); + Submarine sub = Submarine.SavedSubmarines.Find(s => s.Name == subName); + sender.SetVote(voteType, sub); + UpdateVoteTexts(GameMain.Server.ConnectedClients, voteType); + break; + + case VoteType.Mode: + string modeName = inc.ReadString(); + GameModePreset mode = GameModePreset.list.Find(gm => gm.Name == modeName); + sender.SetVote(voteType, mode); + UpdateVoteTexts(GameMain.Server.ConnectedClients, voteType); + break; + case VoteType.EndRound: + if (sender.Character == null) return; + sender.SetVote(voteType, inc.ReadBoolean()); + + GameMain.NetworkMember.EndVoteCount = GameMain.Server.ConnectedClients.Count(c => c.Character != null && c.GetVote(VoteType.EndRound)); + GameMain.NetworkMember.EndVoteMax = GameMain.Server.ConnectedClients.Count(c => c.Character != null); + + break; + case VoteType.Kick: + byte kickedClientID = inc.ReadByte(); + + Client kicked = GameMain.Server.ConnectedClients.Find(c => c.ID == kickedClientID); + if (kicked == null) return; + + kicked.AddKickVote(sender); + + GameMain.Server.SendChatMessage(sender.name + " has voted to kick " + kicked.name, ChatMessageType.Server, null); + + break; + } + + inc.ReadPadBits(); + + GameMain.Server.UpdateVoteStatus(); + } + + public void ServerWrite(NetBuffer msg) + { + if (GameMain.Server == null) return; + + msg.Write(allowSubVoting); + if (allowSubVoting) + { + List> voteList = GetVoteList(VoteType.Sub, GameMain.Server.ConnectedClients); + msg.Write((byte)voteList.Count); + foreach (Pair vote in voteList) + { + msg.Write((byte)vote.Second); + msg.Write(((Submarine)vote.First).Name); + } + } + msg.Write(AllowModeVoting); + if (allowModeVoting) + { + List> voteList = GetVoteList(VoteType.Mode, GameMain.Server.ConnectedClients); + msg.Write((byte)voteList.Count); + foreach (Pair vote in voteList) + { + msg.Write((byte)vote.Second); + msg.Write(((GameModePreset)vote.First).Name); + } + } + msg.Write(AllowEndVoting); + if (AllowEndVoting) + { + msg.Write((byte)GameMain.Server.ConnectedClients.Count(v => v.GetVote(VoteType.EndRound))); + msg.Write((byte)GameMain.Server.ConnectedClients.Count); + } + + msg.Write(AllowVoteKick); + + msg.WritePadBits(); + } + + public void ClientRead(NetIncomingMessage inc) + { + if (GameMain.Server != null) return; + + AllowSubVoting = inc.ReadBoolean(); + if (allowSubVoting) + { + foreach (Submarine sub in Submarine.SavedSubmarines) + { + SetVoteText(GameMain.NetLobbyScreen.SubList, sub, 0); + } + int votableCount = inc.ReadByte(); + for (int i = 0; i < votableCount; i++) + { + int votes = inc.ReadByte(); + string subName = inc.ReadString(); + Submarine sub = Submarine.SavedSubmarines.Find(sm => sm.Name == subName); + SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes); + } + } + AllowModeVoting = inc.ReadBoolean(); + if (allowModeVoting) + { + int votableCount = inc.ReadByte(); + for (int i = 0; i < votableCount; i++) + { + int votes = inc.ReadByte(); + string modeName = inc.ReadString(); + GameModePreset mode = GameModePreset.list.Find(m => m.Name == modeName); + SetVoteText(GameMain.NetLobbyScreen.ModeList, mode, votes); + } + } + AllowEndVoting = inc.ReadBoolean(); + if (AllowEndVoting) + { + GameMain.NetworkMember.EndVoteCount = inc.ReadByte(); + GameMain.NetworkMember.EndVoteMax = inc.ReadByte(); + } + AllowVoteKick = inc.ReadBoolean(); + + inc.ReadPadBits(); + } } } diff --git a/Subsurface/Source/Screens/NetLobbyScreen.cs b/Subsurface/Source/Screens/NetLobbyScreen.cs index 6b45badf9..39d22fe11 100644 --- a/Subsurface/Source/Screens/NetLobbyScreen.cs +++ b/Subsurface/Source/Screens/NetLobbyScreen.cs @@ -382,8 +382,8 @@ namespace Barotrauma missionTypeButtons[0].Enabled = GameMain.Server != null; missionTypeButtons[1].Enabled = GameMain.Server != null; - ServerName = (GameMain.Server==null) ? "Server" : GameMain.Server.Name; - + ServerName = (GameMain.Server == null) ? "Server" : GameMain.Server.Name; + infoFrame.RemoveChild(StartButton); infoFrame.RemoveChild(infoFrame.children.Find(c => c.UserData as string == "settingsButton")); infoFrame.RemoveChild(infoFrame.children.Find(c => c.UserData as string == "spectateButton")); @@ -732,7 +732,7 @@ namespace Barotrauma { if (GameMain.Client == null) return false; - VoteType voteType = VoteType.Unknown; + VoteType voteType; if (component.Parent == GameMain.NetLobbyScreen.SubList) { if (!GameMain.Client.Voting.AllowSubVoting) return false; @@ -748,7 +748,7 @@ namespace Barotrauma return false; } - //GameMain.Client.Vote(voteType, userData); + GameMain.Client.Vote(voteType, userData); return true; } @@ -1195,7 +1195,9 @@ namespace Barotrauma var matchingListSub = subList.children.Find(c => c.UserData != null && (c.UserData as Submarine).Name == subName) as GUITextBlock; if (matchingListSub != null) { + subList.OnSelected -= VotableClicked; subList.Select(subList.children.IndexOf(matchingListSub), true); + subList.OnSelected += VotableClicked; } Submarine sub = Submarine.SavedSubmarines.Find(m => m.Name == subName);