9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-29 11:59:11 +00:00

添加区块脏位标记

This commit is contained in:
XiaoMoMi
2025-04-29 15:20:00 +08:00
parent 7146ab335e
commit 329f129e5f
11 changed files with 94 additions and 17 deletions

View File

@@ -49,6 +49,7 @@ import net.momirealms.craftengine.core.util.SectionPosUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.CEWorld;
import net.momirealms.craftengine.core.world.SectionPos;
import net.momirealms.craftengine.core.world.chunk.CEChunk;
import net.momirealms.craftengine.core.world.chunk.CESection;
import net.momirealms.craftengine.core.world.chunk.InjectedPalettedContainerHolder;
import net.momirealms.craftengine.shared.ObjectHolder;
@@ -101,8 +102,9 @@ public class BukkitInjector {
.name("net.minecraft.world.level.chunk.InjectedPalettedContainer")
.implement(InjectedPalettedContainerHolder.class)
.defineField("target", Reflections.clazz$PalettedContainer, Visibility.PRIVATE)
.defineField("cesection", CESection.class, Visibility.PRIVATE)
.defineField("ceworld", CEWorld.class, Visibility.PRIVATE)
.defineField("cesection", CESection.class, Visibility.PRIVATE)
.defineField("cechunk", CEChunk.class, Visibility.PRIVATE)
.defineField("cepos", SectionPos.class, Visibility.PRIVATE)
.method(ElementMatchers.any()
.and(ElementMatchers.not(ElementMatchers.is(Reflections.method$PalettedContainer$getAndSet)))
@@ -117,6 +119,8 @@ public class BukkitInjector {
.intercept(FieldAccessor.ofField("target"))
.method(ElementMatchers.named("ceSection"))
.intercept(FieldAccessor.ofField("cesection"))
.method(ElementMatchers.named("ceChunk"))
.intercept(FieldAccessor.ofField("cechunk"))
.method(ElementMatchers.named("ceWorld"))
.intercept(FieldAccessor.ofField("ceworld"))
.method(ElementMatchers.named("cePos"))
@@ -384,14 +388,15 @@ public class BukkitInjector {
// }
// }
public static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, SectionPos pos) {
public static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, CEChunk chunk, SectionPos pos) {
try {
Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection);
if (!clazz$InjectedPalettedContainer.isInstance(container)) {
InjectedPalettedContainerHolder injectedObject = (InjectedPalettedContainerHolder) Reflections.UNSAFE.allocateInstance(clazz$InjectedPalettedContainer);
varHandle$InjectedPalettedContainer$target.set(injectedObject, container);
injectedObject.ceSection(ceSection);
injectedObject.ceWorld(ceWorld);
injectedObject.ceChunk(chunk);
injectedObject.ceSection(ceSection);
injectedObject.cePos(pos);
Reflections.varHandle$PalettedContainer$data.setVolatile(injectedObject, Reflections.varHandle$PalettedContainer$data.get(container));
Reflections.field$LevelChunkSection$states.set(targetSection, injectedObject);
@@ -682,16 +687,24 @@ public class BukkitInjector {
Object newState = args[3];
int stateId = BlockStateUtils.blockStateToId(newState);
CESection section = holder.ceSection();
// 如果是原版方块
if (BlockStateUtils.isVanillaBlock(stateId)) {
section.setBlockState(x, y, z, EmptyBlock.INSTANCE.defaultState());
// 那么应该情况自定义块
ImmutableBlockState previous = section.setBlockState(x, y, z, EmptyBlock.INSTANCE.defaultState());
// 如果先前不是空气则标记
if (!previous.isEmpty()) {
holder.ceChunk().setDirty(true);
}
if (Config.enableLightSystem() && Config.forceUpdateLight()) {
updateLightIfChanged(holder, previousState, newState, null, y, z, x);
}
} else {
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
section.setBlockState(x, y, z, immutableBlockState);
if (!immutableBlockState.isEmpty()) {
if (Config.enableLightSystem()) {
ImmutableBlockState previousImmutableBlockState = section.setBlockState(x, y, z, immutableBlockState);
// 如果之前的自定义块(空气)和当前自定义块不同
if (previousImmutableBlockState != immutableBlockState) {
holder.ceChunk().setDirty(true);
if (Config.enableLightSystem() && !immutableBlockState.isEmpty()) {
updateLightIfChanged(holder, previousState, newState, immutableBlockState.vanillaBlockState().handle(), y, z, x);
}
}

View File

@@ -375,7 +375,7 @@ public class BukkitWorldManager implements WorldManager, Listener {
}
}
}
BukkitInjector.injectLevelChunkSection(section, ceSection, ceWorld, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z));
BukkitInjector.injectLevelChunkSection(section, ceSection, ceWorld, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z));
}
if (Config.enableRecipeSystem()) {
@SuppressWarnings("unchecked")

View File

@@ -47,7 +47,11 @@ public abstract class CEWorld {
this.loadedChunkMapLock.readLock().lock();
try {
for (Map.Entry<Long, CEChunk> entry : this.loadedChunkMap.entrySet()) {
worldDataStorage.writeChunkAt(new ChunkPos(entry.getKey()), entry.getValue(), true);
CEChunk chunk = entry.getValue();
if (chunk.dirty()) {
worldDataStorage.writeChunkAt(new ChunkPos(entry.getKey()), chunk, true);
chunk.setDirty(false);
}
}
} catch (IOException e) {
CraftEngine.instance().logger().warn("Failed to save world chunks", e);

View File

@@ -16,6 +16,7 @@ public class CEChunk {
private final CESection[] sections;
private final WorldHeight worldHeightAccessor;
private final List<Vec3d> entities;
private boolean dirty;
public CEChunk(CEWorld world, ChunkPos chunkPos) {
this.world = world;
@@ -44,6 +45,14 @@ public class CEChunk {
this.fillEmptySection();
}
public boolean dirty() {
return dirty;
}
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
public boolean isEmpty() {
if (!this.entities.isEmpty()) return false;
for (CESection section : this.sections) {
@@ -73,7 +82,10 @@ public class CEChunk {
if (section == null) {
return;
}
section.setBlockState((y & 15) << 8 | (z & 15) << 4 | x & 15, state);
ImmutableBlockState previous = section.setBlockState((y & 15) << 8 | (z & 15) << 4 | x & 15, state);
if (previous != state) {
setDirty(true);
}
}
@Nullable

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.world.chunk;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.world.BlockPos;
import org.jetbrains.annotations.ApiStatus;
public class CESection {
public static final int SECTION_WIDTH = 16;
@@ -16,30 +17,37 @@ public class CESection {
this.statesContainer = statesContainer;
}
public void setBlockState(BlockPos pos, ImmutableBlockState state) {
this.setBlockState(pos.x() & 15, pos.y() & 15, pos.z() & 15, state);
@ApiStatus.Internal
public ImmutableBlockState setBlockState(BlockPos pos, ImmutableBlockState state) {
return this.setBlockState(pos.x() & 15, pos.y() & 15, pos.z() & 15, state);
}
public void setBlockState(int x, int y, int z, ImmutableBlockState state) {
this.statesContainer.set((y << 4 | z) << 4 | x, state);
@ApiStatus.Internal
public ImmutableBlockState setBlockState(int x, int y, int z, ImmutableBlockState state) {
return this.setBlockState((y << 4 | z) << 4 | x, state);
}
public void setBlockState(int index, ImmutableBlockState state) {
this.statesContainer.set(index, state);
@ApiStatus.Internal
public ImmutableBlockState setBlockState(int index, ImmutableBlockState state) {
return this.statesContainer.getAndSet(index, state);
}
@ApiStatus.Internal
public ImmutableBlockState getBlockState(BlockPos pos) {
return getBlockState(pos.x() & 15, pos.y() & 15, pos.z() & 15);
}
@ApiStatus.Internal
public ImmutableBlockState getBlockState(int x, int y, int z) {
return statesContainer.get((y << 4 | z) << 4 | x);
}
@ApiStatus.Internal
public ImmutableBlockState getBlockState(int index) {
return statesContainer.get(index);
}
@ApiStatus.Internal
public PalettedContainer<ImmutableBlockState> statesContainer() {
return statesContainer;
}

View File

@@ -6,35 +6,48 @@ import java.util.function.IntConsumer;
public record EmptyPaletteStorage(int size) implements PaletteStorage {
public static final long[] EMPTY_DATA = new long[0];
@Override
public int swap(int index, int value) {
return 0;
}
@Override
public void set(int index, int value) {
}
@Override
public int getAndSet(int index, int value) {
return 0;
}
@Override
public int get(int index) {
return 0;
}
@Override
public long[] getData() {
return EMPTY_DATA;
}
@Override
public int getElementBits() {
return 0;
}
@Override
public void forEach(IntConsumer action) {
for (int i = 0; i < this.size; ++i) {
action.accept(0);
}
}
@Override
public void writePaletteIndices(int[] out) {
Arrays.fill(out, 0, this.size, 0);
}
@Override
public PaletteStorage copy() {
return this;
}

View File

@@ -11,6 +11,10 @@ public interface InjectedPalettedContainerHolder {
void ceSection(CESection section);
CEChunk ceChunk();
void ceChunk(CEChunk chunk);
CEWorld ceWorld();
void ceWorld(CEWorld world);

View File

@@ -81,7 +81,7 @@ public class PackedIntegerArray implements PaletteStorage {
int i = this.getStorageIndex(index);
long l = this.data[i];
int j = (index - i * this.elementsPerLong) * this.elementBits;
this.data[i] = l & ~(this.maxValue << j) | ((long)value & this.maxValue) << j;
this.data[i] = l & ~(this.maxValue << j) | ((long) value & this.maxValue) << j;
}
@Override
@@ -92,6 +92,15 @@ public class PackedIntegerArray implements PaletteStorage {
return (int)(l >> j & this.maxValue);
}
@Override
public int getAndSet(int index, int value) {
int i = this.getStorageIndex(index);
long l = this.data[i];
int j = (index - i * this.elementsPerLong) * this.elementBits;
this.data[i] = l & ~(this.maxValue << j) | ((long) value & this.maxValue) << j;
return (int)(l >> j & this.maxValue);
}
@Override
public long[] getData() {
return this.data;

View File

@@ -8,6 +8,8 @@ public interface PaletteStorage {
void set(int index, int value);
int getAndSet(int index, int value);
int get(int index);
long[] getData();

View File

@@ -125,6 +125,17 @@ public class PalettedContainer<T> implements PaletteResizeListener<T>, ReadableC
return data.palette.get(data.storage.get(index));
}
public T getAndSet(int index, T state) {
this.lock();
try {
int i = this.data.palette.index(state);
int preIndex = this.data.storage.getAndSet(index, i);
return this.data.palette.get(preIndex);
} finally {
this.unlock();
}
}
public void set(int x, int y, int z, T value) {
this.lock();
try {

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.mod;
import net.minecraft.world.level.chunk.PalettedContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.tree.ClassNode;