Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite: Partially fix bed spawning for SSC #3031

Open
wants to merge 1 commit into
base: general-devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 42 additions & 28 deletions TShockAPI/GetDataHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2248,7 +2248,7 @@ private static bool OnSyncTilePicking(TSPlayer player, MemoryStream data, byte p

var args = new SyncTilePickingEventArgs
{
Player = player,
Player = player,
PlayerIndex = playerIndex,
TileX = tileX,
TileY = tileY,
Expand Down Expand Up @@ -2719,49 +2719,63 @@ private static bool HandleSpawn(GetDataHandlerArgs args)
}

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))
if (OnPlayerSpawn(args.Player, args.Data, player, spawnX, spawnY, respawnTimer, numberOfDeathsPVE, numberOfDeathsPVP, context))
return true;

if ((Main.ServerSideCharacter) && (spawnx == -1 && spawny == -1)) //this means they want to spawn to vanilla spawn
{
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));
}
TShock.Log.ConsoleInfo("GetDataHandlers / HandleSpawn spawnXY ({0}, {1})", spawnX, spawnY);

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)))
if (Main.ServerSideCharacter)
{
args.Player.sX = args.TPlayer.SpawnX;
args.Player.sY = args.TPlayer.SpawnY;
// As long as the player has not changed his spawnpoint since initial connection,
// we should not let the client handle spawning the player. This is because the
// spawnpoint value is not saved in the client, and the game does not allow the
// server to edit it directly. Hence, we have to assert the correct spawnpoint value
// until we can detect that the player has changed his spawn (when the player attempts
// to respawn at a changed location). We can then safely sync the spawnpoint values
// on both the client and the server.

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)))
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;


// initial client spawn point, do not use this to spawn the player
// we only use it to detect if the spawnpoint has changed
args.Player.initialClientSpawnX = spawnX;
args.Player.initialClientSpawnY = spawnY;

// we let the game handle completing the connection (state 3 => 10), we will spawn the player at the
// saved spawnpoint in the next second, and reassert the correct spawnpoint value
return false;
}
}

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)))
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 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;
// here, we assert the correct spawnpoint by teleporting the player instead of letting the client handle it.
args.TPlayer.respawnTimer = respawnTimer;
args.TPlayer.numberOfDeathsPVE = numberOfDeathsPVE;
args.TPlayer.numberOfDeathsPVP = numberOfDeathsPVP;
args.Player.Dead = respawnTimer > 0;

args.Player.TeleportSpawnpoint();
TShock.Log.ConsoleDebug(GetString("GetDataHandlers / HandleSpawn ssc teleport for {0} at ({1},{2})", args.Player.Name, args.TPlayer.SpawnX, args.TPlayer.SpawnY));
return true;
}
return false;
}

Expand Down
14 changes: 2 additions & 12 deletions TShockAPI/PlayerData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,8 @@ public void CopyCharacter(TSPlayer player)
this.maxHealth = player.TPlayer.statLifeMax;
this.mana = player.TPlayer.statMana;
this.maxMana = player.TPlayer.statManaMax;
if (player.sX > 0 && player.sY > 0)
{
this.spawnX = player.sX;
this.spawnY = player.sY;
}
else
{
this.spawnX = player.TPlayer.SpawnX;
this.spawnY = player.TPlayer.SpawnY;
}
this.spawnX = player.TPlayer.SpawnX;
this.spawnY = player.TPlayer.SpawnY;
extraSlot = player.TPlayer.extraAccessory ? 1 : 0;
this.skinVariant = player.TPlayer.skinVariant;
this.hair = player.TPlayer.hair;
Expand Down Expand Up @@ -266,8 +258,6 @@ public void RestoreCharacter(TSPlayer player)
player.TPlayer.statManaMax = this.maxMana;
player.TPlayer.SpawnX = this.spawnX;
player.TPlayer.SpawnY = this.spawnY;
player.sX = this.spawnX;
player.sY = this.spawnY;
player.TPlayer.hairDye = this.hairDye;
player.TPlayer.anglerQuestsFinished = this.questsCompleted;
player.TPlayer.UsingBiomeTorches = this.usingBiomeTorches == 1;
Expand Down
33 changes: 23 additions & 10 deletions TShockAPI/TSPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,13 @@ public static List<TSPlayer> FindByNameOrID(string search)
/// </summary>
public int RPPending = 0;

