Merge branch 'general-devel' into patch-1

This commit is contained in:
Lucas Nicodemus 2025-01-25 23:08:28 +09:00 committed by GitHub
commit 8f5a81014f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 1792 additions and 1015 deletions

View file

@ -1,15 +1,20 @@
# ignore every file # Ignore all Git metadata and build output (in all directories).
* **/.git*
**/bin/
**/obj/
# except for the ones required for building # Ignore other specific files that aren't needed for the build itself.
!i18n/ /.all-contributorsrc
!prebuilts/ /.dockerignore
!TerrariaServerAPI/ /.editorconfig
!TShockAPI/ /.vscode
!TShockLauncher/ /appveyor.yml
!TShockLauncher.Tests/ /COPYING
!TShock.sln /crowdin.yml
/Dockerfile
# but exclude build artifacts /docs
*/bin/ /README.md
*/obj/ /README_cn.md
/renovate.json
/scripts
/SECURITY.md

View file

@ -1,3 +1,5 @@
> By participating in the TShock for Terraria community, all members will adhere to maintaining decorum with respect to all humans, in and out of the community. Members will not engage in discussion that inappropriately disparages or marginalizes any group of people or any individual. Members will not attempt to further or advance an agenda to the point of being overbearing or close minded (such as through spreading FUD). Members will not abuse services provided to them and will follow the guidance of community leaders on a situational basis about what abuse consists of. Members will adhere to United States and international law. If members notice a violation of this code of conduct, they will not engage but will instead contact the leadership team on either the forums or Discord. > By participating in the TShock for Terraria community, all members will adhere to maintaining decorum with respect to all humans, in and out of the community. Members will not engage in discussion that inappropriately disparages or marginalizes any group of people or any individual. Members will not attempt to further or advance an agenda to the point of being overbearing or close minded (such as through spreading FUD). Members will not abuse services provided to them and will follow the guidance of community leaders on a situational basis about what abuse consists of. Members will adhere to United States and international law. If members notice a violation of this code of conduct, they will not engage but will instead contact the leadership team on either the forums or Discord.
> Do not attempt to circumvent or bypass the code of conduct by using clever logic or reasoning (e.g., insulting Facepunch members, because they weren't directly mentioned here). > Do not attempt to circumvent or bypass the code of conduct by using clever logic or reasoning (e.g., insulting Facepunch members, because they weren't directly mentioned here).
> Do not abuse GitHub services by generating useless emails to all people who watch the repo. This includes unnecessary PR approvals and off-topic discussion, issue, and PR comments that serve no purpose. Due to the high visibility nature of actions that create emails, you may be blocked temporarily as your first warning.

2
.github/FUNDING.yml vendored
View file

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

60
.github/workflows/ci-docker.yml vendored Normal file
View file

