diff --git a/CHANGELOG.md b/CHANGELOG.md index e8cda12b..cd2292ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,18 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * All `GetDataHandlers` hooks now inherit from `GetDataHandledEventArgs` which includes a `TSPlayer` and a `MemoryStream` of raw data. (@hakusaro) * Removed _all obsolete methods in TShock marked obsolete prior to this version (all of them)_ (@hakusaro). * Removed broken noclip detection and attempted prevention. TShock wasn't doing a good job at stopping noclip. It's always worse to claim that you do something that you can't/don't do, so removing this is better than keeping broken detection in. (@hakusaro) +* Replaced `Utils.FindPlayer` with `TSPlayer.FindByNameOrID` to more appropriately be object orientated. (@hakusaro) +* Moved `Utils.Kick()` to `TSPlayer` since its first argument was a `TSPlayer` object. (@hakusaro) +* Removed `Utils.ForceKick()`. (@hakusaro) +* Removed `Utils.GetPlayerIP()`. (@hakusaro) +* Moved `Utils.Ban()` to `TSPlayer.Ban()`. (@hakusaro) +* Moved `Utils.SendMultipleMatchError()` to `TSPlayer.SendMultipleMatchError`. (@hakusaro) +* Removed `Utils.GetPlayers()`. Iterate over the TSPlayers on the server and make your own list. +* Removed `Utils.HasBanExpired()` and replaced with `Bans.RemoveBanIfExpired()`. (@hakusaro) +* Removed `Utils.SendFileToUser()` and replaced with `TSPlayer.SendFileTextAsMessage()`. (@hakusaro) +* Removed `Utils.GetGroup()` also have you seen `Groups.GetGroupByName()`? (@hakusaro) +* `Utils.MaxChests()` is now `Utils.HasWorldReachedMaxChests()`. (@hakusaro) +* `Utils.GetIPv4Address()` is now `Utils.GetIPv4AddressFromHostname()`. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index f051ee37..6605f1e5 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -77,7 +77,7 @@ namespace TShockAPI if (String.IsNullOrEmpty(args.Player.Name)) { - TShock.Utils.ForceKick(args.Player, "Blank name.", true); + args.Player.Kick("Your client sent a blank character name.", true, true); args.Handled = true; return; } @@ -256,7 +256,7 @@ namespace TShockAPI { if (TShock.Config.KickOnDamageThresholdBroken) { - TShock.Utils.Kick(args.Player, string.Format("NPC damage exceeded {0}.", TShock.Config.MaxDamage)); + args.Player.Kick(string.Format("NPC damage exceeded {0}.", TShock.Config.MaxDamage)); args.Handled = true; return; } @@ -313,7 +313,7 @@ namespace TShockAPI { if (TShock.Config.KickOnDamageThresholdBroken) { - TShock.Utils.Kick(args.Player, string.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage)); + args.Player.Kick(string.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage)); args.Handled = true; return; } @@ -627,7 +627,7 @@ namespace TShockAPI && Main.tile[tileX, tileY].type != TileID.Containers && Main.tile[tileX, tileY].type != TileID.Dressers && Main.tile[tileX, tileY].type != TileID.Containers2 - && (!TShock.Utils.MaxChests() && Main.tile[tileX, tileY].type != TileID.Dirt)) //Chest + && (!TShock.Utils.HasWorldReachedMaxChests() && Main.tile[tileX, tileY].type != TileID.Dirt)) //Chest { args.Player.SendTileSquare(tileX, tileY, 3); args.Handled = true; @@ -925,7 +925,7 @@ namespace TShockAPI if (damage > 20000) //Abnormal values have the potential to cause infinite loops in the server. { - TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true); + args.Player.Kick("Failed to shade polygon normals.", true, true); TShock.Log.ConsoleError("Death Exploit Attempt: Damage {0}", damage); args.Handled = true; return; @@ -942,7 +942,7 @@ namespace TShockAPI { if (playerDeathReason.GetDeathText(TShock.Players[id].Name).ToString().Length > 500) { - TShock.Utils.Kick(TShock.Players[id], "Death reason outside of normal bounds.", true); + TShock.Players[id].Kick("Death reason outside of normal bounds.", true); args.Handled = true; return; } @@ -1409,7 +1409,7 @@ namespace TShockAPI } if (action == EditAction.PlaceTile && (editData == TileID.Containers || editData == TileID.Containers2)) { - if (TShock.Utils.MaxChests()) + if (TShock.Utils.HasWorldReachedMaxChests()) { args.Player.SendErrorMessage("The world's chest limit has been reached - unable to place more."); args.Player.SendTileSquare(tileX, tileY, 3); diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index a5203995..36dabc6b 100644 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -783,7 +783,7 @@ namespace TShockAPI { TShock.Log.Warn(String.Format("{0} ({1}) had {2} or more invalid login attempts and was kicked automatically.", args.Player.IP, args.Player.Name, TShock.Config.MaximumLoginAttempts)); - TShock.Utils.Kick(args.Player, "Too many invalid login attempts."); + args.Player.Kick("Too many invalid login attempts."); return; } @@ -842,7 +842,7 @@ namespace TShockAPI { args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, account.ID); - var group = TShock.Utils.GetGroup(account.Group); + var group = TShock.Groups.GetGroupByName(account.Group); args.Player.Group = group; args.Player.tempGroup = null; @@ -1195,11 +1195,11 @@ namespace TShockAPI return; } - var players = TShock.Utils.FindPlayer(args.Parameters[0]); + var players = TSPlayer.FindByNameOrID(args.Parameters[0]); if (players.Count < 1) args.Player.SendErrorMessage("Invalid player."); else if (players.Count > 1) - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); else { var message = new StringBuilder(); @@ -1265,21 +1265,21 @@ namespace TShockAPI } string plStr = args.Parameters[0]; - var players = TShock.Utils.FindPlayer(plStr); + var players = TSPlayer.FindByNameOrID(plStr); if (players.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); } else { string reason = args.Parameters.Count > 1 ? String.Join(" ", args.Parameters.GetRange(1, args.Parameters.Count - 1)) : "Misbehaviour."; - if (!TShock.Utils.Kick(players[0], reason, !args.Player.RealPlayer, false, args.Player.Name)) + if (!players[0].Kick(reason, !args.Player.RealPlayer, false, args.Player.Name)) { args.Player.SendErrorMessage("You can't kick another admin!"); } @@ -1308,7 +1308,7 @@ namespace TShockAPI string targetGeneralizedName = ""; // Effective ban target assignment - List players = TShock.Utils.FindPlayer(args.Parameters[1]); + List players = TSPlayer.FindByNameOrID(args.Parameters[1]); UserAccount offlineUserAccount = TShock.UserAccounts.GetUserAccountByName(args.Parameters[1]); // Storage variable to determine if the command executor is the server console @@ -1355,7 +1355,7 @@ namespace TShockAPI // Bad case: Players contains more than 1 person so we can't ban them if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); return; } @@ -1658,7 +1658,7 @@ namespace TShockAPI } string playerNameToMatch = string.Join(" ", args.Parameters); - var matchedPlayers = TShock.Utils.FindPlayer(playerNameToMatch); + var matchedPlayers = TSPlayer.FindByNameOrID(playerNameToMatch); if (matchedPlayers.Count < 1) { args.Player.SendErrorMessage("No players matched \"{0}\".", playerNameToMatch); @@ -1666,7 +1666,7 @@ namespace TShockAPI } else if (matchedPlayers.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, matchedPlayers.Select(p => p.Name)); + args.Player.SendMultipleMatchError(matchedPlayers.Select(p => p.Name)); return; } @@ -1696,10 +1696,10 @@ namespace TShockAPI TSPlayer targetPlayer = args.Player; if (args.Parameters.Count == 1 && args.Player.HasPermission(Permissions.uploadothersdata)) { - List players = TShock.Utils.FindPlayer(args.Parameters[0]); + List players = TSPlayer.FindByNameOrID(args.Parameters[0]); if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); return; } else if (players.Count == 0) @@ -1777,7 +1777,7 @@ namespace TShockAPI return; } - List ply = TShock.Utils.FindPlayer(args.Parameters[0]); + List ply = TSPlayer.FindByNameOrID(args.Parameters[0]); if (ply.Count < 1) { args.Player.SendErrorMessage("Could not find player {0}.", args.Parameters[0]); @@ -1786,7 +1786,7 @@ namespace TShockAPI if (ply.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, ply.Select(p => p.Account.Name)); + args.Player.SendMultipleMatchError(ply.Select(p => p.Account.Name)); } if (!TShock.Groups.GroupExists(args.Parameters[1])) @@ -1810,7 +1810,7 @@ namespace TShockAPI ply[0].tempGroupTimer.Start(); } - Group g = TShock.Utils.GetGroup(args.Parameters[1]); + Group g = TShock.Groups.GetGroupByName(args.Parameters[1]); ply[0].tempGroup = g; @@ -2326,7 +2326,7 @@ namespace TShockAPI } else if (npcs.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, npcs.Select(n => $"{n.FullName}({n.type})")); + args.Player.SendMultipleMatchError(npcs.Select(n => $"{n.FullName}({n.type})")); } else { @@ -2396,11 +2396,11 @@ namespace TShockAPI if (args.Parameters.Count == 1) { - var players = TShock.Utils.FindPlayer(args.Parameters[0]); + var players = TSPlayer.FindByNameOrID(args.Parameters[0]); if (players.Count == 0) args.Player.SendErrorMessage("Invalid player!"); else if (players.Count > 1) - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); else { var target = players[0]; @@ -2425,13 +2425,13 @@ namespace TShockAPI return; } - var players1 = TShock.Utils.FindPlayer(args.Parameters[0]); - var players2 = TShock.Utils.FindPlayer(args.Parameters[1]); + var players1 = TSPlayer.FindByNameOrID(args.Parameters[0]); + var players2 = TSPlayer.FindByNameOrID(args.Parameters[1]); if (players2.Count == 0) args.Player.SendErrorMessage("Invalid player!"); else if (players2.Count > 1) - TShock.Utils.SendMultipleMatchError(args.Player, players2.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players2.Select(p => p.Name)); else if (players1.Count == 0) { if (args.Parameters[0] == "*") @@ -2471,7 +2471,7 @@ namespace TShockAPI args.Player.SendErrorMessage("Invalid player!"); } else if (players1.Count > 1) - TShock.Utils.SendMultipleMatchError(args.Player, players1.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players1.Select(p => p.Name)); else { var source = players1[0]; @@ -2520,7 +2520,7 @@ namespace TShockAPI } string playerName = String.Join(" ", args.Parameters); - var players = TShock.Utils.FindPlayer(playerName); + var players = TSPlayer.FindByNameOrID(playerName); if (players.Count == 0) { if (playerName == "*") @@ -2544,7 +2544,7 @@ namespace TShockAPI args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); else { var plr = players[0]; @@ -2583,7 +2583,7 @@ namespace TShockAPI if (matches.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, matches.Select(n => $"{n.FullName}({n.whoAmI})")); + args.Player.SendMultipleMatchError(matches.Select(n => $"{n.FullName}({n.whoAmI})")); return; } if (matches.Count == 0) @@ -2605,14 +2605,14 @@ namespace TShockAPI player = String.Join(" ", args.Parameters); } - var players = TShock.Utils.FindPlayer(player); + var players = TSPlayer.FindByNameOrID(player); if (players.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); } else { @@ -2766,7 +2766,7 @@ namespace TShockAPI return; } - var foundplr = TShock.Utils.FindPlayer(args.Parameters[1]); + var foundplr = TSPlayer.FindByNameOrID(args.Parameters[1]); if (foundplr.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); @@ -2774,7 +2774,7 @@ namespace TShockAPI } else if (foundplr.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, foundplr.Select(p => p.Name)); + args.Player.SendMultipleMatchError(foundplr.Select(p => p.Name)); return; } @@ -3225,7 +3225,7 @@ namespace TShockAPI args.Player.SendErrorMessage("Invalid group."); return; } - Group grp = TShock.Utils.GetGroup(args.Parameters[1]); + Group grp = TShock.Groups.GetGroupByName(args.Parameters[1]); List permissions = grp.TotalPermissions; PaginationTools.SendPage(args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(permissions), @@ -3265,7 +3265,7 @@ namespace TShockAPI } else if (items.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, items.Select(i => $"{i.Name}({i.netID})")); + args.Player.SendMultipleMatchError(items.Select(i => $"{i.Name}({i.netID})")); } else { @@ -3291,7 +3291,7 @@ namespace TShockAPI } else if (items.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, items.Select(i => $"{i.Name}({i.netID})")); + args.Player.SendMultipleMatchError(items.Select(i => $"{i.Name}({i.netID})")); } else { @@ -3336,7 +3336,7 @@ namespace TShockAPI } else if (items.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, items.Select(i => $"{i.Name}({i.netID})")); + args.Player.SendMultipleMatchError(items.Select(i => $"{i.Name}({i.netID})")); } else { @@ -3362,7 +3362,7 @@ namespace TShockAPI } else if (items.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, items.Select(i => $"{i.Name}({i.netID})")); + args.Player.SendMultipleMatchError(items.Select(i => $"{i.Name}({i.netID})")); } else { @@ -3798,7 +3798,8 @@ namespace TShockAPI private static void Reload(CommandArgs args) { - TShock.Utils.Reload(args.Player); + TShock.Utils.Reload(); + Hooks.GeneralHooks.OnReloadEvent(args.Player); args.Player.SendSuccessMessage( "Configuration, permissions, and regions reload complete. Some changes may require a server restart."); @@ -4075,14 +4076,14 @@ namespace TShockAPI } string plStr = args.Parameters[0]; - var players = TShock.Utils.FindPlayer(plStr); + var players = TSPlayer.FindByNameOrID(plStr); if (players.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); } else { @@ -4818,9 +4819,27 @@ namespace TShockAPI return; } - args.Player.SendSuccessMessage("Online Players ({0}/{1})", TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots); + args.Player.SendSuccessMessage("Online Players ({0}/{1})", TShock.Utils.GetActivePlayerCount(), TShock.Config.MaxSlots); + + var players = new List(); + + foreach (TSPlayer ply in TShock.Players) + { + if (ply != null && ply.Active) + { + if (displayIdsRequested) + { + players.Add(String.Format("{0} (ID: {1}{2})", ply.Name, ply.Index, ply.Account != null ? ", ID: " + ply.Account.ID : "")); + } + else + { + players.Add(ply.Name); + } + } + } + PaginationTools.SendPage( - args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(TShock.Utils.GetPlayers(displayIdsRequested)), + args.Player, pageNumber, PaginationTools.BuildLinesFromTerms(players), new PaginationTools.Settings { IncludeHeader = false, @@ -4838,7 +4857,6 @@ namespace TShockAPI else { args.Player.SendWarningMessage("The initial setup system is disabled. This incident has been logged."); - TShock.Utils.ForceKick(args.Player, "The initial setup system is disabled.", true, true); TShock.Log.Warn("{0} attempted to use the initial setup system even though it's disabled.", args.Player.IP); return; } @@ -4929,14 +4947,14 @@ namespace TShockAPI return; } - var players = TShock.Utils.FindPlayer(args.Parameters[0]); + var players = TSPlayer.FindByNameOrID(args.Parameters[0]); if (players.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); } else if (players[0].HasPermission(Permissions.mute)) { @@ -4961,12 +4979,12 @@ namespace TShockAPI private static void Motd(CommandArgs args) { - TShock.Utils.ShowFileToUser(args.Player, FileTools.MotdPath); + args.Player.SendFileTextAsMessage(FileTools.MotdPath); } private static void Rules(CommandArgs args) { - TShock.Utils.ShowFileToUser(args.Player, FileTools.RulesPath); + args.Player.SendFileTextAsMessage(FileTools.RulesPath); } private static void Whisper(CommandArgs args) @@ -4977,14 +4995,14 @@ namespace TShockAPI return; } - var players = TShock.Utils.FindPlayer(args.Parameters[0]); + var players = TSPlayer.FindByNameOrID(args.Parameters[0]); if (players.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); } else if (args.Player.mute) { @@ -5029,11 +5047,11 @@ namespace TShockAPI int annoy = 5; int.TryParse(args.Parameters[1], out annoy); - var players = TShock.Utils.FindPlayer(args.Parameters[0]); + var players = TSPlayer.FindByNameOrID(args.Parameters[0]); if (players.Count == 0) args.Player.SendErrorMessage("Invalid player!"); else if (players.Count > 1) - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); else { var ply = players[0]; @@ -5049,11 +5067,11 @@ namespace TShockAPI args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}confuse ", Specifier); return; } - var players = TShock.Utils.FindPlayer(args.Parameters[0]); + var players = TSPlayer.FindByNameOrID(args.Parameters[0]); if (players.Count == 0) args.Player.SendErrorMessage("Invalid player!"); else if (players.Count > 1) - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); else { var ply = players[0]; @@ -5069,11 +5087,11 @@ namespace TShockAPI args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}rocket ", Specifier); return; } - var players = TShock.Utils.FindPlayer(args.Parameters[0]); + var players = TSPlayer.FindByNameOrID(args.Parameters[0]); if (players.Count == 0) args.Player.SendErrorMessage("Invalid player!"); else if (players.Count > 1) - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); else { var ply = players[0]; @@ -5098,11 +5116,11 @@ namespace TShockAPI args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}firework [red|green|blue|yellow]", Specifier); return; } - var players = TShock.Utils.FindPlayer(args.Parameters[0]); + var players = TSPlayer.FindByNameOrID(args.Parameters[0]); if (players.Count == 0) args.Player.SendErrorMessage("Invalid player!"); else if (players.Count > 1) - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); else { int type = 167; @@ -5266,14 +5284,14 @@ namespace TShockAPI } string plStr = String.Join(" ", args.Parameters); - var players = TShock.Utils.FindPlayer(plStr); + var players = TSPlayer.FindByNameOrID(plStr); if (players.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); } else { @@ -5304,7 +5322,7 @@ namespace TShockAPI } else if (npcs.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, npcs.Select(n => $"{n.FullName}({n.type})")); + args.Player.SendMultipleMatchError(npcs.Select(n => $"{n.FullName}({n.type})")); return; } else @@ -5359,7 +5377,7 @@ namespace TShockAPI } else if (matchedItems.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, matchedItems.Select(i => $"{i.Name}({i.netID})")); + args.Player.SendMultipleMatchError(matchedItems.Select(i => $"{i.Name}({i.netID})")); return; } else @@ -5389,7 +5407,7 @@ namespace TShockAPI if (prefixIds.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, prefixIds.Select(p => p.ToString())); + args.Player.SendMultipleMatchError(prefixIds.Select(p => p.ToString())); return; } else if (prefixIds.Count == 0) @@ -5442,7 +5460,7 @@ namespace TShockAPI } else if (npcs.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, npcs.Select(n => $"{n.FullName}({n.type})")); + args.Player.SendMultipleMatchError(npcs.Select(n => $"{n.FullName}({n.type})")); return; } else if (args.Parameters[1].Length > 200) @@ -5507,7 +5525,7 @@ namespace TShockAPI } else if (items.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, items.Select(i => $"{i.Name}({i.netID})")); + args.Player.SendMultipleMatchError(items.Select(i => $"{i.Name}({i.netID})")); } else { @@ -5531,14 +5549,14 @@ namespace TShockAPI if (item.type >= 1 && item.type < Main.maxItemTypes) { - var players = TShock.Utils.FindPlayer(plStr); + var players = TSPlayer.FindByNameOrID(plStr); if (players.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); } else if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); } else { @@ -5577,7 +5595,7 @@ namespace TShockAPI if (args.Parameters.Count > 0) { string plStr = String.Join(" ", args.Parameters); - var players = TShock.Utils.FindPlayer(plStr); + var players = TSPlayer.FindByNameOrID(plStr); if (players.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); @@ -5585,7 +5603,7 @@ namespace TShockAPI } else if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); return; } else @@ -5634,7 +5652,7 @@ namespace TShockAPI } else if (found.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, found.Select(f => Lang.GetBuffName(f))); + args.Player.SendMultipleMatchError(found.Select(f => Lang.GetBuffName(f))); return; } id = found[0]; @@ -5662,7 +5680,7 @@ namespace TShockAPI } int id = 0; int time = 60; - var foundplr = TShock.Utils.FindPlayer(args.Parameters[0]); + var foundplr = TSPlayer.FindByNameOrID(args.Parameters[0]); if (foundplr.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); @@ -5670,7 +5688,7 @@ namespace TShockAPI } else if (foundplr.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, foundplr.Select(p => p.Name)); + args.Player.SendMultipleMatchError(foundplr.Select(p => p.Name)); return; } else @@ -5685,7 +5703,7 @@ namespace TShockAPI } else if (found.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, found.Select(b => Lang.GetBuffName(b))); + args.Player.SendMultipleMatchError(found.Select(b => Lang.GetBuffName(b))); return; } id = found[0]; @@ -5794,7 +5812,7 @@ namespace TShockAPI return; } string plStr = String.Join(" ", args.Parameters); - var players = TShock.Utils.FindPlayer(plStr); + var players = TSPlayer.FindByNameOrID(plStr); if (players.Count == 0) { args.Player.SendErrorMessage("Invalid player!"); @@ -5802,7 +5820,7 @@ namespace TShockAPI } else if (players.Count > 1) { - TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); + args.Player.SendMultipleMatchError(players.Select(p => p.Name)); return; } else diff --git a/TShockAPI/DB/BanManager.cs b/TShockAPI/DB/BanManager.cs index 53a258d2..c83ff7e0 100644 --- a/TShockAPI/DB/BanManager.cs +++ b/TShockAPI/DB/BanManager.cs @@ -294,6 +294,20 @@ namespace TShockAPI.DB } return false; } + + /// Removes a ban if it has expired. + /// The candidate ban to check. + /// If the ban has been removed. + public bool RemoveBanIfExpired(Ban ban) + { + if (!string.IsNullOrWhiteSpace(ban.Expiration) && (ban.ExpirationDateTime != null) && (DateTime.UtcNow >= ban.ExpirationDateTime)) + { + RemoveBan(ban.IP, false, false, false); + return true; + } + + return false; + } } /// diff --git a/TShockAPI/DB/GroupManager.cs b/TShockAPI/DB/GroupManager.cs index 11f1cc06..9b399dd1 100644 --- a/TShockAPI/DB/GroupManager.cs +++ b/TShockAPI/DB/GroupManager.cs @@ -434,7 +434,7 @@ namespace TShockAPI.DB if (database.Query("DELETE FROM GroupList WHERE GroupName=@0", name) == 1) { - groups.Remove(TShock.Utils.GetGroup(name)); + groups.Remove(TShock.Groups.GetGroupByName(name)); return "Group " + name + " has been deleted successfully."; } @@ -454,7 +454,7 @@ namespace TShockAPI.DB if (!GroupExists(name)) return "Error: Group doesn't exist."; - var group = TShock.Utils.GetGroup(name); + var group = TShock.Groups.GetGroupByName(name); var oldperms = group.Permissions; // Store old permissions in case of error permissions.ForEach(p => group.AddPermission(p)); @@ -477,7 +477,7 @@ namespace TShockAPI.DB if (!GroupExists(name)) return "Error: Group doesn't exist."; - var group = TShock.Utils.GetGroup(name); + var group = TShock.Groups.GetGroupByName(name); var oldperms = group.Permissions; // Store old permissions in case of error permissions.ForEach(p => group.RemovePermission(p)); diff --git a/TShockAPI/FileTools.cs b/TShockAPI/FileTools.cs index 6938149c..3059a3af 100644 --- a/TShockAPI/FileTools.cs +++ b/TShockAPI/FileTools.cs @@ -26,7 +26,7 @@ namespace TShockAPI public class FileTools { private const string MotdFormat = - "This server is running TShock for Terraria.\n Type /help for a list of commands.\n%255,000,000%Current map: %map%\nCurrent players: %players%"; + "This is [c/FF0000:%map%] on [c/00FFFF:TShock for Terraria].\n[c/00FF00:Current players:] [c/FFFF00:%players%]\nType [c/FF0000:/help] for a list of commands.\n"; /// /// Path to the file containing the rules. /// @@ -154,7 +154,7 @@ namespace TShockAPI { if (string.IsNullOrWhiteSpace(line)) continue; - contains = TShock.Utils.GetIPv4Address(line).Equals(ip); + contains = TShock.Utils.GetIPv4AddressFromHostname(line).Equals(ip); if (contains) return true; } diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index a8f2442e..f4cd0a9e 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -349,7 +349,7 @@ namespace TShockAPI } /// /// PlayerInfo - called at a PlayerInfo event - /// If this is cancelled, the server will ForceKick the player. If this should be changed in the future, let someone know. + /// If this is cancelled, the server will kick the player. If this should be changed in the future, let someone know. /// public static HandlerList PlayerInfo = new HandlerList(); @@ -1660,13 +1660,13 @@ namespace TShockAPI if (OnPlayerInfo(args.Player, args.Data, playerid, hair, skinVariant, difficulty, name)) { - TShock.Utils.ForceKick(args.Player, "A plugin cancelled the event.", true); + args.Player.Kick("A plugin on this server stopped your login.", true, true); return true; } if (name.Trim().Length == 0) { - TShock.Utils.ForceKick(args.Player, "Empty Name.", true); + args.Player.Kick("You have been Bounced.", true, true); return true; } if (args.Player.ReceivedInfo) @@ -1694,12 +1694,12 @@ namespace TShockAPI } if (TShock.Config.MediumcoreOnly && difficulty < 1) { - TShock.Utils.ForceKick(args.Player, "Server is set to mediumcore and above characters only!", true); + args.Player.Kick("You need to join with a mediumcore player or higher.", true, true); return true; } if (TShock.Config.HardcoreOnly && difficulty < 2) { - TShock.Utils.ForceKick(args.Player, "Server is set to hardcore characters only!", true); + args.Player.Kick("You need to join with a hardcore player.", true, true); return true; } args.Player.Difficulty = difficulty; @@ -1725,7 +1725,7 @@ namespace TShockAPI args.Player.PlayerData = TShock.CharacterDB.GetPlayerData(args.Player, account.ID); - var group = TShock.Utils.GetGroup(account.Group); + var group = TShock.Groups.GetGroupByName(account.Group); args.Player.Group = group; args.Player.tempGroup = null; @@ -1797,7 +1797,7 @@ namespace TShockAPI args.Player.State = 2; NetMessage.SendData((int)PacketTypes.WorldInfo, args.Player.Index); - var group = TShock.Utils.GetGroup(account.Group); + var group = TShock.Groups.GetGroupByName(account.Group); args.Player.Group = group; args.Player.tempGroup = null; @@ -1829,9 +1829,10 @@ namespace TShockAPI Hooks.PlayerHooks.OnPlayerPostLogin(args.Player); return true; } - TShock.Utils.ForceKick(args.Player, "Invalid user account password.", true); + args.Player.Kick("Your password did not match this character's password.", true, true); return true; } + if (!string.IsNullOrEmpty(TShock.Config.ServerPassword)) { if (TShock.Config.ServerPassword == password) @@ -1842,11 +1843,11 @@ namespace TShockAPI NetMessage.SendData((int)PacketTypes.WorldInfo, args.Player.Index); return true; } - TShock.Utils.ForceKick(args.Player, "Incorrect server password", true); + args.Player.Kick("Invalid server password.", true, true); return true; } - TShock.Utils.ForceKick(args.Player, "Bad password attempt", true); + args.Player.Kick("You have been Bounced.", true, true); return true; } @@ -1891,10 +1892,10 @@ namespace TShockAPI if (OnGetSection(args.Player, args.Data, args.Data.ReadInt32(), args.Data.ReadInt32())) return true; - if (TShock.Utils.ActivePlayers() + 1 > TShock.Config.MaxSlots && + if (TShock.Utils.GetActivePlayerCount() + 1 > TShock.Config.MaxSlots && !args.Player.HasPermission(Permissions.reservedslot)) { - TShock.Utils.ForceKick(args.Player, TShock.Config.ServerFullReason, true); + args.Player.Kick(TShock.Config.ServerFullReason, true, true); return true; } @@ -2383,12 +2384,12 @@ namespace TShockAPI { if (TShock.Config.BanOnHardcoreDeath) { - if (!TShock.Utils.Ban(args.Player, TShock.Config.HardcoreBanReason, false, "hardcore-death")) - TShock.Utils.ForceKick(args.Player, "Death results in a ban, but you are immune to bans.", true); + if (!args.Player.Ban(TShock.Config.HardcoreBanReason, false, "hardcore-death")) + args.Player.Kick("You died! Normally, you'd be banned.", true, true); } else { - TShock.Utils.ForceKick(args.Player, TShock.Config.HardcoreKickReason, true, false); + args.Player.Kick(TShock.Config.HardcoreKickReason, true, true, null, false); } } @@ -2447,12 +2448,12 @@ namespace TShockAPI { if (TShock.Config.BanOnMediumcoreDeath) { - if (!TShock.Utils.Ban(args.Player, TShock.Config.MediumcoreBanReason, false, "mediumcore-death")) - TShock.Utils.ForceKick(args.Player, "Death results in a ban, but you are immune to bans.", true); + if (!args.Player.Ban(TShock.Config.MediumcoreBanReason, false, "mediumcore-death")) + args.Player.Kick("You died! Normally, you'd be banned.", true, true); } else { - TShock.Utils.ForceKick(args.Player, TShock.Config.MediumcoreKickReason, true, false); + args.Player.Kick(TShock.Config.MediumcoreKickReason, true, true, null, false); } return true; } diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs index f9f1308e..073d7fb8 100644 --- a/TShockAPI/Rest/RestManager.cs +++ b/TShockAPI/Rest/RestManager.cs @@ -339,7 +339,8 @@ namespace TShockAPI [Token] private object ServerReload(RestRequestArgs args) { - TShock.Utils.Reload(new TSRestPlayer(args.TokenData.Username, TShock.Groups.GetGroupByName(args.TokenData.UserGroupName))); + TShock.Utils.Reload(); + Hooks.GeneralHooks.OnReloadEvent(new TSRestPlayer(args.TokenData.Username, TShock.Groups.GetGroupByName(args.TokenData.UserGroupName))); return RestResponse("Configuration, permissions, and regions reload complete. Some changes may require a server restart."); } @@ -410,7 +411,7 @@ namespace TShockAPI var players = new ArrayList(); foreach (TSPlayer tsPlayer in TShock.Players.Where(p => null != p)) { - var p = PlayerFilter(tsPlayer, args.Parameters, ((args.TokenData.UserGroupName) != "" && TShock.Utils.GetGroup(args.TokenData.UserGroupName).HasPermission(RestPermissions.viewips))); + var p = PlayerFilter(tsPlayer, args.Parameters, ((args.TokenData.UserGroupName) != "" && TShock.Groups.GetGroupByName(args.TokenData.UserGroupName).HasPermission(RestPermissions.viewips))); if (null != p) players.Add(p); } @@ -982,7 +983,7 @@ namespace TShockAPI return ret; TSPlayer player = (TSPlayer)ret; - TShock.Utils.ForceKick(player, null == args.Parameters["reason"] ? "Kicked via web" : args.Parameters["reason"], false, true); + player.Kick(null == args.Parameters["reason"] ? "Kicked via web" : args.Parameters["reason"], false, true, null, true); return RestResponse("Player " + player.Name + " was kicked"); } @@ -1002,7 +1003,7 @@ namespace TShockAPI TSPlayer player = (TSPlayer)ret; var reason = null == args.Parameters["reason"] ? "Banned via web" : args.Parameters["reason"]; TShock.Bans.AddBan(player.IP, player.Name, "", "", reason); - TShock.Utils.ForceKick(player, reason, false, true); + player.Kick(reason, true, false, null, true); return RestResponse("Player " + player.Name + " was banned"); } @@ -1244,7 +1245,7 @@ namespace TShockAPI if (string.IsNullOrWhiteSpace(name)) return RestMissingParam("player"); - var found = TShock.Utils.FindPlayer(name); + var found = TSPlayer.FindByNameOrID(name); switch(found.Count) { case 1: diff --git a/TShockAPI/Rest/SecureRest.cs b/TShockAPI/Rest/SecureRest.cs index 4000efab..fb6a395d 100644 --- a/TShockAPI/Rest/SecureRest.cs +++ b/TShockAPI/Rest/SecureRest.cs @@ -144,7 +144,7 @@ namespace Rests return new RestObject("403") { Error = "Username or password may be incorrect or this account may not have sufficient privileges." }; } - Group userGroup = TShock.Utils.GetGroup(userAccount.Group); + Group userGroup = TShock.Groups.GetGroupByName(userAccount.Group); if (!userGroup.HasPermission(RestPermissions.restapi) && userAccount.Group != "superadmin") { AddTokenToBucket(context.RemoteEndPoint.Address.ToString()); diff --git a/TShockAPI/StatTracker.cs b/TShockAPI/StatTracker.cs index 1151d170..807c530c 100644 --- a/TShockAPI/StatTracker.cs +++ b/TShockAPI/StatTracker.cs @@ -144,7 +144,7 @@ namespace TShockAPI return new JsonData() { port = Terraria.Netplay.ListenPort, - currentPlayers = TShock.Utils.ActivePlayers(), + currentPlayers = TShock.Utils.GetActivePlayerCount(), maxPlayers = TShock.Config.MaxSlots, systemRam = GetTotalSystemRam(ServerApi.RunningMono), version = TShock.VersionNum.ToString(), diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index 5a2e393a..c71141e7 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -34,6 +34,7 @@ using TShockAPI.DB; using TShockAPI.Hooks; using TShockAPI.Net; using Timer = System.Timers.Timer; +using System.Linq; namespace TShockAPI { @@ -73,6 +74,43 @@ namespace TShockAPI /// public static readonly TSPlayer All = new TSPlayer("All"); + /// + /// Finds a TSPlayer based on name or ID + /// + /// Player name or ID + /// A list of matching players + public static List FindByNameOrID(string plr) + { + var found = new List(); + // Avoid errors caused by null search + if (plr == null) + return found; + + byte plrID; + if (byte.TryParse(plr, out plrID) && plrID < Main.maxPlayers) + { + TSPlayer player = TShock.Players[plrID]; + if (player != null && player.Active) + { + return new List { player }; + } + } + + string plrLower = plr.ToLower(); + foreach (TSPlayer player in TShock.Players) + { + if (player != null) + { + // Must be an EXACT match + if (player.Name == plr) + return new List { player }; + if (player.Name.ToLower().StartsWith(plrLower)) + found.Add(player); + } + } + return found; + } + /// /// The amount of tiles that the player has killed in the last second. /// @@ -1420,6 +1458,43 @@ namespace TShockAPI SendDataFromPlayer(PacketTypes.SmartTextMessage, ply, msg, red, green, blue, -1); } + /// + /// Sends the text of a given file to the player. Replacement of %map% and %players% if in the file. + /// + /// Filename relative to + public void SendFileTextAsMessage(string file) + { + string foo = ""; + bool containsOldFormat = false; + using (var tr = new StreamReader(file)) + { + Color lineColor; + while ((foo = tr.ReadLine()) != null) + { + lineColor = Color.White; + if (string.IsNullOrWhiteSpace(foo)) + { + continue; + } + + var players = new List(); + + foreach (TSPlayer ply in TShock.Players) + { + if (ply != null && ply.Active) + { + players.Add(ply.Name); + } + } + + foo = foo.Replace("%map%", (TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName)); + foo = foo.Replace("%players%", String.Join(",", players)); + + SendMessage(foo, lineColor); + } + } + } + /// /// Wounds the player with the given damage. /// @@ -1505,6 +1580,79 @@ namespace TShockAPI LogStackFrame(); } + /// + /// Disconnects this player from the server with a reason. + /// + /// The reason to display to the user and to the server on kick. + /// If the kick should happen regardless of immunity to kick permissions. + /// If no message should be broadcasted to the server. + /// The originator of the kick, for display purposes. + /// If the player's server side character should be saved on kick. + public bool Kick(string reason, bool force = false, bool silent = false, string adminUserName = null, bool saveSSI = false) + { + if (!ConnectionAlive) + return true; + if (force || !HasPermission(Permissions.immunetokick)) + { + SilentKickInProgress = silent; + if (IsLoggedIn && saveSSI) + SaveServerCharacter(); + Disconnect(string.Format("Kicked: {0}", reason)); + TShock.Log.ConsoleInfo(string.Format("Kicked {0} for : '{1}'", Name, reason)); + string verb = force ? "force " : ""; + if (!silent) + { + if (string.IsNullOrWhiteSpace(adminUserName)) + TShock.Utils.Broadcast(string.Format("{0} was {1}kicked for '{2}'", Name, verb, reason.ToLower()), Color.Green); + else + TShock.Utils.Broadcast(string.Format("{0} {1}kicked {2} for '{3}'", adminUserName, verb, Name, reason.ToLower()), Color.Green); + } + return true; + } + return false; + } + + /// + /// Bans and disconnects the player from the server. + /// + /// The reason to be displayed to the server. + /// If the ban should bypass immunity to ban checks. + /// The player who initiated the ban. + public bool Ban(string reason, bool force = false, string adminUserName = null) + { + if (!ConnectionAlive) + return true; + if (force || !HasPermission(Permissions.immunetoban)) + { + string ip = IP; + string uuid = UUID; + TShock.Bans.AddBan(ip, Name, uuid, "", reason, false, adminUserName); + Disconnect(string.Format("Banned: {0}", reason)); + string verb = force ? "force " : ""; + if (string.IsNullOrWhiteSpace(adminUserName)) + TSPlayer.All.SendInfoMessage("{0} was {1}banned for '{2}'.", Name, verb, reason); + else + TSPlayer.All.SendInfoMessage("{0} {1}banned {2} for '{3}'.", adminUserName, verb, Name, reason); + return true; + } + return false; + } + + /// + /// Sends the player an error message stating that more than one match was found + /// appending a csv list of the matches. + /// + /// An enumerable list with the matches + public void SendMultipleMatchError(IEnumerable matches) + { + SendErrorMessage("More than one match found: "); + + var lines = PaginationTools.BuildLinesFromTerms(matches.ToArray()); + lines.ForEach(SendInfoMessage); + + SendErrorMessage("Use \"my query\" for items with spaces."); + } + [Conditional("DEBUG")] private void LogStackFrame() { diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 6c4cc5fd..5a795972 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -481,13 +481,13 @@ namespace TShockAPI // And then get rid of them. if (potentialBan.Expiration == "") { - Utils.ForceKick(args.Player, String.Format("Permanently banned by {0} for {1}", potentialBan.BanningUser - ,potentialBan.Reason), false, false); + args.Player.Kick(String.Format("Permanently banned by {0} for {1}", potentialBan.BanningUser + ,potentialBan.Reason), true, true); } else { - Utils.ForceKick(args.Player, String.Format("Still banned by {0} for {1}", potentialBan.BanningUser, - potentialBan.Reason), false, false); + args.Player.Kick(String.Format("Still banned by {0} for {1}", potentialBan.BanningUser, + potentialBan.Reason), true, true); } } } @@ -1241,16 +1241,16 @@ namespace TShockAPI var player = new TSPlayer(args.Who); - if (Utils.ActivePlayers() + 1 > Config.MaxSlots + Config.ReservedSlots) + if (Utils.GetActivePlayerCount() + 1 > Config.MaxSlots + Config.ReservedSlots) { - Utils.ForceKick(player, Config.ServerFullNoReservedReason, true, false); + player.Kick(Config.ServerFullNoReservedReason, true, true, null, false); args.Handled = true; return; } if (!FileTools.OnWhitelist(player.IP)) { - Utils.ForceKick(player, Config.WhitelistKickReason, true, false); + player.Kick(Config.WhitelistKickReason, true, true, null, false); args.Handled = true; return; } @@ -1263,7 +1263,7 @@ namespace TShockAPI { if (Config.KickProxyUsers) { - Utils.ForceKick(player, "Proxies are not allowed.", true, false); + player.Kick("Connecting via a proxy is not allowed.", true, true, null, false); args.Handled = true; return; } @@ -1285,7 +1285,7 @@ namespace TShockAPI if (Config.KickEmptyUUID && String.IsNullOrWhiteSpace(player.UUID)) { - Utils.ForceKick(player, "Your client did not send a UUID, this server is not configured to accept such a client.", true); + player.Kick("Your client sent a blank UUID. Configure it to send one or use a different client.", true, true, null, false); args.Handled = true; return; } @@ -1310,7 +1310,7 @@ namespace TShockAPI if (ban != null) { - if (!Utils.HasBanExpired(ban)) + if (!Bans.RemoveBanIfExpired(ban)) { DateTime exp; if (!DateTime.TryParse(ban.Expiration, out exp)) @@ -1400,7 +1400,7 @@ namespace TShockAPI } // The last player will leave after this hook is executed. - if (Utils.ActivePlayers() == 1) + if (Utils.GetActivePlayerCount() == 1) { if (Config.SaveWorldOnLastPlayerExit) SaveManager.Instance.SaveWorld(); @@ -1424,7 +1424,7 @@ namespace TShockAPI if (args.Text.Length > 500) { - Utils.Kick(tsplr, "Crash attempt via long chat packet.", true); + tsplr.Kick("Crash attempt via long chat packet.", true); args.Handled = true; return; } @@ -1621,7 +1621,7 @@ namespace TShockAPI if (Config.EnableGeoIP && TShock.Geo != null) { Log.Info("{0} ({1}) from '{2}' group from '{3}' joined. ({4}/{5})", player.Name, player.IP, - player.Group.Name, player.Country, TShock.Utils.ActivePlayers(), + player.Group.Name, player.Country, TShock.Utils.GetActivePlayerCount(), TShock.Config.MaxSlots); if (!player.SilentJoinInProgress) Utils.Broadcast(string.Format("{0} ({1}) has joined.", player.Name, player.Country), Color.Yellow); @@ -1629,7 +1629,7 @@ namespace TShockAPI else { Log.Info("{0} ({1}) from '{2}' group joined. ({3}/{4})", player.Name, player.IP, - player.Group.Name, TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots); + player.Group.Name, TShock.Utils.GetActivePlayerCount(), TShock.Config.MaxSlots); if (!player.SilentJoinInProgress) Utils.Broadcast(player.Name + " has joined.", Color.Yellow); } @@ -1637,7 +1637,7 @@ namespace TShockAPI if (Config.DisplayIPToAdmins) Utils.SendLogs(string.Format("{0} has joined. IP: {1}", player.Name, player.IP), Color.Blue); - Utils.ShowFileToUser(player, FileTools.MotdPath); + player.SendFileTextAsMessage(FileTools.MotdPath); string pvpMode = Config.PvPMode.ToLowerInvariant(); if (pvpMode == "always") diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs index 26493d67..09e7d542 100644 --- a/TShockAPI/Utils.cs +++ b/TShockAPI/Utils.cs @@ -69,52 +69,6 @@ namespace TShockAPI return mess.Split(':')[0]; } - /// - /// Returns a list of current players on the server - /// - /// bool includeIDs - whether or not the string of each player name should include ID data - /// List of strings with names - public List GetPlayers(bool includeIDs) - { - var players = new List(); - - foreach (TSPlayer ply in TShock.Players) - { - if (ply != null && ply.Active) - { - if (includeIDs) - { - players.Add(String.Format("{0} (IX: {1}{2})", ply.Name, ply.Index, ply.Account != null ? ", ID: " + ply.Account.ID : "")); - } - else - { - players.Add(ply.Name); - } - } - } - - return players; - } - - /// - /// Finds a player and gets IP as string - /// - /// string playername - public string GetPlayerIP(string playername) - { - foreach (TSPlayer player in TShock.Players) - { - if (player != null && player.Active) - { - if (playername.ToLower() == player.Name.ToLower()) - { - return player.IP; - } - } - } - return null; - } - /// /// It's a clamp function /// @@ -199,48 +153,11 @@ namespace TShockAPI /// Gets the number of active players on the server. /// /// The number of active players on the server. - public int ActivePlayers() + public int GetActivePlayerCount() { return Main.player.Where(p => null != p && p.active).Count(); } - /// - /// Finds a TSPlayer based on name or ID - /// - /// Player name or ID - /// A list of matching players - public List FindPlayer(string plr) - { - var found = new List(); - // Avoid errors caused by null search - if (plr == null) - return found; - - byte plrID; - if (byte.TryParse(plr, out plrID) && plrID < Main.maxPlayers) - { - TSPlayer player = TShock.Players[plrID]; - if (player != null && player.Active) - { - return new List { player }; - } - } - - string plrLower = plr.ToLower(); - foreach (TSPlayer player in TShock.Players) - { - if (player != null) - { - // Must be an EXACT match - if (player.Name == plr) - return new List { player }; - if (player.Name.ToLower().StartsWith(plrLower)) - found.Add(player); - } - } - return found; - } - //Random should not be generated in a method Random r = new Random(); @@ -536,21 +453,6 @@ namespace TShockAPI return GetPrefixByName(idOrName); } - /// - /// Kicks all player from the server without checking for immunetokick permission. - /// - /// string reason - public void ForceKickAll(string reason) - { - foreach (TSPlayer player in TShock.Players) - { - if (player != null && player.Active) - { - ForceKick(player, reason, false, true); - } - } - } - /// /// Stops the server after kicking all players with a reason message, and optionally saving the world /// @@ -560,12 +462,10 @@ namespace TShockAPI { TShock.ShuttingDown = true; - ForceKickAll(reason); if (save) SaveManager.Instance.SaveWorld(); - // Save takes a while so kick again - ForceKickAll(reason); + TSPlayer.All.Kick(reason, true, true, null, true); // Broadcast so console can see we are shutting down as well TShock.Utils.Broadcast(reason, Color.Red); @@ -577,7 +477,7 @@ namespace TShockAPI /// /// Reloads all configuration settings, groups, regions and raises the reload event. /// - public void Reload(TSPlayer player) + public void Reload() { FileTools.SetupConfig(); TShock.HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs()); @@ -586,156 +486,13 @@ namespace TShockAPI TShock.Itembans.UpdateItemBans(); TShock.ProjectileBans.UpdateBans(); TShock.TileBans.UpdateBans(); - Hooks.GeneralHooks.OnReloadEvent(player); - } - - /// - /// Kicks a player from the server without checking for immunetokick permission. - /// - /// TSPlayer player - /// string reason - /// bool silent (default: false) - /// bool saveSSI (default: false) - public void ForceKick(TSPlayer player, string reason, bool silent = false, bool saveSSI = false) - { - Kick(player, reason, true, silent, null, saveSSI); - } - - /// - /// Kicks a player from the server.. - /// - /// TSPlayer player - /// string reason - /// bool force (default: false) - /// bool silent (default: false) - /// string adminUserName (default: null) - /// bool saveSSI (default: false) - public bool Kick(TSPlayer player, string reason, bool force = false, bool silent = false, string adminUserName = null, bool saveSSI = false) - { - if (!player.ConnectionAlive) - return true; - if (force || !player.HasPermission(Permissions.immunetokick)) - { - string playerName = player.Name; - player.SilentKickInProgress = silent; - if (player.IsLoggedIn && saveSSI) - player.SaveServerCharacter(); - player.Disconnect(string.Format("Kicked: {0}", reason)); - TShock.Log.ConsoleInfo(string.Format("Kicked {0} for : '{1}'", playerName, reason)); - string verb = force ? "force " : ""; - if (!silent) - { - if (string.IsNullOrWhiteSpace(adminUserName)) - Broadcast(string.Format("{0} was {1}kicked for '{2}'", playerName, verb, reason.ToLower()), Color.Green); - else - Broadcast(string.Format("{0} {1}kicked {2} for '{3}'", adminUserName, verb, playerName, reason.ToLower()), Color.Green); - } - return true; - } - return false; - } - - /// - /// Bans and kicks a player from the server. - /// - /// TSPlayer player - /// string reason - /// bool force (default: false) - /// string adminUserName (default: null) - public bool Ban(TSPlayer player, string reason, bool force = false, string adminUserName = null) - { - if (!player.ConnectionAlive) - return true; - if (force || !player.HasPermission(Permissions.immunetoban)) - { - string ip = player.IP; - string uuid = player.UUID; - string playerName = player.Name; - TShock.Bans.AddBan(ip, playerName, uuid, "", reason, false, adminUserName); - player.Disconnect(string.Format("Banned: {0}", reason)); - string verb = force ? "force " : ""; - if (string.IsNullOrWhiteSpace(adminUserName)) - TSPlayer.All.SendInfoMessage("{0} was {1}banned for '{2}'.", playerName, verb, reason); - else - TSPlayer.All.SendInfoMessage("{0} {1}banned {2} for '{3}'.", adminUserName, verb, playerName, reason); - return true; - } - return false; - } - - /// HasBanExpired - Returns whether or not a ban has expired or not. - /// ban - The ban object to check. - /// byName - Defines whether or not the ban should be checked by name. - /// bool - True if the ban has expired. - public bool HasBanExpired(Ban ban, bool byName = false) - { - if (!string.IsNullOrWhiteSpace(ban.Expiration) && (ban.ExpirationDateTime != null) && (DateTime.UtcNow >= ban.ExpirationDateTime)) - { - if (byName) - { - TShock.Bans.RemoveBan(ban.Name, true, true, false); - } - else - { - TShock.Bans.RemoveBan(ban.IP, false, false, false); - } - - return true; - } - - return false; - } - - /// - /// Shows a file to the user. - /// - /// Player the file contents will be sent to - /// Filename relative to - public void ShowFileToUser(TSPlayer player, string file) - { - string foo = ""; - bool containsOldFormat = false; - using (var tr = new StreamReader(file)) - { - Color lineColor; - while ((foo = tr.ReadLine()) != null) - { - lineColor = Color.White; - if (string.IsNullOrWhiteSpace(foo)) - { - continue; - } - - foo = foo.Replace("%map%", (TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName)); - foo = foo.Replace("%players%", String.Join(",", GetPlayers(false))); - - player.SendMessage(foo, lineColor); - } - } - } - - /// - /// Returns a Group from the name of the group - /// - /// string groupName - public Group GetGroup(string groupName) - { - //first attempt on cached groups - for (int i = 0; i < TShock.Groups.groups.Count; i++) - { - if (TShock.Groups.groups[i].Name.Equals(groupName)) - { - return TShock.Groups.groups[i]; - } - } - return Group.DefaultGroup; } /// /// Returns an IPv4 address from a DNS query /// /// string ip - public string GetIPv4Address(string hostname) + public string GetIPv4AddressFromHostname(string hostname) { try { @@ -750,28 +507,11 @@ namespace TShockAPI return ""; } - /// - /// Sends the player an error message stating that more than one match was found - /// appending a csv list of the matches. - /// - /// Player to send the message to - /// An enumerable list with the matches - public void SendMultipleMatchError(TSPlayer ply, IEnumerable matches) - { - ply.SendErrorMessage("More than one match found: "); - - var lines = PaginationTools.BuildLinesFromTerms(matches.ToArray()); - - lines.ForEach(ply.SendInfoMessage); - - ply.SendErrorMessage("Use \"my query\" for items with spaces."); - } - /// /// Checks if world has hit the max number of chests /// /// True if the entire chest array is used - public bool MaxChests() + public bool HasWorldReachedMaxChests() { for (int i = 0; i < Main.chest.Length; i++) { @@ -1377,7 +1117,7 @@ namespace TShockAPI } else { - invasionSize = 100 + (TShock.Config.InvasionMultiplier * ActivePlayers()); + invasionSize = 100 + (TShock.Config.InvasionMultiplier * GetActivePlayerCount()); } // Order matters @@ -1411,12 +1151,12 @@ namespace TShockAPI } /// Updates the console title with some pertinent information. - /// If the server is empty; determines if we should use Utils.ActivePlayers() for player count or 0. + /// If the server is empty; determines if we should use Utils.GetActivePlayerCount() for player count or 0. internal void SetConsoleTitle(bool empty) { Console.Title = string.Format("{0}{1}/{2} on {3} @ {4}:{5} (TShock for Terraria v{6})", !string.IsNullOrWhiteSpace(TShock.Config.ServerName) ? TShock.Config.ServerName + " - " : "", - empty ? 0 : ActivePlayers(), + empty ? 0 : GetActivePlayerCount(), TShock.Config.MaxSlots, Main.worldName, Netplay.ServerIP.ToString(), Netplay.ListenPort, TShock.VersionNum); }