Merge branch 'general-devel' into general-devel

This commit is contained in:
Chris 2022-02-22 19:17:08 +10:30 committed by GitHub
commit a3cde701f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 227 additions and 303 deletions

2
.github/FUNDING.yml vendored
View file

@ -1,2 +1,2 @@
# These are supported funding model platforms
github: [DeathCradle, hakusaro, Stealownz, QuiCM]
github: [SignatureBeef, hakusaro, Stealownz, QuiCM]

View file

@ -11,12 +11,19 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
* Do not insert tabs into this file, under any circumstances, ever.
* Do not forget to sign every line you change with your name. (@hakusaro)
* 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
* Added hook `GetDataHandlers.OnReleaseNpc` to handling ReleaseNPC packet and a bouncer to stops unregistered and logged out players on SSC servers from releasing critters NPC. The bouncer has additional filter to stops players who tried to release different critter using crafted packet, e.g. using bunny item to release golden bunny. (@tru321)
* Added filter in `GetDataHandlers.HandleCatchNpc` that stops unregistered and logged out players on SSC servers to catch critters. (@tru321)
## Upcoming changes
* Improved the `/grow` command to reduce code duplication, use `TileID` constants for less ambiguous types. (@drunderscore)
## TShock 4.5.13
* Added hook `GetDataHandlers.OnReleaseNpc` to handling ReleaseNPC packet and a bouncer to stops unregistered and logged out players on SSC servers from releasing critters NPC. The bouncer has additional filter to stops players who tried to release different critter using crafted packet, e.g. using bunny item to release golden bunny. (@tru321)
* Added filter in `GetDataHandlers.HandleCatchNpc` that stops unregistered and logged out players on SSC servers to catch critters. (@tru321)
* Fixed rejection check inside of `HandlePaintTile` to account for the Paint Sprayer (or Architect Gizmo Pack) being inside your inventory, rather than on an accessory slot. (@drunderscore)
* Added the lanterns night event to the `/worldevent` command. (@0x3fcf1bbd)
* Marked `TSPlayer.SendTileSquare` as deprecated, and created `TSPlayer.SendTileSquareCentered` that sends a tile square centered around the passed coordinates. (@0x3fcf1bbd)
* Added coordinates clamping to `TSPlayer.SendTileRect` so as to avoid OOBs. (@0x3fcf1bbd)
* Removed extraneous space causing build commands in README to fail. (@EtherTyper)
## TShock 4.5.12
* Fixed the ability to spawn Zenith projectile with non-original items. (@AgaSpace)

View file