@ -0,0 +1,60 @@
name: CI (Docker image)
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
permissions:
attestations: write
id-token: write
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: 'recursive'
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up buildx
uses: docker/setup-buildx-action@v3
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate version information
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=schedule
type=ref,event=branch
type=ref,event=tag,enable=${{ !startsWith(github.ref, 'refs/tags/v') }}
type=ref,event=pr
type=semver,pattern={{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=semver,pattern={{major}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
flavor: |
latest=${{ startsWith(github.ref, 'refs/tags/v') }}
- name: Build image
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7,windows/amd64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
pull: true
cache-from: type=gha, scope=${{ github.workflow }}
cache-to: type=gha, scope=${{ github.workflow }}
- name: Generate build provenance attestation
if: ${{ github.event_name != 'pull_request' }}
uses: actions/attest-build-provenance@v2
with:
subject-name: ghcr.io/${{ github.repository }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true

View file

@ -1,10 +1,8 @@
ARG TARGETPLATFORM=linux/amd64 # TARGETPLATFORM and BUILDPLATFORM are automatically filled in by Docker buildx.
ARG BUILDPLATFORM=${TARGETPLATFORM} # They should not be set in the global scope manually.
FROM --platform=${BUILDPLATFORM} mcr.microsoft.com/dotnet/sdk:6.0 AS builder FROM --platform=${BUILDPLATFORM} mcr.microsoft.com/dotnet/sdk:6.0 AS builder
ARG TARGETPLATFORM
# Copy build context # Copy build context
WORKDIR /TShock WORKDIR /TShock
COPY . ./ COPY . ./
@ -12,6 +10,10 @@ COPY . ./
# Build and package release based on target architecture # Build and package release based on target architecture
RUN dotnet build -v m RUN dotnet build -v m
WORKDIR /TShock/TShockLauncher WORKDIR /TShock/TShockLauncher
# Make TARGETPLATFORM available to the container.
ARG TARGETPLATFORM
RUN \ RUN \
case "${TARGETPLATFORM}" in \ case "${TARGETPLATFORM}" in \
"linux/amd64") export ARCH="linux-x64" \ "linux/amd64") export ARCH="linux-x64" \

View file

@ -1,5 +1,5 @@
<p align="center"> <p align="center">
<img src="https://tshock.co/newlogo.png" alt="TShock for Terraria"><br /> <img src="https://tshock.s3.us-west-001.backblazeb2.com/newlogo.png" alt="TShock for Terraria"><br />
<a href="https://ci.appveyor.com/project/hakusaro/tshock"> <a href="https://ci.appveyor.com/project/hakusaro/tshock">
<img src="https://ci.appveyor.com/api/projects/status/chhe61q227lqdlg1?svg=true" alt="AppVeyor Build Status"> <img src="https://ci.appveyor.com/api/projects/status/chhe61q227lqdlg1?svg=true" alt="AppVeyor Build Status">
</a> </a>

View file

@ -1,5 +1,5 @@
<p align="center"> <p align="center">
<img src="https://tshock.co/newlogo.png" alt="TShock for Terraria"><br /> <img src="https://tshock.s3.us-west-001.backblazeb2.com/newlogo.png" alt="TShock for Terraria"><br />
<a href="https://ci.appveyor.com/project/hakusaro/tshock"> <a href="https://ci.appveyor.com/project/hakusaro/tshock">
<img src="https://ci.appveyor.com/api/projects/status/chhe61q227lqdlg1?svg=true" alt="AppVeyor Build Status"> <img src="https://ci.appveyor.com/api/projects/status/chhe61q227lqdlg1?svg=true" alt="AppVeyor Build Status">
</a> </a>

View file

@ -2659,9 +2659,12 @@ namespace TShockAPI
* If the player was not specified, that is, the player index is -1, then it is definitely a custom cause, as you can only deal damage with a projectile or another player. * If the player was not specified, that is, the player index is -1, then it is definitely a custom cause, as you can only deal damage with a projectile or another player.
* This is how everything else works. If an NPC is specified, its value is not -1, which is a custom cause. * This is how everything else works. If an NPC is specified, its value is not -1, which is a custom cause.
* *
* An exception to this is damage dealt by the Inferno potion to other players -- it is only identified by the other index value of 16,
* even lacking a source player index.
*
* Checking whether this damage came from the player is necessary, because the damage from the player can come even when it is hit by a NPC * Checking whether this damage came from the player is necessary, because the damage from the player can come even when it is hit by a NPC
*/ */
if (TShock.Config.Settings.DisableCustomDeathMessages && id != args.Player.Index && if (TShock.Config.Settings.DisableCustomDeathMessages && id != args.Player.Index && reason._sourceOtherIndex != 16 &&
(reason._sourcePlayerIndex == -1 || reason._sourceNPCIndex != -1 || reason._sourceOtherIndex != -1 || reason._sourceCustomReason != null)) (reason._sourcePlayerIndex == -1 || reason._sourceNPCIndex != -1 || reason._sourceOtherIndex != -1 || reason._sourceCustomReason != null))
{ {
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerDamage rejected custom death message from {0}", args.Player.Name)); TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerDamage rejected custom death message from {0}", args.Player.Name));
@ -2851,7 +2854,7 @@ namespace TShockAPI
{ BuffID.Poisoned, 3600 }, // BuffID: 20 { BuffID.Poisoned, 3600 }, // BuffID: 20
{ BuffID.OnFire, 1200 }, // BuffID: 24 { BuffID.OnFire, 1200 }, // BuffID: 24
{ BuffID.Confused, short.MaxValue }, // BuffID: 31 Brain of Confusion Internal Item ID: 3223 { BuffID.Confused, short.MaxValue }, // BuffID: 31 Brain of Confusion Internal Item ID: 3223
{ BuffID.CursedInferno, 420 }, // BuffID: 39 { BuffID.CursedInferno, 600 }, // BuffID: 39
{ BuffID.Frostburn, 900 }, // BuffID: 44 { BuffID.Frostburn, 900 }, // BuffID: 44
{ BuffID.Ichor, 1200 }, // BuffID: 69 { BuffID.Ichor, 1200 }, // BuffID: 69
{ BuffID.Venom, 1800 }, // BuffID: 70 { BuffID.Venom, 1800 }, // BuffID: 70

View file

@ -6462,7 +6462,7 @@ namespace TShockAPI
if (target == user) if (target == user)
user.SendSuccessMessage(GetString($"You buffed yourself with {TShock.Utils.GetBuffName(id)} ({TShock.Utils.GetBuffDescription(id)}) for {time} seconds.")); user.SendSuccessMessage(GetString($"You buffed yourself with {TShock.Utils.GetBuffName(id)} ({TShock.Utils.GetBuffDescription(id)}) for {time} seconds."));
else else
target.SendSuccessMessage(GetString($"You have buffed {user.Name} with {TShock.Utils.GetBuffName(id)} ({TShock.Utils.GetBuffDescription(id)}) for {time} seconds!")); user.SendSuccessMessage(GetString($"You have buffed {target.Name} with {TShock.Utils.GetBuffName(id)} ({TShock.Utils.GetBuffDescription(id)}) for {time} seconds!"));
if (!args.Silent && target != user) if (!args.Silent && target != user)
target.SendSuccessMessage(GetString($"{user.Name} has buffed you with {TShock.Utils.GetBuffName(id)} ({TShock.Utils.GetBuffDescription(id)}) for {time} seconds!")); target.SendSuccessMessage(GetString($"{user.Name} has buffed you with {TShock.Utils.GetBuffName(id)} ({TShock.Utils.GetBuffDescription(id)}) for {time} seconds!"));
} }
@ -6740,10 +6740,6 @@ namespace TShockAPI
playerToGod.GodMode = !playerToGod.GodMode; playerToGod.GodMode = !playerToGod.GodMode;
var godPower = CreativePowerManager.Instance.GetPower<CreativePowers.GodmodePower>();
godPower.SetEnabledState(playerToGod.Index, playerToGod.GodMode);
if (playerToGod != args.Player) if (playerToGod != args.Player)
{ {
args.Player.SendSuccessMessage(playerToGod.GodMode args.Player.SendSuccessMessage(playerToGod.GodMode

View file

@ -320,8 +320,8 @@ namespace TShockAPI.Configuration
[Description("The reason given if banning a mediumcore player on death.")] [Description("The reason given if banning a mediumcore player on death.")]
public string MediumcoreBanReason = GetString("Death results in a ban"); public string MediumcoreBanReason = GetString("Death results in a ban");
/// <summary>Disbales IP bans by default, if no arguments are passed to the ban command.</summary> /// <summary>Disables IP bans by default, if no arguments are passed to the ban command.</summary>
[Description("Disbales IP bans by default, if no arguments are passed to the ban command.")] [Description("Disables IP bans by default, if no arguments are passed to the ban command.")]
public bool DisableDefaultIPBan; public bool DisableDefaultIPBan;
/// <summary>Enable or disable the whitelist based on IP addresses in the whitelist.txt file.</summary> /// <summary>Enable or disable the whitelist based on IP addresses in the whitelist.txt file.</summary>

View file

@ -189,6 +189,9 @@ namespace TShockAPI.DB
if (!player.IsLoggedIn) if (!player.IsLoggedIn)
return false; return false;
if (player.State < 10)
return false;
if (player.HasPermission(Permissions.bypassssc) && !fromCommand) if (player.HasPermission(Permissions.bypassssc) && !fromCommand)
{ {
TShock.Log.ConsoleInfo(GetParticularString("{0} is a player name", $"Skipping SSC save (due to tshock.ignore.ssc) for {player.Account.Name}")); TShock.Log.ConsoleInfo(GetParticularString("{0} is a player name", $"Skipping SSC save (due to tshock.ignore.ssc) for {player.Account.Name}"));

File diff suppressed because it is too large Load diff

View file

@ -529,18 +529,9 @@ namespace TShockAPI
field.GetCustomAttributes(false).FirstOrDefault(o => o is DescriptionAttribute) as DescriptionAttribute; field.GetCustomAttributes(false).FirstOrDefault(o => o is DescriptionAttribute) as DescriptionAttribute;
var desc = descattr != null && !string.IsNullOrWhiteSpace(descattr.Description) ? descattr.Description : GetString("No description available."); var desc = descattr != null && !string.IsNullOrWhiteSpace(descattr.Description) ? descattr.Description : GetString("No description available.");
var commands = GetCommands(name); var strs = GetCommands(name).Select(c => c.Names.Count > 1
foreach (var c in commands) ? $"/{c.Name} (/{string.Join(" /", c.Names.Skip(1))})"
{ : $"/{c.Name}");
for (var i = 0; i < c.Names.Count; i++)
{
c.Names[i] = "/" + c.Names[i];
}
}
var strs =
commands.Select(
c =>
c.Name + (c.Names.Count > 1 ? " ({0})".SFormat(string.Join(" ", c.Names.ToArray(), 1, c.Names.Count - 1)) : ""));
sb.AppendLine($"## {name}"); sb.AppendLine($"## {name}");
sb.AppendLine($"{desc}"); sb.AppendLine($"{desc}");

View file

@ -34,6 +34,7 @@ using TShockAPI.Hooks;
using TShockAPI.Net; using TShockAPI.Net;
using Timer = System.Timers.Timer; using Timer = System.Timers.Timer;
using System.Linq; using System.Linq;
using Terraria.GameContent.Creative;
namespace TShockAPI namespace TShockAPI
{ {
@ -935,9 +936,15 @@ namespace TShockAPI
public bool LoginHarassed = false; public bool LoginHarassed = false;
/// <summary> /// <summary>
/// Player cant die, unless onehit /// Controls the journey godmode
/// </summary> /// </summary>
public bool GodMode = false; public bool GodMode
{
get =>
CreativePowerManager.Instance.GetPower<CreativePowers.GodmodePower>().IsEnabledForPlayer(Index);
set =>
CreativePowerManager.Instance.GetPower<CreativePowers.GodmodePower>().SetEnabledState(Index, value);
}
/// <summary> /// <summary>
/// Players controls are inverted if using SSC /// Players controls are inverted if using SSC
@ -981,7 +988,7 @@ namespace TShockAPI
get get
{ {
return RealPlayer return RealPlayer
&& (Netplay.Clients[Index] != null && Netplay.Clients[Index].IsActive && !Netplay.Clients[Index].PendingTermination); && (Client != null && Client.IsActive && !Client.PendingTermination);
} }
} }
@ -998,8 +1005,8 @@ namespace TShockAPI
/// </summary> /// </summary>
public int State public int State
{ {
get { return Netplay.Clients[Index].State; } get { return Client.State; }
set { Netplay.Clients[Index].State = value; } set { Client.State = value; }
} }
/// <summary> /// <summary>
@ -1007,7 +1014,7 @@ namespace TShockAPI
/// </summary> /// </summary>
public string UUID public string UUID
{ {
get { return RealPlayer ? Netplay.Clients[Index].ClientUUID : ""; } get { return RealPlayer ? Client.ClientUUID : ""; }
} }
/// <summary> /// <summary>
@ -1019,8 +1026,8 @@ namespace TShockAPI
{ {
if (string.IsNullOrEmpty(CacheIP)) if (string.IsNullOrEmpty(CacheIP))
return return
CacheIP = RealPlayer ? (Netplay.Clients[Index].Socket.IsConnected() CacheIP = RealPlayer ? (Client.Socket.IsConnected()
? TShock.Utils.GetRealIP(Netplay.Clients[Index].Socket.GetRemoteAddress().ToString()) ? TShock.Utils.GetRealIP(Client.Socket.GetRemoteAddress().ToString())
: "") : "")
: "127.0.0.1"; : "127.0.0.1";
else else
@ -1103,6 +1110,11 @@ namespace TShockAPI
} }
/// <summary>
/// Player RemoteClient.
/// </summary>
public RemoteClient Client => Netplay.Clients[Index];
/// <summary> /// <summary>
/// Gets the Terraria Player object associated with the player. /// Gets the Terraria Player object associated with the player.
/// </summary> /// </summary>
@ -1135,6 +1147,11 @@ namespace TShockAPI
get { return TPlayer.team; } get { return TPlayer.team; }
} }
/// <summary>
/// Gets PvP player mode.
/// </summary>
public bool Hostile => TPlayer.hostile;
/// <summary> /// <summary>
/// Gets the player's X coordinate. /// Gets the player's X coordinate.
/// </summary> /// </summary>
@ -1487,6 +1504,41 @@ namespace TShockAPI
return false; return false;
} }
/// <summary>
/// Changes the values of the <see cref="RemoteClient.TileSections"/> array.
/// </summary>
/// <param name="rectangle">The area of the sections you want to set a value to.
/// The minimum size should be set to 200x150. If null, then the entire map is specified.</param>
/// <param name="isLoaded">Is the section loaded.</param>
// The server does not send the player the whole world, it sends it in sections. To do this, it sets up visible and invisible sections.
// If the player was not in any section(Client.TileSections[x, y] == false) then the server will send the missing section of the world.
// This method allows you to simulate what the player has or has not seen these sections.
// For example, we can put some number of earths blocks in some vast area, for example, for the whole world, but the player will not see the changes, because some section is already loaded for him. At this point this method can come into effect! With it we will be able to select some zone and make it both visible and invisible to the player.
// The server will assume that the zone is not loaded on the player, and will resend the data, but with earth blocks.
public void UpdateSection(Rectangle? rectangle = null, bool isLoaded = false)
{
if (rectangle.HasValue)
{
for (int i = Netplay.GetSectionX(rectangle.Value.X); i < Netplay.GetSectionX(rectangle.Value.X + rectangle.Value.Width) && i < Main.maxSectionsX; i++)
{
for (int j = Netplay.GetSectionY(rectangle.Value.Y); j < Netplay.GetSectionY(rectangle.Value.Y + rectangle.Value.Height) && j < Main.maxSectionsY; j++)
{
Client.TileSections[i, j] = isLoaded;
}
}
}
else
{
for (int i = 0; i < Main.maxSectionsX; i++)
{
for (int j = 0; j < Main.maxSectionsY; j++)
{
Client.TileSections[i, j] = isLoaded;
}
}
}
}
/// <summary> /// <summary>
/// Gives an item to the player. Includes banned item spawn prevention to check if the player can spawn the item. /// Gives an item to the player. Includes banned item spawn prevention to check if the player can spawn the item.
/// </summary> /// </summary>
@ -1519,6 +1571,15 @@ namespace TShockAPI
GiveItemByDrop(type, stack, prefix); GiveItemByDrop(type, stack, prefix);
} }
/// <summary>
/// Gives an item to the player.
/// </summary>
/// <param name="item">Item with data to be given to the player.</param>
public virtual void GiveItem(NetItem item)
{
GiveItem(item.NetId, item.Stack, item.PrefixId);
}
private Item EmptySentinelItem = new Item(); private Item EmptySentinelItem = new Item();
private bool Depleted(Item item) private bool Depleted(Item item)
@ -1815,7 +1876,17 @@ namespace TShockAPI
/// <param name="damage">The amount of damage the player will take.</param> /// <param name="damage">The amount of damage the player will take.</param>
public virtual void DamagePlayer(int damage) public virtual void DamagePlayer(int damage)
{ {
NetMessage.SendPlayerHurt(Index, PlayerDeathReason.LegacyDefault(), damage, (new Random()).Next(-1, 1), false, false, 0, -1, -1); DamagePlayer(damage, PlayerDeathReason.LegacyDefault());
}
/// <summary>
/// Wounds the player with the given damage.
/// </summary>
/// <param name="damage">The amount of damage the player will take.</param>
/// <param name="reason">The reason for causing damage to player.</param>
public virtual void DamagePlayer(int damage, PlayerDeathReason reason)
{
NetMessage.SendPlayerHurt(Index, reason, damage, (new Random()).Next(-1, 1), false, false, 0, -1, -1);
} }
/// <summary> /// <summary>
@ -1823,7 +1894,16 @@ namespace TShockAPI
/// </summary> /// </summary>
public virtual void KillPlayer() public virtual void KillPlayer()
{ {
NetMessage.SendPlayerDeath(Index, PlayerDeathReason.LegacyDefault(), 99999, (new Random()).Next(-1, 1), false, -1, -1); KillPlayer(PlayerDeathReason.LegacyDefault());
}
/// <summary>
/// Kills the player.
/// </summary>
/// <param name="reason">Reason for killing a player.</param>
public virtual void KillPlayer(PlayerDeathReason reason)
{
NetMessage.SendPlayerDeath(Index, reason, 99999, (new Random()).Next(-1, 1), false, -1, -1);
} }
/// <summary> /// <summary>
@ -1832,6 +1912,8 @@ namespace TShockAPI
/// <param name="team">The team color index.</param> /// <param name="team">The team color index.</param>
public virtual void SetTeam(int team) public virtual void SetTeam(int team)
{ {
if (team < 0 || team >= Main.teamColor.Length)
throw new ArgumentException("The player's team is not in the range of available.");
Main.player[Index].team = team; Main.player[Index].team = team;
NetMessage.SendData((int)PacketTypes.PlayerTeam, -1, -1, NetworkText.Empty, Index); NetMessage.SendData((int)PacketTypes.PlayerTeam, -1, -1, NetworkText.Empty, Index);
} }
@ -1840,6 +1922,7 @@ namespace TShockAPI
/// Sets the player's pvp. /// Sets the player's pvp.
/// </summary> /// </summary>
/// <param name="mode">The state of the pvp mode.</param> /// <param name="mode">The state of the pvp mode.</param>
/// <param name="withMsg">Whether a chat message about the change should be sent.</param>
public virtual void SetPvP(bool mode, bool withMsg = false) public virtual void SetPvP(bool mode, bool withMsg = false)
{ {
Main.player[Index].hostile = mode; Main.player[Index].hostile = mode;
@ -2064,7 +2147,7 @@ namespace TShockAPI
if (!RealPlayer || !ConnectionAlive) if (!RealPlayer || !ConnectionAlive)
return; return;
Netplay.Clients[Index].Socket.AsyncSend(data, 0, data.Length, Netplay.Clients[Index].ServerWriteCallBack); Client.Socket.AsyncSend(data, 0, data.Length, Client.ServerWriteCallBack);
} }
/// <summary> /// <summary>

