mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-29 11:59:11 +00:00
添加区块脏位标记
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ public interface InjectedPalettedContainerHolder {
|
||||
|
||||
void ceSection(CESection section);
|
||||
|
||||
CEChunk ceChunk();
|
||||
|
||||
void ceChunk(CEChunk chunk);
|
||||
|
||||
CEWorld ceWorld();
|
||||
|
||||
void ceWorld(CEWorld world);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user