Skip quiet block update checks

- ChunkBlockUpdateListener remembers the last state with no update or custom effect
- Plain terrain runs skip the per-block isUpdatable and isCustom checks
- Test replays random writes against the per-write catch semantics
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-28 14:13:20 -04:00
1 parent 2ac9609407
commit cb31510b89
3 files changed
+114 -1

No files matched your search

@@ -0,0 +1,53 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2026 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package art.arcane.iris.generation.runtime;
import art.arcane.iris.generation.block.B;
import art.arcane.iris.generation.chunk.ColumnExtentListeningHunk;
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
/**
* Forwards a chunk's block writes to {@link BlockUpdater#catchBlockUpdates} at world coordinates.
* The last state seen to need neither a block update nor custom handling is remembered, so the
* long runs of plain terrain skip the per-block checks. Racing writers only ever store such states.
*/
final class ChunkBlockUpdateListener implements ColumnExtentListeningHunk.Listener<NativeBlockState> {
private final BlockUpdater updater;
private final int originX;
private final int originZ;
private NativeBlockState quiet;
ChunkBlockUpdateListener(BlockUpdater updater, int originX, int originZ) {
this.updater = updater;
this.originX = originX;
this.originZ = originZ;
}
@Override
public void onWrite(int x, int y, int z, NativeBlockState state) {
if (state == null || state == quiet) {
return;
}
if (B.isUpdatable(state) || state.isCustom()) {
updater.catchBlockUpdates(originX + x, y, originZ + z, state);
return;
}
quiet = state;
}
}
@@ -1472,7 +1472,7 @@ public class IrisEngine implements Engine {
IrisContext.Scope generationScope = IrisContext.open(this, lease.sessionId(), null)) {
getEngineData().getStatistics().generatedChunk();
PrecisionStopwatch p = PrecisionStopwatch.start();
Hunk<NativeBlockState> blocks = new ColumnExtentListeningHunk<>(vblocks, (xx, y, zz, t) -> catchBlockUpdates(x + xx, y, z + zz, t));
Hunk<NativeBlockState> blocks = new ColumnExtentListeningHunk<>(vblocks, new ChunkBlockUpdateListener(this, x, z));
if (getDimension().isDebugChunkCrossSections() && ((x >> 4) % getDimension().getDebugCrossSectionsMod() == 0 || (z >> 4) % getDimension().getDebugCrossSectionsMod() == 0)) {
NativeBlockState crossSection = B.getState("CRYING_OBSIDIAN");