View file

@ -63,7 +63,7 @@ namespace TShockAPI
/// <summary>VersionNum - The version number the TerrariaAPI will return back to the API. We just use the Assembly info.</summary> /// <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; 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> /// <summary>VersionCodename - The version codename is displayed when the server starts. Inspired by software codenames conventions.</summary>
public static readonly string VersionCodename = "Thank you, everyone, for your support of TShock all these years! <3"; public static readonly string VersionCodename = "Intensity";
/// <summary>SavePath - This is the path TShock saves its data in. This path is relative to the TerrariaServer.exe (not in ServerPlugins).</summary> /// <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"; public static string SavePath = "tshock";
@ -428,6 +428,8 @@ namespace TShockAPI
Hooks.AccountHooks.AccountDelete += OnAccountDelete; Hooks.AccountHooks.AccountDelete += OnAccountDelete;
Hooks.AccountHooks.AccountCreate += OnAccountCreate; Hooks.AccountHooks.AccountCreate += OnAccountCreate;
On.Terraria.RemoteClient.Reset += RemoteClient_Reset;
GetDataHandlers.InitGetDataHandler(); GetDataHandlers.InitGetDataHandler();
Commands.InitCommands(); Commands.InitCommands();
@ -496,6 +498,12 @@ namespace TShockAPI
} }
} }
private static void RemoteClient_Reset(On.Terraria.RemoteClient.orig_Reset orig, RemoteClient client)
{
client.ClientUUID = null;
orig(client);
}
private static void OnAchievementInitializerLoad(ILContext il) private static void OnAchievementInitializerLoad(ILContext il)
{ {
// Modify AchievementInitializer.Load to remove the Main.netMode == 2 check (occupies the first 4 IL instructions) // Modify AchievementInitializer.Load to remove the Main.netMode == 2 check (occupies the first 4 IL instructions)
@ -676,17 +684,13 @@ namespace TShockAPI
if (args.Chest != null) if (args.Chest != null)
{ {
// After checking for protected regions, no further range checking is necessarily because the client packet only specifies the
// inventory slot to quick stack. The vanilla Terraria server itself determines what chests are close enough to the player.
if (Config.Settings.RegionProtectChests && !Regions.CanBuild((int)args.WorldPosition.X, (int)args.WorldPosition.Y, tsplr)) if (Config.Settings.RegionProtectChests && !Regions.CanBuild((int)args.WorldPosition.X, (int)args.WorldPosition.Y, tsplr))
{ {
args.Handled = true; args.Handled = true;
return; return;
} }
if (!tsplr.IsInRange(args.Chest.x, args.Chest.y))
{
args.Handled = true;
return;
}
} }
} }

