Skip to content

Commit

Permalink
Merge branch 'general-devel' into general-devel
Browse files Browse the repository at this point in the history
  • Loading branch information
hakusaro committed May 30, 2020
2 parents 770d17c + 791a6be commit 38d99de
Show file tree
Hide file tree
Showing 16 changed files with 853 additions and 88 deletions.
1 change: 0 additions & 1 deletion .github/FUNDING.yml
@@ -1,3 +1,2 @@
# These are supported funding model platforms

custom: https://www.givedirectly.org/
8 changes: 7 additions & 1 deletion .github/ISSUE_TEMPLATE/defect-report.md
Expand Up @@ -9,6 +9,8 @@ assignees: ''

<!-- Please provide the information requested below -->

<!-- STOP! Please set DebugLogs to true in your config file, restart the server, and then produce the problem again. Please attach the new debug log to this report. -->

* TShock version:
* TShock build number (if known):

Expand All @@ -31,8 +33,12 @@ PUT SUPER LONG ERROR MESSAGES IN THE TICK MARKS

<!-- If providing screenshots of client, send before and after pressing F8 to show network debug -->

#### Any log messages from files that end in `.log` or `.txt`?
#### Any log messages from files that end in `.log` or `.txt`? What are the last 100 log messages from the server console?

<!-- Please add context. Even if you don't have an error message, please show recent server logs at least. -->

<!-- STOP! If you do not provide any logs or screenshots, your issue may be closed or converted to a discussion without warning! -->

#### What plugins and what versions of those plugins are you running?

If I didn't provide any logs this issue, please close my issue immediately. I'm sorry for the inconvenience.
52 changes: 50 additions & 2 deletions CHANGELOG.md
Expand Up @@ -2,10 +2,58 @@

This is the rolling changelog for TShock for Terraria. Use past tense when adding new entries; sign your name off when you add or change something. This should primarily be things like user changes, not necessarily codebase changes unless it's really relevant or large.