@ -207,7 +207,7 @@ You need to re-run the patcher any time `OTAPI` updates. You need to rebuild `Te
$ cd ./TerrariaServerAPI/TShock.Modifications.Bootstrapper/bin/$BUILD_MODE/
$ mono TShock.Modifications.Bootstrapper.exe -in=OTAPI.dll \
-mod=../../../TShock.Modifications.**/bin/$BUILD_MODE/TShock.Modifications.*.dll \
-mod=../../../TShock.Modifications.**/bin/$BUILD_MODE/TShock.Modifications.*.dll \
-o=Output/OTAPI.dll
1. Verify that non-zero modifications ran successfully. Then, build the Terraria Server API executable.

View file

@ -406,7 +406,7 @@ namespace TShockAPI
((action == EditAction.PlaceWall || action == EditAction.ReplaceWall) && editData >= Main.maxWallTypes))
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from editData out of bounds {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -421,7 +421,7 @@ namespace TShockAPI
if (args.Player.Dead && TShock.Config.Settings.PreventDeadModification)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (pdm) {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -435,7 +435,7 @@ namespace TShockAPI
if (TShock.TileBans.TileIsBanned(editData, args.Player))
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (tb) {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Player.SendErrorMessage("You do not have permission to place this tile.");
args.Handled = true;
return;
@ -458,7 +458,7 @@ namespace TShockAPI
{
TShock.Log.ConsoleError("Bouncer / OnTileEdit rejected from (placestyle) {0} {1} {2} placeStyle: {3} expectedStyle: {4}",
args.Player.Name, action, editData, requestedPlaceStyle, actualItemPlaceStyle);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -469,7 +469,7 @@ namespace TShockAPI
{
TShock.Log.ConsoleError("Bouncer / OnTileEdit rejected from (placestyle) {0} {1} {2} placeStyle: {3} expectedStyle: {4}",
args.Player.Name, action, editData, requestedPlaceStyle, correctedPlaceStyle);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -484,7 +484,7 @@ namespace TShockAPI
if (Main.tileAxe[tile.type] && ((args.Player.TPlayer.mount.Type != 8 && selectedItem.axe == 0) && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0))
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (axe) {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -492,7 +492,7 @@ namespace TShockAPI
else if (Main.tileHammer[tile.type] && ((args.Player.TPlayer.mount.Type != 8 && selectedItem.hammer == 0) && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0))
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (hammer) {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -503,7 +503,7 @@ namespace TShockAPI
&& !Main.tileAxe[tile.type] && !Main.tileHammer[tile.type] && tile.wall == 0 && args.Player.TPlayer.mount.Type != 8 && selectedItem.pick == 0 && selectedItem.type != ItemID.GravediggerShovel && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (pick) {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -514,7 +514,7 @@ namespace TShockAPI
if (selectedItem.hammer == 0 && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0 && selectedItem.createWall == 0)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (hammer2) {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -533,7 +533,7 @@ namespace TShockAPI
!p.Killed && Math.Abs((int)(Main.projectile[p.Index].position.X / 16f) - tileX) <= Math.Abs(Main.projectile[p.Index].velocity.X)))
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (inconceivable rope coil) {0} {1} {2} selectedItem:{3} itemCreateTile:{4}", args.Player.Name, action, editData, selectedItem.netID, selectedItem.createTile);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -544,7 +544,7 @@ namespace TShockAPI
requestedPlaceStyle > GetMaxPlaceStyle(editData))
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (ms1) {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -553,7 +553,7 @@ namespace TShockAPI
if (selectedItem.netID == ItemID.IceRod && editData != TileID.MagicalIceBlock)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from using ice rod but not placing ice block {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
}
/// If they aren't selecting the item which creates the tile, they're hacking.
@ -563,7 +563,7 @@ namespace TShockAPI
if (selectedItem.netID != ItemID.IceRod && selectedItem.netID != ItemID.DirtBomb && selectedItem.netID != ItemID.StickyBomb)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from tile placement not matching selected item createTile {0} {1} {2} selectedItemID:{3} createTile:{4}", args.Player.Name, action, editData, selectedItem.netID, selectedItem.createTile);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -572,7 +572,7 @@ namespace TShockAPI
if ((action == EditAction.PlaceWall || action == EditAction.ReplaceWall) && editData != selectedItem.createWall)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from wall placement not matching selected item createWall {0} {1} {2} selectedItemID:{3} createWall:{4}", args.Player.Name, action, editData, selectedItem.netID, selectedItem.createWall);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -582,7 +582,7 @@ namespace TShockAPI
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from (chestcap) {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendErrorMessage("The world's chest limit has been reached - unable to place more.");
args.Player.SendTileSquare(tileX, tileY, 3);
args.Player.SendTileSquareCentered(tileX, tileY, 3);
args.Handled = true;
return;
}
@ -600,7 +600,7 @@ namespace TShockAPI
&& selectedItem.type != ItemID.WireKite)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from place wire from {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -614,7 +614,7 @@ namespace TShockAPI
&& selectedItem.type != ItemID.MulticolorWrench)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from wire cutter from {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -625,7 +625,7 @@ namespace TShockAPI
if (selectedItem.type != ItemID.Actuator && !args.Player.TPlayer.autoActuator)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from actuator/presserator from {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -635,7 +635,7 @@ namespace TShockAPI
if (action == EditAction.KillWall || action == EditAction.ReplaceWall)
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from sts allow cut from {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -646,7 +646,7 @@ namespace TShockAPI
if (args.Player.IsBeingDisabled())
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from disable from {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -685,7 +685,7 @@ namespace TShockAPI
}
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from explosives/fuses from {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -699,7 +699,7 @@ namespace TShockAPI
else
{
args.Player.Disable("Reached TileKill threshold.", DisableFlags.WriteToLogAndConsole);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
}
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from tile kill threshold from {0}, (value: {1})", args.Player.Name, args.Player.TileKillThreshold);
@ -717,7 +717,7 @@ namespace TShockAPI
else
{
args.Player.Disable("Reached TilePlace threshold.", DisableFlags.WriteToLogAndConsole);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
}
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from tile place threshold from {0}, (value: {1})", args.Player.Name, args.Player.TilePlaceThreshold);
@ -729,7 +729,7 @@ namespace TShockAPI
if (args.Player.IsBouncerThrottled())
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from throttled from {0} {1} {2}", args.Player.Name, action, editData);
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -763,7 +763,7 @@ namespace TShockAPI
{
TShock.Log.ConsoleDebug("Bouncer / OnTileEdit rejected from weird confusing flow control from {0}", args.Player.Name);
TShock.Log.ConsoleDebug("If you're seeing this message and you know what that player did, please report it to TShock for further investigation.");
args.Player.SendTileSquare(tileX, tileY, 4);
args.Player.SendTileSquareCentered(tileX, tileY, 4);
args.Handled = true;
return;
}
@ -1318,7 +1318,7 @@ namespace TShockAPI
if (args.Player.IsBeingDisabled())
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceChest rejected from disabled from {0}", args.Player.Name);
args.Player.SendTileSquare(tileX, tileY, 3);
args.Player.SendTileSquareCentered(tileX, tileY, 3);
args.Handled = true;
return;
}
@ -1326,7 +1326,7 @@ namespace TShockAPI
if (args.Player.SelectedItem.placeStyle != style)
{
TShock.Log.ConsoleError(string.Format("Bouncer / OnPlaceChest / rejected from invalid place style from {0}", args.Player.Name));
args.Player.SendTileSquare(tileX, tileY, 3);
args.Player.SendTileSquareCentered(tileX, tileY, 3);
args.Handled = true;
return;
}
@ -1338,7 +1338,7 @@ namespace TShockAPI
&& (!TShock.Utils.HasWorldReachedMaxChests() && Main.tile[tileX, tileY].type != TileID.Dirt)) //Chest
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceChest rejected from weird check from {0}", args.Player.Name);
args.Player.SendTileSquare(tileX, tileY, 3);
args.Player.SendTileSquareCentered(tileX, tileY, 3);
args.Handled = true;
return;
}
@ -1350,7 +1350,7 @@ namespace TShockAPI
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceChest rejected from weird placement check from {0}", args.Player.Name);
//Prevent a dresser from being placed on a teleporter, as this can cause client and server crashes.
args.Player.SendTileSquare(tileX, tileY, 3);
args.Player.SendTileSquareCentered(tileX, tileY, 3);
args.Handled = true;
return;
}
@ -1359,7 +1359,7 @@ namespace TShockAPI
if (!args.Player.HasBuildPermission(tileX, tileY))
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceChest rejected from invalid permission from {0}", args.Player.Name);
args.Player.SendTileSquare(tileX, tileY, 3);
args.Player.SendTileSquareCentered(tileX, tileY, 3);
args.Handled = true;
return;
}
@ -1367,7 +1367,7 @@ namespace TShockAPI
if (!args.Player.IsInRange(tileX, tileY))
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceChest rejected from range check from {0}", args.Player.Name);
args.Player.SendTileSquare(tileX, tileY, 3);
args.Player.SendTileSquareCentered(tileX, tileY, 3);
args.Handled = true;
return;
}
@ -1452,7 +1452,7 @@ namespace TShockAPI
if (args.Player.IsBeingDisabled())
{
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected disabled from {0}", args.Player.Name);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -1466,7 +1466,7 @@ namespace TShockAPI
else
{
args.Player.Disable("Reached TileLiquid threshold.", DisableFlags.WriteToLogAndConsole);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
}
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected from liquid threshold from {0} {1}/{2}", args.Player.Name, args.Player.TileLiquidThreshold, TShock.Config.Settings.TileLiquidThreshold);
@ -1539,7 +1539,7 @@ namespace TShockAPI
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected bucket check 1 from {0}", args.Player.Name);
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Spreading lava without holding a lava bucket", DisableFlags.WriteToLogAndConsole);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -1549,7 +1549,7 @@ namespace TShockAPI
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected lava bucket from {0}", args.Player.Name);
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Using banned lava bucket without permissions", DisableFlags.WriteToLogAndConsole);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -1559,7 +1559,7 @@ namespace TShockAPI
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected bucket check 2 from {0}", args.Player.Name);
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Spreading water without holding a water bucket", DisableFlags.WriteToLogAndConsole);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -1569,7 +1569,7 @@ namespace TShockAPI
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected bucket check 3 from {0}", args.Player.Name);
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Using banned water bucket without permissions", DisableFlags.WriteToLogAndConsole);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -1579,7 +1579,7 @@ namespace TShockAPI
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected bucket check 4 from {0}", args.Player.Name);
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Spreading honey without holding a honey bucket", DisableFlags.WriteToLogAndConsole);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -1589,7 +1589,7 @@ namespace TShockAPI
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected bucket check 5 from {0}", args.Player.Name);
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Using banned honey bucket without permissions", DisableFlags.WriteToLogAndConsole);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -1598,7 +1598,7 @@ namespace TShockAPI
if (!args.Player.HasBuildPermission(tileX, tileY))
{
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected build permission from {0}", args.Player.Name);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -1606,7 +1606,7 @@ namespace TShockAPI
if (!wasThereABombNearby && !args.Player.IsInRange(tileX, tileY, 16))
{
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected range checks from {0}", args.Player.Name);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -1614,7 +1614,7 @@ namespace TShockAPI
if (args.Player.IsBouncerThrottled())
{
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected throttle from {0}", args.Player.Name);
args.Player.SendTileSquare(tileX, tileY, 1);
args.Player.SendTileSquareCentered(tileX, tileY, 1);
args.Handled = true;
return;
}
@ -1926,7 +1926,7 @@ namespace TShockAPI
if (type == TileID.FakeContainers && (style == 52 || style == 53))
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected fake containers from {0}", args.Player.Name);
args.Player.SendTileSquare(x, y, 4);
args.Player.SendTileSquareCentered(x, y, 4);
args.Handled = true;
return;
}
@ -1935,7 +1935,7 @@ namespace TShockAPI
if (TShock.TileBans.TileIsBanned(type, args.Player))
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected banned tiles from {0}", args.Player.Name);
args.Player.SendTileSquare(x, y, 1);
args.Player.SendTileSquareCentered(x, y, 1);
args.Player.SendErrorMessage("You do not have permission to place this tile.");
args.Handled = true;
return;
@ -1944,7 +1944,7 @@ namespace TShockAPI
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);
args.Player.SendTileSquare(x, y, 4);
args.Player.SendTileSquareCentered(x, y, 4);
args.Handled = true;
return;
}
@ -1952,7 +1952,7 @@ namespace TShockAPI
if (args.Player.IsBeingDisabled())
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected disabled from {0}", args.Player.Name);
args.Player.SendTileSquare(x, y, 4);
args.Player.SendTileSquareCentered(x, y, 4);
args.Handled = true;
return;
}
@ -1963,7 +1963,7 @@ namespace TShockAPI
if (type != args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].createTile)
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected awkward tile creation/selection from {0}", args.Player.Name);
args.Player.SendTileSquare(x, y, 4);
args.Player.SendTileSquareCentered(x, y, 4);
args.Handled = true;
return;
}
@ -1987,7 +1987,7 @@ namespace TShockAPI
&& !args.Player.HasBuildPermission(i, j))
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected mad loop from {0}", args.Player.Name);
args.Player.SendTileSquare(i, j, 4);
args.Player.SendTileSquareCentered(i, j, 4);
args.Handled = true;
return;
}
@ -2003,7 +2003,7 @@ namespace TShockAPI
&& !args.Player.IsInRange(x, y))
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected range checks from {0}", args.Player.Name);
args.Player.SendTileSquare(x, y, 4);
args.Player.SendTileSquareCentered(x, y, 4);
args.Handled = true;
return;
}
@ -2012,7 +2012,7 @@ namespace TShockAPI
{
TShock.Log.ConsoleDebug("Bouncer / OnPlaceObject rejected tile place threshold from {0} {1}/{2}", args.Player.Name, args.Player.TilePlaceThreshold, TShock.Config.Settings.TilePlaceThreshold);
args.Player.Disable("Reached TilePlace threshold.", DisableFlags.WriteToLogAndConsole);
args.Player.SendTileSquare(x, y, 4);
args.Player.SendTileSquareCentered(x, y, 4);
args.Handled = true;
return;
}
@ -2410,7 +2410,7 @@ namespace TShockAPI
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);
args.Player.SendTileSquare(args.TileX, args.TileY, 1);
args.Player.SendTileSquareCentered(args.TileX, args.TileY, 1);
args.Handled = true;
return;
}
@ -2420,7 +2420,7 @@ namespace TShockAPI
Item item = new Item();
item.netDefaults(args.ItemID);
args.Player.GiveItemCheck(args.ItemID, item.Name, args.Stack, args.Prefix);
args.Player.SendTileSquare(args.TileX, args.TileY, 1);
args.Player.SendTileSquareCentered(args.TileX, args.TileY, 1);
args.Handled = true;
return;
}
@ -2431,7 +2431,7 @@ namespace TShockAPI
Item item = new Item();
item.netDefaults(args.ItemID);
args.Player.GiveItemCheck(args.ItemID, item.Name, args.Stack, args.Prefix);
args.Player.SendTileSquare(args.TileX, args.TileY, 1);
args.Player.SendTileSquareCentered(args.TileX, args.TileY, 1);
args.Handled = true;
return;
}
@ -2439,7 +2439,7 @@ namespace TShockAPI
if (!args.Player.IsInRange(args.TileX, args.TileY, range: 13)) // To my knowledge, max legit tile reach with accessories.
{
TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected range checks from {0}", args.Player.Name);
args.Player.SendTileSquare(args.TileX, args.TileY, 1);
args.Player.SendTileSquareCentered(args.TileX, args.TileY, 1);
args.Handled = true;
return;
}

View file

@ -2066,7 +2066,8 @@ namespace TShockAPI
"eclipse",
"invasion",
"sandstorm",
"rain"
"rain",
"lanternsnight"
};
static readonly List<string> _validInvasions = new List<string>()
{
@ -2165,6 +2166,16 @@ namespace TShockAPI
Rain(args);
return;
case "lanternsnight":
case "lanterns":
if (!args.Player.HasPermission(Permissions.managelanternsnightevent))
{
FailedPermissionCheck();
return;
}
LanternsNight(args);
return;
default:
args.Player.SendErrorMessage("Invalid event type! Valid event types: {0}", String.Join(", ", _validEvents));
return;
@ -2380,6 +2391,20 @@ namespace TShockAPI
}
}
private static void LanternsNight(CommandArgs args)
{
LanternNight.ToggleManualLanterns();
string msg = $" st{(LanternNight.LanternsUp ? "art" : "opp")}ed a lantern night.";
if (args.Silent)
{
args.Player.SendInfoMessage("You" + msg);
}
else
{
TSPlayer.All.SendInfoMessage(args.Player.Name + msg);
}
}
private static void ClearAnglerQuests(CommandArgs args)
{
if (args.Parameters.Count > 0)
@ -4880,7 +4905,7 @@ namespace TShockAPI
try
{
args.Player.SendTileSquare(boundaryPoint.X, boundaryPoint.Y, 1);
args.Player.SendTileSquareCentered(boundaryPoint.X, boundaryPoint.Y, 1);
}
finally
{
@ -4894,7 +4919,7 @@ namespace TShockAPI
{
foreach (Point boundaryPoint in Utils.Instance.EnumerateRegionBoundaries(regionArea))
if ((boundaryPoint.X + boundaryPoint.Y & 1) == 0)
args.Player.SendTileSquare(boundaryPoint.X, boundaryPoint.Y, 1);
args.Player.SendTileSquareCentered(boundaryPoint.X, boundaryPoint.Y, 1);
Debug.Assert(boundaryHideTimer != null);
boundaryHideTimer.Dispose();
@ -5651,7 +5676,7 @@ namespace TShockAPI
private static void SyncLocalArea(CommandArgs args)
{
args.Player.SendTileSquare((int) args.Player.TileX, (int) args.Player.TileY, 32);
args.Player.SendTileSquareCentered(args.Player.TileX, args.Player.TileY, 32);
args.Player.SendWarningMessage("Sync'd!");
return;
}
@ -6307,7 +6332,7 @@ namespace TShockAPI
public static void Grow(CommandArgs args)
{
bool growevilAmb = args.Player.HasPermission(Permissions.growevil);
bool canGrowEvil = args.Player.HasPermission(Permissions.growevil);
string subcmd = args.Parameters.Count == 0 ? "help" : args.Parameters[0].ToLower();
var name = "Fail";
@ -6349,284 +6374,163 @@ namespace TShockAPI
}
break;
case "basic":
for (int i = x - 2; i < x + 3; i++)
bool rejectCannotGrowEvil()
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 2;
Main.tile[i, y].wall = 0;
if(!canGrowEvil)
{
args.Player.SendErrorMessage("You do not have permission to grow this tree type");
return false;
}
return true;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.GrowTree(x, y);
name = "Basic Tree";
bool prepareAreaForGrow(ushort groundType = TileID.Grass, bool evil = false)
{
if(evil && !rejectCannotGrowEvil())
return false;
for (var i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = groundType;
Main.tile[i, y].wall = WallID.None;
}
Main.tile[x, y - 1].wall = WallID.None;
return true;
}
bool growTree(ushort groundType, string fancyName, bool evil = false)
{
if(!prepareAreaForGrow(groundType, evil))
return false;
WorldGen.GrowTree(x, y);
name = fancyName;
return true;
}
bool growTreeByType(ushort groundType, string fancyName, ushort typeToPrepare = 2, bool evil = false)
{
if(!prepareAreaForGrow(typeToPrepare, evil))
return false;
WorldGen.TryGrowingTreeByType(groundType, x, y);
name = fancyName;
return true;
}
bool growPalmTree(ushort sandType, ushort supportingType, string properName, bool evil = false)
{
if(evil && !rejectCannotGrowEvil())
return false;
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = sandType;
Main.tile[i, y].wall = WallID.None;
}
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y + 1].active(true);
Main.tile[i, y + 1].type = supportingType;
Main.tile[i, y + 1].wall = WallID.None;
}
Main.tile[x, y - 1].wall = WallID.None;
WorldGen.GrowPalmTree(x, y);
name = properName;
return true;
}
case "basic":
growTree(TileID.Grass, "Basic Tree");
break;
case "boreal":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 147;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.GrowTree(x, y);
name = "Boreal Tree";
growTree(TileID.SnowBlock, "Boreal Tree");
break;
case "mahogany":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 60;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.GrowTree(x, y);
name = "Rich Mahogany";
growTree(TileID.JungleGrass, "Rich Mahogany");
break;
case "sakura":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 2;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.TryGrowingTreeByType(596, x, y);
name = "Sakura Tree";
growTreeByType(TileID.VanityTreeSakura, "Sakura Tree");
break;
case "willow":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 2;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.TryGrowingTreeByType(616, x, y);
name = "Willow Tree";
growTreeByType(TileID.VanityTreeYellowWillow, "Willow Tree");
break;
case "shadewood":
if (growevilAmb)
{
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 199;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.GrowTree(x, y);
name = "Shadewood tree";
}
else args.Player.SendErrorMessage("You do not have permission to grow this tree type");
if(!growTree(TileID.CrimsonGrass, "Shadewood Tree", true))
return;
break;
case "ebonwood":
if (growevilAmb)
{
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 23;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.GrowTree(x, y);
name = "Ebonwood Tree";
}
else args.Player.SendErrorMessage("You do not have permission to grow this tree type");
if(!growTree(TileID.CorruptGrass, "Ebonwood Tree", true))
return;
break;
case "pearlwood":
if (growevilAmb)
{
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 109;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.GrowTree(x, y);
name = "Pearlwood Tree";
}
else args.Player.SendErrorMessage("You do not have permission to grow this tree type");
if(!growTree(TileID.HallowedGrass, "Pearlwood Tree", true))
return;
break;
case "palm":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 53;
Main.tile[i, y].wall = 0;
}
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y + 1].active(true);
Main.tile[i, y + 1].type = 397;
Main.tile[i, y + 1].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.GrowPalmTree(x, y);
name = "Desert Palm";
growPalmTree(TileID.Sand, TileID.HardenedSand, "Desert Palm");
break;
case "hallowpalm":
if (growevilAmb)
{
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 116;
Main.tile[i, y].wall = 0;
}
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y + 1].active(true);
Main.tile[i, y + 1].type = 402;
Main.tile[i, y + 1].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.GrowPalmTree(x, y);
name = "Hallow Palm";
}
else args.Player.SendErrorMessage("You do not have permission to grow this tree type");
if(!growPalmTree(TileID.Pearlsand, TileID.HallowHardenedSand, "Hallow Palm", true))
return;
break;
case "crimsonpalm":
if (growevilAmb)
{
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 234;
Main.tile[i, y].wall = 0;
}
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y + 1].active(true);
Main.tile[i, y + 1].type = 399;
Main.tile[i, y + 1].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.GrowPalmTree(x, y);
name = "Crimson Palm";
}
else args.Player.SendErrorMessage("You do not have permission to grow this tree type");
if(!growPalmTree(TileID.Crimsand, TileID.CrimsonHardenedSand, "Crimson Palm", true))
return;
break;
case "corruptpalm":
if (growevilAmb)
{
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 112;
Main.tile[i, y].wall = 0;
}
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y + 1].active(true);
Main.tile[i, y + 1].type = 398;
Main.tile[i, y + 1].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.GrowPalmTree(x, y);
name = "Corruption Palm";
}
else args.Player.SendErrorMessage("You do not have permission to grow this tree type");
if(!growPalmTree(TileID.Ebonsand, TileID.CorruptHardenedSand, "Corruption Palm", true))
return;
break;
case "topaz":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 1;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.TryGrowingTreeByType(583, x, y);
name = "Topaz Gemtree";
growTreeByType(TileID.TreeTopaz, "Topaz Gemtree", 1);
break;
case "amethyst":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 1;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.TryGrowingTreeByType(584, x, y);
name = "Amethyst Gemtree";
growTreeByType(TileID.TreeAmethyst, "Amethyst Gemtree", 1);
break;
case "sapphire":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 1;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.TryGrowingTreeByType(585, x, y);
name = "Sapphire Gemtree";
growTreeByType(TileID.TreeSapphire, "Sapphire Gemtree", 1);
break;
case "emerald":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 1;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.TryGrowingTreeByType(586, x, y);
name = "Emerald Gemtree";
growTreeByType(TileID.TreeEmerald, "Emerald Gemtree", 1);
break;
case "ruby":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 1;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.TryGrowingTreeByType(587, x, y);
name = "Ruby Gemtree";
growTreeByType(TileID.TreeRuby, "Ruby Gemtree", 1);
break;
case "diamond":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 1;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.TryGrowingTreeByType(588, x, y);
name = "Diamond Gemtree";
growTreeByType(TileID.TreeDiamond, "Diamond Gemtree", 1);
break;
case "amber":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 1;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
WorldGen.TryGrowingTreeByType(589, x, y);
name = "Amber Gemtree";
growTreeByType(TileID.TreeAmber, "Amber Gemtree", 1);
break;
case "cactus":
Main.tile[x, y].type = 53;
Main.tile[x, y].type = TileID.Sand;
WorldGen.GrowCactus(x, y);
name = "Cactus";
break;
@ -6634,19 +6538,13 @@ namespace TShockAPI
case "herb":
Main.tile[x, y].active(true);
Main.tile[x, y].frameX = 36;
Main.tile[x, y].type = 83;
Main.tile[x, y].type = TileID.MatureHerbs;
WorldGen.GrowAlch(x, y);
name = "Herb";
break;
case "mushroom":
for (int i = x - 2; i < x + 3; i++)
{
Main.tile[i, y].active(true);
Main.tile[i, y].type = 70;
Main.tile[i, y].wall = 0;
}
Main.tile[x, y - 1].wall = 0;
prepareAreaForGrow(TileID.MushroomGrass);
WorldGen.GrowShroom(x, y);
name = "Glowing Mushroom Tree";
break;
@ -6657,7 +6555,7 @@ namespace TShockAPI
}
if (args.Parameters.Count == 1)
{
args.Player.SendTileSquare(x - 2, y - 20, 25);
args.Player.SendTileSquareCentered(x - 2, y - 20, 25);
args.Player.SendSuccessMessage("Tried to grow a " + name + ".");
}
}

View file

@ -3895,7 +3895,7 @@ namespace TShockAPI
if (TShock.TileBans.TileIsBanned((short)TileID.LogicSensor, args.Player))
{
args.Player.SendTileSquare(x, y, 1);
args.Player.SendTileSquareCentered(x, y, 1);
args.Player.SendErrorMessage("You do not have permission to place Logic Sensors.");
return true;
}

View file

@ -199,7 +199,7 @@ namespace TShockAPI
{
if (args.Player.TPlayer.autoActuator && DataModel.ItemIsBanned("Actuator", args.Player))
{
args.Player.SendTileSquare(args.X, args.Y, 1);
args.Player.SendTileSquareCentered(args.X, args.Y, 1);
args.Player.SendErrorMessage("You do not have permission to place actuators.");
args.Handled = true;
return;
@ -207,7 +207,7 @@ namespace TShockAPI
if (DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(args.Player.SelectedItem.netID), args.Player))
{
args.Player.SendTileSquare(args.X, args.Y, 4);
args.Player.SendTileSquareCentered(args.X, args.Y, 4);
args.Handled = true;
return;
}

View file

@ -307,6 +307,9 @@ namespace TShockAPI
[Description("User can use the 'rain' subcommand of the 'worldevent' command")]
public static readonly string managerainevent = "tshock.world.events.rain";
[Description("User can use the 'lanternsnight' subcommand of the 'worldevent' command")]
public static readonly string managelanternsnightevent = "tshock.world.events.lanternsnight";
[Description("User can change expert state.")]
public static readonly string toggleexpert = "tshock.world.toggleexpert";

View file

@ -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.12")]
[assembly: AssemblyFileVersion("4.5.12")]
[assembly: AssemblyVersion("4.5.13")]
[assembly: AssemblyFileVersion("4.5.13")]

View file

@ -171,7 +171,7 @@ namespace TShockAPI
}
// Revert all tile changes and handle the event
player.SendTileSquare(e.X, e.Y, 4);
player.SendTileSquareCentered(e.X, e.Y, 4);
e.Handled = true;
}
@ -190,7 +190,7 @@ namespace TShockAPI
player.AwaitingTempPoint = 0;
// Revert all tile changes and handle the event
player.SendTileSquare(e.X, e.Y, 4);
player.SendTileSquareCentered(e.X, e.Y, 4);
e.Handled = true;
}

View file

@ -1227,7 +1227,7 @@ namespace TShockAPI
y = 992;
}
SendTileSquare((int)(x / 16), (int)(y / 16), 15);
SendTileSquareCentered((int)(x / 16), (int)(y / 16), 15);
TPlayer.Teleport(new Vector2(x, y), style);
NetMessage.SendData((int)PacketTypes.Teleport, -1, -1, NetworkText.Empty, 0, TPlayer.whoAmI, x, y, style);
return true;
@ -1309,11 +1309,27 @@ namespace TShockAPI
/// <param name="y">The y coordinate to send.</param>
/// <param name="size">The size square set of tiles to send.</param>
/// <returns>true if the tile square was sent successfully, else false</returns>
[Obsolete("This method may not send tiles the way you would expect it to. The (x,y) coordinates are the top left corner of the tile square, switch to " + nameof(SendTileSquareCentered) + " if you wish for the coordindates to be the center of the square.")]
public virtual bool SendTileSquare(int x, int y, int size = 10)
{
return SendTileRect((short)x, (short)y, (byte)size, (byte)size);
}
/// <summary>
/// Sends a tile square at a center location with a given size.
/// Typically used to revert changes by Bouncer through sending the
/// "old" version of modified data back to a client.
/// Prevents desync issues.
/// </summary>
/// <param name="x">The x coordinates of the center of the square.</param>
/// <param name="y">The y coordinates of the center of the square.</param>
/// <param name="size">The size square set of tiles to send.</param>
/// <returns>true if the tile square was sent successfully, else false</returns>
public virtual bool SendTileSquareCentered(int x, int y, byte size = 10)
{
return SendTileRect((short)(x - (size / 2)), (short)(y - (size / 2)), size, size);
}
/// <summary>
/// Sends a rectangle of tiles at a location with the given length and width.
/// </summary>
@ -1348,7 +1364,7 @@ namespace TShockAPI
public bool GiveItemCheck(int type, string name, int stack, int prefix = 0)
{
if ((TShock.ItemBans.DataModel.ItemIsBanned(name) && TShock.Config.Settings.PreventBannedItemSpawn) &&
(TShock.ItemBans.DataModel.ItemIsBanned(name, this) || !TShock.Config.Settings.AllowAllowedGroupsToSpawnBannedItems))
(TShock.ItemBans.DataModel.ItemIsBanned(name, this) || !TShock.Config.Settings.AllowAllowedGroupsToSpawnBannedItems))
return false;
GiveItem(type, stack, prefix);

View file

@ -190,7 +190,7 @@ namespace TShockAPI
// Send all players updated tile squares
foreach (Vector2 coords in tiles.Keys)
{
All.SendTileSquare((int)coords.X, (int)coords.Y, 3);
All.SendTileSquareCentered((int)coords.X, (int)coords.Y, 3);
}
}

View file

@ -58,7 +58,7 @@ namespace TShockAPI
/// <summary>VersionNum - The version number the TerrariaAPI will return back to the API. We just use the Assembly info.</summary>
public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version;
/// <summary>VersionCodename - The version codename is displayed when the server starts. Inspired by software codenames conventions.</summary>
public static readonly string VersionCodename = "Herrscher of Logic";
public static readonly string VersionCodename = "Let us know if you're using this on raspberry pi or we might drop support for it";
/// <summary>SavePath - This is the path TShock saves its data in. This path is relative to the TerrariaServer.exe (not in ServerPlugins).</summary>
public static string SavePath = "tshock";