View file

@ -18,11 +18,11 @@
Also, be sure to release on github with the exact assembly version tag as below Also, be sure to release on github with the exact assembly version tag as below
so that the update manager works correctly (via the Github releases api and mimic) so that the update manager works correctly (via the Github releases api and mimic)
--> -->
<Version>5.1.3</Version> <Version>5.2.1</Version>
<AssemblyTitle>TShock for Terraria</AssemblyTitle> <AssemblyTitle>TShock for Terraria</AssemblyTitle>
<Company>Pryaxis &amp; TShock Contributors</Company> <Company>Pryaxis &amp; TShock Contributors</Company>
<Product>TShockAPI</Product> <Product>TShockAPI</Product>
<Copyright>Copyright © Pryaxis &amp; TShock Contributors 2011-2022</Copyright> <Copyright>Copyright © Pryaxis &amp; TShock Contributors 2011-2023</Copyright>
<!-- extras for nuget --> <!-- extras for nuget -->
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
@ -34,7 +34,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" /> <PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="GetText.NET" Version="1.7.14" /> <PackageReference Include="GetText.NET" Version="1.7.14" />
<PackageReference Include="MySql.Data" Version="8.0.31" /> <PackageReference Include="MySql.Data" Version="8.4.0" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.11" /> <PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.11" />
</ItemGroup> </ItemGroup>

