Merge branch 'general-devel' into otapi3
This commit is contained in:
commit
cec53c780f
7 changed files with 231 additions and 17 deletions
|
|
@ -44,6 +44,20 @@ namespace TShockAPI
|
|||
internal Handlers.LandGolfBallInCupHandler LandGolfBallInCupHandler { get; private set; }
|
||||
internal Handlers.SyncTilePickingHandler SyncTilePickingHandler { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Represents a place style corrector.
|
||||
/// </summary>
|
||||
/// <param name="player">The player placing the tile.</param>
|
||||
/// <param name="requestedPlaceStyle">The requested place style to be placed.</param>
|
||||
/// <param name="actualItemPlaceStyle">The actual place style that should be placed, based of the player's held item.</param>
|
||||
/// <returns>The correct place style in the current context.</returns>
|
||||
internal delegate int PlaceStyleCorrector(Player player, int requestedPlaceStyle, int actualItemPlaceStyle);
|
||||
|
||||
/// <summary>
|
||||
/// Represents a dictionary of <see cref="PlaceStyleCorrector"/>s, the key is the tile ID and the value is the corrector.
|
||||
/// </summary>
|
||||
internal Dictionary<int, PlaceStyleCorrector> PlaceStyleCorrectors = new Dictionary<int, PlaceStyleCorrector>();
|
||||
|
||||
/// <summary>Constructor call initializes Bouncer and related functionality.</summary>
|
||||
/// <returns>A new Bouncer.</returns>
|
||||
internal Bouncer()
|
||||
|
|
@ -100,6 +114,122 @@ namespace TShockAPI
|
|||
GetDataHandlers.KillMe += OnKillMe;
|
||||
GetDataHandlers.FishOutNPC += OnFishOutNPC;
|
||||
GetDataHandlers.FoodPlatterTryPlacing += OnFoodPlatterTryPlacing;
|
||||
|
||||
|
||||
// The following section is based off Player.PlaceThing_Tiles_PlaceIt and Player.PlaceThing_Tiles_PlaceIt_GetLegacyTileStyle.
|
||||
// Multi-block tiles are intentionally ignored because they don't pass through OnTileEdit.
|
||||
PlaceStyleCorrectors.Add(TileID.Torches,
|
||||
(player, requestedPlaceStyle, actualItemPlaceStyle) =>
|
||||
{
|
||||
// If the client is attempting to place a default torch, we need to check that the torch they are attempting to place is valid.
|
||||
// The place styles may mismatch if the player is placing a biome torch.
|
||||
// Biome torches can only be placed if the player has unlocked them (Torch God's Favor)
|
||||
// Therefore, the following conditions need to be true:
|
||||
// - The client's selected item will create a default torch(this should be true if this handler is running)
|
||||
// - The client's selected item's place style will be that of a default torch
|
||||
// - The client has unlocked biome torches
|
||||
if (actualItemPlaceStyle == TorchID.Torch && player.unlockedBiomeTorches)
|
||||
{
|
||||
// The server isn't notified when the player turns on biome torches.
|
||||
// So on the client it can be on, while on the server it's off.
|
||||
// BiomeTorchPlaceStyle returns placeStyle as-is if biome torches is off.
|
||||
// Because of the uncertainty, we:
|
||||
// 1. Ensure that UsingBiomeTorches is on, so we can get the correct
|
||||
// value from BiomeTorchPlaceStyle.
|
||||
// 2. Check if the torch is either 0 or the biome torch since we aren't
|
||||
// sure if the player has biome torches on
|
||||
var usingBiomeTorches = player.UsingBiomeTorches;
|
||||
player.UsingBiomeTorches = true;
|
||||
// BiomeTorchPlaceStyle returns the place style of the player's current biome's biome torch
|
||||
var biomeTorchPlaceStyle = player.BiomeTorchPlaceStyle(actualItemPlaceStyle);
|
||||
// Reset UsingBiomeTorches value
|
||||
player.UsingBiomeTorches = usingBiomeTorches;
|
||||
|
||||
return biomeTorchPlaceStyle;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the player isn't holding the default torch, then biome torches don't apply and return item place style.
|
||||
// Or, they are holding the default torch but haven't unlocked biome torches yet, so return item place style.
|
||||
return actualItemPlaceStyle;
|
||||
}
|
||||
});
|
||||
PlaceStyleCorrectors.Add(TileID.Presents,
|
||||
(player, requestedPlaceStyle, actualItemPlaceStyle) =>
|
||||
{
|
||||
// RNG only generates placeStyles less than 7, so permit only <7
|
||||
// Note: there's an 8th present(blue, golden stripes) that's unplaceable.
|
||||
// https://terraria.fandom.com/wiki/Presents, last present of the 8 displayed
|
||||
if (requestedPlaceStyle < 7)
|
||||
{
|
||||
return requestedPlaceStyle;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return 0 for now, but ideally 0-7 should be returned.
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
PlaceStyleCorrectors.Add(TileID.Explosives,
|
||||
(player, requestedPlaceStyle, actualItemPlaceStyle) =>
|
||||
{
|
||||
// RNG only generates placeStyles less than 2, so permit only <2
|
||||
if (requestedPlaceStyle < 2)
|
||||
{
|
||||
return requestedPlaceStyle;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return 0 for now, but ideally 0-1 should be returned.
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
PlaceStyleCorrectors.Add(TileID.Crystals,
|
||||
(player, requestedPlaceStyle, actualItemPlaceStyle) =>
|
||||
{
|
||||
// RNG only generates placeStyles less than 18, so permit only <18.
|
||||
// Note: Gelatin Crystals(Queen Slime summon) share the same ID as Crystal Shards.
|
||||
// <18 includes all shards except Gelatin Crystals.
|
||||
if (requestedPlaceStyle < 18)
|
||||
{
|
||||
return requestedPlaceStyle;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return 0 for now, but ideally 0-17 should be returned.
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
PlaceStyleCorrectors.Add(TileID.MinecartTrack,
|
||||
(player, requestedPlaceStyle, actualItemPlaceStyle) =>
|
||||
{
|
||||
// Booster tracks have 2 variations, but only 1 item.
|
||||
// The variation depends on the direction the player is facing.
|
||||
if (actualItemPlaceStyle == 2)
|
||||
{
|
||||
// Check the direction the player is facing.
|
||||
// 1 is right and -1 is left, these are the only possible values.
|
||||
if (player.direction == 1)
|
||||
{
|
||||
// Right-facing booster tracks
|
||||
return 3;
|
||||
}
|
||||
else if (player.direction == -1)
|
||||
{
|
||||
// Left-facing booster tracks
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Unrecognized player direction");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not a booster track, return as-is.
|
||||
return actualItemPlaceStyle;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal void OnGetSection(object sender, GetDataHandlers.GetSectionEventArgs args)
|
||||
|
|
@ -255,7 +385,10 @@ namespace TShockAPI
|
|||
int tileY = args.Y;
|
||||
short editData = args.EditData;
|
||||
EditType type = args.editDetail;
|
||||
byte style = args.Style;
|
||||
|
||||
// 'placeStyle' is a term used in Terraria land to determine which frame of a sprite is displayed when the sprite is placed. The placeStyle
|
||||
// determines the frameX and frameY offsets
|
||||
byte requestedPlaceStyle = args.Style;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -306,14 +439,38 @@ namespace TShockAPI
|
|||
return;
|
||||
}
|
||||
|
||||
if ((args.Player.TPlayer.BiomeTorchHoldStyle(style) != args.Player.TPlayer.BiomeTorchPlaceStyle(style))
|
||||
&& (selectedItem.placeStyle != style))
|
||||
// This is the actual tile ID we expect the selected item to create. If the tile ID from the packet and the tile ID from the item do not match
|
||||
// we need to inspect further to determine if Terraria is sending funny information (which it does sometimes) or if someone is being malicious
|
||||
var actualTileToBeCreated = selectedItem.createTile;
|
||||
// This is the actual place style we expect the selected item to create. Same as above - if it differs from what the client tells us,
|
||||
// we need to do some inspection to check if its valid
|
||||
var actualItemPlaceStyle = selectedItem.placeStyle;
|
||||
|
||||
// The client has requested to place a style that does not match their held item's actual place style
|
||||
if (requestedPlaceStyle != actualItemPlaceStyle)
|
||||
{
|
||||
TShock.Log.ConsoleError("Bouncer / OnTileEdit rejected from (placestyle) {0} {1} {2} placeStyle: {3} expectedStyle: {4}",
|
||||
args.Player.Name, action, editData, style, selectedItem.placeStyle);
|
||||
args.Player.SendTileSquare(tileX, tileY, 1);
|
||||
args.Handled = true;
|
||||
return;
|
||||
var tplayer = args.Player.TPlayer;
|
||||
// Search for an extraneous tile corrector
|
||||
// If none found then it can't be a false positive so deny the action
|
||||
if (!PlaceStyleCorrectors.TryGetValue(actualTileToBeCreated, out PlaceStyleCorrector corrector))
|
||||
{
|
||||
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.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// See if the corrector's expected style matches
|
||||
var correctedPlaceStyle = corrector(tplayer, requestedPlaceStyle, actualItemPlaceStyle);
|
||||
if (requestedPlaceStyle != correctedPlaceStyle)
|
||||
{
|
||||
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.Handled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,8 +539,7 @@ namespace TShockAPI
|
|||
else if (action == EditAction.PlaceTile || action == EditAction.ReplaceTile || action == EditAction.PlaceWall || action == EditAction.ReplaceWall)
|
||||
{
|
||||
if ((action == EditAction.PlaceTile && TShock.Config.Settings.PreventInvalidPlaceStyle) &&
|
||||
(MaxPlaceStyles.ContainsKey(editData) && style > MaxPlaceStyles[editData]) &&
|
||||
(ExtraneousPlaceStyles.ContainsKey(editData) && style > ExtraneousPlaceStyles[editData]))
|
||||
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);
|
||||
|
|
@ -2206,6 +2362,25 @@ namespace TShockAPI
|
|||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the max <see cref="Item.placeStyle"/> associated with the given <paramref name="tileID"/>. Or -1 if there's no association
|
||||
/// </summary>
|
||||
/// <param name="tileID">Tile ID to query for</param>
|
||||
/// <returns>The max <see cref="Item.placeStyle"/>, otherwise -1 if there's no association</returns>
|
||||
internal static int GetMaxPlaceStyle(int tileID)
|
||||
{
|
||||
int result;
|
||||
if (ExtraneousPlaceStyles.TryGetValue(tileID, out result)
|
||||
|| MaxPlaceStyles.TryGetValue(tileID, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// These time values are references from Projectile.cs, at npc.AddBuff() calls.
|
||||
private static Dictionary<int, short> NPCAddBuffTimeMax = new Dictionary<int, short>()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1934,6 +1934,7 @@ namespace TShockAPI
|
|||
return args.Handled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For use in an Emoji event.
|
||||
/// </summary>
|
||||
public class EmojiEventArgs : GetDataHandledEventArgs
|
||||
|
|
@ -1967,6 +1968,7 @@ namespace TShockAPI
|
|||
return args.Handled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For use in a TileEntityDisplayDollItemSync event.
|
||||
/// </summary>
|
||||
public class DisplayDollItemSyncEventArgs : GetDataHandledEventArgs
|
||||
|
|
@ -2025,6 +2027,7 @@ namespace TShockAPI
|
|||
return args.Handled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For use in an OnRequestTileEntityInteraction event.
|
||||
/// </summary>
|
||||
public class RequestTileEntityInteractionEventArgs : GetDataHandledEventArgs
|
||||
|
|
@ -4262,6 +4265,10 @@ namespace TShockAPI
|
|||
/// </summary>
|
||||
internal static Dictionary<int, int> ExtraneousPlaceStyles = new Dictionary<int, int>
|
||||
{
|
||||
{TileID.Presents, 6},
|
||||
{TileID.Explosives, 1},
|
||||
{TileID.MagicalIceBlock, 0},
|
||||
{TileID.Crystals, 17},
|
||||
{TileID.MinecartTrack, 3}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1561,6 +1561,18 @@ namespace TShockAPI
|
|||
Main.player[Index].team = team;
|
||||
NetMessage.SendData((int)PacketTypes.PlayerTeam, -1, -1, NetworkText.Empty, Index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the player's pvp.
|
||||
/// </summary>
|
||||
/// <param name="mode">The state of the pvp mode.</param>
|
||||
public virtual void SetPvP(bool mode, bool withMsg = false)
|
||||
{
|
||||
Main.player[Index].hostile = mode;
|
||||
NetMessage.SendData((int)PacketTypes.TogglePvp, -1, -1, NetworkText.Empty, Index);
|
||||
if (withMsg)
|
||||
TSPlayer.All.SendMessage(Language.GetTextValue(mode ? "LegacyMultiplayer.11" : "LegacyMultiplayer.12", Name), Main.teamColor[Team]);
|
||||
}
|
||||
|
||||
private DateTime LastDisableNotification = DateTime.UtcNow;
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ namespace TShockAPI
|
|||
|
||||
/// <summary>Players - Contains all TSPlayer objects for accessing TSPlayers currently on the server</summary>
|
||||
public static TSPlayer[] Players = new TSPlayer[Main.maxPlayers];
|
||||
/// <summary>Bans - Static reference to the ban manager for accessing bans & related functions.</summary>
|
||||
/// <summary>Bans - Static reference to the ban manager for accessing bans & related functions.</summary>
|
||||
public static BanManager Bans;
|
||||
/// <summary>Warps - Static reference to the warp manager for accessing the warp system.</summary>
|
||||
public static WarpManager Warps;
|
||||
|
|
@ -149,7 +149,7 @@ namespace TShockAPI
|
|||
/// </summary>
|
||||
public static event Action Initialized;
|
||||
|
||||
/// <summary>Version - The version required by the TerrariaAPI to be passed back for checking & loading the plugin.</summary>
|
||||
/// <summary>Version - The version required by the TerrariaAPI to be passed back for checking & loading the plugin.</summary>
|
||||
/// <value>value - The version number specified in the Assembly, based on the VersionNum variable set in this class.</value>
|
||||
public override Version Version
|
||||
{
|
||||
|
|
@ -690,15 +690,24 @@ namespace TShockAPI
|
|||
}
|
||||
}
|
||||
|
||||
private bool tryingToShutdown = false;
|
||||
|
||||
/// <summary> ConsoleCancelHandler - Handles when Ctrl + C is sent to the server for a safe shutdown. </summary>
|
||||
/// <param name="sender">The sender</param>
|
||||
/// <param name="args">The ConsoleCancelEventArgs associated with the event.</param>
|
||||
private void ConsoleCancelHandler(object sender, ConsoleCancelEventArgs args)
|
||||
{
|
||||
if (tryingToShutdown)
|
||||
{
|
||||
System.Environment.Exit(1);
|
||||
return;
|
||||
}
|
||||
// Cancel the default behavior
|
||||
args.Cancel = true;
|
||||
|
||||
Log.ConsoleInfo("Interrupt received. Saving the world and shutting down.");
|
||||
tryingToShutdown = true;
|
||||
|
||||
Log.ConsoleInfo("Shutting down safely. To force shutdown, send SIGINT (CTRL + C) again.");
|
||||
|
||||
// Perform a safe shutdown
|
||||
TShock.Utils.StopServer(true, "Server console interrupted!");
|
||||
|
|
|
|||
|
|
@ -894,7 +894,7 @@ namespace TShockAPI
|
|||
Main.recipe[i] = new Recipe();
|
||||
}
|
||||
|
||||
/// <summary>Dumps a matrix of all permissions & all groups in Markdown table format.</summary>
|
||||
/// <summary>Dumps a matrix of all permissions & all groups in Markdown table format.</summary>
|
||||
/// <param name="path">The save destination.</param>
|
||||
internal void DumpPermissionMatrix(string path)
|
||||
{
|
||||
|
|
@ -1230,7 +1230,7 @@ namespace TShockAPI
|
|||
for (int i = 0; i < Main.maxItemTypes; i++)
|
||||
{
|
||||
item.netDefaults(i);
|
||||
if (item.placeStyle > 0)
|
||||
if (item.placeStyle >= 0)
|
||||
{
|
||||
if (GetDataHandlers.MaxPlaceStyles.ContainsKey(item.createTile))
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue