Skip to content

Commit df8a3af

Browse files
authored
Merge pull request #62 from binury/main
Feat: ban reasons
2 parents a067687 + 5dfaba5 commit df8a3af

File tree

3 files changed

+132
-71
lines changed

3 files changed

+132
-71
lines changed

Cove/Server/Plugins/CovePlugin.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,14 @@ public virtual void onChatMessage(WFPlayer sender, string message) { }
2424
public virtual void onPlayerJoin(WFPlayer player) { }
2525
// triggered when a player leaves the server
2626
public virtual void onPlayerLeave(WFPlayer player) { }
27-
// triggered when a packet arrives
28-
public virtual void onNetworkPacket(WFPlayer sender, Dictionary<string, object> packet) { }
27+
/// <summary>
28+
/// Triggered when a player is banned from the server
29+
/// </summary>
30+
/// <param name="player">If unknown, this will be an empty string</param>
31+
/// <param name="reason">If not given, this will be an empty string</param>
32+
public virtual void onPlayerBanned(WFPlayer player, string reason) { }
33+
// triggered when a packet arrives
34+
public virtual void onNetworkPacket(WFPlayer sender, Dictionary<string, object> packet) { }
2935

3036
public WFPlayer[] GetAllPlayers()
3137
{
@@ -75,15 +81,9 @@ public void KickPlayer(WFPlayer player)
7581
ParentServer.kickPlayer(player.SteamId);
7682
}
7783

78-
public void BanPlayer(WFPlayer player)
84+
public void BanPlayer(WFPlayer player, string reason = "")
7985
{
80-
if (ParentServer.isPlayerBanned(player.SteamId))
81-
{
82-
ParentServer.banPlayer(player.SteamId);
83-
} else
84-
{
85-
ParentServer.banPlayer(player.SteamId, true); // save to file if they are not already in there!
86-
}
86+
ParentServer.banPlayer(player.SteamId, !ParentServer.isPlayerBanned(player.SteamId), reason);
8787
}
8888

8989
public void Log(string message)

Cove/Server/Server.Commands.cs

Lines changed: 104 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -85,70 +85,121 @@ void RegisterDefaultCommands()
8585
});
8686
SetCommandDescription("kick", "Kicks a player from the server");
8787

