Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.function.LongFunction;

/**
Expand Down Expand Up @@ -45,10 +46,20 @@ public static <S> boolean shouldRestore(S current, S placed) {

/** Splits entries into the ones to restore and the ones a player has changed since. */
public static <S> Plan<S> plan(List<Entry<S>> entries, LongFunction<S> currentState) {
return plan(entries, currentState, ArenaRestoreRules::shouldRestore);
}

/**
* Same as {@link #plan(List, LongFunction)} with a custom "still what the arena placed" check.
* In game this compares the block type only: leaves recompute their distance, water and
* redstone settle after placement, and those state changes are not player edits.
*/
public static <S> Plan<S> plan(List<Entry<S>> entries, LongFunction<S> currentState,
BiPredicate<S, S> stillPlaced) {
List<Entry<S>> restore = new ArrayList<>();
List<Entry<S>> skipped = new ArrayList<>();
for (Entry<S> e : entries) {
if (shouldRestore(currentState.apply(e.pos()), e.placed())) {
if (stillPlaced.test(currentState.apply(e.pos()), e.placed())) {
restore.add(e);
} else {
skipped.add(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ public static boolean restore(ServerLevel level, UUID boss) {
if (!level.hasChunksAt(min, max)) return false;

List<ArenaRestoreRules.Entry<BlockState>> entries = arena.entries();
ArenaRestoreRules.Plan<BlockState> plan = ArenaRestoreRules.plan(entries, p -> level.getBlockState(BlockPos.of(p)));
ArenaRestoreRules.Plan<BlockState> plan = ArenaRestoreRules.plan(entries, p -> level.getBlockState(BlockPos.of(p)),
(current, placed) -> current.is(placed.getBlock()));

// 1) empty pavilion containers so nothing spills into the world
for (ArenaRestoreRules.Entry<BlockState> e : plan.restore()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,28 @@ int record = boss.indexOf("EpsteinArenaSnapshots.record(");
String events = Files.readString(Path.of("src/main/java/com/israelsimulator/event/ModGameEvents.java"));
assertTrue(events.contains("EpsteinArenaSnapshots.tickOrphans(level)"));
}
}

@Test
@DisplayName("Block-state updates after placement (leaf distance) are not player changes")
void planIgnoresStateOnlyChangesWithBlockCheck() {
List<ArenaRestoreRules.Entry<String>> entries = List.of(
new ArenaRestoreRules.Entry<>(1L, "air", "oak_leaves[distance=7]"),
new ArenaRestoreRules.Entry<>(2L, "air", "glass"),
new ArenaRestoreRules.Entry<>(3L, "air", "oak_leaves[distance=7]"));
Map<Long, String> world = new HashMap<>(Map.of(
1L, "oak_leaves[distance=2]", 2L, "glass", 3L, "cobblestone"));
java.util.function.BiPredicate<String, String> sameBlock =
(current, placed) -> current.split("\\[")[0].equals(placed.split("\\[")[0]);

ArenaRestoreRules.Plan<String> plan = ArenaRestoreRules.plan(entries, world::get, sameBlock);
assertEquals(List.of(1L, 2L), plan.restore().stream().map(ArenaRestoreRules.Entry::pos).toList());
assertEquals(List.of(3L), plan.skipped().stream().map(ArenaRestoreRules.Entry::pos).toList());
String snap = assertDoesNotThrowRead();
assertTrue(snap.contains("current.is(placed.getBlock())"), "in game the restore compares block types");
}

private static String assertDoesNotThrowRead() {
return assertDoesNotThrow(() -> Files.readString(Path.of(
"src/main/java/com/israelsimulator/entity/boss/EpsteinArenaSnapshots.java")));
}
}
6 changes: 6 additions & 0 deletions test.md
Original file line number Diff line number Diff line change
Expand Up @@ -953,3 +953,9 @@ Non provato dall'utente in gioco.
- Problema riscontrato: quando si evoca Bibi con la Stella di Davide la chat mostra "%s used the Star of David. Bibi is here!". Il nome del giocatore non c'è.
- Funzionamento atteso: "Dev used the Star of David. Bibi is here!" (in italiano "Dev ha usato la Stella di Davide...").
- Soluzione: `StarOfDavidItem` passa a `Component.translatable` il nome del giocatore come argomento. Il nuovo test `testTranslatablePlaceholdersHaveArguments` cerca nel codice i messaggi tradotti che contengono `%s` ma vengono creati senza argomenti.

## Arena di Epstein: foglie del padiglione rimaste dopo il ripristino
- Problema riscontrato: dopo la morte di Epstein il terreno viene ripristinato, ma restano sospese in aria le chiome delle palme del padiglione. Nel log, a ogni combattimento, 82–106 blocchi risultano "left as changed by players" anche se nessun giocatore li ha toccati.
- Causa: le foglie ricalcolano lo stato `distance` subito dopo il piazzamento. Il ripristino confrontava lo stato completo del blocco, quindi trattava quelle foglie come una modifica del giocatore e le lasciava lì.
- Funzionamento atteso: alla fine del combattimento sparisce tutto quello che l'arena ha piazzato. Restano solo i blocchi che un giocatore ha davvero sostituito.
- Soluzione: in gioco il ripristino confronta solo il tipo di blocco (`current.is(placed.getBlock())`). Il nuovo test `planIgnoresStateOnlyChangesWithBlockCheck` lo verifica. La correzione vale anche per il palco del Public Speech, che usa gli stessi snapshot.
Loading