9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-31 04:46:37 +00:00

重构区块缓存

This commit is contained in:
XiaoMoMi
2025-05-07 19:49:21 +08:00
parent 1b93704a4e
commit c3bf97a3f5
17 changed files with 154 additions and 147 deletions

View File

@@ -17,6 +17,7 @@ import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.implementation.bind.annotation.This;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
import net.bytebuddy.implementation.bytecode.member.FieldAccess;
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
@@ -77,6 +78,7 @@ public class BukkitInjector {
private static Class<?> clazz$InjectedPalettedContainer;
private static Class<?> clazz$InjectedLevelChunkSection;
private static MethodHandle constructor$InjectedLevelChunkSection;
private static VarHandle varHandle$InjectedPalettedContainer$target;
@@ -104,6 +106,7 @@ public class BukkitInjector {
.name("net.minecraft.world.level.chunk.InjectedPalettedContainer")
.implement(InjectedHolder.Palette.class)
.defineField("target", Reflections.clazz$PalettedContainer, Visibility.PUBLIC)
.defineField("active", boolean.class, Visibility.PUBLIC)
.defineField("cesection", CESection.class, Visibility.PRIVATE)
.defineField("cechunk", CEChunk.class, Visibility.PRIVATE)
.defineField("cepos", SectionPos.class, Visibility.PRIVATE)
@@ -116,6 +119,10 @@ public class BukkitInjector {
.intercept(MethodDelegation.to(GetAndSetInterceptor.INSTANCE))
.method(ElementMatchers.named("target"))
.intercept(FieldAccessor.ofField("target"))
.method(ElementMatchers.named("setTarget"))
.intercept(FieldAccessor.ofField("target").withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC))
.method(ElementMatchers.named("isActive").or(ElementMatchers.named("setActive")))
.intercept(FieldAccessor.ofField("active"))
.method(ElementMatchers.named("ceSection"))
.intercept(FieldAccessor.ofField("cesection"))
.method(ElementMatchers.named("ceChunk"))
@@ -125,13 +132,14 @@ public class BukkitInjector {
.make()
.load(BukkitInjector.class.getClassLoader())
.getLoaded();
varHandle$InjectedPalettedContainer$target = Objects.requireNonNull(ReflectionUtils.findVarHandle(clazz$InjectedPalettedContainer, "target", Reflections.clazz$PalettedContainer));
//varHandle$InjectedPalettedContainer$target = Objects.requireNonNull(ReflectionUtils.findVarHandle(clazz$InjectedPalettedContainer, "target", Reflections.clazz$PalettedContainer));
// Level Chunk Section
clazz$InjectedLevelChunkSection = byteBuddy
.subclass(Reflections.clazz$LevelChunkSection)
.subclass(Reflections.clazz$LevelChunkSection, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
.name("net.minecraft.world.level.chunk.InjectedLevelChunkSection")
.implement(InjectedHolder.Section.class)
.defineField("active", boolean.class, Visibility.PUBLIC)
.defineField("cesection", CESection.class, Visibility.PRIVATE)
.defineField("cechunk", CEChunk.class, Visibility.PRIVATE)
.defineField("cepos", SectionPos.class, Visibility.PRIVATE)
@@ -143,10 +151,16 @@ public class BukkitInjector {
.intercept(FieldAccessor.ofField("cechunk"))
.method(ElementMatchers.named("cePos"))
.intercept(FieldAccessor.ofField("cepos"))
.method(ElementMatchers.named("isActive").or(ElementMatchers.named("setActive")))
.intercept(FieldAccessor.ofField("active"))
.make()
.load(BukkitInjector.class.getClassLoader())
.getLoaded();
constructor$InjectedLevelChunkSection = MethodHandles.publicLookup().in(clazz$InjectedLevelChunkSection)
.findConstructor(clazz$InjectedLevelChunkSection, MethodType.methodType(void.class, Reflections.clazz$PalettedContainer, Reflections.clazz$PalettedContainer))
.asType(MethodType.methodType(Reflections.clazz$LevelChunkSection, Reflections.clazz$PalettedContainer, Reflections.clazz$PalettedContainer));
// State Predicate
DynamicType.Unloaded<?> alwaysTrue = byteBuddy
.subclass(Reflections.clazz$StatePredicate)
@@ -408,32 +422,50 @@ public class BukkitInjector {
try {
if (Config.injectionTarget()) {
Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection);
if (!(container instanceof InjectedHolder.Palette)) {
if (!(container instanceof InjectedHolder.Palette holder)) {
InjectedHolder.Palette injectedObject;
if (Config.fastInjection()) {
injectedObject = FastNMS.INSTANCE.createInjectedPalettedContainerHolder(container);
} else {
injectedObject = (InjectedHolder.Palette) Reflections.UNSAFE.allocateInstance(clazz$InjectedPalettedContainer);
varHandle$InjectedPalettedContainer$target.set(injectedObject, container);
injectedObject.setTarget(container);
//varHandle$InjectedPalettedContainer$target.set(injectedObject, container);
}
injectedObject.ceChunk(chunk);
injectedObject.ceSection(ceSection);
injectedObject.cePos(pos);
injectedObject.setActive(true);
Reflections.varHandle$PalettedContainer$data.setVolatile(injectedObject, Reflections.varHandle$PalettedContainer$data.get(container));
Reflections.field$LevelChunkSection$states.set(targetSection, injectedObject);
} else {
holder.ceChunk(chunk);
holder.ceSection(ceSection);
holder.cePos(pos);
holder.setActive(true);
}
} else {
InjectedHolder.Section injectedObject;
if (true) {
injectedObject = FastNMS.INSTANCE.createInjectedLevelChunkSectionHolder(targetSection);
if (!(targetSection instanceof InjectedHolder.Section holder)) {
InjectedHolder.Section injectedObject;
if (Config.fastInjection()) {
injectedObject = FastNMS.INSTANCE.createInjectedLevelChunkSectionHolder(targetSection);
} else {
injectedObject = (InjectedHolder.Section) constructor$InjectedLevelChunkSection.invoke(
FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection), FastNMS.INSTANCE.field$LevelChunkSection$biomes(targetSection));
}
injectedObject.ceChunk(chunk);
injectedObject.ceSection(ceSection);
injectedObject.cePos(pos);
injectedObject.setActive(true);
callback.accept(injectedObject);
} else {
holder.ceChunk(chunk);
holder.ceSection(ceSection);
holder.cePos(pos);
holder.setActive(true);
}
injectedObject.ceChunk(chunk);
injectedObject.ceSection(ceSection);
injectedObject.cePos(pos);
callback.accept(injectedObject);
}
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to inject chunk section", e);
} catch (Throwable e) {
CraftEngine.instance().logger().severe("Failed to inject chunk section " + pos, e);
}
}
@@ -450,15 +482,17 @@ public class BukkitInjector {
if (Config.injectionTarget()) {
Object states = FastNMS.INSTANCE.field$LevelChunkSection$states(section);
if (states instanceof InjectedHolder.Palette holder) {
try {
Reflections.field$LevelChunkSection$states.set(section, holder.target());
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().severe("Failed to uninject palette", e);
}
holder.setActive(false);
// try {
// Reflections.field$LevelChunkSection$states.set(section, holder.target());
// } catch (ReflectiveOperationException e) {
// CraftEngine.instance().logger().severe("Failed to uninject palette", e);
// }
}
} else {
if (section instanceof InjectedHolder.Section holder) {
return FastNMS.INSTANCE.constructor$LevelChunkSection(holder);
holder.setActive(false);
//return FastNMS.INSTANCE.constructor$LevelChunkSection(holder);
}
}
return section;
@@ -730,7 +764,9 @@ public class BukkitInjector {
int z = (int) args[2];
Object newState = args[3];
Object previousState = superMethod.call();
compareAndUpdateBlockState(x, y, z, newState, previousState, holder);
if (holder.isActive()) {
compareAndUpdateBlockState(x, y, z, newState, previousState, holder);
}
return previousState;
}
}
@@ -747,7 +783,9 @@ public class BukkitInjector {
int z = (int) args[2];
Object newState = args[3];
Object previousState = FastNMS.INSTANCE.method$PalettedContainer$getAndSet(targetStates, x, y, z, newState);
compareAndUpdateBlockState(x, y, z, newState, previousState, holder);
if (holder.isActive()) {
compareAndUpdateBlockState(x, y, z, newState, previousState, holder);
}
return previousState;
}
}

View File

@@ -266,27 +266,24 @@ public class BukkitWorldManager implements WorldManager, Listener {
if (ceChunk != null) {
if (ceChunk.dirty()) {
try {
world.worldDataStorage().writeChunkAt(pos, ceChunk, false);
this.plugin.debug(() -> "[Dirty Chunk]" + pos + " unloaded");
world.worldDataStorage().writeChunkAt(pos, ceChunk);
ceChunk.setDirty(false);
} catch (IOException e) {
this.plugin.logger().warn("Failed to write chunk tag at " + chunk.getX() + " " + chunk.getZ(), e);
}
}
if (Config.restoreVanillaBlocks()) {
boolean unsaved = false;
CESection[] ceSections = ceChunk.sections();
Object worldServer = FastNMS.INSTANCE.field$CraftChunk$worldServer(chunk);
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer);
Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ());
Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk);
for (int i = 0; i < ceSections.length; i++) {
CESection ceSection = ceSections[i];
Object section = sections[i];
Object uninjectedSection = BukkitInjector.uninjectLevelChunkSection(section);
if (uninjectedSection != section) {
sections[i] = uninjectedSection;
section = uninjectedSection;
}
boolean unsaved = false;
CESection[] ceSections = ceChunk.sections();
Object worldServer = FastNMS.INSTANCE.field$CraftChunk$worldServer(chunk);
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer);
Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ());
Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk);
for (int i = 0; i < ceSections.length; i++) {
CESection ceSection = ceSections[i];
Object section = sections[i];
BukkitInjector.uninjectLevelChunkSection(section);
if (Config.restoreVanillaBlocks()) {
if (!ceSection.statesContainer().isEmpty()) {
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
@@ -301,9 +298,9 @@ public class BukkitWorldManager implements WorldManager, Listener {
}
}
}
if (unsaved && !FastNMS.INSTANCE.method$LevelChunk$isUnsaved(levelChunk)) {
FastNMS.INSTANCE.method$LevelChunk$markUnsaved(levelChunk);
}
}
if (unsaved && !FastNMS.INSTANCE.method$LevelChunk$isUnsaved(levelChunk)) {
FastNMS.INSTANCE.method$LevelChunk$markUnsaved(levelChunk);
}
ceChunk.unload();
}