From 8ae2fb225c784c824dc7adfdd0c1c939435ed67e Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Sun, 2 Jul 2017 21:36:17 +0300 Subject: [PATCH] - Ban duration can be set in the UI prompt. - Ban reasons & durations are listed in the banlist menu. - Clients tell the server the reason when kicking/banning another client. - Added GUINumberInput GUIComponent. - Ban duration saving/loading fixes. --- .../BarotraumaClient/BarotraumaClient.csproj | 1 + .../Source/GUI/GUINumberInput.cs | 104 ++++++++++++++++++ .../Source/Networking/BanList.cs | 21 +++- .../Source/Networking/GameClient.cs | 6 +- .../Source/Networking/NetworkMember.cs | 47 ++++++-- .../BarotraumaShared/Content/UI/style.xml | 13 +++ .../Source/Networking/BanList.cs | 14 ++- .../Source/Networking/GameServer.cs | 14 ++- 8 files changed, 193 insertions(+), 27 deletions(-) create mode 100644 Barotrauma/BarotraumaClient/Source/GUI/GUINumberInput.cs diff --git a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj index 1aaea586e..f845f84d6 100644 --- a/Barotrauma/BarotraumaClient/BarotraumaClient.csproj +++ b/Barotrauma/BarotraumaClient/BarotraumaClient.csproj @@ -113,6 +113,7 @@ + diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUINumberInput.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUINumberInput.cs new file mode 100644 index 000000000..cb2c220c1 --- /dev/null +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUINumberInput.cs @@ -0,0 +1,104 @@ +using Microsoft.Xna.Framework; +using System; +using Microsoft.Xna.Framework.Graphics; + +namespace Barotrauma +{ + class GUINumberInput : GUIComponent + { + private GUITextBox textBox; + private GUIButton plusButton, minusButton; + + public int? MinValue, MaxValue; + + private int value; + public int Value + { + get { return value; } + set + { + this.value = value; + if (MinValue != null) + { + this.value = Math.Max(this.value, (int)MinValue); + } + if (MaxValue != null) + { + this.value = Math.Min(this.value, (int)MaxValue); + } + textBox.Text = this.value.ToString(); + } + } + + public GUINumberInput(Rectangle rect, string style, int? minValue = null, int? maxValue = null, GUIComponent parent = null) + : this(rect, style, Alignment.TopLeft, minValue, maxValue, parent) + { + } + + public GUINumberInput(Rectangle rect, string style, Alignment alignment, int? minValue = null, int? maxValue = null, GUIComponent parent = null) + : base(style) + { + this.rect = rect; + + this.alignment = alignment; + + if (parent != null) + parent.AddChild(this); + + textBox = new GUITextBox(Rectangle.Empty, style, this); + + textBox.OnTextChanged += TextChanged; + + plusButton = new GUIButton(new Rectangle(0, 0, 15, rect.Height / 2), "+", Alignment.TopRight, style, this); + plusButton.OnClicked += ChangeValue; + minusButton = new GUIButton(new Rectangle(0, 0, 15, rect.Height / 2), "-", Alignment.BottomRight, style, this); + minusButton.OnClicked += ChangeValue; + + MinValue = minValue; + MaxValue = maxValue; + + Value = minValue != null ? (int)minValue : 0; + } + + private bool ChangeValue(GUIButton button, object userData) + { + if (button == plusButton) + { + Value++; + } + else + { + Value--; + } + + return false; + } + + private bool TextChanged(GUITextBox textBox, string text) + { + int newValue = Value; + if (text == "" || text == "-") + { + Value = 0; + textBox.Text = text; + } + else if (int.TryParse(text, out newValue)) + { + Value = newValue; + } + else + { + textBox.Text = Value.ToString(); + } + + return true; + } + + public override void Draw(SpriteBatch spriteBatch) + { + if (!Visible) return; + + DrawChildren(spriteBatch); + } + } +} diff --git a/Barotrauma/BarotraumaClient/Source/Networking/BanList.cs b/Barotrauma/BarotraumaClient/Source/Networking/BanList.cs index 7e7640176..e0cf41a44 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/BanList.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/BanList.cs @@ -23,23 +23,32 @@ namespace Barotrauma.Networking foreach (BannedPlayer bannedPlayer in bannedPlayers) { GUITextBlock textBlock = new GUITextBlock( - new Rectangle(0, 0, 0, 25), + new Rectangle(0, 0, 0, 55), bannedPlayer.IP + " (" + bannedPlayer.Name + ")", "", - Alignment.Left, Alignment.Left, banFrame); - textBlock.Padding = new Vector4(10.0f, 10.0f, 0.0f, 0.0f); + Alignment.Left, Alignment.TopLeft, banFrame); + textBlock.Padding = new Vector4(10.0f, 10.0f, 10.0f, 10.0f); textBlock.UserData = banFrame; - textBlock.ToolTip = bannedPlayer.Reason; - var removeButton = new GUIButton(new Rectangle(0, 0, 100, 20), "Remove", Alignment.Right | Alignment.CenterY, "", textBlock); + var removeButton = new GUIButton(new Rectangle(0, 0, 80, 20), "Remove", Alignment.TopRight, "", textBlock); removeButton.UserData = bannedPlayer; removeButton.OnClicked = RemoveBan; if (bannedPlayer.IP.IndexOf(".x") <= -1) { - var rangeBanButton = new GUIButton(new Rectangle(-100, 0, 100, 20), "Ban range", Alignment.Right | Alignment.CenterY, "", textBlock); + var rangeBanButton = new GUIButton(new Rectangle(-85, 0, 90, 20), "Ban range", Alignment.TopRight, "", textBlock); rangeBanButton.UserData = bannedPlayer; rangeBanButton.OnClicked = RangeBan; } + + var reasonText = new GUITextBlock(new Rectangle(0, 0, 170, 20), + string.IsNullOrEmpty(bannedPlayer.Reason) ? "Reason: none" : ToolBox.LimitString("Reason: " + bannedPlayer.Reason, GUI.SmallFont, 170), + "", Alignment.BottomLeft, Alignment.TopLeft, textBlock, false, GUI.SmallFont); + reasonText.ToolTip = bannedPlayer.Reason; + + new GUITextBlock(new Rectangle(0, 0, 100, 20), + bannedPlayer.ExpirationTime == null ? "Permanent" : "Expires " + bannedPlayer.ExpirationTime.Value.ToString(), + "", Alignment.BottomRight, Alignment.TopRight, textBlock, false, GUI.SmallFont); + } return banFrame; diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index 1b9054c8f..05934eec1 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -1245,9 +1245,9 @@ namespace Barotrauma.Networking { NetOutgoingMessage msg = client.CreateMessage(); msg.Write((byte)ClientPacketHeader.SERVER_COMMAND); - msg.Write((byte)ClientPermissions.Kick); - //TODO: write the reason + msg.Write((byte)ClientPermissions.Kick); msg.Write(kickedName); + msg.Write(reason); client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); } @@ -1257,8 +1257,8 @@ namespace Barotrauma.Networking NetOutgoingMessage msg = client.CreateMessage(); msg.Write((byte)ClientPacketHeader.SERVER_COMMAND); msg.Write((byte)ClientPermissions.Ban); - //TODO: write the reason msg.Write(kickedName); + msg.Write(reason); client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); } diff --git a/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs b/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs index cf13b312c..6729be024 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/NetworkMember.cs @@ -164,25 +164,58 @@ namespace Barotrauma.Networking public void CreateKickReasonPrompt(string clientName, bool ban, bool rangeBan = false) { - var banReasonPrompt = new GUIMessageBox(ban ? "Reason for the ban?" : "Reason for kicking?", "", new string[] { "OK" }, 400, 250); - var textBox = new GUITextBox(new Rectangle(0, 0, 0, 50), Alignment.Center, "", banReasonPrompt.children[0]); - textBox.Wrap = true; - textBox.MaxTextLength = 100; + var banReasonPrompt = new GUIMessageBox(ban ? "Reason for the ban?" : "Reason for kicking?", "", new string[] { "OK", "Cancel" }, 400, 300); + var banReasonBox = new GUITextBox(new Rectangle(0, 30, 0, 50), Alignment.TopCenter, "", banReasonPrompt.children[0]); + banReasonBox.Wrap = true; + banReasonBox.MaxTextLength = 100; + + GUINumberInput durationInputDays = null, durationInputHours = null; + GUITickBox permaBanTickBox = null; + + if (ban) + { + new GUITextBlock(new Rectangle(0, 80, 0, 0), "Duration:", "", banReasonPrompt.children[0]); + permaBanTickBox = new GUITickBox(new Rectangle(0, 110, 15, 15), "Permanent", Alignment.TopLeft, banReasonPrompt.children[0]); + permaBanTickBox.Selected = true; + + var durationContainer = new GUIFrame(new Rectangle(0, 130, 0, 40), null, banReasonPrompt.children[0]); + durationContainer.Visible = false; + + permaBanTickBox.OnSelected += (tickBox) => + { + durationContainer.Visible = !tickBox.Selected; + return true; + }; + + new GUITextBlock(new Rectangle(0, 0, 30, 20), "Days:", "", Alignment.TopLeft, Alignment.CenterLeft, durationContainer); + durationInputDays = new GUINumberInput(new Rectangle(40, 0, 50, 20), "", 0, 1000, durationContainer); + + new GUITextBlock(new Rectangle(100, 0, 30, 20), "Hours:", "", Alignment.TopLeft, Alignment.CenterLeft, durationContainer); + durationInputHours = new GUINumberInput(new Rectangle(150, 0, 50, 20), "", 0, 24, durationContainer); + } banReasonPrompt.Buttons[0].OnClicked += (btn, userData) => { if (ban) { - //TODO: a way to set ban duration in the prompt - BanPlayer(clientName, textBox.Text, ban, null); + if (!permaBanTickBox.Selected) + { + TimeSpan banDuration = new TimeSpan(durationInputDays.Value, durationInputHours.Value, 0, 0); + BanPlayer(clientName, banReasonBox.Text, ban, banDuration); + } + else + { + BanPlayer(clientName, banReasonBox.Text, ban); + } } else { - KickPlayer(clientName, textBox.Text); + KickPlayer(clientName, banReasonBox.Text); } return true; }; banReasonPrompt.Buttons[0].OnClicked += banReasonPrompt.Close; + banReasonPrompt.Buttons[1].OnClicked += banReasonPrompt.Close; } } } diff --git a/Barotrauma/BarotraumaShared/Content/UI/style.xml b/Barotrauma/BarotraumaShared/Content/UI/style.xml index 67040a865..28bc37af4 100644 --- a/Barotrauma/BarotraumaShared/Content/UI/style.xml +++ b/Barotrauma/BarotraumaShared/Content/UI/style.xml @@ -194,6 +194,19 @@ + + + + + + + + 2) + DateTime? expirationTime = null; + if (separatedLine.Length > 2 && !string.IsNullOrEmpty(separatedLine[2])) { DateTime parsedTime; if (DateTime.TryParse(separatedLine[2], out parsedTime)) @@ -78,7 +78,7 @@ namespace Barotrauma.Networking } string reason = separatedLine.Length > 3 ? string.Join(",", separatedLine.Skip(3)) : ""; - if (expirationTime.HasValue && expirationTime.Value > DateTime.Now) continue; + if (expirationTime.HasValue && DateTime.Now > expirationTime.Value) continue; bannedPlayers.Add(new BannedPlayer(name, ip, reason, expirationTime)); } @@ -91,7 +91,11 @@ namespace Barotrauma.Networking System.Diagnostics.Debug.Assert(!name.Contains(',')); - DebugConsole.Log("Banned " + name); + string logMsg = "Banned " + name; + if (!string.IsNullOrEmpty(reason)) logMsg += ", reason: " + reason; + if (duration.HasValue) logMsg += ", duration: " + duration.Value.ToString(); + + DebugConsole.Log(logMsg); DateTime? expirationTime = null; if (duration.HasValue) @@ -158,7 +162,7 @@ namespace Barotrauma.Networking foreach (BannedPlayer banned in bannedPlayers) { string line = banned.Name + "," + banned.IP; - if (banned.ExpirationTime.HasValue) line += "," + banned.ExpirationTime.Value.ToString(); + line += "," + (banned.ExpirationTime.HasValue ? banned.ExpirationTime.Value.ToString() : ""); if (!string.IsNullOrWhiteSpace(banned.Reason)) line += "," + banned.Reason; lines.Add(line); diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index 04b77aa1c..a2b80be33 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -754,21 +754,23 @@ namespace Barotrauma.Networking switch (command) { case ClientPermissions.Kick: - string kickedName = inc.ReadString(); - var kickedClient = connectedClients.Find(cl => cl != sender && cl.name == kickedName); + string kickedName = inc.ReadString().ToLowerInvariant(); + string kickReason = inc.ReadString(); + var kickedClient = connectedClients.Find(cl => cl != sender && cl.name.ToLowerInvariant() == kickedName); if (kickedClient != null) { Log("Client \"" + sender.name + "\" kicked \"" + kickedClient.name + "\".", ServerLog.MessageType.ServerMessage); - KickClient(kickedClient, "Kicked by " + sender.name); + KickClient(kickedClient, string.IsNullOrEmpty(kickReason) ? "Kicked by " + sender.name : kickReason); } break; case ClientPermissions.Ban: - string bannedName = inc.ReadString(); - var bannedClient = connectedClients.Find(cl => cl != sender && cl.name == bannedName); + string bannedName = inc.ReadString().ToLowerInvariant(); + string banReason = inc.ReadString(); + var bannedClient = connectedClients.Find(cl => cl != sender && cl.name.ToLowerInvariant() == bannedName); if (bannedClient != null) { Log("Client \"" + sender.name + "\" banned \"" + bannedClient.name + "\".", ServerLog.MessageType.ServerMessage); - BanClient(bannedClient, "Banned by " + sender.name, false); + BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.name : banReason, false); } break; case ClientPermissions.EndRound: