diff --git a/CHANGELOG.md b/CHANGELOG.md index c9369eea..8f3e103c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Fixed torchgod settings to include whether or not torchgod has been fought by the player before and respect `usingBiomeTorches` setting. (@Quinci135) * Fixed /worldmode not synchronising data to players after updating the world state (@bartico6, @Arthri) * Added `OnSendNetData` hook to TSAPI, which enables developers to intercept traffic being sent from the server to clients. (@Stealownz) -* Changed `TSPlayer.FindByNameOrID` so that it will continue searching for players and return a list of many players whem ambiguous matches exist in all cases. Specifically, this avoids a scenario where a griefer names themselves `1` and is difficult to enact justice on, because their name will not be found by the matching system used to kick players. (@hakusaro, @Onusai) +* Changed `TSPlayer.FindByNameOrID` so that it will continue searching for players and return a list of many players whem ambiguous matches exist in all cases. Specifically, this avoids a scenario where a griefer names themselves `1` and is difficult to enact justice on, because their name will not be found by the matching system used to kick players. To help with ambiguity, this method now processes requests with prefixes `tsi:` and `tsn:`. `tsi:[number]` will process the search as looking for an exact player by ID. `tsn:` will process the search as looking for an exact name, case sensitive. In both cases, the system will return an exact result in the "old-style" result, i.e., a `List` with exactly one result. For example, `/kick tsid:1` will match the player with the ID `1`. `/kick tsn:1` will match the username `1`. In addition, players who attempt to join the server with the name prefixes `tsn:` and `tsi:` will be rejected for having invalid names. (@hakusaro, @Onusai) ## TShock 4.5.3 * Added permissions for using Teleportation Potions, Magic Conch, and Demon Conch. (@drunderscore) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 1cab65dc..27173d4a 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2282,6 +2282,14 @@ namespace TShockAPI args.Player.Kick("You have been Bounced.", true, true); return true; } + + if (name.Trim().StartsWith("tsi:") || name.Trim().StartsWith("tsn:")) + { + TShock.Log.ConsoleDebug("GetDataHandlers / rejecting player for name prefix starting with tsi: or tsn:."); + args.Player.Kick("Illegal name: prefixes tsi: and tsn: are forbidden.", true, true); + return true; + } + if (args.Player.ReceivedInfo) { // Since Terraria 1.2.3 these character properties can change ingame. diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 12fb2d69..aeaf17b3 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -75,33 +75,52 @@ namespace TShockAPI public static readonly TSPlayer All = new TSPlayer("All"); /// - /// Finds a TSPlayer based on name or ID + /// Finds a TSPlayer based on name or ID. + /// If the string comes with tsi: or tsn:, we'll only return a list with one element, + /// either the player with the matching ID or name, respectively. /// /// Player name or ID /// A list of matching players - public static List FindByNameOrID(string plr) + public static List FindByNameOrID(string search) { var found = new List(); + + search = search.Trim(); + + // tsi: and tsn: are used to disambiguate between usernames and not + // and are also both 3 characters to remove them from the search + // (the goal was to pick prefixes unlikely to be used by names) + // (and not to collide with other prefixes used by other commands) + var exactIndexOnly = search.StartsWith("tsi:"); + var exactNameOnly = search.StartsWith("tsn:"); + + if (exactNameOnly || exactIndexOnly) + search = search.Remove(0, 4); + // Avoid errors caused by null search - if (plr == null) + if (search == null || search == "") return found; - byte plrID; - if (byte.TryParse(plr, out plrID) && plrID < Main.maxPlayers) + byte searchID; + if (byte.TryParse(search, out searchID) && searchID < Main.maxPlayers) { - TSPlayer player = TShock.Players[plrID]; + TSPlayer player = TShock.Players[searchID]; if (player != null && player.Active) { + if (exactIndexOnly) + return new List { player }; found.Add(player); } } - string plrLower = plr.ToLower(); + string searchLower = search.ToLower(); foreach (TSPlayer player in TShock.Players) { if (player != null) { - if (player.Name.ToLower().StartsWith(plrLower)) + if ((search == player.Name) && exactNameOnly) + return new List { player }; + if (player.Name.ToLower().StartsWith(searchLower)) found.Add(player); } } @@ -1664,12 +1683,13 @@ namespace TShockAPI /// An enumerable list with the matches public void SendMultipleMatchError(IEnumerable matches) { - SendErrorMessage("More than one match found: "); + SendErrorMessage("More than one match found -- unable to decide which is correct: "); var lines = PaginationTools.BuildLinesFromTerms(matches.ToArray()); lines.ForEach(SendInfoMessage); SendErrorMessage("Use \"my query\" for items with spaces."); + SendErrorMessage("Use tsi:[number] or tsn:[username] to distinguish between user IDs and usernames."); } [Conditional("DEBUG")]