88-
RegisterCommand("ban", (player, args) =>
89-
{
90-
if (!isPlayerAdmin(player.SteamId)) return;
91-
// hacky fix,
92-
// Extract player name from the command message
93-
string playerIdent = string.Join(" ", args);
94-
// try to find a user with the username first
95-
var playerToBan = AllPlayers.ToList().Find(p => p.Username.Equals(playerIdent, StringComparison.OrdinalIgnoreCase));
96-
// if there is no player with the username try to find someone with that fisher ID
97-
if (playerToBan == null)
98-
playerToBan = AllPlayers.ToList().Find(p => p.FisherID.Equals(playerIdent, StringComparison.OrdinalIgnoreCase));
99-
100-
// this could be programmed better, but it works
101-
if (playerToBan == null)
88+
RegisterCommand(
89+
"ban",
90+
(player, args) =>
10291
{
103-
var previousPlayer = PreviousPlayers.ToList().Find(p => p.FisherID.Equals(playerIdent, StringComparison.OrdinalIgnoreCase));
104-
if (previousPlayer != null)
105-
{
106-
messagePlayer($"There is a previous player with that name, if you meant to ban them add a # before the ID: #{playerIdent}", player.SteamId);
92+
if (!isPlayerAdmin(player.SteamId))
10793
return;
94+
95+
WFPlayer? playerToBan = null;
96+
string playerIdent;
97+
98+
string rawArgs = string.Join(" ", args);
99+
string banReason = string.Empty;
100+
101+
var numQuotesInArgs = rawArgs.Count(c => c == '"');
102+
var hasBanReason = numQuotesInArgs >= 2;
103+
// While we'd hope admins use delimiters properly, it's actually totally fine for this case if they
104+
// e.g. use quotes inside quotes to quote the target's offending message within the banReason
105+
if (hasBanReason)
106+
{
107+
var firstQuoteIndex = rawArgs.IndexOf('"');
108+
var lastQuoteIndex = rawArgs.LastIndexOf('"');
109+
banReason = rawArgs
110+
.Substring(firstQuoteIndex + 1, lastQuoteIndex - firstQuoteIndex - 1)
111+
.Trim();
112+
rawArgs = rawArgs.Remove(
113+
firstQuoteIndex,
114+
lastQuoteIndex - firstQuoteIndex + 1
115+
);
108116
}
109-
110-
previousPlayer = PreviousPlayers.ToList().Find(p => $"#{p.FisherID}".Equals(playerIdent, StringComparison.OrdinalIgnoreCase));
111-
if (previousPlayer != null)
117+
playerIdent = rawArgs.Trim();
118+
119+
var targetIsSteamID = System.Text.RegularExpressions.Regex.IsMatch(
120+
playerIdent,
121+
@"^7656119\d{10}$"
122+
);
123+
124+
// find player by username
125+
var playerMatchingUsername = AllPlayers
126+
.ToList()
127+
.Find(p =>
128+
p.Username.Equals(playerIdent, StringComparison.OrdinalIgnoreCase)
129+
);
130+
// find player by fisher ID shortcode
131+
var targetIsFID = AllPlayers
132+
.ToList()
133+
.Find(p =>
134+
p.FisherID.Equals(playerIdent, StringComparison.OrdinalIgnoreCase)
135+
);
136+
137+
if (targetIsSteamID)
112138
{
113-
playerToBan = new WFPlayer(previousPlayer.SteamId, previousPlayer.Username, new SteamNetworkingIdentity())
139+
CSteamID steamId = new CSteamID(Convert.ToUInt64(playerIdent));
140+
var username = Steamworks.SteamFriends.GetFriendPersonaName(steamId);
141+
playerToBan = new WFPlayer(steamId, username, new SteamNetworkingIdentity())
114142
{
115-
FisherID = previousPlayer.FisherID,
116-
Username = previousPlayer.Username,
143+
Username = username == string.Empty ? playerIdent : username
117144
};
118145
}
119-
}
120-
121-
// use regex to check if its a steam ID
122-
if (playerToBan == null && System.Text.RegularExpressions.Regex.IsMatch(playerIdent, @"^7656119\d{10}$"))
123-
{
124-
// if it is a steam ID, try to find the player by steam ID
125-
CSteamID steamId = new CSteamID(Convert.ToUInt64(playerIdent));
126-
if (isPlayerBanned(steamId))
127-
banPlayer(steamId);
146+
else if (playerMatchingUsername != null)
147+
{
148+
playerToBan = playerMatchingUsername;
149+
}
150+
else if (targetIsFID != null)
151+
{
152+
playerToBan = targetIsFID;
153+
}
128154
else
129-
banPlayer(steamId, true);
130-
131-
messagePlayer($"Banned player with Steam ID {playerIdent}", player.SteamId);
132-
return;
133-
}
134-
135-
if (playerToBan == null)
136-
{
137-
messagePlayer("Player not found!", player.SteamId);
138-
}
139-
else
140-
{
155+
{
156+
// (Defer these searches to last resort, as they could potentially be costlier)
157+
var previousPlayer = PreviousPlayers
158+
.ToList()
159+
.Find(p =>
160+
$"#{p.FisherID}".Equals(
161+
playerIdent,
162+
StringComparison.OrdinalIgnoreCase
163+
)
164+
);
165+
if (previousPlayer != null)
166+
{
167+
messagePlayer(
168+
$"There is a previous player with that FisherID, if you meant to ban them add a # before the ID: #{playerIdent}",
169+
player.SteamId
170+
);
171+
return;
172+
}
173+
previousPlayer = PreviousPlayers
174+
.ToList()
175+
.Find(p =>
176+
p.FisherID.Equals(playerIdent, StringComparison.OrdinalIgnoreCase)
177+
);
178+
if (previousPlayer != null)
179+
{
180+
playerToBan = new WFPlayer(
181+
previousPlayer.SteamId,
182+
previousPlayer.Username,
183+
new SteamNetworkingIdentity()
184+
);
185+
}
186+
}
141187

142-
if (isPlayerBanned(playerToBan.SteamId))
143-
banPlayer(playerToBan.SteamId);
188+
if (playerToBan == null)
189+
{
190+
messagePlayer("Player not found!", player.SteamId);
191+
}
144192
else
145-
banPlayer(playerToBan.SteamId, true); // save to file if they are not already in there!
146-
147-
messagePlayer($"Banned {playerToBan.Username}", player.SteamId);
148-
messageGlobal($"{playerToBan.Username} has been banned from the server.");
193+
{
194+
banPlayer(
195+
playerToBan.SteamId,
196+
!isPlayerBanned(playerToBan.SteamId),
197+
banReason
198+
);
199+
}
149200
}
150-
});
151-
SetCommandDescription("ban", "Bans a player from the server");
201+
);
202+
SetCommandDescription("ban", "Usage: !ban (username|steamID|FisherID) \"Reason for ban\"");
152203

153204
RegisterCommand("prev", (player, args) =>
154205
{

Cove/Server/Server.Punish.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,17 @@ limitations under the License.
2121
using System.Text;
2222
using System.Threading.Tasks;
2323
using Cove.Server.Actor;
24+
using Cove.Server.Plugins;
2425
using Steamworks;
2526

2627
namespace Cove.Server
2728
{
2829
public partial class CoveServer
2930
{
30-
31-
public void banPlayer(CSteamID id, bool saveToFile = false)
31+
public void banPlayer(CSteamID id, bool saveToFile = false, string banReason = "")
3232
{
33+
var player = new WFPlayer(id, Steamworks.SteamFriends.GetFriendPersonaName(id), new SteamNetworkingIdentity());
34+
3335
Dictionary<string, object> banPacket = new();
3436
banPacket["type"] = "client_was_banned";
3537
sendPacketToPlayer(banPacket, id);
@@ -39,8 +41,14 @@ public void banPlayer(CSteamID id, bool saveToFile = false)
3941
leftPacket["user_id"] = (long)id.m_SteamID;
4042
sendPacketToPlayers(leftPacket);
4143

44+
45+
foreach (PluginInstance plugin in loadedPlugins)
46+
{
47+
plugin.plugin.onPlayerBanned(player, banReason);
48+
}
49+
4250
if (saveToFile)
43-
writeToBansFile(id);
51+
writeToBansFile(id, banReason);
4452

4553
sendBlacklistPacketToAll(id.m_SteamID.ToString());
4654
}
@@ -61,12 +69,14 @@ public bool isPlayerBanned(CSteamID id)
6169
return false;
6270
}
6371

64-
private void writeToBansFile(CSteamID id)
72+
private void writeToBansFile(CSteamID id, string reason)
6573
{
66-
string fileDir = $"{AppDomain.CurrentDomain.BaseDirectory}bans.txt";
67-
PreviousPlayer player = PreviousPlayers.Find(p => p.SteamId == id);
68-
string username = player != null ? player.Username : "Unknown";
69-
File.AppendAllLines(fileDir, [$"{id.m_SteamID} #{username}"]);
74+
string entry = $"{id.m_SteamID} # ";
75+
string username = PreviousPlayers.Find(p => p.SteamId == id)?.Username ?? "Unknown";
76+
entry += username;
77+
if (!string.IsNullOrEmpty(reason))
78+
entry += $" - {reason}";
79+
File.AppendAllLines($"{AppDomain.CurrentDomain.BaseDirectory}bans.txt", [entry]);
7080
}
7181

7282
public void kickPlayer(CSteamID id)

0 commit comments

Comments
 (0)