View file

@ -29,7 +29,8 @@ namespace TShockAPI
/// </summary> /// </summary>
public class TextLog : ILog, IDisposable public class TextLog : ILog, IDisposable
{ {
private readonly StreamWriter _logWriter; private readonly bool ClearFile;
private StreamWriter _logWriter;
/// <summary> /// <summary>
/// File name of the Text log /// File name of the Text log
@ -44,7 +45,7 @@ namespace TShockAPI
public TextLog(string filename, bool clear) public TextLog(string filename, bool clear)
{ {
FileName = filename; FileName = filename;
_logWriter = new StreamWriter(filename, !clear); ClearFile = clear;
} }
public bool MayWriteType(TraceLevel type) public bool MayWriteType(TraceLevel type)
@ -247,6 +248,10 @@ namespace TShockAPI
{ {
if (!MayWriteType(level)) if (!MayWriteType(level))
return; return;
if (_logWriter is null)
{
_logWriter = new StreamWriter(FileName, !ClearFile);
}
var caller = "TShock"; var caller = "TShock";
@ -278,7 +283,10 @@ namespace TShockAPI
public void Dispose() public void Dispose()
{ {
_logWriter.Dispose(); if (_logWriter != null)
{
_logWriter.Dispose();
}
} }
} }
} }

