Merge branch 'general-devel' into playerdata-changes

This commit is contained in:
Lucas Nicodemus 2025-03-10 00:39:33 +09:00 committed by GitHub
commit 13a4a0864b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 2219 additions and 1145 deletions

View file

@ -95,6 +95,7 @@ namespace TShockAPI
{ PacketTypes.TileSendSquare, HandleSendTileRect },
{ PacketTypes.ItemDrop, HandleItemDrop },
{ PacketTypes.ItemOwner, HandleItemOwner },
{ PacketTypes.NpcItemStrike, HandleNpcItemStrike },
{ PacketTypes.ProjectileNew, HandleProjectileNew },
{ PacketTypes.NpcStrike, HandleNpcStrike },
{ PacketTypes.ProjectileDestroy, HandleProjectileKill },
@ -2248,7 +2249,7 @@ namespace TShockAPI
var args = new SyncTilePickingEventArgs
{
Player = player,
Player = player,
PlayerIndex = playerIndex,
TileX = tileX,
TileY = tileY,
@ -2719,49 +2720,71 @@ namespace TShockAPI
}
byte player = args.Data.ReadInt8();
short spawnx = args.Data.ReadInt16();
short spawny = args.Data.ReadInt16();
short spawnX = args.Data.ReadInt16();
short spawnY = args.Data.ReadInt16();
int respawnTimer = args.Data.ReadInt32();
short numberOfDeathsPVE = args.Data.ReadInt16();
short numberOfDeathsPVP = args.Data.ReadInt16();
PlayerSpawnContext context = (PlayerSpawnContext)args.Data.ReadByte();
if (OnPlayerSpawn(args.Player, args.Data, player, spawnx, spawny, respawnTimer, numberOfDeathsPVE, numberOfDeathsPVP, context))
args.Player.FinishedHandshake = true;
if (OnPlayerSpawn(args.Player, args.Data, player, spawnX, spawnY, respawnTimer, numberOfDeathsPVE, numberOfDeathsPVP, context))
return true;
args.Player.Dead = respawnTimer > 0;
if ((Main.ServerSideCharacter) && (spawnx == -1 && spawny == -1)) //this means they want to spawn to vanilla spawn
if (Main.ServerSideCharacter)
{
args.Player.sX = Main.spawnTileX;
args.Player.sY = Main.spawnTileY;
args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) - 48);
TShock.Log.ConsoleDebug(GetString("GetDataHandlers / HandleSpawn force teleport 'vanilla spawn' {0}", args.Player.Name));
}
// As long as the player has not changed his spawnpoint since initial connection,
// we should not use the client's spawnpoint value. This is because the spawnpoint
// value is not saved on the client when SSC is enabled. Hence, we have to assert
// the server-saved spawnpoint value until we can detect that the player has changed
// his spawn. Once we detect the spawnpoint changed, the client's spawnpoint value
// becomes the correct one to use.
//
// Note that spawnpoint changes (right-clicking beds) are not broadcasted to the
// server. Hence, the only way to detect spawnpoint changes is from the
// PlayerSpawn packet.
else if ((Main.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0) && (args.TPlayer.SpawnX > 0) && ((args.TPlayer.SpawnX != args.Player.sX) && (args.TPlayer.SpawnY != args.Player.sY)))
{
args.Player.sX = args.TPlayer.SpawnX;
args.Player.sY = args.TPlayer.SpawnY;
if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == TileID.Beds)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY - 1)))
// handle initial connection
if (args.Player.State == 3)
{
args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) - 48);
TShock.Log.ConsoleDebug(GetString("GetDataHandlers / HandleSpawn force teleport phase 1 {0}", args.Player.Name));
}
}
// server saved spawnpoint value
args.Player.initialSpawn = true;
args.Player.initialServerSpawnX = args.TPlayer.SpawnX;
args.Player.initialServerSpawnY = args.TPlayer.SpawnY;
else if ((Main.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0))
{
if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == TileID.Beds)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY - 1)))
// initial client spawn point, do not use this to spawn the player
// we only use it to detect if the spawnpoint has changed during this session
args.Player.initialClientSpawnX = spawnX;
args.Player.initialClientSpawnY = spawnY;
// we first let the game handle completing the connection (state 3 => 10),
// then we will spawn the player at the saved spawnpoint in the next second,
// by reasserting the correct spawnpoint value
return false;
}
// once we detect the client has changed his spawnpoint in the current session,
// the client spawnpoint value will be correct for the rest of the session
if (args.Player.spawnSynced || args.Player.initialClientSpawnX != spawnX || args.Player.initialClientSpawnY != spawnY)
{
args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) - 48);
TShock.Log.ConsoleDebug(GetString("GetDataHandlers / HandleSpawn force teleport phase 2 {0}", args.Player.Name));
// Player has changed his spawnpoint, client and server TPlayer.Spawn{X,Y} is now synced
args.Player.spawnSynced = true;
return false;
}
}
if (respawnTimer > 0)
args.Player.Dead = true;
else
args.Player.Dead = false;
// the player has not changed his spawnpoint yet, so we assert the server-saved spawnpoint
// by teleporting the player instead of letting the game use the client's incorrect spawnpoint.
TShock.Log.ConsoleDebug(GetString("GetDataHandlers / HandleSpawn force ssc teleport for {0} at ({1},{2})", args.Player.Name, args.TPlayer.SpawnX, args.TPlayer.SpawnY));
args.Player.TeleportSpawnpoint();
args.TPlayer.respawnTimer = respawnTimer;
args.TPlayer.numberOfDeathsPVE = numberOfDeathsPVE;
args.TPlayer.numberOfDeathsPVP = numberOfDeathsPVP;
return true;
}
return false;
}
@ -2942,6 +2965,13 @@ namespace TShockAPI
return false;
}
private static bool HandleNpcItemStrike(GetDataHandlerArgs args)
{
// Never sent by vanilla client, ignore this
TShock.Log.ConsoleDebug(GetString("GetDataHandlers / HandleNpcItemStrike surprise packet! Someone tell the TShock team! {0}", args.Player.Name));
return true;
}
private static bool HandleProjectileNew(GetDataHandlerArgs args)
{
short ident = args.Data.ReadInt16();
@ -4445,6 +4475,11 @@ namespace TShockAPI
return true;
}
// Don't modify the player data if it isn't there.
// This is the case whilst the player is connecting, as we receive the SyncLoadout packet before the ContinueConnecting2 packet.
if (args.Player.PlayerData == null)
return false;
// The client does not sync slot changes when changing loadouts, it only tells the server the loadout index changed,
// and the server will replicate the changes the client did. This means that PlayerData.StoreSlot is never called, so we need to
// swap around the PlayerData items ourself.