Skip to content

Commit ed2152b

Browse files
committed
test: cover stale far reward pickups
1 parent 8ca398d commit ed2152b

2 files changed

Lines changed: 62 additions & 0 deletions

File tree

internal/minimal/shared_world_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15762,6 +15762,67 @@ func TestSharedWorldRegistryGroundGoldRemovalRejectsOutOfRangeCollector(t *testi
1576215762
}
1576315763
}
1576415764

15765+
func TestSharedWorldRegistryGroundRewardPickupRejectsStaleFarCollectorSnapshotAfterCollectorMovesNear(t *testing.T) {
15766+
topology := worldruntime.NewBootstrapTopology(1).WithRadiusVisibilityPolicy(4000, 200)
15767+
registry := newSharedWorldRegistryWithTopology(topology)
15768+
owner := peerVisibilityCharacter("FarSnapshotOwner", 0x01030140, 0x02040140, 1100, 2100, 0, 101, 201)
15769+
collector := peerVisibilityCharacter("FarThenNearCollector", 0x01030141, 0x02040141, 2500, 3500, 1, 102, 202)
15770+
ownerID, _ := registry.Join(owner, newPendingServerFrames(), nil)
15771+
collectorID, _ := registry.Join(collector, newPendingServerFrames(), nil)
15772+
if ownerID == 0 || collectorID == 0 {
15773+
t.Fatalf("expected owner and collector to join shared world, got owner=%d collector=%d", ownerID, collectorID)
15774+
}
15775+
groundVID := uint32(0x0A0B0C34)
15776+
item := inventory.ItemInstance{ID: 1034, Vnum: 27004, Count: 1, Slot: 5}
15777+
if !registry.RegisterGroundItem(ownerID, "far-snapshot-owner", owner, groundVID, item) {
15778+
t.Fatal("expected owner ground item registration to succeed")
15779+
}
15780+
nearCollector := collector
15781+
nearCollector.X = 1120
15782+
nearCollector.Y = 2120
15783+
registry.UpdateCharacter(collectorID, nearCollector)
15784+
15785+
if _, ok := registry.GroundItemPickupFor(collectorID, collector, groundVID); ok {
15786+
t.Fatal("expected stale far collector snapshot pickup to fail closed even after registered collector moved near")
15787+
}
15788+
if removed := registry.RemoveGroundItem(collectorID, collector, groundVID); removed {
15789+
t.Fatal("expected stale far collector snapshot removal to fail closed even after registered collector moved near")
15790+
}
15791+
if !registry.GroundItemExists(groundVID) {
15792+
t.Fatal("expected rejected stale far snapshot pickup/removal to leave ground item registered")
15793+
}
15794+
}
15795+
15796+
func TestSharedWorldRegistryGroundGoldPickupRejectsStaleFarCollectorSnapshotAfterCollectorMovesNear(t *testing.T) {
15797+
topology := worldruntime.NewBootstrapTopology(1).WithRadiusVisibilityPolicy(4000, 200)
15798+
registry := newSharedWorldRegistryWithTopology(topology)
15799+
owner := peerVisibilityCharacter("FarGoldSnapshotOwner", 0x01030142, 0x02040142, 1100, 2100, 0, 101, 201)
15800+
collector := peerVisibilityCharacter("FarThenNearGoldCollector", 0x01030143, 0x02040143, 2500, 3500, 1, 102, 202)
15801+
ownerID, _ := registry.Join(owner, newPendingServerFrames(), nil)
15802+
collectorID, _ := registry.Join(collector, newPendingServerFrames(), nil)
15803+
if ownerID == 0 || collectorID == 0 {
15804+
t.Fatalf("expected owner and collector to join shared world, got owner=%d collector=%d", ownerID, collectorID)
15805+
}
15806+
groundVID := uint32(0x0A0B0C35)
15807+
if !registry.RegisterGroundGold(ownerID, "far-gold-snapshot-owner", owner, groundVID, 275) {
15808+
t.Fatal("expected owner ground gold registration to succeed")
15809+
}
15810+
nearCollector := collector
15811+
nearCollector.X = 1120
15812+
nearCollector.Y = 2120
15813+
registry.UpdateCharacter(collectorID, nearCollector)
15814+
15815+
if pickup, ok := registry.GroundItemPickupFor(collectorID, collector, groundVID); ok || pickup.GoldAmount != 0 {
15816+
t.Fatalf("expected stale far collector snapshot ground-gold pickup to fail closed even after registered collector moved near, got ok=%v pickup=%+v", ok, pickup)
15817+
}
15818+
if removed := registry.RemoveGroundItem(collectorID, collector, groundVID); removed {
15819+
t.Fatal("expected stale far collector snapshot ground-gold removal to fail closed even after registered collector moved near")
15820+
}
15821+
if !registry.GroundItemExists(groundVID) {
15822+
t.Fatal("expected rejected stale far snapshot ground-gold pickup/removal to leave ground gold registered")
15823+
}
15824+
}
15825+
1576515826
func TestSharedWorldRegistryGroundGoldPickupSkipsDeadOwnerDelivery(t *testing.T) {
1576615827
topology := worldruntime.NewBootstrapTopology(1).WithRadiusVisibilityPolicy(400, 200)
1576715828
registry := newSharedWorldRegistryWithTopology(topology)

spec/protocol/non-player-reward-bootstrap.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ Ground reward registration re-checks the registered owner snapshot before trusti
133133
Lookup, pickup-resolution, and removal also re-check the registered collector snapshot before trusting the caller-supplied character copy, so a stale collector snapshot cannot see, resolve, or remove item-shaped or gold-shaped reward ground entries after that collector has already reached the bootstrap `0`-HP floor, changed selected-character identity (`id`, `vid`, or name), or moved out of the exact runtime location represented by the supplied pickup attempt.
134134
Dedicated coverage now freezes the gold-shaped reward half of stale collector-identity, stale collector-location, stale owner-identity owner-delivery, and stale owner-location owner-delivery cases, not just ordinary item-shaped drops, because both reward families share the same ground-entry visibility/pickup seam.
135135
This guard applies in both directions for item-shaped and gold-shaped rewards: a stale near snapshot cannot pick up after the registered collector has moved away or rebound to a different selected-character identity, and a stale far snapshot cannot become valid merely because the registered collector later moved near the ground reward.
136+
Dedicated shared-world coverage freezes the stale-far-then-near case for both item-shaped drops and gold-shaped ground rewards: the stale snapshot cannot resolve pickup or remove the ground entry, and the reward remains registered for a fresh current pickup attempt.
136137
When that living, identity-current, and currently reachable collector succeeds, the collector receives the ordinary self pickup shape (`ITEM_GROUND_DEL`, inventory `ITEM_SET`, and normal `ITEM_GET` feedback) and the dead, rebound, or relocated owner receives no queued party-style pickup feedback.
137138

138139
This keeps death/restart cleanup and concurrent movement from leaking new pickup surfaces, stale delete noise, debug/runtime-visible pickup affordances, stale collector pickup affordances, stale owner-location ground registration, transfer-entry ground visibility, or late owner-delivery mutations for players that are already dead or no longer at the supplied reward location.

0 commit comments

Comments
 (0)