View file

@ -330,7 +330,7 @@ namespace TShockAPI
/// <returns>The item represented by the tag.</returns> /// <returns>The item represented by the tag.</returns>
public Item GetItemFromTag(string tag) public Item GetItemFromTag(string tag)
{ {
Regex regex = new Regex(@"\[i(tem)?(?:\/s(?<Stack>\d{1,3}))?(?:\/p(?<Prefix>\d{1,3}))?:(?<NetID>-?\d{1,4})\]"); Regex regex = new Regex(@"\[i(tem)?(?:\/s(?<Stack>\d{1,4}))?(?:\/p(?<Prefix>\d{1,3}))?:(?<NetID>-?\d{1,4})\]");
Match match = regex.Match(tag); Match match = regex.Match(tag);
if (!match.Success) if (!match.Success)
return null; return null;

View file

@ -12,6 +12,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="SharpZipLib" Version="1.4.1" /> <PackageReference Include="SharpZipLib" Version="1.4.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -30,7 +30,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" /> <PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="MySql.Data" Version="8.0.31" /> <PackageReference Include="MySql.Data" Version="8.4.0" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.11" /> <PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.11" />
<PackageReference Include="ModFramework" Version="1.1.7" GeneratePathProperty="true" /> <!-- only used to extract out to ./bin. --> <PackageReference Include="ModFramework" Version="1.1.7" GeneratePathProperty="true" /> <!-- only used to extract out to ./bin. -->
<PackageReference Include="GetText.NET" Version="1.7.14" /> <!-- only used to extract out to ./bin. --> <PackageReference Include="GetText.NET" Version="1.7.14" /> <!-- only used to extract out to ./bin. -->

View file

@ -7,8 +7,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NuGet.Packaging" Version="6.3.1" /> <PackageReference Include="NuGet.Packaging" Version="6.3.4" />
<PackageReference Include="NuGet.Protocol" Version="6.3.1" /> <PackageReference Include="NuGet.Protocol" Version="6.3.3" />
<PackageReference Include="NuGet.Resolver" Version="6.3.1" /> <PackageReference Include="NuGet.Resolver" Version="6.3.1" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" /> <PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageReference Include="System.Reflection.MetadataLoadContext" Version="6.0.0" /> <PackageReference Include="System.Reflection.MetadataLoadContext" Version="6.0.0" />

@ -1 +1 @@
Subproject commit e0e2df24dbc618683cc75595c59bf7f88acada08 Subproject commit 8a3fffd71db401736ea80619122c70c449c10ff3

View file

@ -78,7 +78,31 @@ Use past tense when adding new entries; sign your name off when you add or chang
* If there is no section called "Upcoming changes" below this line, please add one with `## Upcoming changes` as the first line, and then a bulleted item directly after with the first change. --> * If there is no section called "Upcoming changes" below this line, please add one with `## Upcoming changes` as the first line, and then a bulleted item directly after with the first change. -->
## Upcoming changes ## Upcoming changes
* An additional option `pvpwithnoteam` is added at `PvPMode` to enable PVP with no team.(@CelestialAnarchy, #2617, @ATFGK) * Fixed `/dump-reference-data` mutate the command names. (#2943, @sgkoishi)
* You know the drill
* Fix typo in config for IP bans. (@redchess64)
* Fixed unable to transfer long response body for REST API. (@sgkoishi, #2925)
## TShock 5.2.1
* Updated `TSPlayer.GodMode`. (@AgaSpace)
* Previously the field was used as some kind of dataset changed by /godmode command, but now it is a property that receives/changes data in journey mode.
* Added the `TSPlayer.Client` property. It allows the developer to get the `RemoteClient` player, without an additional call to `Terraria.Netplay.Clients`. (@AgaSpace)
* Updated the documentation for the `TSPlayer.SetPvP` method. The `sendMsg` parameter, which is responsible for sending a pvp mode change message, was not documented earlier. (@AgaSpace)
* Added methods `TSPlayer.KillPlayer` and `TSPlayer.DamagePlayer` for which you can specify the cause (`PlayerDeathReason`) in parameters. (@AgaSpace)
* Added an error when trying to change a `TSPlayer` team to, say, 9, when there are only 6. (@AgaSpace)
* Added an error when trying to call the `TSPlayer.SetTeam` method with an argument (team) greater than 5 or less than 0. (@AgaSpace)
* Added a method `TSPlayer.UpdateSection` with arguments `rectangle` and `isLoaded`, which will load some area from the server to the player. (@AgaSpace)
* Added a method `TSPlayer.GiveItem`, which has `TShockAPI.NetItem` structure in its arguments. (@AgaSpace)
* Added a property `TSPlayer.Hostile`, which gets pvp player mode. (@AgaSpace)
* Fixed bug where when the `UseSqlLogs` config property is true, an empty log file would still get created. (@ZakFahey)
* Fixed typo in `/gbuff`. (@sgkoishi, #2955)
* Rewrote the `.dockerignore` file into a denylist. (@timschumi)
* Added CI for Docker images. (@timschumi)
* Fixed Cursed Flares kicking players for invalid buff. (@Arthri)
* Added automatic publishing of Docker images to GHCR. (@timschumi)
## TShock 5.2
* An additional option `pvpwithnoteam` is added at `PvPMode` to enable PVP with no team. (@CelestialAnarchy, #2617, @ATFGK)
* Corrected and updated deserialization of the following packets (@ATFGK): * Corrected and updated deserialization of the following packets (@ATFGK):
* `ProjectileNew`: Read the third `AI` value. * `ProjectileNew`: Read the third `AI` value.
* Before this change, it was previously possible for the projectile damage limit to falsely trigger, such as when using the Terra Balde and Fire Gauntlet together. * Before this change, it was previously possible for the projectile damage limit to falsely trigger, such as when using the Terra Balde and Fire Gauntlet together.
@ -106,7 +130,6 @@ Use past tense when adding new entries; sign your name off when you add or chang
* Allowed multiple test cases to be in TShock's test suite. (@drunderscore) * Allowed multiple test cases to be in TShock's test suite. (@drunderscore)
* Fixed unable to use Purification/Evil Powder in jungle. (@sgkoishi) * Fixed unable to use Purification/Evil Powder in jungle. (@sgkoishi)
* Set the `GetDataHandledEventArgs.Player` property for the `SyncTilePicking` data handler. (@drunderscore) * Set the `GetDataHandledEventArgs.Player` property for the `SyncTilePicking` data handler. (@drunderscore)
* Fixed unable to transfer long response body for REST API. (@sgkoishi, #2925)
## TShock 5.1.3 ## TShock 5.1.3
* Added support for Terraria 1.4.4.9 via OTAPI 3.1.20. (@SignatureBeef) * Added support for Terraria 1.4.4.9 via OTAPI 3.1.20. (@SignatureBeef)

View file

@ -14,32 +14,27 @@ Open ports can also be passed through using `-p <host_port>:<container_port>`.
For Example: For Example:
```bash ```bash
# Building the image
docker build -t tshock:linux-amd64 --build-arg TARGETPLATFORM=linux/amd64 .
# Running the image
docker run -p 7777:7777 -p 7878:7878 \ docker run -p 7777:7777 -p 7878:7878 \
-v /home/cider/tshock/:/tshock \ -v /home/cider/tshock/:/tshock \
-v /home/cider/.local/share/Terraria/Worlds:/worlds \ -v /home/cider/.local/share/Terraria/Worlds:/worlds \
-v /home/cider/tshock/plugins:/plugins \ -v /home/cider/tshock/plugins:/plugins \
--rm -it tshock:linux-amd64 \ --rm -it ghcr.io/pryaxis/tshock:latest \
-world /worlds/backflip.wld -motd "OMFG DOCKER" -world /worlds/backflip.wld -motd "OMFG DOCKER"
``` ```
## Building for Other Platforms ## Building custom images
Using `docker buildx`, you could build [multi-platform images](https://docs.docker.com/build/building/multi-platform/) for TShock. Occasionally, it may be necessary to adjust TShock with customizations that are not included in the upstream project.
Therefore, these changes are also not available in the officially provided Docker images.
To build and load a Docker image from your local checkout, use the following `buildx` command:
For Example:
```bash ```bash
# Building the image using buildx and loading it into docker docker buildx build -t tshock:latest --load .
sudo docker buildx build -t tshock:linux-arm64 --platform linux/arm64 --load . ```
# Running the image It is also possible to build [multi-platform images](https://docs.docker.com/build/building/multi-platform/) for TShock (e.g. an image targeting `arm64`, on a host that is not `arm64`):
docker run -p 7777:7777 -p 7878:7878 \
-v /home/cider/tshock/:/tshock \ ```bash
-v /home/cider/.local/share/Terraria/Worlds:/worlds \ docker buildx build -t tshock:linux-arm64 --platform linux/arm64 --load .
-v /home/cider/tshock/plugins:/plugins \
--rm -it tshock:linux-arm64 \
-world /worlds/backflip.wld -motd "ARM64 ftw"
``` ```

File diff suppressed because it is too large Load diff

View file

@ -1,17 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
],
"git-submodules": {
"enabled": true
},
"packageRules": [
{
"matchPackageNames": ["OTAPI.Upcoming", "ModFramework", "TerrariaServerAPI"],
"ignoreUnstable": "false",
"bumpVersion": "prerelease",
"groupName": "OTAPI things"
}
]
}