## Upcoming release
## Upcoming Release
* Fixed pet licenses. (@Olink)
* Added initial support for Journey mode in SSC worlds. (@Olink)
* Made TShock database MySQL 8 compatible by escaping column names in our IQueryBuilder code. (Name `Groups` is a reserved element in this version, which is used in our `Region` table.) (@Patrikkk)
* Reintroduced `-worldselectpath` per feedback from @fjfnaranjo. This command line argument should be used to specify the place where the interactive server startup will look for worlds to show on the world select screen. The original version of this argument, `-worldpath`, was removed because several game service providers have broken configurations that stop the server from running with an unhelpful error. This specific configuration was `-world` and `-worldpath`. In the new world, you can do the following:
* `-worldselectpath` should be used if you want to customize the server interactive boot world list (so that you can select from a number of worlds in non-standard locations).
* `-world` will behave as an absolute path to the world to load. This is the most common thing you want if you're starting the server and have a specific world in mind.
* `-worldselectpath` and `-worldname` should work together enabling you to select from a world from the list that you specify. This is *not* a world file name, but a world name as described by Terraria.
* `-worldselectpath` is identical to the old `-worldpath`. If you specify `-worldselectpath` and `-world` without specifying an absolute path the server will crash for sure.
* Thank you again to @fjfnaranjo for supplying a [detailed feature request](https://github.com/Pryaxis/TShock/issues/1914) explaining precisely why this option should be available. Without this, we would have had no context as to why this feature was useful or important. Thank you, @fjfnaranjo!
* This change was implemented by (@QuiCM, @hakusaro).
* Updated Bouncer to include Sparkle Slime debuff that can be applied to town NPCs. (@moisterrific)
* Updated `/spawnboss` command to include Empress of Light and Queen Slime. (@moisterrific)
* Added journey mode permissions to owner group by default. (@moisterrific)
* Fixed kick on hardcore death / kick on mediumcore death / ban on either from taking action against journey mode players. (@hakusaro)
* Attempted to fix the problem with the magic mirror spawn problems. You should be able to remove your spawn point in SSC by right clicking on a bed now. (@hakusaro, @AxeelAnder)
* Added HandleFoodPlatterTryPlacing event, which is called whenever a player places a food in a plate. Add antihack to bouncer, to prevent removing food from plates if the region is protected; To prevent placement if they are not in range; To prevent placement if the item is not placed from player hand. (@Patrikkk)
* Fixed an offset error in NetTile that impacted `SendTileSquare`. It was being read as a `byte` and not a `ushort`. (@QuiCM)
* Fixed coins not dropping after being picked up by npcs. The ExtraValue packet was not being read correctly. (@Olink)
* Removed packet monitoring from debug logs. To achieve the same results, install @QuiCM's packet monitor plugin (it does better things). (@hakusaro)
* Updated packet monitoring in send tile square handler for Bouncer debugging. (@hakusaro)
* Added `/sync`, activated with `tshock.synclocalarea`. This is a default guest permission. When the command is issued, the server will resync area around the player in the event of a desync issue. (@hakusaro)
* If your doors disappear, this command will allow a player to resync without having to disconnect from the server.
* The default group that gets this permission is `Guest` for the time being.
* To add this command to your guest group, give them `tshock.synclocalarea`, with `/group addperm guest tshock.synclocalarea`.
* This command may be removed at any time in the future (and will likely be removed when send tile square handling is fixed).

## TShock 4.4.0 (Pre-release 8)
* Update for OTAPI 2.0.0.36 and Terraria 1.4.0.4. (@hakusaro, @Patrikkk, @DeathCradle)
* Fixed /wind command. (@AxeelAnder)
* Fixed NPC buff bouncer. (@AxeelAnder)
* Fixed NPC debuff issue when attempting to fight bosses resulting in kicks. (@AxeelAnder)
* Fixed players are unable to remove an NPC. Change `byte NPCHomeChangeEventArgs.Homeless` to `HouseholdStatus NPCHomeChangeEventArgs.HouseholdStatus`. (@AxeelAnder)
* Fixed lava, wet, honey, and dry bombs;
and lava, wet, honey, and dry grenades;
and lava, wet, honey, and dry rockets;
and lava, wet, honey, and dry mines. (@Olink)
* Fix Bloody Tear displaying the wrong text when used. (@Olink)
* Fix the visibility toggle for the last two accessory slots. (@Olink)
* Adding Journey mode user account permissions. Journey mode must be enabled for these to have any effect. (@Patrikkk)
* `tshock.journey.time.freeze`
* `tshock.journey.time.set`
* `tshock.journey.time.setspeed`
* `tshock.journey.godmode`
* `tshock.journey.wind.strength`
* `tshock.journey.wind.freeze`
* `tshock.journey.rain.strength`
* `tshock.journey.rain.freeze`
* `tshock.journey.placementrange`
* `tshock.journey.setdifficulty`
* `tshock.journey.biomespreadfreeze`
* `tshock.journey.setspawnrate`
* Changed default thresholds for some changes in the config file to accommodate new items & changes to Terraria. (@hakusaro)

## TShock 4.4.0 (Pre-release 7 (Entangled))
* Fixed bed spawn issues when trying to remove spawn point in SSC. (@Olink)
Expand Down
117 changes: 100 additions & 17 deletions TShockAPI/Bouncer.cs
Expand Up @@ -19,18 +19,17 @@
using System.Collections.Generic;
using System.Linq;
using Terraria.ID;
using TShockAPI.DB;
using TShockAPI.Net;
using Terraria;
using Microsoft.Xna.Framework;
using OTAPI.Tile;
using TShockAPI.Localization;
using static TShockAPI.GetDataHandlers;
using TerrariaApi.Server;
using Terraria.ObjectData;
using Terraria.DataStructures;
using Terraria.Localization;
using TShockAPI.Models.PlayerUpdate;
using System.Threading.Tasks;

namespace TShockAPI
{
Expand Down Expand Up @@ -68,6 +67,7 @@ internal Bouncer()
GetDataHandlers.MassWireOperation += OnMassWireOperation;
GetDataHandlers.PlayerDamage += OnPlayerDamage;
GetDataHandlers.KillMe += OnKillMe;
GetDataHandlers.FoodPlatterTryPlacing += OnFoodPlatterTryPlacing;
}

internal void OnGetSection(object sender, GetDataHandlers.GetSectionEventArgs args)
Expand Down Expand Up @@ -528,7 +528,7 @@ internal void OnSendTileSquare(object sender, GetDataHandlers.SendTileSquareEven

if (args.Player.HasPermission(Permissions.allowclientsideworldedit))
{
TShock.Log.ConsoleDebug("Bouncer / SendTileSquare rejected clientside world edit from {0}", args.Player.Name);
TShock.Log.ConsoleDebug("Bouncer / SendTileSquare accepted clientside world edit from {0}", args.Player.Name);
args.Handled = false;
return;
}
Expand Down Expand Up @@ -558,6 +558,8 @@ internal void OnSendTileSquare(object sender, GetDataHandlers.SendTileSquareEven
return;
}

bool changed = false;
bool failed = false;
try
{
var tiles = new NetTile[size, size];
Expand All @@ -569,7 +571,6 @@ internal void OnSendTileSquare(object sender, GetDataHandlers.SendTileSquareEven
}
}

bool changed = false;
for (int x = 0; x < size; x++)
{
int realx = tileX + x;
Expand Down Expand Up @@ -709,9 +710,10 @@ internal void OnSendTileSquare(object sender, GetDataHandlers.SendTileSquareEven
catch
{
args.Player.SendTileSquare(tileX, tileY, size);
failed = true;
}

TShock.Log.ConsoleDebug("Bouncer / SendTileSquare rejected from spaghetti from {0}", args.Player.Name);
TShock.Log.ConsoleDebug("Bouncer / SendTileSquare from {0} {1} {2}", args.Player.Name, changed, failed);
args.Handled = true;
}

Expand Down Expand Up @@ -865,7 +867,6 @@ internal void OnNewProjectile(object sender, GetDataHandlers.NewProjectileEventA
return;
}


if (stabProjectile.ContainsKey(type))
{
if (stabProjectile[type] == args.Player.TPlayer.HeldItem.type)
Expand All @@ -875,7 +876,6 @@ internal void OnNewProjectile(object sender, GetDataHandlers.NewProjectileEventA
}
}


// Main.projHostile contains projectiles that can harm players
// without PvP enabled and belong to enemy mobs, so they shouldn't be
// possible for players to create. (Source: Ijwu, QuiCM)
Expand All @@ -888,6 +888,8 @@ internal void OnNewProjectile(object sender, GetDataHandlers.NewProjectileEventA
}

// Tombstones should never be permitted by players
// This check means like, invalid or hacked tombstones (sent from hacked clients)
// Death does not create a tombstone projectile by default
if (type == ProjectileID.Tombstone)
{
TShock.Log.ConsoleDebug("Bouncer / OnNewProjectile rejected from tombstones from {0}", args.Player.Name);
Expand Down Expand Up @@ -1290,6 +1292,24 @@ internal void OnLiquidSet(object sender, GetDataHandlers.LiquidSetEventArgs args
args.Player.TileLiquidThreshold++;
}

bool wasThereABombNearby = false;
lock (args.Player.RecentlyCreatedProjectiles)
{
IEnumerable<int> projectileTypesThatPerformThisOperation;
if (amount > 0) //handle the projectiles that create fluid.
{
projectileTypesThatPerformThisOperation = projectileCreatesLiquid.Where(k => k.Value == type).Select(k => k.Key);
}
else //handle the scenario where we are removing liquid
{
projectileTypesThatPerformThisOperation = projectileCreatesLiquid.Where(k => k.Value == LiquidType.Removal).Select(k => k.Key);
}

var recentBombs = args.Player.RecentlyCreatedProjectiles.Where(p => projectileTypesThatPerformThisOperation.Contains(Main.projectile[p.Index].type));
wasThereABombNearby = recentBombs.Any(r => Math.Abs(args.TileX - (Main.projectile[r.Index].position.X / 16.0f)) < TShock.Config.BombExplosionRadius
&& Math.Abs(args.TileY - (Main.projectile[r.Index].position.Y / 16.0f)) < TShock.Config.BombExplosionRadius);
}

// Liquid anti-cheat
// Arguably the banned buckets bit should be in the item bans system
if (amount != 0)
Expand Down Expand Up @@ -1326,7 +1346,7 @@ internal void OnLiquidSet(object sender, GetDataHandlers.LiquidSetEventArgs args
bucket = 6;
}

if (type == LiquidType.Lava && !(bucket == 2 || bucket == 0 || bucket == 5 || bucket == 6))
if (!wasThereABombNearby && type == LiquidType.Lava && !(bucket == 2 || bucket == 0 || bucket == 5 || bucket == 6))
{
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.");
Expand All @@ -1336,7 +1356,7 @@ internal void OnLiquidSet(object sender, GetDataHandlers.LiquidSetEventArgs args
return;
}

if (type == LiquidType.Lava && TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player))
if (!wasThereABombNearby && type == LiquidType.Lava && TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player))
{
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.");
Expand All @@ -1346,7 +1366,7 @@ internal void OnLiquidSet(object sender, GetDataHandlers.LiquidSetEventArgs args
return;
}

if (type == LiquidType.Water && !(bucket == 1 || bucket == 0 || bucket == 4))
if (!wasThereABombNearby && type == LiquidType.Water && !(bucket == 1 || bucket == 0 || bucket == 4))
{
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.");
Expand All @@ -1356,7 +1376,7 @@ internal void OnLiquidSet(object sender, GetDataHandlers.LiquidSetEventArgs args
return;
}

if (type == LiquidType.Water && TShock.Itembans.ItemIsBanned("Water Bucket", args.Player))
if (!wasThereABombNearby && type == LiquidType.Water && TShock.Itembans.ItemIsBanned("Water Bucket", args.Player))
{
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.");
Expand All @@ -1366,7 +1386,7 @@ internal void OnLiquidSet(object sender, GetDataHandlers.LiquidSetEventArgs args
return;
}

if (type == LiquidType.Honey && !(bucket == 3 || bucket == 0))
if (!wasThereABombNearby && type == LiquidType.Honey && !(bucket == 3 || bucket == 0))
{
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.");
Expand All @@ -1376,7 +1396,7 @@ internal void OnLiquidSet(object sender, GetDataHandlers.LiquidSetEventArgs args
return;
}

if (type == LiquidType.Honey && TShock.Itembans.ItemIsBanned("Honey Bucket", args.Player))
if (!wasThereABombNearby && type == LiquidType.Honey && TShock.Itembans.ItemIsBanned("Honey Bucket", args.Player))
{
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.");
Expand All @@ -1395,7 +1415,7 @@ internal void OnLiquidSet(object sender, GetDataHandlers.LiquidSetEventArgs args
return;
}

if (!args.Player.IsInRange(tileX, tileY, 16))
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);
Expand Down Expand Up @@ -1520,7 +1540,7 @@ internal void OnNPCAddBuff(object sender, GetDataHandlers.NPCAddBuffEventArgs ar
if (npc.townNPC && npc.netID != NPCID.Guide && npc.netID != NPCID.Clothier)
{
if (type != BuffID.Lovestruck && type != BuffID.Stinky && type != BuffID.DryadsWard &&
type != BuffID.Wet && type != BuffID.Slimed)
type != BuffID.Wet && type != BuffID.Slimed && type != BuffID.GelBalloonBuff)
{
detectedNPCBuffTimeCheat = true;
}
Expand All @@ -1547,7 +1567,6 @@ internal void OnUpdateNPCHome(object sender, GetDataHandlers.NPCHomeChangeEventA
int id = args.ID;
short x = args.X;
short y = args.Y;
byte homeless = args.Homeless;

if (!args.Player.HasBuildPermission(x, y))
{
Expand All @@ -1558,7 +1577,8 @@ internal void OnUpdateNPCHome(object sender, GetDataHandlers.NPCHomeChangeEventA
return;
}

if (!args.Player.IsInRange(x, y))
// When kicking out an npc, x and y in args are 0, we shouldn't check range at this case
if (args.HouseholdStatus != HouseholdStatus.Homeless && !args.Player.IsInRange(x, y))
{
args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY,
Convert.ToByte(Main.npc[id].homeless));
Expand Down Expand Up @@ -2045,6 +2065,69 @@ internal void OnKillMe(object sender, GetDataHandlers.KillMeEventArgs args)
}
}

/// <summary>
/// Called when a player is trying to place an item into a food plate.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
internal void OnFoodPlatterTryPlacing(object sender, GetDataHandlers.FoodPlatterTryPlacingEventArgs args)
{
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.Handled = true;
return;
}
if (args.Player.IsBeingDisabled())
{
TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected disabled from {0}", args.Player.Name);
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.Handled = true;
return;
}

if (!args.Player.HasBuildPermission(args.TileX, args.TileY))
{
TShock.Log.ConsoleDebug("Bouncer / OnFoodPlatterTryPlacing rejected permissions from {0}", args.Player.Name);
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.Handled = true;
return;
}

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.Handled = true;
return;
}
}

internal void OnSecondUpdate()
{
Task.Run(() =>
{
foreach (var player in TShock.Players)
{
if (player != null && player.TPlayer.whoAmI >= 0)
{
var threshold = DateTime.Now.AddSeconds(-5);
lock (player.RecentlyCreatedProjectiles)
{
player.RecentlyCreatedProjectiles = player.RecentlyCreatedProjectiles.Where(s => s.CreatedAt > threshold).ToList();
}
}
}
});
}

// These time values are references from Projectile.cs, at npc.AddBuff() calls.
private static Dictionary<int, short> NPCAddBuffTimeMax = new Dictionary<int, short>()
{
Expand Down

0 comments on commit 38d99de

Please sign in to comment.