Merge branch 'general-devel' of github.com:Pryaxis/TShock into general-devel
This commit is contained in:
commit
ad82afd800
6 changed files with 152 additions and 21 deletions
|
|
@ -7,6 +7,12 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
|
||||||
* Fixed /wind command. (@AxeelAnder)
|
* Fixed /wind command. (@AxeelAnder)
|
||||||
* Fixed NPC buff bouncer. (@AxeelAnder)
|
* Fixed NPC buff bouncer. (@AxeelAnder)
|
||||||
* Fixed players are unable to remove an NPC. Change `byte NPCHomeChangeEventArgs.Homeless` to `HouseholdStatus NPCHomeChangeEventArgs.HouseholdStatus`. (@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)
|
||||||
|
|
||||||
|
|
||||||
## TShock 4.4.0 (Pre-release 7 (Entangled))
|
## TShock 4.4.0 (Pre-release 7 (Entangled))
|
||||||
* Fixed bed spawn issues when trying to remove spawn point in SSC. (@Olink)
|
* Fixed bed spawn issues when trying to remove spawn point in SSC. (@Olink)
|
||||||
|
|
|
||||||
|
|
@ -19,18 +19,17 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Terraria.ID;
|
using Terraria.ID;
|
||||||
using TShockAPI.DB;
|
|
||||||
using TShockAPI.Net;
|
using TShockAPI.Net;
|
||||||
using Terraria;
|
using Terraria;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using OTAPI.Tile;
|
using OTAPI.Tile;
|
||||||
using TShockAPI.Localization;
|
using TShockAPI.Localization;
|
||||||
using static TShockAPI.GetDataHandlers;
|
using static TShockAPI.GetDataHandlers;
|
||||||
using TerrariaApi.Server;
|
|
||||||
using Terraria.ObjectData;
|
using Terraria.ObjectData;
|
||||||
using Terraria.DataStructures;
|
using Terraria.DataStructures;
|
||||||
using Terraria.Localization;
|
using Terraria.Localization;
|
||||||
using TShockAPI.Models.PlayerUpdate;
|
using TShockAPI.Models.PlayerUpdate;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace TShockAPI
|
namespace TShockAPI
|
||||||
{
|
{
|
||||||
|
|
@ -1290,6 +1289,24 @@ namespace TShockAPI
|
||||||
args.Player.TileLiquidThreshold++;
|
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
|
// Liquid anti-cheat
|
||||||
// Arguably the banned buckets bit should be in the item bans system
|
// Arguably the banned buckets bit should be in the item bans system
|
||||||
if (amount != 0)
|
if (amount != 0)
|
||||||
|
|
@ -1326,7 +1343,7 @@ namespace TShockAPI
|
||||||
bucket = 6;
|
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);
|
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.SendErrorMessage("You do not have permission to perform this action.");
|
||||||
|
|
@ -1336,7 +1353,7 @@ namespace TShockAPI
|
||||||
return;
|
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);
|
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.SendErrorMessage("You do not have permission to perform this action.");
|
||||||
|
|
@ -1346,7 +1363,7 @@ namespace TShockAPI
|
||||||
return;
|
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);
|
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.SendErrorMessage("You do not have permission to perform this action.");
|
||||||
|
|
@ -1356,7 +1373,7 @@ namespace TShockAPI
|
||||||
return;
|
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);
|
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.SendErrorMessage("You do not have permission to perform this action.");
|
||||||
|
|
@ -1366,7 +1383,7 @@ namespace TShockAPI
|
||||||
return;
|
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);
|
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.SendErrorMessage("You do not have permission to perform this action.");
|
||||||
|
|
@ -1376,7 +1393,7 @@ namespace TShockAPI
|
||||||
return;
|
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);
|
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.SendErrorMessage("You do not have permission to perform this action.");
|
||||||
|
|
@ -1395,7 +1412,7 @@ namespace TShockAPI
|
||||||
return;
|
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);
|
TShock.Log.ConsoleDebug("Bouncer / OnLiquidSet rejected range checks from {0}", args.Player.Name);
|
||||||
args.Player.SendTileSquare(tileX, tileY, 1);
|
args.Player.SendTileSquare(tileX, tileY, 1);
|
||||||
|
|
@ -2045,6 +2062,24 @@ namespace TShockAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
// These time values are references from Projectile.cs, at npc.AddBuff() calls.
|
||||||
private static Dictionary<int, short> NPCAddBuffTimeMax = new Dictionary<int, short>()
|
private static Dictionary<int, short> NPCAddBuffTimeMax = new Dictionary<int, short>()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -527,6 +527,9 @@ namespace TShockAPI
|
||||||
[Description("Whether or not the server should output debug level messages related to system operation.")]
|
[Description("Whether or not the server should output debug level messages related to system operation.")]
|
||||||
public bool DebugLogs = false;
|
public bool DebugLogs = false;
|
||||||
|
|
||||||
|
[Description("Determines the range in tiles that a bomb can affect tiles from detonation point.")]
|
||||||
|
public int BombExplosionRadius = 5;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a configuration file from a given path
|
/// Reads a configuration file from a given path
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -1141,7 +1141,8 @@ namespace TShockAPI
|
||||||
{
|
{
|
||||||
Water = 0,
|
Water = 0,
|
||||||
Lava = 1,
|
Lava = 1,
|
||||||
Honey = 2
|
Honey = 2,
|
||||||
|
Removal = 255 //@Olink: lets hope they never invent 255 fluids or decide to also use this :(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -2329,6 +2330,17 @@ namespace TShockAPI
|
||||||
if (OnNewProjectile(args.Data, ident, pos, vel, knockback, dmg, owner, type, index, args.Player))
|
if (OnNewProjectile(args.Data, ident, pos, vel, knockback, dmg, owner, type, index, args.Player))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
lock (args.Player.RecentlyCreatedProjectiles)
|
||||||
|
{
|
||||||
|
if (!args.Player.RecentlyCreatedProjectiles.Any(p => p.Index == index))
|
||||||
|
{
|
||||||
|
args.Player.RecentlyCreatedProjectiles.Add(new GetDataHandlers.ProjectileStruct()
|
||||||
|
{
|
||||||
|
Index = index,
|
||||||
|
CreatedAt = DateTime.Now
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2393,6 +2405,10 @@ namespace TShockAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
args.Player.LastKilledProjectile = type;
|
args.Player.LastKilledProjectile = type;
|
||||||
|
lock (args.Player.RecentlyCreatedProjectiles)
|
||||||
|
{
|
||||||
|
args.Player.RecentlyCreatedProjectiles.ForEach(s => { if (s.Index == index) { s.Killed = true; } });
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -2834,38 +2850,44 @@ namespace TShockAPI
|
||||||
string thing;
|
string thing;
|
||||||
switch (thingType)
|
switch (thingType)
|
||||||
{
|
{
|
||||||
|
case -11:
|
||||||
|
thing = "applied advanced combat techniques";
|
||||||
|
break;
|
||||||
|
case -10:
|
||||||
|
thing = "summoned a Blood Moon";
|
||||||
|
break;
|
||||||
case -8:
|
case -8:
|
||||||
thing = "a Moon Lord";
|
thing = "summoned a Moon Lord";
|
||||||
break;
|
break;
|
||||||
case -7:
|
case -7:
|
||||||
thing = "a Martian invasion";
|
thing = "summoned a Martian invasion";
|
||||||
break;
|
break;
|
||||||
case -6:
|
case -6:
|
||||||
thing = "an eclipse";
|
thing = "summoned an eclipse";
|
||||||
break;
|
break;
|
||||||
case -5:
|
case -5:
|
||||||
thing = "a frost moon";
|
thing = "summoned a frost moon";
|
||||||
break;
|
break;
|
||||||
case -4:
|
case -4:
|
||||||
thing = "a pumpkin moon";
|
thing = "summoned a pumpkin moon";
|
||||||
break;
|
break;
|
||||||
case -3:
|
case -3:
|
||||||
thing = "the Pirates";
|
thing = "summoned the Pirates";
|
||||||
break;
|
break;
|
||||||
case -2:
|
case -2:
|
||||||
thing = "the Snow Legion";
|
thing = "summoned the Snow Legion";
|
||||||
break;
|
break;
|
||||||
case -1:
|
case -1:
|
||||||
thing = "a Goblin Invasion";
|
thing = "summoned a Goblin Invasion";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
thing = String.Format("the {0}", npc.FullName);
|
thing = String.Format("summoned the {0}", npc.FullName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (TShock.Config.AnonymousBossInvasions)
|
if (TShock.Config.AnonymousBossInvasions)
|
||||||
TShock.Utils.SendLogs(string.Format("{0} summoned {1}!", args.Player.Name, thing), Color.PaleVioletRed, args.Player);
|
TShock.Utils.SendLogs(string.Format("{0} {1}!", args.Player.Name, thing), Color.PaleVioletRed, args.Player);
|
||||||
else
|
else
|
||||||
TShock.Utils.Broadcast(String.Format("{0} summoned {1}!", args.Player.Name, thing), 175, 75, 255);
|
TShock.Utils.Broadcast(String.Format("{0} {1}!", args.Player.Name, thing), 175, 75, 255);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3453,6 +3475,30 @@ namespace TShockAPI
|
||||||
{ ProjectileID.MysticSnakeCoil, TileID.MysticSnakeRope }
|
{ ProjectileID.MysticSnakeCoil, TileID.MysticSnakeRope }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
internal static Dictionary<int, LiquidType> projectileCreatesLiquid = new Dictionary<int, LiquidType>
|
||||||
|
{
|
||||||
|
{ProjectileID.LavaBomb, LiquidType.Lava},
|
||||||
|
{ProjectileID.LavaRocket, LiquidType.Lava },
|
||||||
|
{ProjectileID.LavaGrenade, LiquidType.Lava },
|
||||||
|
{ProjectileID.LavaMine, LiquidType.Lava },
|
||||||
|
//{ProjectileID.LavaSnowmanRocket, LiquidType.Lava }, //these require additional checks.
|
||||||
|
{ProjectileID.WetBomb, LiquidType.Water},
|
||||||
|
{ProjectileID.WetRocket, LiquidType.Water },
|
||||||
|
{ProjectileID.WetGrenade, LiquidType.Water},
|
||||||
|
{ProjectileID.WetMine, LiquidType.Water},
|
||||||
|
//{ProjectileID.WetSnowmanRocket, LiquidType.Water}, //these require additional checks.
|
||||||
|
{ProjectileID.HoneyBomb, LiquidType.Honey},
|
||||||
|
{ProjectileID.HoneyRocket, LiquidType.Honey },
|
||||||
|
{ProjectileID.HoneyGrenade, LiquidType.Honey },
|
||||||
|
{ProjectileID.HoneyMine, LiquidType.Honey },
|
||||||
|
//{ProjectileID.HoneySnowmanRocket, LiquidType.Honey }, //these require additional checks.
|
||||||
|
{ProjectileID.DryBomb, LiquidType.Removal },
|
||||||
|
{ProjectileID.DryRocket, LiquidType.Removal },
|
||||||
|
{ProjectileID.DryGrenade, LiquidType.Removal },
|
||||||
|
{ProjectileID.DryMine, LiquidType.Removal },
|
||||||
|
//{ProjectileID.DrySnowmanRocket, LiquidType.Removal } //these require additional checks.
|
||||||
|
};
|
||||||
|
|
||||||
internal static Dictionary<int, int> ropeCoilPlacements = new Dictionary<int, int>
|
internal static Dictionary<int, int> ropeCoilPlacements = new Dictionary<int, int>
|
||||||
{
|
{
|
||||||
{ItemID.RopeCoil, TileID.Rope},
|
{ItemID.RopeCoil, TileID.Rope},
|
||||||
|
|
@ -3468,5 +3514,12 @@ namespace TShockAPI
|
||||||
{
|
{
|
||||||
{TileID.MinecartTrack, 3}
|
{TileID.MinecartTrack, 3}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
internal struct ProjectileStruct
|
||||||
|
{
|
||||||
|
public int Index { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public bool Killed { get; internal set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -764,6 +764,12 @@ namespace TShockAPI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int LastKilledProjectile = 0;
|
public int LastKilledProjectile = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Keeps track of recently created projectiles by this player. TShock.cs OnSecondUpdate() removes from this in an async task.
|
||||||
|
/// Projectiles older than 5 seconds are purged from this collection as they are no longer "recent."
|
||||||
|
/// </summary>
|
||||||
|
internal List<TShockAPI.GetDataHandlers.ProjectileStruct> RecentlyCreatedProjectiles = new List<TShockAPI.GetDataHandlers.ProjectileStruct>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current region this player is in, or null if none.
|
/// The current region this player is in, or null if none.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -1065,6 +1065,8 @@ namespace TShockAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bouncer.OnSecondUpdate();
|
||||||
Utils.SetConsoleTitle(false);
|
Utils.SetConsoleTitle(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1620,6 +1622,32 @@ namespace TShockAPI
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (e.MsgId == PacketTypes.ProjectileNew)
|
||||||
|
{
|
||||||
|
if (e.number >= 0 && e.number < Main.projectile.Length)
|
||||||
|
{
|
||||||
|
var projectile = Main.projectile[e.number];
|
||||||
|
if (projectile.active && projectile.owner >= 0 && GetDataHandlers.projectileCreatesLiquid.ContainsKey(projectile.type))
|
||||||
|
{
|
||||||
|
var player = Players[projectile.owner];
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
|
if (player.RecentlyCreatedProjectiles.Any(p => p.Index == e.number && p.Killed))
|
||||||
|
{
|
||||||
|
player.RecentlyCreatedProjectiles.RemoveAll(p => p.Index == e.number && p.Killed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player.RecentlyCreatedProjectiles.Any(p => p.Index == e.number)) {
|
||||||
|
player.RecentlyCreatedProjectiles.Add(new GetDataHandlers.ProjectileStruct()
|
||||||
|
{
|
||||||
|
Index = e.number,
|
||||||
|
CreatedAt = DateTime.Now
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue