fix(recovery): silence clean equipment arrival warnings
This commit is contained in:
1 parent
7ea6e254eb
commit
a2140bd8d7
2 files changed
+70
-9
No files matched your search
@@ -624,19 +624,22 @@ public final class EquipmentSessions implements AutoCloseable {
|
||||
if (hasRemnants(attempt.player) || !gameModes.available(attempt.player)
|
||||
|| vitals != null && !vitals.available(attempt.player)) return false;
|
||||
var marker = EquipmentSessionMarker.read(attempt.player).orElse(null);
|
||||
if (EquipmentSessionMarker.present(attempt.player)) {
|
||||
// A terminal marker is resolved only by its matching completed file acknowledgment.
|
||||
// Keep it until the next successful entry; worker acknowledgments never touch PDC.
|
||||
var exit = state == null ? null : state.lastExit();
|
||||
if (marker == null || marker.phase() != EquipmentSessionMarker.Phase.RESTORED
|
||||
|| state == null || state.pending() != null || exit == null
|
||||
|| !marker.matches(exit.sessionId(), exit.characterId())) return false;
|
||||
}
|
||||
if (EquipmentSessionMarker.present(attempt.player) && !completedRestoredMarker(marker, state)) return false;
|
||||
attempt.entryMarker = marker;
|
||||
attempt.markerValidated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean completedRestoredMarker(EquipmentSessionMarker.Token marker,
|
||||
EquipmentSessionStore.State state) {
|
||||
// A terminal marker is resolved only by its matching completed file acknowledgment.
|
||||
// Keep it until the next successful entry; worker acknowledgments never touch PDC.
|
||||
var exit = state == null ? null : state.lastExit();
|
||||
return marker != null && marker.phase() == EquipmentSessionMarker.Phase.RESTORED
|
||||
&& state != null && state.pending() == null && exit != null
|
||||
&& marker.matches(exit.sessionId(), exit.characterId());
|
||||
}
|
||||
|
||||
private static boolean hasRemnants(Player player) {
|
||||
return Arrays.stream(player.getInventory().getContents()).anyMatch(EquipmentSessions::remnant)
|
||||
|| remnant(player.getItemOnCursor());
|
||||
@@ -1940,7 +1943,9 @@ public final class EquipmentSessions implements AutoCloseable {
|
||||
var arrivingOwner = attempt.owner;
|
||||
var episode=downedDirectory==null?null:downedDirectory.all().stream().filter(value->value.player().equals(arrivingOwner)&&value.phase()==DownedEpisode.Phase.PENDING).findFirst().orElse(null);
|
||||
if (sheets.identify(attempt.player.getInventory().getItemInOffHand()).isPresent()) enter(attempt.player,episode);
|
||||
else if (EquipmentSessionMarker.present(attempt.player) || hasRemnants(attempt.player)) {
|
||||
else if (hasRemnants(attempt.player)
|
||||
|| (EquipmentSessionMarker.present(attempt.player)
|
||||
&& !completedRestoredMarker(EquipmentSessionMarker.read(attempt.player).orElse(null), state.orElse(null)))) {
|
||||
notice(attempt.owner, "NATIVE_RECOVERY_REQUIRED", "Native equipment remnants have no pending receipt; items were retained for inspection.");
|
||||
}
|
||||
return; // Ordinary no-sheet/no-receipt arrivals are not rejected entry attempts.
|
||||
|
||||
@@ -1128,6 +1128,62 @@ class EquipmentSessionEventsNativeTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test void joinAfterCleanExitIsQuietAndPreservesPlayerAndReceiptState() throws Exception {
|
||||
try (var f = new Fixture()) {
|
||||
var a = f.actor; f.core.activate(a);
|
||||
assertEquals(games.dmg.fantasystick.items.EquipmentStorage.RestoreResult.RESTORED,
|
||||
f.core.sessions.exit(a.player));
|
||||
var completed = f.core.state(a);
|
||||
assertNull(completed.pending()); assertNotNull(completed.lastExit());
|
||||
a.inventory.setItemInOffHand(new ItemStack(Material.EMERALD));
|
||||
var before = a.snapshot(); var cursor = a.cursor.clone(); var marker = a.marker();
|
||||
var record = f.core.characters.find(a.record.id()).join().orElseThrow();
|
||||
int notices = f.core.notices.size();
|
||||
|
||||
f.dispatcher.accept(new org.bukkit.event.player.PlayerJoinEvent(a.player,
|
||||
(net.kyori.adventure.text.Component) null));
|
||||
f.core.tick();
|
||||
|
||||
assertEquals(notices, f.core.notices.size(),
|
||||
"A matching completed RESTORED marker is clean arrival proof, not a recovery warning");
|
||||
assertArrayEquals(before, a.snapshot()); assertEquals(cursor, a.cursor);
|
||||
assertEquals(marker, a.marker()); assertEquals(completed, f.core.state(a));
|
||||
assertEquals(record, f.core.characters.find(a.record.id()).join().orElseThrow());
|
||||
assertTrue(f.core.sessions.active(a.id).isEmpty()); assertTrue(f.ticks.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@Test void joinWarnsWithoutMutationForUnsafeMarkersAndGenuineRemnants() throws Exception {
|
||||
for (int scenario = 0; scenario < 4; scenario++) try (var f = new Fixture()) {
|
||||
var a = f.actor; f.core.activate(a);
|
||||
var genuineBox = a.inventory.getItem(9).clone();
|
||||
assertEquals(games.dmg.fantasystick.items.EquipmentStorage.RestoreResult.RESTORED,
|
||||
f.core.sessions.exit(a.player));
|
||||
var completed = f.core.state(a);
|
||||
assertNull(completed.pending()); assertNotNull(completed.lastExit());
|
||||
a.inventory.setItemInOffHand(new ItemStack(Material.EMERALD));
|
||||
if (scenario == 0) a.pdc.set(new org.bukkit.NamespacedKey("fantasystick", "equipment_session"),
|
||||
org.bukkit.persistence.PersistentDataType.STRING, "malformed");
|
||||
if (scenario == 1) a.marker(java.util.UUID.randomUUID(), "RESTORED");
|
||||
if (scenario == 2) a.marker(completed.lastExit().sessionId(), "PACKED");
|
||||
if (scenario == 3) a.inventory.setItem(12, genuineBox);
|
||||
var before = a.snapshot(); var cursor = a.cursor.clone(); var marker = a.marker();
|
||||
var record = f.core.characters.find(a.record.id()).join().orElseThrow();
|
||||
int notices = f.core.notices.size();
|
||||
|
||||
f.dispatcher.accept(new org.bukkit.event.player.PlayerJoinEvent(a.player,
|
||||
(net.kyori.adventure.text.Component) null));
|
||||
f.core.tick();
|
||||
|
||||
assertEquals(notices + 1, f.core.notices.size());
|
||||
assertEquals("NATIVE_RECOVERY_REQUIRED", f.core.notices.getLast().code());
|
||||
assertArrayEquals(before, a.snapshot()); assertEquals(cursor, a.cursor);
|
||||
assertEquals(marker, a.marker()); assertEquals(completed, f.core.state(a));
|
||||
assertEquals(record, f.core.characters.find(a.record.id()).join().orElseThrow());
|
||||
assertTrue(f.core.sessions.active(a.id).isEmpty()); assertTrue(f.ticks.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@Test void reservedWorldAndInventorySwapsRestoreBeforeExchangingOrdinaryGear() throws Exception {
|
||||
for (int route = 0; route < 3; route++) {
|
||||
try (var f = new Fixture()) {
|
||||
|
||||
Reference in new issue
Block a user