diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 4cf87d10..473130c4 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,19 +1,3 @@
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
-?????? HAVE YOU UPDATED THE CHANGELOG? ??????
\ No newline at end of file
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fedc5a69..fb6e525a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,18 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
* If there is no section called "Upcoming changes" below this line, please add one with `## Upcoming changes` as the first line, and then a bulleted item directly after with the first change.
## Upcoming changes
+* Fixed SendTileRectHandler not sending tile rect updates like Pylons/Mannequins to other clients. (@Stealownz)
+* Introduced `SoftcoreOnly` config option to allow only softcore characters to connect. (@drunderscore)
+* Fixed some typos that have been in the repository for over a lustrum. (@Killia0)
+* Added a `tshock.npc.summonboss` permission check for Lunatic Cultist, players who do not have this permission will not be able to kill Cultist Archers/Devotees to summon the Lunatic Cultist. (@moisterrific)
+* Added more usage examples for the `ban` command under `ban help examples` to explain how users can ban: offline players by account, offline players by IP, and online players by player index - useful for banning hard to type character names. (@moisterrific)
+* Changed `/login` and `/register` to provide login help depending on if UUID login is enabled or disabled, and whether or not a player can login via any username or not. In addition, the message parameters will now be differentiated by colour instead of `<>` (@moisterrific, @hakusaro)
+* Added a new `DisablePrimeBombs` config option (`false` by default). Highly recommended to set this to `true` in order to prevent griefing on servers doing a `for the worthy` play-through, since the prime bombs on this seed can destroy most tiles and bypass region protection. (@moisterrific)
+* Added a new `/respawn` command that lets you respawn yourself or another player. Respawning yourself requires the `tshock.respawn` permission and respawning others requires the `tshock.respawn.other` permission. The full command syntax is `/respawn [player]`. (@moisterrific)
+* Added a notification message and silent command support for permanently changing a target player's user group. Now players who received a group change will be notified of their new group if they are currently online. (@moisterrific, @QuiCM)
+* Changed the TSPlayer IP method to return the loopback IP if RealPlayer is false. (@Rozen4334)
+
+## TShock 4.5.5
* Changed the world autosave message so that it no longer warns of a "potential lag spike." (@hakusaro)
* Added `/slay` as an alias for `/kill` to be more consistent with other server mods. (@hakusaro)
* Added `/god` as an alias for `/godmode` to be more consistent with other server mods. (@hakusaro)
@@ -29,12 +41,18 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
* Correct rejection message in LandGolfBallInCupHandler to output the proper expected player id. (@drunderscore)
* Clarified the error mesage that the console is presented if a rate-limit is reached over REST to indicate that "tokens" actually refers to rate-limit tokens, and not auth tokens, and added a hint as to what config setting determines this. (@hakusaro, @patsore)
* Fixed an issue where, when the console was redirected, input was disabled and commands didn't work, in TSAPI. You can now pass `-disable-commands` to disable the input thread, but by default, it will be enabled. Fixes [#1450](https://github.com/Pryaxis/TShock/issues/1450). (@DeathCradle, @QuiCM)
-* Added `summonboss` permission check for Prismatic Lacewing. Players who do not have said permission will be unable to kill this critter, as it will summon the Empress of Light. Also added support for the `AnonymousBossInvasions` config option, if this is set to `false` it will now broadcast the name of the player who summoned her. (@moisterrific)
+* Added `summonboss` permission check for Empress of Light. Players who do not have this permission will be unable to kill Prismatic Lacewings. Also added support for the `AnonymousBossInvasions` config option, if this is set to `false` it will now broadcast the name of the player who summoned her. (@moisterrific)
* Added `ForceTime` config setting check for Enchanted Sundial usage. If `ForceTime` is set to anything other than `normal`, Sundial use will be rejected as this would lead to very janky game behavior. Additionally, players with `cfgreload` permission will be advised to change it back to `normal` in order to use sundial. (@moisterrific, @bartico6)
* Added `%onlineplayers%` and `%serverslots%` placeholders for MOTD. The default MOTD message was also updated to use this. (@moisterrific, @bartico6)
* Fixed Bouncer exploits allowing for invalid tiles' placement. These tiles(specifically torches) caused clients to crash. The fixed exploits are listed below. (@Arthri)
- [Biome Torch Correction](https://github.com/Pryaxis/TShock/blob/3ba1e7419d63535eeb8b5634ec668448499f71df/TShockAPI/Bouncer.cs#L310). Previously, it used unrelated values to validate biome torches, and unintentionally passed on invalid tiles. It's now fixed to use the correct values and block invalid torches. As well as a new right booster track correction/check, to allow right booster tracks to be placed. Right booster track is an extraneous place style because it depends on the direction the player is facing. The new check takes that into consideration so that the place style isn't considered mismatched and rejected.
- [Max Place Styles](https://github.com/Pryaxis/TShock/blob/3ba1e7419d63535eeb8b5634ec668448499f71df/TShockAPI/Bouncer.cs#L385). Previously, it rejects only if both `MaxPlaceStyles` and `ExtraneousPlaceStyles` contains an entry for a tile, and unintentionally passed on invalid tiles. `ExtraneousPlaceStyles` only contains special max placeStyles, not all placeables unlike `MaxPlaceStyles`. It's now corrected to take from `ExtraneousPlaceStyles` first, then fallback to `MaxPlaceStyles` if there's no entry for that tile, and then finally -1 if there's no entry in either.
+* Fixed Bouncer inconsistently using `TilePlacementValid` when validating tile coordinates, which could cause a DoS attack due to unexpectedly large world framing. The list below shows the corrected methods within Bouncer. This was assigned [GHSA-jq4j-v8pr-jv7j](https://github.com/Pryaxis/TShock/security/advisories/GHSA-jq4j-v8pr-jv7j). (@drunderscore)
+ * `OnTileEdit`: The check was moved to be the first, and will no longer `SendTileSquare` upon failure.
+ * `OnPlaceObject`: The check was moved to be the first, and will no longer `SendTileSquare` upon failure.
+ * `OnPlaceTileEntity`: The check was newly added.
+ * `OnPlaceItemFrame`: The check was newly added.
+ * `OnFoodPlatterTryPlacing`: The check was newly added.
## TShock 4.5.4
* Fixed ridiculous typo in `GetDataHandlers` which caused TShock to read the wrong field in the packet for `usingBiomeTorches`. (@hakusaro, @Arthri)
diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs
index 16b0a3fa..71621bf8 100644
--- a/TShockAPI/Bouncer.cs
+++ b/TShockAPI/Bouncer.cs
@@ -263,6 +263,13 @@ namespace TShockAPI
try
{
+ if (!TShock.Utils.TilePlacementValid(tileX, tileY))
+ {
+ TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (tile placement valid) {0} {1} {2}", args.Player.Name, action, editData);
+ args.Handled = true;
+ return;
+ }
+
if (editData < 0 ||
((action == EditAction.PlaceTile || action == EditAction.ReplaceTile) && editData >= Main.maxTileSets) ||
((action == EditAction.PlaceWall || action == EditAction.ReplaceWall) && editData >= Main.maxWallTypes))
@@ -273,14 +280,6 @@ namespace TShockAPI
return;
}
- if (!TShock.Utils.TilePlacementValid(tileX, tileY))
- {
- TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (tile placement valid) {0} {1} {2}", args.Player.Name, action, editData);
- args.Player.SendTileSquare(tileX, tileY, 1);
- args.Handled = true;
- return;
- }
-
if (action == EditAction.KillTile && Main.tile[tileX, tileY].type == TileID.MagicalIceBlock)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit super accepted from (ice block) {0} {1} {2}", args.Player.Name, action, editData);
@@ -1705,6 +1704,13 @@ namespace TShockAPI
short type = args.Type;
short style = args.Style;
+ if (!TShock.Utils.TilePlacementValid(x, y))
+ {
+ TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected valid placements from {0}", args.Player.Name);
+ args.Handled = true;
+ return;
+ }
+
if (type < 0 || type >= Main.maxTileSets)
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected out of bounds tile from {0}", args.Player.Name);
@@ -1753,14 +1759,6 @@ namespace TShockAPI
return;
}
- if (!TShock.Utils.TilePlacementValid(x, y))
- {
- TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected valid placements from {0}", args.Player.Name);
- args.Player.SendTileSquare(x, y, 1);
- args.Handled = true;
- return;
- }
-
if (args.Player.Dead && TShock.Config.Settings.PreventDeadModification)
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected dead people don't do things from {0}", args.Player.Name);
@@ -1777,7 +1775,7 @@ namespace TShockAPI
return;
}
- // This is neccessary to check in order to prevent special tiles such as
+ // This is necessary to check in order to prevent special tiles such as
// queen bee larva, paintings etc that use this packet from being placed
// without selecting the right item.
if (type != args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].createTile)
@@ -1852,6 +1850,13 @@ namespace TShockAPI
/// The packet arguments that the event has.
internal void OnPlaceTileEntity(object sender, GetDataHandlers.PlaceTileEntityEventArgs args)
{
+ if (!TShock.Utils.TilePlacementValid(args.X, args.Y))
+ {
+ TShock.Log.ConsoleDebug("Bouncer / OnPlaceTileEntity rejected tile placement valid from {0}", args.Player.Name);
+ args.Handled = true;
+ return;
+ }
+
if (args.Player.IsBeingDisabled())
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceTileEntity rejected disabled from {0}", args.Player.Name);
@@ -1879,6 +1884,13 @@ namespace TShockAPI
/// The packet arguments that the event has.
internal void OnPlaceItemFrame(object sender, GetDataHandlers.PlaceItemFrameEventArgs args)
{
+ if (!TShock.Utils.TilePlacementValid(args.X, args.Y))
+ {
+ TShock.Log.ConsoleDebug("Bouncer / OnPlaceItemFrame rejected tile placement valid from {0}", args.Player.Name);
+ args.Handled = true;
+ return;
+ }
+
if (args.Player.IsBeingDisabled())
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceItemFrame rejected disabled from {0}", args.Player.Name);
@@ -2180,6 +2192,13 @@ namespace TShockAPI
///
internal void OnFoodPlatterTryPlacing(object sender, GetDataHandlers.FoodPlatterTryPlacingEventArgs args)
{
+ if (!TShock.Utils.TilePlacementValid(args.TileX, args.TileY))
+ {
+ TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected tile placement valid from {0}", args.Player.Name);
+ args.Handled = true;
+ return;
+ }
+
if ((args.Player.SelectedItem.type != args.ItemID && args.Player.ItemInHand.type != args.ItemID))
{
TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected item not placed by hand from {0}", args.Player.Name);
diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs
index b6ba179f..55d281c3 100644
--- a/TShockAPI/Commands.cs
+++ b/TShockAPI/Commands.cs
@@ -50,7 +50,7 @@ namespace TShockAPI
public bool Silent { get; private set; }
///
- /// Parameters passed to the arguement. Does not include the command name.
+ /// Parameters passed to the argument. Does not include the command name.
/// IE '/kick "jerk face"' will only have 1 argument
///
public List Parameters { get; private set; }
@@ -599,6 +599,10 @@ namespace TShockAPI
{
HelpText = "Sends all tiles from the server to the player to resync the client with the actual world state."
});
+ add(new Command(Permissions.respawn, Respawn, "respawn")
+ {
+ HelpText = "Respawn yourself or another player."
+ });
#endregion
add(new Command(Aliases, "aliases")
@@ -807,10 +811,15 @@ namespace TShockAPI
}
else
{
- args.Player.SendErrorMessage("Syntax: {0}login - Logs in using your UUID and character name", Specifier);
- args.Player.SendErrorMessage(" {0}login - Logs in using your password and character name", Specifier);
- args.Player.SendErrorMessage(" {0}login - Logs in using your username and password", Specifier);
- args.Player.SendErrorMessage("If you forgot your password, there is no way to recover it.");
+ if (!TShock.Config.Settings.DisableUUIDLogin)
+ args.Player.SendMessage($"{Specifier}login - Logs in using your UUID and character name.", Color.White);
+
+ if (TShock.Config.Settings.AllowLoginAnyUsername)
+ args.Player.SendMessage($"{Specifier}login {"username".Color(Utils.GreenHighlight)} {"password".Color(Utils.BoldHighlight)} - Logs in using your username and password.", Color.White);
+ else
+ args.Player.SendMessage($"{Specifier}login {"password".Color(Utils.BoldHighlight)} - Logs in using your password and character name.", Color.White);
+
+ args.Player.SendWarningMessage("If you forgot your password, there is no way to recover it.");
return;
}
try
@@ -939,7 +948,7 @@ namespace TShockAPI
}
catch (UserAccountManagerException ex)
{
- args.Player.SendErrorMessage("Sorry, an error occured: " + ex.Message + ".");
+ args.Player.SendErrorMessage("Sorry, an error occurred: " + ex.Message + ".");
TShock.Log.ConsoleError("PasswordUser returned an error: " + ex);
}
}
@@ -991,6 +1000,15 @@ namespace TShockAPI
{
args.Player.SendSuccessMessage("Account \"{0}\" has been registered.", account.Name);
args.Player.SendSuccessMessage("Your password is {0}.", echoPassword);
+
+ if (!TShock.Config.Settings.DisableUUIDLogin)
+ args.Player.SendMessage($"Type {Specifier}login to sign in to your account using your UUID.", Color.White);
+
+ if (TShock.Config.Settings.AllowLoginAnyUsername)
+ args.Player.SendMessage($"Type {Specifier}login \"{account.Name.Color(Utils.GreenHighlight)}\" {echoPassword.Color(Utils.BoldHighlight)} to sign in to your account.", Color.White);
+ else
+ args.Player.SendMessage($"Type {Specifier}login {echoPassword.Color(Utils.BoldHighlight)} to sign in to your account.", Color.White);
+
TShock.UserAccounts.AddUserAccount(account);
TShock.Log.ConsoleInfo("{0} registered an account: \"{1}\".", args.Player.Name, account.Name);
}
@@ -1003,7 +1021,7 @@ namespace TShockAPI
}
catch (UserAccountManagerException ex)
{
- args.Player.SendErrorMessage("Sorry, an error occured: " + ex.Message + ".");
+ args.Player.SendErrorMessage("Sorry, an error occurred: " + ex.Message + ".");
TShock.Log.ConsoleError("RegisterUser returned an error: " + ex);
}
}
@@ -1116,6 +1134,11 @@ namespace TShockAPI
TShock.UserAccounts.SetUserGroup(account, args.Parameters[2]);
TShock.Log.ConsoleInfo(args.Player.Name + " changed account " + account.Name + " to group " + args.Parameters[2] + ".");
args.Player.SendSuccessMessage("Account " + account.Name + " has been changed to group " + args.Parameters[2] + "!");
+
+ //send message to player with matching account name
+ var player = TShock.Players.FirstOrDefault(p => p != null && p.Account?.Name == account.Name);
+ if (player != null && !args.Silent)
+ player.SendSuccessMessage($"{args.Player.Name} has changed your group to {args.Parameters[2]}");
}
catch (GroupNotExistsException)
{
@@ -1216,7 +1239,7 @@ namespace TShockAPI
if (DateTime.TryParse(account.LastAccessed, out LastSeen))
{
LastSeen = DateTime.Parse(account.LastAccessed).ToLocalTime();
- args.Player.SendSuccessMessage("{0}'s last login occured {1} {2} UTC{3}.", account.Name, LastSeen.ToShortDateString(),
+ args.Player.SendSuccessMessage("{0}'s last login occurred {1} {2} UTC{3}.", account.Name, LastSeen.ToShortDateString(),
LastSeen.ToShortTimeString(), Timezone);
}
@@ -1303,7 +1326,7 @@ namespace TShockAPI
args.Player.SendMessage($"ban {"list".Color(Utils.RedHighlight)}", Color.White);
args.Player.SendMessage($"ban {"details".Color(Utils.RedHighlight)} ", Color.White);
args.Player.SendMessage($"Quick usage: {"ban add".Color(Utils.BoldHighlight)} {args.Player.Name.Color(Utils.RedHighlight)} \"Griefing\"", Color.White);
- args.Player.SendMessage($"For more info, use {"ban help".Color(Utils.BoldHighlight)} {"command".Color(Utils.RedHighlight)}", Color.White);
+ args.Player.SendMessage($"For more info, use {"ban help".Color(Utils.BoldHighlight)} {"command".Color(Utils.RedHighlight)} or {"ban help".Color(Utils.BoldHighlight)} {"examples".Color(Utils.RedHighlight)}", Color.White);
}
void MoreHelp(string cmd)
@@ -1327,7 +1350,7 @@ namespace TShockAPI
args.Player.SendMessage("", Color.White);
args.Player.SendMessage("Ban Del Syntax", Color.White);
args.Player.SendMessage($"{"ban del".Color(Utils.BoldHighlight)} <{"Ticket Number".Color(Utils.RedHighlight)}>", Color.White);
- args.Player.SendMessage($"- {"Ticket Number".Color(Utils.RedHighlight)}s are provided when you add a ban, and can also be viewed with the {"ban list".Color(Utils.BoldHighlight)} command.", Color.White);
+ args.Player.SendMessage($"- {"Ticket Numbers".Color(Utils.RedHighlight)} are provided when you add a ban, and can also be viewed with the {"ban list".Color(Utils.BoldHighlight)} command.", Color.White);
args.Player.SendMessage($"Example usage: {"ban del".Color(Utils.BoldHighlight)} {"12345".Color(Utils.RedHighlight)}", Color.White);
break;
@@ -1343,14 +1366,14 @@ namespace TShockAPI
args.Player.SendMessage("", Color.White);
args.Player.SendMessage("Ban Details Syntax", Color.White);
args.Player.SendMessage($"{"ban details".Color(Utils.BoldHighlight)} <{"Ticket Number".Color(Utils.RedHighlight)}>", Color.White);
- args.Player.SendMessage($"- {"Ticket Number".Color(Utils.RedHighlight)}s are provided when you add a ban, and can be found with the {"ban list".Color(Utils.BoldHighlight)} command.", Color.White);
+ args.Player.SendMessage($"- {"Ticket Numbers".Color(Utils.RedHighlight)} are provided when you add a ban, and can be found with the {"ban list".Color(Utils.BoldHighlight)} command.", Color.White);
args.Player.SendMessage($"Example usage: {"ban details".Color(Utils.BoldHighlight)} {"12345".Color(Utils.RedHighlight)}", Color.White);
break;
case "identifiers":
if (!PaginationTools.TryParsePageNumber(args.Parameters, 2, args.Player, out int pageNumber))
{
- args.Player.SendMessage($"Invalid page number. Page number should be numeric.", Color.White);
+ args.Player.SendMessage($"Invalid page number. Page number must be numeric.", Color.White);
return;
}
@@ -1368,10 +1391,23 @@ namespace TShockAPI
LineTextColor = Color.White
});
break;
+
+ case "examples":
+ args.Player.SendMessage("", Color.White);
+ args.Player.SendMessage("Ban Usage Examples", Color.White);
+ args.Player.SendMessage("- Ban an offline player by account name", Color.White);
+ args.Player.SendMessage($" {Specifier}{"ban add".Color(Utils.BoldHighlight)} \"{"acc:".Color(Utils.RedHighlight)}{args.Player.Account.Color(Utils.RedHighlight)}\" {"\"Multiple accounts are not allowed\"".Color(Utils.BoldHighlight)} {"-e".Color(Utils.GreenHighlight)} (Permanently bans this account name)", Color.White);
+ args.Player.SendMessage("- Ban an offline player by IP address", Color.White);
+ args.Player.SendMessage($" {Specifier}{"ai".Color(Utils.BoldHighlight)} \"{args.Player.Account.Color(Utils.RedHighlight)}\" (Find the IP associated with the offline target's account)", Color.White);
+ args.Player.SendMessage($" {Specifier}{"ban add".Color(Utils.BoldHighlight)} {"ip:".Color(Utils.RedHighlight)}{args.Player.IP.Color(Utils.RedHighlight)} {"\"Griefing\"".Color(Utils.BoldHighlight)} {"-e".Color(Utils.GreenHighlight)} (Permanently bans this IP address)", Color.White);
+ args.Player.SendMessage($"- Ban an online player by index (Useful for hard to type names)", Color.White);
+ args.Player.SendMessage($" {Specifier}{"who".Color(Utils.BoldHighlight)} {"-i".Color(Utils.GreenHighlight)} (Find the player index for the target)", Color.White);
+ args.Player.SendMessage($" {Specifier}{"ban add".Color(Utils.BoldHighlight)} {"tsi:".Color(Utils.RedHighlight)}{args.Player.Index.Color(Utils.RedHighlight)} {"\"Trolling\"".Color(Utils.BoldHighlight)} {"-a -u -ip".Color(Utils.GreenHighlight)} (Permanently bans the online player by Account, UUID, and IP)", Color.White);
+ // Ban by account ID when?
+ break;
default:
- args.Player.SendMessage($"Unknown ban command. Try {"add".Color(Utils.RedHighlight)}, {"del".Color(Utils.RedHighlight)}, {"list".Color(Utils.RedHighlight)}, or {"details".Color(Utils.RedHighlight)}.", Color.White);
- break;
+ args.Player.SendMessage($"Unknown ban command. Try {"ban help".Color(Utils.BoldHighlight)} {"add".Color(Utils.RedHighlight)}, {"del".Color(Utils.RedHighlight)}, {"list".Color(Utils.RedHighlight)}, {"details".Color(Utils.RedHighlight)}, {"identifiers".Color(Utils.RedHighlight)}, or {"examples".Color(Utils.RedHighlight)}.", Color.White); break;
}
}
@@ -5518,7 +5554,7 @@ namespace TShockAPI
#endregion General Commands
- #region Cheat Commands
+ #region Game Commands
private static void Clear(CommandArgs args)
{
@@ -5632,6 +5668,55 @@ namespace TShockAPI
plr.SendErrorMessage("{0} just killed you!", args.Player.Name);
}
}
+
+ private static void Respawn(CommandArgs args)
+ {
+ if (!args.Player.RealPlayer)
+ {
+ args.Player.SendErrorMessage("You can't respawn the server console!");
+ return;
+ }
+ TSPlayer playerToRespawn;
+ if (args.Parameters.Count > 0)
+ {
+ if (!args.Player.HasPermission(Permissions.respawnother))
+ {
+ args.Player.SendErrorMessage("You do not have permission to respawn another player.");
+ return;
+ }
+ string plStr = String.Join(" ", args.Parameters);
+ var players = TSPlayer.FindByNameOrID(plStr);
+ if (players.Count == 0)
+ {
+ args.Player.SendErrorMessage($"Could not find any player named \"{plStr}\"");
+ return;
+ }
+ if (players.Count > 1)
+ {
+ args.Player.SendMultipleMatchError(players.Select(p => p.Name));
+ return;
+ }
+ playerToRespawn = players[0];
+ }
+ else
+ playerToRespawn = args.Player;
+
+ if (!playerToRespawn.Dead)
+ {
+ args.Player.SendErrorMessage($"{(playerToRespawn == args.Player ? "You" : playerToRespawn.Name)} {(playerToRespawn == args.Player ? "are" : "is")} not dead.");
+ return;
+ }
+ playerToRespawn.Spawn(PlayerSpawnContext.ReviveFromDeath);
+
+ if (playerToRespawn != args.Player)
+ {
+ args.Player.SendSuccessMessage($"You have respawned {playerToRespawn.Name}");
+ if (!args.Silent)
+ playerToRespawn.SendSuccessMessage($"{args.Player.Name} has respawned you.");
+ }
+ else
+ playerToRespawn.SendSuccessMessage("You have respawned yourself.");
+ }
private static void Butcher(CommandArgs args)
{
@@ -6472,6 +6557,6 @@ namespace TShockAPI
}
}
- #endregion Cheat Comamnds
+ #endregion Game Commands
}
}
diff --git a/TShockAPI/Configuration/TShockConfig.cs b/TShockAPI/Configuration/TShockConfig.cs
index 801a4c5f..14e56cb6 100644
--- a/TShockAPI/Configuration/TShockConfig.cs
+++ b/TShockAPI/Configuration/TShockConfig.cs
@@ -133,6 +133,10 @@ namespace TShockAPI.Configuration
[Description("Prevents softcore players from connecting.")]
public bool MediumcoreOnly;
+ /// Prevents non-softcore players from connecting.
+ [Description("Prevents non-softcore players from connecting.")]
+ public bool SoftcoreOnly;
+
/// Disables any placing, or removal of blocks.
[Description("Disables any placing, or removal of blocks.")]
public bool DisableBuild;
@@ -156,6 +160,12 @@ namespace TShockAPI.Configuration
/// Disables tombstone dropping during death for all players.
[Description("Disables tombstone dropping during death for all players.")]
public bool DisableTombstones = true;
+
+ ///
+ /// Disables Skeletron Prime Bombs from spawning, useful for preventing unwanted world destruction on for the worthy seed world.
+ ///
+ [Description("Disables Skeletron Prime Bombs from spawning, useful for preventing unwanted world destruction on for the worthy seed world.")]
+ public bool DisablePrimeBombs;
/// Forces the world time to be normal, day, or night.
[Description("Forces the world time to be normal, day, or night.")]
diff --git a/TShockAPI/DB/GroupManager.cs b/TShockAPI/DB/GroupManager.cs
index 7b3b62dd..3bb50881 100644
--- a/TShockAPI/DB/GroupManager.cs
+++ b/TShockAPI/DB/GroupManager.cs
@@ -425,14 +425,14 @@ namespace TShockAPI.DB
}
catch (Exception ex)
{
- TShock.Log.Error($"An exception has occured during database transaction: {ex.Message}");
+ TShock.Log.Error($"An exception has occurred during database transaction: {ex.Message}");
try
{
transaction.Rollback();
}
catch (Exception rollbackEx)
{
- TShock.Log.Error($"An exception has occured during database rollback: {rollbackEx.Message}");
+ TShock.Log.Error($"An exception has occurred during database rollback: {rollbackEx.Message}");
}
}
}
diff --git a/TShockAPI/DB/RegionManager.cs b/TShockAPI/DB/RegionManager.cs
index eaf8f1ba..60ff0ed5 100644
--- a/TShockAPI/DB/RegionManager.cs
+++ b/TShockAPI/DB/RegionManager.cs
@@ -168,7 +168,7 @@ namespace TShockAPI.DB
}
///
- /// Delets the region from this world with a given ID.
+ /// Deletes the region from this world with a given ID.
///
/// The ID of the region to delete.
/// Whether the region was successfully deleted.
@@ -584,7 +584,7 @@ namespace TShockAPI.DB
///
/// Region name
/// New owner's username
- /// Whether the change was successfull
+ /// Whether the change was successful
public bool ChangeOwner(string regionName, string newOwner)
{
var region = GetRegionByName(regionName);
@@ -604,7 +604,7 @@ namespace TShockAPI.DB
///
/// Region name
/// Group's name
- /// Whether the change was successfull
+ /// Whether the change was successful
public bool AllowGroup(string regionName, string groupName)
{
string mergedGroups = "";
@@ -646,7 +646,7 @@ namespace TShockAPI.DB
///
/// Region name
/// Group name
- /// Whether the change was successfull
+ /// Whether the change was successful
public bool RemoveGroup(string regionName, string group)
{
Region r = GetRegionByName(regionName);
@@ -688,7 +688,7 @@ namespace TShockAPI.DB
///
/// Region name
/// New Z index
- /// Whether the change was successfull
+ /// Whether the change was successful
public bool SetZ(string name, int z)
{
try
diff --git a/TShockAPI/DB/RememberedPosManager.cs b/TShockAPI/DB/RememberedPosManager.cs
index 77fef847..c49c5912 100644
--- a/TShockAPI/DB/RememberedPosManager.cs
+++ b/TShockAPI/DB/RememberedPosManager.cs
@@ -56,7 +56,7 @@ namespace TShockAPI.DB
{
int checkX=reader.Get("X");
int checkY=reader.Get("Y");
- //fix leftover inconsistancies
+ //fix leftover inconsistencies
if (checkX==0)
checkX++;
if (checkY==0)
diff --git a/TShockAPI/DB/UserManager.cs b/TShockAPI/DB/UserManager.cs
index 2d09ba5a..4fedaaed 100644
--- a/TShockAPI/DB/UserManager.cs
+++ b/TShockAPI/DB/UserManager.cs
@@ -378,7 +378,7 @@ namespace TShockAPI.DB
/// The hashed password for the user account.
public string Password { get; internal set; }
- /// The user's saved Univerally Unique Identifier token.
+ /// The user's saved Universally Unique Identifier token.
public string UUID { get; set; }
/// The group object that the user account is a part of.
diff --git a/TShockAPI/DB/WarpsManager.cs b/TShockAPI/DB/WarpsManager.cs
index a409580e..bd13ce4d 100644
--- a/TShockAPI/DB/WarpsManager.cs
+++ b/TShockAPI/DB/WarpsManager.cs
@@ -139,7 +139,7 @@ namespace TShockAPI.DB
/// The warp name.
/// The X position.
/// The Y position.
- /// Whether the operation suceeded.
+ /// Whether the operation succeeded.
public bool Position(string warpName, int x, int y)
{
try
@@ -163,7 +163,7 @@ namespace TShockAPI.DB
///
/// The warp name.
/// The state.
- /// Whether the operation suceeded.
+ /// Whether the operation succeeded.
public bool Hide(string warpName, bool state)
{
try
@@ -216,4 +216,4 @@ namespace TShockAPI.DB
IsPrivate = false;
}
}
-}
\ No newline at end of file
+}
diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index ed701f2f..3bed28b2 100644
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -346,7 +346,7 @@ namespace TShockAPI
///
public Vector2 Velocity { get; set; }
///
- /// Original poisition of the player when using Potion of Return.
+ /// Original position of the player when using Potion of Return.
///
public Vector2? OriginalPos { get; set; }
///
@@ -770,7 +770,7 @@ namespace TShockAPI
{
/// The projectile's identity...?
public int ProjectileIdentity;
- /// The the player index of the projectile's owner (Main.players).
+ /// The player index of the projectile's owner (Main.players).
public byte ProjectileOwner;
/// The index of the projectile in Main.projectile.
public int ProjectileIndex;
@@ -1846,7 +1846,7 @@ namespace TShockAPI
///
public byte ID { get; set; }
///
- /// The direction the damage is occuring from
+ /// The direction the damage is occurring from
///
public byte Direction { get; set; }
///
@@ -1902,7 +1902,7 @@ namespace TShockAPI
///
public byte Direction { get; set; }
///
- /// Amount of damage delt
+ /// Amount of damage dealt
///
public short Damage { get; set; }
///
@@ -1989,7 +1989,7 @@ namespace TShockAPI
///
public int Slot { get; set; }
///
- /// Wether or not the slot that is being modified is a Dye slot.
+ /// Whether or not the slot that is being modified is a Dye slot.
///
public bool IsDye { get; set; }
///
@@ -2364,6 +2364,12 @@ namespace TShockAPI
NetMessage.SendData((int)PacketTypes.PlayerInfo, -1, args.Player.Index, NetworkText.FromLiteral(args.Player.Name), args.Player.Index);
return true;
}
+ if (TShock.Config.Settings.SoftcoreOnly && difficulty != 0)
+ {
+ TShock.Log.ConsoleDebug("GetDataHandlers / HandlePlayerInfo rejected softcore required");
+ args.Player.Kick("You need to join with a softcore player.", true, true);
+ return true;
+ }
if (TShock.Config.Settings.MediumcoreOnly && difficulty < 1)
{
TShock.Log.ConsoleDebug("GetDataHandlers / HandlePlayerInfo rejected mediumcore required");
@@ -2829,6 +2835,17 @@ namespace TShockAPI
else
TShock.Utils.SendLogs(string.Format($"{args.Player.Name} summoned the Empress of Light!"), Color.PaleVioletRed, args.Player);
}
+
+ if (Main.npc[id].netID == NPCID.CultistDevote || Main.npc[id].netID == NPCID.CultistArcherBlue)
+ {
+ if (!args.Player.HasPermission(Permissions.summonboss))
+ {
+ args.Player.SendErrorMessage("You do not have permission to summon the Lunatic Cultist!");
+ args.Player.SendData(PacketTypes.NpcUpdate, "", id);
+ TShock.Log.ConsoleDebug($"GetDataHandlers / HandleNpcStrike rejected Cultist summon from {args.Player.Name}");
+ return true;
+ }
+ }
return false;
}
diff --git a/TShockAPI/Group.cs b/TShockAPI/Group.cs
index fa2d1975..ff2ba2e9 100644
--- a/TShockAPI/Group.cs
+++ b/TShockAPI/Group.cs
@@ -273,7 +273,7 @@ namespace TShockAPI
///
/// Clears the permission list and sets it to the list provided,
- /// will parse "!permssion" and add it to the negated permissions.
+ /// will parse "!permission" and add it to the negated permissions.
///
/// The new list of permissions to associate with the group.
public void SetPermission(List permission)
diff --git a/TShockAPI/Handlers/NetModules/PylonHandler.cs b/TShockAPI/Handlers/NetModules/PylonHandler.cs
index 7cbe054b..10a30b68 100644
--- a/TShockAPI/Handlers/NetModules/PylonHandler.cs
+++ b/TShockAPI/Handlers/NetModules/PylonHandler.cs
@@ -11,7 +11,7 @@ namespace TShockAPI.Handlers.NetModules
public class PylonHandler : INetModuleHandler
{
///
- /// Event occuring
+ /// Event occurring
///
public SubPacketType PylonEventType { get; set; }
///
diff --git a/TShockAPI/Handlers/SendTileRectHandler.cs b/TShockAPI/Handlers/SendTileRectHandler.cs
index b3955618..b5c0bafd 100644
--- a/TShockAPI/Handlers/SendTileRectHandler.cs
+++ b/TShockAPI/Handlers/SendTileRectHandler.cs
@@ -85,7 +85,7 @@ namespace TShockAPI.Handlers
// At this point we should send our state back to the client so they remain in sync with the server
if (args.Handled == true)
{
- args.Player.SendTileRect(args.TileX, args.TileY, args.Width, args.Length);
+ TSPlayer.All.SendTileRect(args.TileX, args.TileY, args.Width, args.Length);
TShock.Log.ConsoleDebug("Bouncer / SendTileRect reimplemented from carbonara from {0}", args.Player.Name);
}
}
diff --git a/TShockAPI/ILog.cs b/TShockAPI/ILog.cs
index 9fac3789..4c560f1f 100644
--- a/TShockAPI/ILog.cs
+++ b/TShockAPI/ILog.cs
@@ -119,7 +119,7 @@ namespace TShockAPI
/// Writes a message to the log
///
/// Message to write
- /// LogLevel assosciated with the message
+ /// LogLevel associated with the message
void Write(string message, TraceLevel level);
///
@@ -152,4 +152,4 @@ namespace TShockAPI
///
void Dispose();
}
-}
\ No newline at end of file
+}
diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs
index 8ce013b8..7de195d2 100644
--- a/TShockAPI/Permissions.cs
+++ b/TShockAPI/Permissions.cs
@@ -399,7 +399,7 @@ namespace TShockAPI
[Description("User can use Creative UI to set world time speed.")]
public static readonly string journey_timespeed = "tshock.journey.time.setspeed";
- [Description("User can use Creative UI to to toggle character godmode.")]
+ [Description("User can use Creative UI to toggle character godmode.")]
public static readonly string journey_godmode = "tshock.journey.godmode";
[Description("User can use Creative UI to set world wind strength/seed.")]
@@ -436,6 +436,12 @@ namespace TShockAPI
[Description("User can kill others.")]
public static readonly string kill = "tshock.kill";
+
+ [Description("Player can respawn themselves.")]
+ public static readonly string respawn = "tshock.respawn";
+
+ [Description("Player can respawn others.")]
+ public static readonly string respawnother = "tshock.respawn.other";
[Description("Allows you to bypass the max slots for up to 5 slots above your max.")]
public static readonly string reservedslot = "tshock.reservedslot";
diff --git a/TShockAPI/Properties/AssemblyInfo.cs b/TShockAPI/Properties/AssemblyInfo.cs
index 819058cb..28c98cd4 100644
--- a/TShockAPI/Properties/AssemblyInfo.cs
+++ b/TShockAPI/Properties/AssemblyInfo.cs
@@ -53,5 +53,5 @@ using System.Runtime.InteropServices;
// Also, be sure to release on github with the exact assembly version tag as below
// so that the update manager works correctly (via the Github releases api and mimic)
-[assembly: AssemblyVersion("4.5.4")]
-[assembly: AssemblyFileVersion("4.5.4")]
+[assembly: AssemblyVersion("4.5.5")]
+[assembly: AssemblyFileVersion("4.5.5")]
diff --git a/TShockAPI/Rest/RestManager.cs b/TShockAPI/Rest/RestManager.cs
index 8a88dbb6..6ca9889e 100644
--- a/TShockAPI/Rest/RestManager.cs
+++ b/TShockAPI/Rest/RestManager.cs
@@ -1117,7 +1117,7 @@ namespace TShockAPI
[Permission(RestPermissions.restmanagegroups)]
[Noun("group", true, "The name of the new group.", typeof(String))]
[Noun("parent", false, "The name of the parent group.", typeof(String))]
- [Noun("permissions", false, "A comma seperated list of permissions for the new group.", typeof(String))]
+ [Noun("permissions", false, "A comma separated list of permissions for the new group.", typeof(String))]
[Noun("chatcolor", false, "A r,g,b string representing the color for this groups chat.", typeof(String))]
[Token]
private object GroupCreate(RestRequestArgs args)
@@ -1142,7 +1142,7 @@ namespace TShockAPI
[Noun("group", true, "The name of the group to modify.", typeof(String))]
[Noun("parent", false, "The name of the new parent for this group.", typeof(String))]
[Noun("chatcolor", false, "The new chat color r,g,b.", typeof(String))]
- [Noun("permissions", false, "The new comma seperated list of permissions.", typeof(String))]
+ [Noun("permissions", false, "The new comma separated list of permissions.", typeof(String))]
[Token]
private object GroupUpdate(RestRequestArgs args)
{
diff --git a/TShockAPI/Sockets/LinuxTcpSocket.cs b/TShockAPI/Sockets/LinuxTcpSocket.cs
index 98892c42..5a95794b 100644
--- a/TShockAPI/Sockets/LinuxTcpSocket.cs
+++ b/TShockAPI/Sockets/LinuxTcpSocket.cs
@@ -200,7 +200,7 @@ namespace TShockAPI.Sockets
this._listener.Stop();
// currently vanilla will stop listening when the slots are full, however it appears that this Netplay.IsListening
- // flag is still set, making the server loop beleive it's still listening when it's actually not.
+ // flag is still set, making the server loop believe it's still listening when it's actually not.
// clearing this flag when we actually have stopped will allow the ServerLoop to start listening again when
// there are enough slots available.
Netplay.IsListening = false;
diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs
index 47dea08b..ba789eea 100644
--- a/TShockAPI/TSPlayer.cs
+++ b/TShockAPI/TSPlayer.cs
@@ -892,7 +892,7 @@ namespace TShockAPI
CacheIP = RealPlayer ? (Netplay.Clients[Index].Socket.IsConnected()
? TShock.Utils.GetRealIP(Netplay.Clients[Index].Socket.GetRemoteAddress().ToString())
: "")
- : "";
+ : "127.0.0.1";
else
return CacheIP;
}
@@ -1018,7 +1018,7 @@ namespace TShockAPI
}
///
- /// Player Y cooridnate divided by 16. Supposed Y world coordinate.
+ /// Player Y coordinate divided by 16. Supposed Y world coordinate.
///
public int TileY
{
diff --git a/TShockAPI/TSServerPlayer.cs b/TShockAPI/TSServerPlayer.cs
index 09642f59..9f59da49 100644
--- a/TShockAPI/TSServerPlayer.cs
+++ b/TShockAPI/TSServerPlayer.cs
@@ -182,12 +182,12 @@ namespace TShockAPI
public void RevertTiles(Dictionary tiles)
{
- // Update Main.Tile first so that when tile sqaure is sent it is correct
+ // Update Main.Tile first so that when tile square is sent it is correct
foreach (KeyValuePair entry in tiles)
{
Main.tile[(int)entry.Key.X, (int)entry.Key.Y] = entry.Value;
}
- // Send all players updated tile sqaures
+ // Send all players updated tile squares
foreach (Vector2 coords in tiles.Keys)
{
All.SendTileSquare((int)coords.X, (int)coords.Y, 3);
diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs
index ed74b882..16fc1cb9 100644
--- a/TShockAPI/TShock.cs
+++ b/TShockAPI/TShock.cs
@@ -58,7 +58,7 @@ namespace TShockAPI
/// VersionNum - The version number the TerrariaAPI will return back to the API. We just use the Assembly info.
public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version;
/// VersionCodename - The version codename is displayed when the server starts. Inspired by software codenames conventions.
- public static readonly string VersionCodename = "Blood Moon edition";
+ public static readonly string VersionCodename = "Olympics maybe?";
/// SavePath - This is the path TShock saves its data in. This path is relative to the TerrariaServer.exe (not in ServerPlugins).
public static string SavePath = "tshock";
@@ -1614,19 +1614,22 @@ namespace TShockAPI
}
/// OnProjectileSetDefaults - Called when a projectile sets the default attributes for itself.
- /// e - The SetDefaultsEventArgs object praameterized with Projectile and int.
+ /// e - The SetDefaultsEventArgs object parameterized with Projectile and int.
private void OnProjectileSetDefaults(SetDefaultsEventArgs e)
{
//tombstone fix.
- if (e.Info == 43 || (e.Info >= 201 && e.Info <= 205) || (e.Info >= 527 && e.Info <= 531))
+ if (e.Info == ProjectileID.Tombstone || (e.Info >= ProjectileID.GraveMarker && e.Info <= ProjectileID.Obelisk) || (e.Info >= ProjectileID.RichGravestone1 && e.Info <= ProjectileID.RichGravestone5))
if (Config.Settings.DisableTombstones)
e.Object.SetDefaults(0);
- if (e.Info == 75)
+ if (e.Info == ProjectileID.HappyBomb)
if (Config.Settings.DisableClownBombs)
e.Object.SetDefaults(0);
- if (e.Info == 109)
+ if (e.Info == ProjectileID.SnowBallHostile)
if (Config.Settings.DisableSnowBalls)
e.Object.SetDefaults(0);
+ if (e.Info == ProjectileID.BombSkeletronPrime)
+ if (Config.Settings.DisablePrimeBombs)
+ e.Object.SetDefaults(0);
}
/// NetHooks_SendData - Fired when the server sends data.
diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs
index 23007b19..92d45299 100644
--- a/TShockAPI/Utils.cs
+++ b/TShockAPI/Utils.cs
@@ -141,7 +141,7 @@ namespace TShockAPI
}
///
- /// Broadcasts a message from a Terraria playerplayer, not TShock
+ /// Broadcasts a message from a Terraria player, not TShock
///
/// ply - the Terraria player index that will send the packet
/// msg - The message to send