public int sX = -1;
public int sY = -1;

public bool initialSpawn = false;
public int initialServerSpawnX = -2;
public int initialServerSpawnY = -2;
public bool spawnSynced = false;
public int initialClientSpawnX = -2;
public int initialClientSpawnY = -2;

/// <summary>
/// A queue of tiles destroyed by the player for reverting.
Expand Down Expand Up @@ -1380,6 +1385,21 @@ public bool Teleport(float x, float y, byte style = 1)
return true;
}

/// <summary>
/// Teleports the player to their spawnpoint. Supports SSC.
/// </summary>
public bool TeleportSpawnpoint()
{
int x = TPlayer.SpawnX;
int y = TPlayer.SpawnY;
if (x == -1 && y == -1)
{
x = Main.spawnTileX;
y = Main.spawnTileY;
}
return Teleport(x * 16, y * 16 - 48);
}

/// <summary>
/// Heals the player.
/// </summary>
Expand All @@ -1394,14 +1414,7 @@ public void Heal(int health = 600)
/// </summary>
public void Spawn(PlayerSpawnContext context, int? respawnTimer = null)
{
if (this.sX > 0 && this.sY > 0)
{
Spawn(this.sX, this.sY, context, respawnTimer);
}
else
{
Spawn(TPlayer.SpawnX, TPlayer.SpawnY, context, respawnTimer);
}
Spawn(TPlayer.SpawnX, TPlayer.SpawnY, context, respawnTimer);
}

/// <summary>
Expand Down
16 changes: 8 additions & 8 deletions TShockAPI/TShock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1182,16 +1182,16 @@ private void OnSecondUpdate()
if (player.RecentFuse > 0)
player.RecentFuse--;

if ((Main.ServerSideCharacter) && (player.TPlayer.SpawnX > 0) && (player.sX != player.TPlayer.SpawnX))
if (Main.ServerSideCharacter && player.initialSpawn)
{
player.sX = player.TPlayer.SpawnX;
player.sY = player.TPlayer.SpawnY;
}
player.initialSpawn = false;

if ((Main.ServerSideCharacter) && (player.sX > 0) && (player.sY > 0) && (player.TPlayer.SpawnX < 0))
{
player.TPlayer.SpawnX = player.sX;
player.TPlayer.SpawnY = player.sY;
// reassert the correct spawnpoint value after the game's Spawn handler changed it
player.TPlayer.SpawnX = player.initialServerSpawnX;
player.TPlayer.SpawnY = player.initialServerSpawnY;

player.TeleportSpawnpoint();
TShock.Log.ConsoleDebug(GetString("OnSecondUpdate / initial ssc spawn for {0} at ({1}, {2})", player.Name, player.TPlayer.SpawnX, player.TPlayer.SpawnY));
}

if (player.RPPending > 0)
Expand Down
3 changes: 3 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ Use past tense when adding new entries; sign your name off when you add or chang
* Fixed /help, /me, and /p commands can't work in non-English languages. (@ACaiCat)
* Added a hook `AccountHooks.AccountGroupUpdate`, which is called when you change the user group. (@AgaSpace)
* * Ensured `TSPlayer.PlayerData` is non-null whilst syncing loadouts. (@drunderscore)
* Rewrote bed spawning for SSC. (@PotatoCider)
* Removed `TSPlayer.s{X,Y}` in favour of using desyncing client and server spawnpoint values (`Terraria.Player.Spawn{X,Y}`) until the player has changed their spawnpoint per session.
* Partially fixed the bed spawning bug when SSC is enabled. Players would need to spawn at their beds at least once to tell TShock that the player's spawnpoint has changed.

## TShock 5.2.1
* Updated `TSPlayer.GodMode`. (@AgaSpace)
Expand Down
Loading