Merge branch 'general-devel' into region-mysql
This commit is contained in:
commit
0e711da8cc
13 changed files with 645 additions and 97 deletions
8
.github/ISSUE_TEMPLATE/defect-report.md
vendored
8
.github/ISSUE_TEMPLATE/defect-report.md
vendored
|
|
@ -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):
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
29
CHANGELOG.md
29
CHANGELOG.md
|
|
@ -2,8 +2,35 @@
|
|||
|
||||
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
|
||||
* Fix pet licenses. (@Olink)
|
||||
* Initial support for Journey mode in SSC worlds. (@Olink)
|
||||
|
||||
## 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 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)
|
||||
|
|
|
|||
|
|
@ -19,18 +19,17 @@ using System;
|
|||
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
|
||||
{
|
||||
|
|
@ -528,7 +527,7 @@ namespace TShockAPI
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
@ -711,7 +710,7 @@ namespace TShockAPI
|
|||
args.Player.SendTileSquare(tileX, tileY, size);
|
||||
}
|
||||
|
||||
TShock.Log.ConsoleDebug("Bouncer / SendTileSquare rejected from spaghetti from {0}", args.Player.Name);
|
||||
TShock.Log.ConsoleDebug("Bouncer / SendTileSquare reimplemented from spaghetti from {0}", args.Player.Name);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
|
|
@ -865,7 +864,6 @@ namespace TShockAPI
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (stabProjectile.ContainsKey(type))
|
||||
{
|
||||
if (stabProjectile[type] == args.Player.TPlayer.HeldItem.type)
|
||||
|
|
@ -875,7 +873,6 @@ namespace TShockAPI
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
|
|
@ -888,6 +885,8 @@ namespace TShockAPI
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
|
@ -1290,6 +1289,24 @@ namespace TShockAPI
|
|||
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)
|
||||
|
|
@ -1326,7 +1343,7 @@ namespace TShockAPI
|
|||
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.");
|
||||
|
|
@ -1336,7 +1353,7 @@ namespace TShockAPI
|
|||
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.");
|
||||
|
|
@ -1346,7 +1363,7 @@ namespace TShockAPI
|
|||
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.");
|
||||
|
|
@ -1356,7 +1373,7 @@ namespace TShockAPI
|
|||
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.");
|
||||
|
|
@ -1366,7 +1383,7 @@ namespace TShockAPI
|
|||
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.");
|
||||
|
|
@ -1376,7 +1393,7 @@ namespace TShockAPI
|
|||
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.");
|
||||
|
|
@ -1395,7 +1412,7 @@ namespace TShockAPI
|
|||
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);
|
||||
|
|
@ -1547,7 +1564,6 @@ namespace TShockAPI
|
|||
int id = args.ID;
|
||||
short x = args.X;
|
||||
short y = args.Y;
|
||||
byte homeless = args.Homeless;
|
||||
|
||||
if (!args.Player.HasBuildPermission(x, y))
|
||||
{
|
||||
|
|
@ -1558,7 +1574,8 @@ namespace TShockAPI
|
|||
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));
|
||||
|
|
@ -2045,39 +2062,56 @@ 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.
|
||||
private static Dictionary<int, short> NPCAddBuffTimeMax = new Dictionary<int, short>()
|
||||
{
|
||||
{ BuffID.Poisoned, 3600 },
|
||||
{ BuffID.OnFire, 1200 },
|
||||
{ BuffID.CursedInferno, 420 },
|
||||
{ BuffID.Frostburn, 900 },
|
||||
{ BuffID.Ichor, 1200 },
|
||||
{ BuffID.Venom, 1260 },
|
||||
{ BuffID.Midas, 120 },
|
||||
{ BuffID.Wet, 1500 },
|
||||
{ BuffID.Slimed, 1500 },
|
||||
{ BuffID.Lovestruck, 1800 },
|
||||
{ BuffID.Stinky, 1800 },
|
||||
{ BuffID.SoulDrain, 30 },
|
||||
{ BuffID.ShadowFlame, 660 },
|
||||
{ BuffID.DryadsWard, 120 },
|
||||
{ BuffID.BoneJavelin, 900 },
|
||||
{ BuffID.StardustMinionBleed, 900 },
|
||||
{ BuffID.DryadsWardDebuff, 120 },
|
||||
{ BuffID.BetsysCurse, 600 },
|
||||
{ BuffID.Oiled, 540 },
|
||||
{ BuffID.Confused, 450 }, // Brain of Confusion Internal Item ID: 3223
|
||||
{ BuffID.Daybreak, 300 }, // Solar Eruption Item ID: 3473, Daybreak Item ID: 3543
|
||||
{ BuffID.BlandWhipEnemyDebuff, 240 },
|
||||
{ BuffID.SwordWhipNPCDebuff, 240 },
|
||||
{ BuffID.ScytheWhipEnemyDebuff, 240 },
|
||||
{ BuffID.FlameWhipEnemyDebuff, 240 },
|
||||
{ BuffID.ThornWhipNPCDebuff, 240 },
|
||||
{ BuffID.RainbowWhipNPCDebuff, 240 },
|
||||
{ BuffID.MaceWhipNPCDebuff, 240 },
|
||||
{ BuffID.GelBalloonBuff, 1800 }
|
||||
|
||||
{ BuffID.Poisoned, 3600 }, // BuffID: 20
|
||||
{ BuffID.OnFire, 1200 }, // BuffID: 24
|
||||
{ BuffID.Confused, short.MaxValue }, // BuffID: 31 Brain of Confusion Internal Item ID: 3223
|
||||
{ BuffID.CursedInferno, 420 }, // BuffID: 39
|
||||
{ BuffID.Frostburn, 900 }, // BuffID: 44
|
||||
{ BuffID.Ichor, 1200 }, // BuffID: 69
|
||||
{ BuffID.Venom, 1800 }, // BuffID: 70
|
||||
{ BuffID.Midas, 120 }, // BuffID: 72
|
||||
{ BuffID.Wet, 1500 }, // BuffID: 103
|
||||
{ BuffID.Lovestruck, 1800 }, // BuffID: 119
|
||||
{ BuffID.Stinky, 1800 }, // BuffID: 120
|
||||
{ BuffID.Slimed, 1500 }, // BuffID: 137
|
||||
{ BuffID.SoulDrain, 30 }, // BuffID: 151
|
||||
{ BuffID.ShadowFlame, 660 }, // BuffID: 153
|
||||
{ BuffID.DryadsWard, 120 }, // BuffID: 165
|
||||
{ BuffID.BoneJavelin, 900 }, // BuffID: 169
|
||||
{ BuffID.StardustMinionBleed, 900 }, // BuffID: 183
|
||||
{ BuffID.DryadsWardDebuff, 120 }, // BuffID: 186
|
||||
{ BuffID.Daybreak, 300 }, // BuffID: 189 Solar Eruption Item ID: 3473, Daybreak Item ID: 3543
|
||||
{ BuffID.BetsysCurse, 600 }, // BuffID: 203
|
||||
{ BuffID.Oiled, 540 }, // BuffID: 204
|
||||
{ BuffID.BlandWhipEnemyDebuff, 240 }, // BuffID: 307
|
||||
{ BuffID.SwordWhipNPCDebuff, 240 }, // BuffID: 309
|
||||
{ BuffID.ScytheWhipEnemyDebuff, 240 }, // BuffID: 310
|
||||
{ BuffID.FlameWhipEnemyDebuff, 240 }, // BuffID: 313
|
||||
{ BuffID.ThornWhipNPCDebuff, 240 }, // BuffID: 315
|
||||
{ BuffID.RainbowWhipNPCDebuff, 240 }, // BuffID: 316
|
||||
{ BuffID.MaceWhipNPCDebuff, 240 }, // BuffID: 319
|
||||
{ BuffID.GelBalloonBuff, 1800 } // BuffID: 320
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -4044,7 +4044,6 @@ namespace TShockAPI
|
|||
{
|
||||
tsply.SaveServerCharacter();
|
||||
}
|
||||
args.Player.SendSuccessMessage("Save succeeded.");
|
||||
}
|
||||
|
||||
private static void Settle(CommandArgs args)
|
||||
|
|
@ -4264,7 +4263,7 @@ namespace TShockAPI
|
|||
}
|
||||
|
||||
Main.windSpeedCurrent = speed;
|
||||
Main.windSpeedTarget = 0f;
|
||||
Main.windSpeedTarget = speed;
|
||||
TSPlayer.All.SendData(PacketTypes.WorldInfo);
|
||||
TSPlayer.All.SendInfoMessage("{0} changed the wind speed to {1}.", args.Player.Name, speed);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,11 +275,11 @@ namespace TShockAPI
|
|||
|
||||
/// <summary>Disables a player and reverts their actions if this number of tile places is exceeded within 1 second.</summary>
|
||||
[Description("Disables a player and reverts their actions if this number of tile places is exceeded within 1 second.")]
|
||||
public int TilePlaceThreshold = 20;
|
||||
public int TilePlaceThreshold = 32;
|
||||
|
||||
/// <summary>Disables a player if this number of liquid sets is exceeded within 1 second.</summary>
|
||||
[Description("Disables a player if this number of liquid sets is exceeded within 1 second.")]
|
||||
public int TileLiquidThreshold = 15;
|
||||
public int TileLiquidThreshold = 50;
|
||||
|
||||
/// <summary>Disable a player if this number of projectiles is created within 1 second.</summary>
|
||||
[Description("Disable a player if this number of projectiles is created within 1 second.")]
|
||||
|
|
@ -527,6 +527,9 @@ namespace TShockAPI
|
|||
[Description("Whether or not the server should output debug level messages related to system operation.")]
|
||||
public bool DebugLogs = false;
|
||||
|
||||
[Description("Determines the range in tiles that a bomb can affect tiles from detonation point.")]
|
||||
public int BombExplosionRadius = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Reads a configuration file from a given path
|
||||
/// </summary>
|
||||
|
|
|
|||
138
TShockAPI/DB/ResearchDatastore.cs
Normal file
138
TShockAPI/DB/ResearchDatastore.cs
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
using MySql.Data.MySqlClient;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Terraria;
|
||||
using Terraria.ID;
|
||||
|
||||
namespace TShockAPI.DB
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is used as the data interface for Journey mode research.
|
||||
/// This information is maintained such that SSC characters will be properly set up with
|
||||
/// the world's current research.
|
||||
/// </summary>
|
||||
public class ResearchDatastore
|
||||
{
|
||||
private IDbConnection database;
|
||||
|
||||
/// <summary>
|
||||
/// In-memory cache of what items have been sacrificed.
|
||||
/// The first call to GetSacrificedItems will load this with data from the database.
|
||||
/// </summary>
|
||||
private Dictionary<int, int> _itemsSacrificed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TShockAPI.DB.ResearchDatastore"/> class.
|
||||
/// </summary>
|
||||
/// <param name="db">A valid connection to the TShock database</param>
|
||||
public ResearchDatastore(IDbConnection db)
|
||||
{
|
||||
database = db;
|
||||
|
||||
var table = new SqlTable("Research",
|
||||
new SqlColumn("WorldId", MySqlDbType.Int32),
|
||||
new SqlColumn("PlayerId", MySqlDbType.Int32),
|
||||
new SqlColumn("ItemId", MySqlDbType.Int32),
|
||||
new SqlColumn("AmountSacrificed", MySqlDbType.Int32),
|
||||
new SqlColumn("TimeSacrificed", MySqlDbType.DateTime)
|
||||
);
|
||||
var creator = new SqlTableCreator(db,
|
||||
db.GetSqlType() == SqlType.Sqlite
|
||||
? (IQueryBuilder)new SqliteQueryCreator()
|
||||
: new MysqlQueryCreator());
|
||||
try
|
||||
{
|
||||
creator.EnsureTableStructure(table);
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
Console.WriteLine("Possible problem with your database - is Sqlite3.dll present?");
|
||||
throw new Exception("Could not find a database library (probably Sqlite3.dll)");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This call will return the memory-cached list of items sacrificed.
|
||||
/// If the cache is not initialized, it will be initialized from the database.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Dictionary<int, int> GetSacrificedItems()
|
||||
{
|
||||
if (_itemsSacrificed == null)
|
||||
{
|
||||
_itemsSacrificed = ReadFromDatabase();
|
||||
}
|
||||
|
||||
return _itemsSacrificed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function will return a Dictionary<ItemId, AmountSacrificed> representing
|
||||
/// what the progress of research on items is for this world.
|
||||
/// </summary>
|
||||
/// <returns>A dictionary of ItemID keys and Amount Sacrificed values.</returns>
|
||||
private Dictionary<int, int> ReadFromDatabase()
|
||||
{
|
||||
Dictionary<int, int> sacrificedItems = new Dictionary<int, int>();
|
||||
|
||||
var sql = @"select itemId, sum(AmountSacrificed) totalSacrificed
|
||||
from Research
|
||||
where WorldId = @0
|
||||
group by itemId";
|
||||
|
||||
try {
|
||||
using (var reader = database.QueryReader(sql, Main.worldID))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var itemId = reader.Get<Int32>("itemId");
|
||||
var amount = reader.Get<Int32>("totalSacrificed");
|
||||
sacrificedItems[itemId] = amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
TShock.Log.Error(ex.ToString());
|
||||
}
|
||||
return sacrificedItems;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method will sacrifice an amount of an item for research.
|
||||
/// </summary>
|
||||
/// <param name="itemId">The net ItemId that is being researched.</param>
|
||||
/// <param name="amount">The amount of items being sacrificed.</param>
|
||||
/// <param name="player">The player who sacrificed the item for research.</param>
|
||||
/// <returns>The cumulative total sacrifices for this item.</returns>
|
||||
public int SacrificeItem(int itemId, int amount, TSPlayer player)
|
||||
{
|
||||
var itemsSacrificed = GetSacrificedItems();
|
||||
if (!(itemsSacrificed.ContainsKey(itemId)))
|
||||
itemsSacrificed[itemId] = 0;
|
||||
|
||||
var sql = @"insert into Research (WorldId, PlayerId, ItemId, AmountSacrificed, TimeSacrificed) values (@0, @1, @2, @3, @4)";
|
||||
|
||||
var result = 0;
|
||||
try
|
||||
{
|
||||
result = database.Query(sql, Main.worldID, player.Account.ID, itemId, amount, DateTime.Now);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
TShock.Log.Error(ex.ToString());
|
||||
}
|
||||
|
||||
if (result == 1)
|
||||
{
|
||||
itemsSacrificed[itemId] += amount;
|
||||
}
|
||||
|
||||
return itemsSacrificed[itemId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -39,6 +39,8 @@ using TShockAPI.Localization;
|
|||
using TShockAPI.Models;
|
||||
using TShockAPI.Models.PlayerUpdate;
|
||||
using TShockAPI.Models.Projectiles;
|
||||
using Terraria.Net;
|
||||
using Terraria.GameContent.NetModules;
|
||||
|
||||
namespace TShockAPI
|
||||
{
|
||||
|
|
@ -125,7 +127,7 @@ namespace TShockAPI
|
|||
{ PacketTypes.NpcSpecial, HandleSpecial },
|
||||
{ PacketTypes.NpcAddBuff, HandleNPCAddBuff },
|
||||
{ PacketTypes.PlayerAddBuff, HandlePlayerAddBuff },
|
||||
{ PacketTypes.UpdateNPCHome, UpdateNPCHome },
|
||||
{ PacketTypes.UpdateNPCHome, HandleUpdateNPCHome },
|
||||
{ PacketTypes.SpawnBossorInvasion, HandleSpawnBoss },
|
||||
{ PacketTypes.PaintTile, HandlePaintTile },
|
||||
{ PacketTypes.PaintWall, HandlePaintWall },
|
||||
|
|
@ -1141,7 +1143,8 @@ namespace TShockAPI
|
|||
{
|
||||
Water = 0,
|
||||
Lava = 1,
|
||||
Honey = 2
|
||||
Honey = 2,
|
||||
Removal = 255 //@Olink: lets hope they never invent 255 fluids or decide to also use this :(
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -1307,6 +1310,13 @@ namespace TShockAPI
|
|||
return args.Handled;
|
||||
}
|
||||
|
||||
public enum HouseholdStatus : byte
|
||||
{
|
||||
None = 0,
|
||||
Homeless = 1,
|
||||
HasRoom = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For use in a NPCHome event
|
||||
/// </summary>
|
||||
|
|
@ -1325,15 +1335,15 @@ namespace TShockAPI
|
|||
/// </summary>
|
||||
public short Y { get; set; }
|
||||
/// <summary>
|
||||
/// ByteBool homeless
|
||||
/// HouseholdStatus of the NPC
|
||||
/// </summary>
|
||||
public byte Homeless { get; set; }
|
||||
public HouseholdStatus HouseholdStatus { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// NPCHome - Called when an NPC's home is changed
|
||||
/// </summary>
|
||||
public static HandlerList<NPCHomeChangeEventArgs> NPCHome = new HandlerList<NPCHomeChangeEventArgs>();
|
||||
private static bool OnUpdateNPCHome(TSPlayer player, MemoryStream data, short id, short x, short y, byte homeless)
|
||||
private static bool OnUpdateNPCHome(TSPlayer player, MemoryStream data, short id, short x, short y, byte houseHoldStatus)
|
||||
{
|
||||
if (NPCHome == null)
|
||||
return false;
|
||||
|
|
@ -1345,7 +1355,7 @@ namespace TShockAPI
|
|||
ID = id,
|
||||
X = x,
|
||||
Y = y,
|
||||
Homeless = homeless,
|
||||
HouseholdStatus = (HouseholdStatus) houseHoldStatus,
|
||||
};
|
||||
NPCHome.Invoke(null, args);
|
||||
return args.Handled;
|
||||
|
|
@ -1915,11 +1925,14 @@ namespace TShockAPI
|
|||
args.Player.TPlayer.shirtColor = shirtColor;
|
||||
args.Player.TPlayer.underShirtColor = underShirtColor;
|
||||
args.Player.TPlayer.shoeColor = shoeColor;
|
||||
//@Olink: If you need to change bool[10], please make sure you also update the for loops below to account for it.
|
||||
//There are two arrays from terraria that we only have a single array for. You will need to make sure that you are looking
|
||||
//at the correct terraria array (hideVisual or hideVisual2).
|
||||
args.Player.TPlayer.hideVisibleAccessory = new bool[10];
|
||||
for (int i = 0; i < 8; i++)
|
||||
args.Player.TPlayer.hideVisibleAccessory[i] = hideVisual[i];
|
||||
for (int i = 8; i < 10; i++)
|
||||
args.Player.TPlayer.hideVisibleAccessory[i] = hideVisual2[i];
|
||||
for (int i = 0; i < 2; i++)
|
||||
args.Player.TPlayer.hideVisibleAccessory[i+8] = hideVisual2[i];
|
||||
args.Player.TPlayer.hideMisc = hideMisc;
|
||||
args.Player.TPlayer.extraAccessory = extraSlot;
|
||||
NetMessage.SendData((int)PacketTypes.PlayerInfo, -1, args.Player.Index, NetworkText.FromLiteral(args.Player.Name), args.Player.Index);
|
||||
|
|
@ -2322,6 +2335,17 @@ namespace TShockAPI
|
|||
if (OnNewProjectile(args.Data, ident, pos, vel, knockback, dmg, owner, type, index, args.Player))
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -2386,6 +2410,10 @@ namespace TShockAPI
|
|||
}
|
||||
|
||||
args.Player.LastKilledProjectile = type;
|
||||
lock (args.Player.RecentlyCreatedProjectiles)
|
||||
{
|
||||
args.Player.RecentlyCreatedProjectiles.ForEach(s => { if (s.Index == index) { s.Killed = true; } });
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2763,14 +2791,14 @@ namespace TShockAPI
|
|||
return true;
|
||||
}
|
||||
|
||||
private static bool UpdateNPCHome(GetDataHandlerArgs args)
|
||||
private static bool HandleUpdateNPCHome(GetDataHandlerArgs args)
|
||||
{
|
||||
var id = args.Data.ReadInt16();
|
||||
var x = args.Data.ReadInt16();
|
||||
var y = args.Data.ReadInt16();
|
||||
var homeless = args.Data.ReadInt8();
|
||||
var householdStatus = args.Data.ReadInt8();
|
||||
|
||||
if (OnUpdateNPCHome(args.Player, args.Data, id, x, y, homeless))
|
||||
if (OnUpdateNPCHome(args.Player, args.Data, id, x, y, householdStatus))
|
||||
return true;
|
||||
|
||||
if (!args.Player.HasPermission(Permissions.movenpc))
|
||||
|
|
@ -2827,38 +2855,53 @@ namespace TShockAPI
|
|||
string thing;
|
||||
switch (thingType)
|
||||
{
|
||||
case -14:
|
||||
thing = "has sent a request to the bunny delivery service";
|
||||
break;
|
||||
case -13:
|
||||
thing = "has sent a request to the dog delivery service";
|
||||
break;
|
||||
case -12:
|
||||
thing = "has sent a request to the cat delivery service";
|
||||
break;
|
||||
case -11:
|
||||
thing = "applied advanced combat techniques";
|
||||
break;
|
||||
case -10:
|
||||
thing = "summoned a Blood Moon";
|
||||
break;
|
||||
case -8:
|
||||
thing = "a Moon Lord";
|
||||
thing = "summoned a Moon Lord";
|
||||
break;
|
||||
case -7:
|
||||
thing = "a Martian invasion";
|
||||
thing = "summoned a Martian invasion";
|
||||
break;
|
||||
case -6:
|
||||
thing = "an eclipse";
|
||||
thing = "summoned an eclipse";
|
||||
break;
|
||||
case -5:
|
||||
thing = "a frost moon";
|
||||
thing = "summoned a frost moon";
|
||||
break;
|
||||
case -4:
|
||||
thing = "a pumpkin moon";
|
||||
thing = "summoned a pumpkin moon";
|
||||
break;
|
||||
case -3:
|
||||
thing = "the Pirates";
|
||||
thing = "summoned the Pirates";
|
||||
break;
|
||||
case -2:
|
||||
thing = "the Snow Legion";
|
||||
thing = "summoned the Snow Legion";
|
||||
break;
|
||||
case -1:
|
||||
thing = "a Goblin Invasion";
|
||||
thing = "summoned a Goblin Invasion";
|
||||
break;
|
||||
default:
|
||||
thing = String.Format("the {0}", npc.FullName);
|
||||
thing = String.Format("summoned the {0}", npc.FullName);
|
||||
break;
|
||||
}
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -3084,6 +3127,144 @@ namespace TShockAPI
|
|||
|
||||
private static bool HandleLoadNetModule(GetDataHandlerArgs args)
|
||||
{
|
||||
short moduleId = args.Data.ReadInt16();
|
||||
if (moduleId == (int)NetModulesTypes.CreativePowers)
|
||||
{
|
||||
CreativePowerTypes powerId = (CreativePowerTypes)args.Data.ReadInt16();
|
||||
switch (powerId)
|
||||
{
|
||||
case CreativePowerTypes.FreezeTime:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_timefreeze))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to freeze the time of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.SetDawn:
|
||||
case CreativePowerTypes.SetNoon:
|
||||
case CreativePowerTypes.SetDusk:
|
||||
case CreativePowerTypes.SetMidnight:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_timeset))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the time of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.Godmode:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_godmode))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to toggle godmode!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.WindStrength:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_windstrength))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the wind strength of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.RainStrength:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_rainstrength))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the rain strength of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.TimeSpeed:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_timespeed))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the time speed of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.RainFreeze:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_rainfreeze))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to freeze the rain strength of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.WindFreeze:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_windfreeze))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to freeze the wind strength of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.IncreasePlacementRange:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_placementrange))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the tile placement range of your character!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.WorldDifficulty:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_setdifficulty))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the world dificulty of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.BiomeSpreadFreeze:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_biomespreadfreeze))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to freeze the biome spread of server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.SetSpawnRate:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_setspawnrate))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the NPC spawn rate of server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (moduleId == (int)NetModulesTypes.CreativeUnlocksPlayerReport)
|
||||
{
|
||||
var unknownField = args.Data.ReadByte();
|
||||
|
||||
if (unknownField == 0) //this is required or something???
|
||||
{
|
||||
var itemId = args.Data.ReadUInt16();
|
||||
var amount = args.Data.ReadUInt16();
|
||||
|
||||
var totalSacrificed = TShock.ResearchDatastore.SacrificeItem(itemId, amount, args.Player);
|
||||
|
||||
var response = NetCreativeUnlocksModule.SerializeItemSacrifice(itemId, totalSacrificed);
|
||||
NetManager.Instance.Broadcast(response);
|
||||
}
|
||||
}
|
||||
|
||||
// As of 1.4.x.x, this is now used for more things:
|
||||
// NetCreativePowersModule
|
||||
// NetCreativePowerPermissionsModule
|
||||
|
|
@ -3446,6 +3627,30 @@ namespace TShockAPI
|
|||
{ 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>
|
||||
{
|
||||
{ItemID.RopeCoil, TileID.Rope},
|
||||
|
|
@ -3461,5 +3666,46 @@ namespace TShockAPI
|
|||
{
|
||||
{TileID.MinecartTrack, 3}
|
||||
};
|
||||
|
||||
internal struct ProjectileStruct
|
||||
{
|
||||
public int Index { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public bool Killed { get; internal set; }
|
||||
}
|
||||
|
||||
public enum NetModulesTypes
|
||||
{
|
||||
Liquid,
|
||||
Text,
|
||||
Ping,
|
||||
Ambience,
|
||||
Bestiary,
|
||||
CreativeUnlocks,
|
||||
CreativePowers,
|
||||
CreativeUnlocksPlayerReport,
|
||||
TeleportPylon,
|
||||
Particles,
|
||||
CreativePowerPermissions
|
||||
}
|
||||
|
||||
public enum CreativePowerTypes
|
||||
{
|
||||
FreezeTime,
|
||||
SetDawn,
|
||||
SetNoon,
|
||||
SetDusk,
|
||||
SetMidnight,
|
||||
Godmode,
|
||||
WindStrength,
|
||||
RainStrength,
|
||||
TimeSpeed,
|
||||
RainFreeze,
|
||||
WindFreeze,
|
||||
IncreasePlacementRange,
|
||||
WorldDifficulty,
|
||||
BiomeSpreadFreeze,
|
||||
SetSpawnRate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ namespace TShockAPI
|
|||
/// <summary>Contains the permission nodes used in TShock.</summary>
|
||||
public static class Permissions
|
||||
{
|
||||
// tshock.account nodes
|
||||
|
||||
#region tshock.account nodes
|
||||
[Description("User can register account in game.")]
|
||||
public static readonly string canregister = "tshock.account.register";
|
||||
|
||||
|
|
@ -44,9 +43,9 @@ namespace TShockAPI
|
|||
|
||||
[Description("User can change password in game.")]
|
||||
public static readonly string canchangepassword = "tshock.account.changepassword";
|
||||
#endregion
|
||||
|
||||
// tshock.admin nodes
|
||||
|
||||
#region tshock.admin nodes
|
||||
[Description("User can set build protection status.")]
|
||||
public static readonly string antibuild = "tshock.admin.antibuild";
|
||||
|
||||
|
|
@ -106,17 +105,17 @@ namespace TShockAPI
|
|||
|
||||
[Description("User can get other users' info.")]
|
||||
public static readonly string userinfo = "tshock.admin.userinfo";
|
||||
#endregion
|
||||
|
||||
// tshock.buff nodes
|
||||
|
||||
#region tshock.buff nodes
|
||||
[Description("User can buff self.")]
|
||||
public static readonly string buff = "tshock.buff.self";
|
||||
|
||||
[Description("User can buff other players.")]
|
||||
public static readonly string buffplayer = "tshock.buff.others";
|
||||
#endregion
|
||||
|
||||
// tshock.cfg nodes
|
||||
|
||||
#region tshock.cfg nodes
|
||||
[Description("User is notified when an update is available, user can turn off / restart the server.")]
|
||||
public static readonly string maintenance = "tshock.cfg.maintenance";
|
||||
|
||||
|
|
@ -131,9 +130,9 @@ namespace TShockAPI
|
|||
|
||||
[Description("User can create reference files of Terraria IDs and the permission matrix in the server folder.")]
|
||||
public static readonly string createdumps = "tshock.cfg.createdumps";
|
||||
#endregion
|
||||
|
||||
// tshock.ignore nodes
|
||||
|
||||
#region tshock.ignore nodes
|
||||
[Description("Prevents you from being reverted by kill tile abuse detection.")]
|
||||
public static readonly string ignorekilltiledetection = "tshock.ignore.removetile";
|
||||
|
||||
|
|
@ -169,9 +168,9 @@ namespace TShockAPI
|
|||
|
||||
[Description("Prevents you from being disabled by abnormal MP.")]
|
||||
public static readonly string ignoremp = "tshock.ignore.mp";
|
||||
#endregion
|
||||
|
||||
// tshock.item nodes
|
||||
|
||||
#region tshock.item nodes
|
||||
[Description("User can give items.")]
|
||||
public static readonly string give = "tshock.item.give";
|
||||
|
||||
|
|
@ -180,9 +179,9 @@ namespace TShockAPI
|
|||
|
||||
[Description("Allows you to use banned items.")]
|
||||
public static readonly string usebanneditem = "tshock.item.usebanned";
|
||||
#endregion
|
||||
|
||||
// tshock.npc nodes
|
||||
|
||||
#region tshock.npc nodes
|
||||
[Description("User can edit the max spawns.")]
|
||||
public static readonly string maxspawns = "tshock.npc.maxspawns";
|
||||
|
||||
|
|
@ -227,9 +226,9 @@ namespace TShockAPI
|
|||
|
||||
[Description("Allows a user to elevate to superadmin for 10 minutes.")]
|
||||
public static readonly string su = "tshock.su";
|
||||
#endregion
|
||||
|
||||
// tshock.tp nodes
|
||||
|
||||
#region tshock.tp nodes
|
||||
[Description("User can teleport *everyone* to them.")]
|
||||
public static readonly string tpallothers = "tshock.tp.allothers";
|
||||
|
||||
|
|
@ -268,9 +267,9 @@ namespace TShockAPI
|
|||
|
||||
[Description("User can use wormhole potions.")]
|
||||
public static readonly string wormhole = "tshock.tp.wormhole";
|
||||
#endregion
|
||||
|
||||
// tshock.world nodes
|
||||
|
||||
#region tshock.world nodes
|
||||
[Description("User can use the 'worldevent' command")]
|
||||
public static readonly string manageevents = "tshock.world.events";
|
||||
|
||||
|
|
@ -372,9 +371,47 @@ namespace TShockAPI
|
|||
|
||||
[Description("Player can toggle party event.")]
|
||||
public static readonly string toggleparty = "tshock.world.toggleparty";
|
||||
#endregion
|
||||
|
||||
// Non-grouped
|
||||
#region tshock.journey nodes
|
||||
[Description("User can use Creative UI freeze time.")]
|
||||
public static readonly string journey_timefreeze = "tshock.journey.time.freeze";
|
||||
|
||||
[Description("User can use Creative UI to set world time.")]
|
||||
public static readonly string journey_timeset = "tshock.journey.time.set";
|
||||
|
||||
[Description("User can use Creative UI to set world time speed.")]
|
||||
public static readonly string journey_timespeed = "tshock.journey.time.setspeed";
|
||||
|
||||
[Description("User can use Creative UI to to toggle character godmode.")]
|
||||
public static readonly string journey_godmode = "tshock.journey.godmode";
|
||||
|
||||
[Description("User can use Creative UI to set world wind strength/seed.")]
|
||||
public static readonly string journey_windstrength = "tshock.journey.wind.strength";
|
||||
|
||||
[Description("User can use Creative UI to stop the world wind strength from changing.")]
|
||||
public static readonly string journey_windfreeze = "tshock.journey.wind.freeze";
|
||||
|
||||
[Description("User can use Creative UI to set world rain strength/seed.")]
|
||||
public static readonly string journey_rainstrength = "tshock.journey.rain.strength";
|
||||
|
||||
[Description("User can use Creative UI to stop the world rain strength from changing.")]
|
||||
public static readonly string journey_rainfreeze = "tshock.journey.rain.freeze";
|
||||
|
||||
[Description("User can use Creative UI to toggle increased placement range.")]
|
||||
public static readonly string journey_placementrange = "tshock.journey.placementrange";
|
||||
|
||||
[Description("User can use Creative UI to set world difficulty/mode.")]
|
||||
public static readonly string journey_setdifficulty = "tshock.journey.setdifficulty";
|
||||
|
||||
[Description("User can use Creative UI to stop the biome spread of the world.")]
|
||||
public static readonly string journey_biomespreadfreeze = "tshock.journey.biomespreadfreeze";
|
||||
|
||||
[Description("User can use Creative UI to set the NPC spawn rate of the world.")]
|
||||
public static readonly string journey_setspawnrate = "tshock.journey.setspawnrate";
|
||||
#endregion
|
||||
|
||||
#region Non-grouped
|
||||
[Description("User can clear items or projectiles.")]
|
||||
public static readonly string clear = "tshock.clear";
|
||||
|
||||
|
|
@ -428,7 +465,7 @@ namespace TShockAPI
|
|||
|
||||
[Description("Player can see advanced information about any user account.")]
|
||||
public static readonly string advaccountinfo = "tshock.accountinfo.details";
|
||||
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Lists all commands associated with a given permission
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ using Microsoft.Xna.Framework;
|
|||
using Terraria;
|
||||
using TShockAPI;
|
||||
using Terraria.Localization;
|
||||
using Terraria.GameContent.NetModules;
|
||||
using Terraria.Net;
|
||||
using Terraria.ID;
|
||||
|
||||
namespace TShockAPI
|
||||
{
|
||||
|
|
@ -480,6 +483,20 @@ namespace TShockAPI
|
|||
NetMessage.SendData(76, -1, -1, NetworkText.Empty, player.Index);
|
||||
|
||||
NetMessage.SendData(39, player.Index, -1, NetworkText.Empty, 400);
|
||||
|
||||
|
||||
var sacrificedItems = TShock.ResearchDatastore.GetSacrificedItems();
|
||||
for(int i = 0; i < ItemID.Count; i++)
|
||||
{
|
||||
var amount = 0;
|
||||
if (sacrificedItems.ContainsKey(i))
|
||||
{
|
||||
amount = sacrificedItems[i];
|
||||
}
|
||||
|
||||
var response = NetCreativeUnlocksModule.SerializeItemSacrifice(i, amount);
|
||||
NetManager.Instance.SendToClient(response, player.TPlayer.whoAmI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ namespace TShockAPI
|
|||
// These can be caused by an unexpected error such as a bad or out of date plugin
|
||||
try
|
||||
{
|
||||
TShock.Utils.Broadcast("Saving world. Momentary lag might result from this.", Color.Red);
|
||||
TShock.Utils.Broadcast("Saving world...", Color.Yellow);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -130,8 +130,11 @@ namespace TShockAPI
|
|||
}
|
||||
else
|
||||
WorldFile.SaveWorld(task.resetTime);
|
||||
|
||||
if (TShock.Config.AnnounceSave)
|
||||
TShock.Utils.Broadcast("World saved.", Color.Yellow);
|
||||
TShock.Log.Info(string.Format("World saved at ({0})", Main.worldPathName));
|
||||
|
||||
TShock.Log.Info(string.Format("World saved at ({0})", Main.worldPathName));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -764,6 +764,12 @@ namespace TShockAPI
|
|||
/// </summary>
|
||||
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>
|
||||
/// The current region this player is in, or null if none.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -57,7 +57,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 = "Go to sleep Patrikkk, Icy, Chris, Death, Axeel, Zaicon, hakusaro, and Yoraiz0r <3";
|
||||
public static readonly string VersionCodename = "Go to sleep Patrikkk, Icy, Chris, Death, Axeel, Zaicon, hakusaro, Zack, and Yoraiz0r <3";
|
||||
|
||||
/// <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";
|
||||
|
|
@ -100,6 +100,8 @@ namespace TShockAPI
|
|||
public static RememberedPosManager RememberedPos;
|
||||
/// <summary>CharacterDB - Static reference to the SSC character manager.</summary>
|
||||
public static CharacterManager CharacterDB;
|
||||
/// <summary>Contains the information about what research has been performed in Journey mode.</summary>
|
||||
public static ResearchDatastore ResearchDatastore;
|
||||
/// <summary>Config - Static reference to the config system, for accessing values set in users' config files.</summary>
|
||||
public static ConfigFile Config { get; set; }
|
||||
/// <summary>ServerSideCharacterConfig - Static reference to the server side character config, for accessing values set by users to modify SSC.</summary>
|
||||
|
|
@ -324,6 +326,7 @@ namespace TShockAPI
|
|||
TileBans = new TileManager(DB);
|
||||
RememberedPos = new RememberedPosManager(DB);
|
||||
CharacterDB = new CharacterManager(DB);
|
||||
ResearchDatastore = new ResearchDatastore(DB);
|
||||
RestApi = new SecureRest(Netplay.ServerIP, Config.RestApiPort);
|
||||
RestManager = new RestManager(RestApi);
|
||||
RestManager.RegisterRestfulCommands();
|
||||
|
|
@ -1065,6 +1068,8 @@ namespace TShockAPI
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bouncer.OnSecondUpdate();
|
||||
Utils.SetConsoleTitle(false);
|
||||
}
|
||||
|
||||
|
|
@ -1620,6 +1625,32 @@ namespace TShockAPI
|
|||
e.Handled = true;
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@
|
|||
<Compile Include="CLI\FlagSet.cs" />
|
||||
<Compile Include="DB\ProjectileManager.cs" />
|
||||
<Compile Include="DB\RegionManager.cs" />
|
||||
<Compile Include="DB\ResearchDatastore.cs" />
|
||||
<Compile Include="DB\TileManager.cs" />
|
||||
<Compile Include="Extensions\ExceptionExt.cs" />
|
||||
<Compile Include="Hooks\AccountHooks.cs" />
|
||||
|
|
@ -220,4 +221,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue