mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-12 03:24:14 +00:00
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:
@@ -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");
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package art.arcane.iris.generation.runtime;
|
||||
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeBlockState;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ChunkBlockUpdateListenerTest {
|
||||
@Test
|
||||
public void forwardsExactlyTheWritesWithBlockUpdateEffects() {
|
||||
NativeBlockState stone = state(false, false);
|
||||
NativeBlockState deepslate = state(false, false);
|
||||
NativeBlockState water = state(true, false);
|
||||
NativeBlockState custom = state(false, true);
|
||||
NativeBlockState[] palette = {stone, deepslate, water, custom, null};
|
||||
Random random = new Random(42L);
|
||||
List<String> expected = new ArrayList<>();
|
||||
List<String> actual = new ArrayList<>();
|
||||
BlockUpdater reference = effects(expected);
|
||||
ChunkBlockUpdateListener listener = new ChunkBlockUpdateListener(effects(actual), 160, -48);
|
||||
|
||||
for (int write = 0; write < 20_000; write++) {
|
||||
NativeBlockState state = palette[random.nextInt(8) < 5 ? random.nextInt(2) : random.nextInt(palette.length)];
|
||||
int x = random.nextInt(16);
|
||||
int y = random.nextInt(384);
|
||||
int z = random.nextInt(16);
|
||||
reference.catchBlockUpdates(160 + x, y, -48 + z, state);
|
||||
listener.onWrite(x, y, z, state);
|
||||
}
|
||||
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
private static BlockUpdater effects(List<String> log) {
|
||||
return (x, y, z, data) -> {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
if (data.isUpdatable()) {
|
||||
log.add("update " + x + "," + y + "," + z);
|
||||
}
|
||||
if (data.isCustom()) {
|
||||
log.add("custom " + (x >> 4) + "," + (z >> 4));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static NativeBlockState state(boolean updatable, boolean custom) {
|
||||
NativeBlockState state = mock(NativeBlockState.class);
|
||||
when(state.isUpdatable()).thenReturn(updatable);
|
||||
when(state.isCustom()).thenReturn(custom);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user