fix(teleport): preserve dungeon cell identity on respawn (#215)
Classify teleport landblock transitions from the source and destination Position cell IDs instead of render-space coordinates. This keeps same-dungeon death respawns on their resident floor physics while preserving the existing true cross-landblock streaming path. Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
parent
b0c175afc0
commit
0ad6700a07
7 changed files with 296 additions and 9 deletions
42
src/AcDream.App/Streaming/TeleportLandblockTransition.cs
Normal file
42
src/AcDream.App/Streaming/TeleportLandblockTransition.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
namespace AcDream.App.Streaming;
|
||||
|
||||
/// <summary>
|
||||
/// Classifies whether a local-player teleport crosses an AC landblock boundary.
|
||||
/// Cell identity comes from the complete retail <c>Position</c>, never from its
|
||||
/// frame coordinates: dungeon EnvCells may have valid negative local origins.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Retail carries <c>Position::objcell_id</c> through
|
||||
/// <c>SmartBox::TeleportPlayer</c> (0x00453910) into
|
||||
/// <c>CPhysicsObj::SetPositionSimple</c> (0x005162B0). acdream's asynchronous
|
||||
/// streaming layer needs this extra comparison, but preserves that identity rule.
|
||||
/// See <c>docs/research/2026-07-13-same-dungeon-respawn-landblock-identity-pseudocode.md</c>.
|
||||
/// </remarks>
|
||||
internal readonly record struct TeleportLandblockTransition(
|
||||
uint SourceLandblockId,
|
||||
uint DestinationLandblockId)
|
||||
{
|
||||
public bool CrossesLandblock => SourceLandblockId != DestinationLandblockId;
|
||||
|
||||
/// <summary>
|
||||
/// Build the transition from the player's current cell and the received
|
||||
/// destination cell. A zero source can occur before initial placement; in
|
||||
/// that case the current streaming center is the only valid identity fallback.
|
||||
/// </summary>
|
||||
public static TeleportLandblockTransition Classify(
|
||||
uint sourceCellId,
|
||||
uint destinationCellId,
|
||||
uint currentStreamingCenterLandblockId)
|
||||
{
|
||||
uint sourceLandblockId = sourceCellId != 0
|
||||
? NormalizeLandblockId(sourceCellId)
|
||||
: NormalizeLandblockId(currentStreamingCenterLandblockId);
|
||||
|
||||
return new TeleportLandblockTransition(
|
||||
sourceLandblockId,
|
||||
NormalizeLandblockId(destinationCellId));
|
||||
}
|
||||
|
||||
private static uint NormalizeLandblockId(uint cellOrLandblockId)
|
||||
=> (cellOrLandblockId & 0xFFFF0000u) | 0xFFFFu;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue