Merge branch 'general-devel' into player-data
This commit is contained in:
commit
16ec98f684
6 changed files with 120 additions and 23 deletions
|
|
@ -85,6 +85,9 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
|
||||||
* Removed `TSPlayer.InitSpawn` field. (@DankRank)
|
* Removed `TSPlayer.InitSpawn` field. (@DankRank)
|
||||||
* `OnPlayerSpawn`'s player ID field is now `PlayerId`. (@DankRank)
|
* `OnPlayerSpawn`'s player ID field is now `PlayerId`. (@DankRank)
|
||||||
* Fixed null reference console spam in non-SSC mode (@QuiCM)
|
* Fixed null reference console spam in non-SSC mode (@QuiCM)
|
||||||
|
* `Utils.TryParseTime` can now take spaces (e.g., `3d 5h 2m 3s`) (@QuiCM)
|
||||||
|
* Enabled banning unregistered users (@QuiCM)
|
||||||
|
* Added filtering and validation on packet 96 (Teleport player through portal) (@QuiCM)
|
||||||
|
|
||||||
## TShock 4.3.25
|
## TShock 4.3.25
|
||||||
* Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6.
|
* Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6.
|
||||||
|
|
|
||||||
|
|
@ -155,9 +155,10 @@ You need to re-run the patcher any time `OTAPI` updates. You need to rebuild `Te
|
||||||
|
|
||||||
1. You need to get NuGet. Download the latest `nuget.exe` from [NuGet](https://www.nuget.org/downloads).
|
1. You need to get NuGet. Download the latest `nuget.exe` from [NuGet](https://www.nuget.org/downloads).
|
||||||
|
|
||||||
1. Make a `~/bin` folder if you don't have one.
|
1. Make a `~/bin` folder if you don't have one. Then, put `nuget.exe` inside it.
|
||||||
|
|
||||||
$ mkdir ~/bin/
|
$ mkdir ~/bin/
|
||||||
|
$ cp ~/downloads/nuget.exe ~/bin/
|
||||||
|
|
||||||
1. Set an environment variable to store if you plan to build in debug or release.
|
1. Set an environment variable to store if you plan to build in debug or release.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ namespace TShockAPI
|
||||||
GetDataHandlers.HealOtherPlayer += OnHealOtherPlayer;
|
GetDataHandlers.HealOtherPlayer += OnHealOtherPlayer;
|
||||||
GetDataHandlers.TileEdit += OnTileEdit;
|
GetDataHandlers.TileEdit += OnTileEdit;
|
||||||
GetDataHandlers.MassWireOperation += OnMassWireOperation;
|
GetDataHandlers.MassWireOperation += OnMassWireOperation;
|
||||||
|
GetDataHandlers.PortalTeleport += OnPlayerPortalTeleport;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnGetSection(object sender, GetDataHandlers.GetSectionEventArgs args)
|
internal void OnGetSection(object sender, GetDataHandlers.GetSectionEventArgs args)
|
||||||
|
|
@ -1721,6 +1722,34 @@ namespace TShockAPI
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void OnPlayerPortalTeleport(object sender, GetDataHandlers.TeleportThroughPortalEventArgs args)
|
||||||
|
{
|
||||||
|
//Packet 96 (player teleport through portal) has no validation on whether or not the player id provided
|
||||||
|
//belongs to the player who sent the packet.
|
||||||
|
if (args.Player.Index != args.TargetPlayerIndex)
|
||||||
|
{
|
||||||
|
//If the player who sent the packet is not the player being teleported, cancel this packet
|
||||||
|
args.Player.Disable("Malicious portal attempt.", DisableFlags.WriteToLogAndConsole); //Todo: this message is not particularly clear - suggestions wanted
|
||||||
|
args.Handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generic bounds checking, though I'm not sure if anyone would willingly hack themselves outside the map?
|
||||||
|
if (args.NewPosition.X > Main.maxTilesX || args.NewPosition.X < 0
|
||||||
|
|| args.NewPosition.Y > Main.maxTilesY || args.NewPosition.Y < 0)
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//May as well reject teleport attempts if the player is being throttled
|
||||||
|
if (args.Player.IsBeingDisabled() || args.Player.IsBouncerThrottled())
|
||||||
|
{
|
||||||
|
args.Handled = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tile IDs that can be oriented:
|
/// Tile IDs that can be oriented:
|
||||||
/// Cannon,
|
/// Cannon,
|
||||||
|
|
@ -1762,4 +1791,4 @@ namespace TShockAPI
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1309,16 +1309,20 @@ namespace TShockAPI
|
||||||
|
|
||||||
// Effective ban target assignment
|
// Effective ban target assignment
|
||||||
List<TSPlayer> players = TSPlayer.FindByNameOrID(args.Parameters[1]);
|
List<TSPlayer> players = TSPlayer.FindByNameOrID(args.Parameters[1]);
|
||||||
|
|
||||||
|
// Bad case: Players contains more than 1 person so we can't ban them
|
||||||
|
if (players.Count > 1)
|
||||||
|
{
|
||||||
|
//Fail fast
|
||||||
|
args.Player.SendMultipleMatchError(players.Select(p => p.Name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
UserAccount offlineUserAccount = TShock.UserAccounts.GetUserAccountByName(args.Parameters[1]);
|
UserAccount offlineUserAccount = TShock.UserAccounts.GetUserAccountByName(args.Parameters[1]);
|
||||||
|
|
||||||
// Storage variable to determine if the command executor is the server console
|
// Storage variable to determine if the command executor is the server console
|
||||||
// If it is, we assume they have full control and let them override permission checks
|
// If it is, we assume they have full control and let them override permission checks
|
||||||
bool callerIsServerConsole = false;
|
bool callerIsServerConsole = args.Player is TSServerPlayer;
|
||||||
|
|
||||||
if (args.Player is TSServerPlayer)
|
|
||||||
{
|
|
||||||
callerIsServerConsole = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The ban reason the ban is going to have
|
// The ban reason the ban is going to have
|
||||||
string banReason = "Unknown.";
|
string banReason = "Unknown.";
|
||||||
|
|
@ -1331,16 +1335,18 @@ namespace TShockAPI
|
||||||
if (args.Parameters.Count >= 3)
|
if (args.Parameters.Count >= 3)
|
||||||
{
|
{
|
||||||
bool parsedOkay = false;
|
bool parsedOkay = false;
|
||||||
if (!(args.Parameters[2] == "0"))
|
if (args.Parameters[2] != "0")
|
||||||
{
|
{
|
||||||
parsedOkay = TShock.Utils.TryParseTime(args.Parameters[2], out banLengthInSeconds);
|
parsedOkay = TShock.Utils.TryParseTime(args.Parameters[2], out banLengthInSeconds);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
parsedOkay = true;
|
parsedOkay = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parsedOkay)
|
if (!parsedOkay)
|
||||||
{
|
{
|
||||||
args.Player.SendErrorMessage("Invalid time format. Example: 10d+5h+3m-2s.");
|
args.Player.SendErrorMessage("Invalid time format. Example: 10d 5h 3m 2s.");
|
||||||
args.Player.SendErrorMessage("Use 0 (zero) for a permanent ban.");
|
args.Player.SendErrorMessage("Use 0 (zero) for a permanent ban.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1352,13 +1358,6 @@ namespace TShockAPI
|
||||||
banReason = String.Join(" ", args.Parameters.Skip(3));
|
banReason = String.Join(" ", args.Parameters.Skip(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bad case: Players contains more than 1 person so we can't ban them
|
|
||||||
if (players.Count > 1)
|
|
||||||
{
|
|
||||||
args.Player.SendMultipleMatchError(players.Select(p => p.Name));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Good case: Online ban for matching character.
|
// Good case: Online ban for matching character.
|
||||||
if (players.Count == 1)
|
if (players.Count == 1)
|
||||||
{
|
{
|
||||||
|
|
@ -1371,7 +1370,7 @@ namespace TShockAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
targetGeneralizedName = target.Name;
|
targetGeneralizedName = target.Name;
|
||||||
success = TShock.Bans.AddBan(target.IP, target.Name, target.UUID, target.Account.Name, banReason, false, args.Player.Account.Name,
|
success = TShock.Bans.AddBan(target.IP, target.Name, target.UUID, target.Account?.Name ?? "", banReason, false, args.Player.Account.Name,
|
||||||
banLengthInSeconds == 0 ? "" : DateTime.UtcNow.AddSeconds(banLengthInSeconds).ToString("s"));
|
banLengthInSeconds == 0 ? "" : DateTime.UtcNow.AddSeconds(banLengthInSeconds).ToString("s"));
|
||||||
|
|
||||||
// Since this is an online ban, we need to dc the player and tell them now.
|
// Since this is an online ban, we need to dc the player and tell them now.
|
||||||
|
|
@ -1399,7 +1398,8 @@ namespace TShockAPI
|
||||||
// If the target is a valid IP...
|
// If the target is a valid IP...
|
||||||
string pattern = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
|
string pattern = @"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
|
||||||
Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
|
Regex r = new Regex(pattern, RegexOptions.IgnoreCase);
|
||||||
if (r.IsMatch(args.Parameters[1])) {
|
if (r.IsMatch(args.Parameters[1]))
|
||||||
|
{
|
||||||
targetGeneralizedName = "IP: " + args.Parameters[1];
|
targetGeneralizedName = "IP: " + args.Parameters[1];
|
||||||
success = TShock.Bans.AddBan(args.Parameters[1], "", "", "", banReason,
|
success = TShock.Bans.AddBan(args.Parameters[1], "", "", "", banReason,
|
||||||
false, args.Player.Account.Name, banLengthInSeconds == 0 ? "" : DateTime.UtcNow.AddSeconds(banLengthInSeconds).ToString("s"));
|
false, args.Player.Account.Name, banLengthInSeconds == 0 ? "" : DateTime.UtcNow.AddSeconds(banLengthInSeconds).ToString("s"));
|
||||||
|
|
@ -1409,7 +1409,9 @@ namespace TShockAPI
|
||||||
args.Player.SendErrorMessage("Note: An account named with this IP address also exists.");
|
args.Player.SendErrorMessage("Note: An account named with this IP address also exists.");
|
||||||
args.Player.SendErrorMessage("Note: It will also be banned.");
|
args.Player.SendErrorMessage("Note: It will also be banned.");
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Apparently there is no way to not IP ban someone
|
// Apparently there is no way to not IP ban someone
|
||||||
// This means that where we would normally just ban a "character name" here
|
// This means that where we would normally just ban a "character name" here
|
||||||
// We can't because it requires some IP as a primary key.
|
// We can't because it requires some IP as a primary key.
|
||||||
|
|
|
||||||
|
|
@ -1488,7 +1488,8 @@ namespace TShockAPI
|
||||||
{ PacketTypes.PlayerHealOther, HandleHealOther },
|
{ PacketTypes.PlayerHealOther, HandleHealOther },
|
||||||
{ PacketTypes.CrystalInvasionStart, HandleOldOnesArmy },
|
{ PacketTypes.CrystalInvasionStart, HandleOldOnesArmy },
|
||||||
{ PacketTypes.PlayerHurtV2, HandlePlayerDamageV2 },
|
{ PacketTypes.PlayerHurtV2, HandlePlayerDamageV2 },
|
||||||
{ PacketTypes.PlayerDeathV2, HandlePlayerKillMeV2 }
|
{ PacketTypes.PlayerDeathV2, HandlePlayerKillMeV2 },
|
||||||
|
{ PacketTypes.PlayerTeleportPortal, HandlePlayerPortalTeleport }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1510,6 +1511,67 @@ namespace TShockAPI
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>The event args object for the PortalTeleport event</summary>
|
||||||
|
public class TeleportThroughPortalEventArgs : GetDataHandledEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>The Terraria player index of the target player</summary>
|
||||||
|
public byte TargetPlayerIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The position the target player will be at after going through the portal
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 NewPosition { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The velocity the target player will have after going through the portal
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 NewVelocity { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Index of the portal's color (for use with <see cref="Terraria.GameContent.PortalHelper.GetPortalColor(int)"/>)
|
||||||
|
/// </summary>
|
||||||
|
public int PortalColorIndex { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>When a player passes through a portal</summary>
|
||||||
|
public static HandlerList<TeleportThroughPortalEventArgs> PortalTeleport = new HandlerList<TeleportThroughPortalEventArgs>();
|
||||||
|
|
||||||
|
private static bool OnPlayerTeleportThroughPortal(TSPlayer sender, byte targetPlayerIndex, MemoryStream data, Vector2 position, Vector2 velocity, int colorIndex)
|
||||||
|
{
|
||||||
|
TeleportThroughPortalEventArgs args = new TeleportThroughPortalEventArgs
|
||||||
|
{
|
||||||
|
TargetPlayerIndex = targetPlayerIndex,
|
||||||
|
Data = data,
|
||||||
|
Player = sender,
|
||||||
|
NewPosition = position,
|
||||||
|
NewVelocity = velocity,
|
||||||
|
PortalColorIndex = colorIndex
|
||||||
|
};
|
||||||
|
|
||||||
|
PortalTeleport.Invoke(null, args);
|
||||||
|
|
||||||
|
return args.Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool HandlePlayerPortalTeleport(GetDataHandlerArgs args)
|
||||||
|
{
|
||||||
|
byte plr = args.Data.ReadInt8();
|
||||||
|
short portalColorIndex = args.Data.ReadInt16();
|
||||||
|
float newPositionX = args.Data.ReadSingle();
|
||||||
|
float newPositionY = args.Data.ReadSingle();
|
||||||
|
float newVelocityX = args.Data.ReadSingle();
|
||||||
|
float newVelocityY = args.Data.ReadSingle();
|
||||||
|
|
||||||
|
return OnPlayerTeleportThroughPortal(
|
||||||
|
args.Player,
|
||||||
|
plr,
|
||||||
|
args.Data,
|
||||||
|
new Vector2(newPositionX, newPositionY),
|
||||||
|
new Vector2(newVelocityX, newVelocityY),
|
||||||
|
portalColorIndex
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static bool HandleHealOther(GetDataHandlerArgs args)
|
private static bool HandleHealOther(GetDataHandlerArgs args)
|
||||||
{
|
{
|
||||||
byte plr = args.Data.ReadInt8();
|
byte plr = args.Data.ReadInt8();
|
||||||
|
|
|
||||||
|
|
@ -534,7 +534,7 @@ namespace TShockAPI
|
||||||
var sb = new StringBuilder(3);
|
var sb = new StringBuilder(3);
|
||||||
for (int i = 0; i < str.Length; i++)
|
for (int i = 0; i < str.Length; i++)
|
||||||
{
|
{
|
||||||
if (Char.IsDigit(str[i]) || (str[i] == '-' || str[i] == '+'))
|
if (Char.IsDigit(str[i]) || (str[i] == '-' || str[i] == '+' || str[i] == ' '))
|
||||||
sb.Append(str[i]);
|
sb.Append(str[i]);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue