9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2026-01-04 15:41:38 +00:00

Merge branch 'Xiao-MoMi:dev' into dev

This commit is contained in:
jhqwqmc
2025-05-07 06:22:21 +08:00
committed by GitHub
9 changed files with 184 additions and 94 deletions

View File

@@ -51,7 +51,7 @@ 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.core.world.chunk.InjectedHolder;
import net.momirealms.craftengine.shared.ObjectHolder;
import net.momirealms.craftengine.shared.block.*;
import org.bukkit.inventory.ItemStack;
@@ -69,12 +69,14 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
public class BukkitInjector {
private static final ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17);
private static final BukkitBlockShape STONE_SHAPE = new BukkitBlockShape(Reflections.instance$Blocks$STONE$defaultState);
private static Class<?> clazz$InjectedPalettedContainer;
private static Class<?> clazz$InjectedLevelChunkSection;
private static VarHandle varHandle$InjectedPalettedContainer$target;
@@ -100,17 +102,14 @@ public class BukkitInjector {
clazz$InjectedPalettedContainer = byteBuddy
.subclass(Reflections.clazz$PalettedContainer)
.name("net.minecraft.world.level.chunk.InjectedPalettedContainer")
.implement(InjectedPalettedContainerHolder.class)
.defineField("target", Reflections.clazz$PalettedContainer, Visibility.PRIVATE)
.defineField("ceworld", CEWorld.class, Visibility.PRIVATE)
.implement(InjectedHolder.Palette.class)
.defineField("target", Reflections.clazz$PalettedContainer, Visibility.PUBLIC)
.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)))
.and(ElementMatchers.not(ElementMatchers.isDeclaredBy(Object.class)))
// TODO Requires Paper Patch
//.and(ElementMatchers.not(ElementMatchers.named("get").and(ElementMatchers.takesArguments(int.class)).and(ElementMatchers.returns(Object.class))))
)
.intercept(MethodDelegation.toField("target"))
.method(ElementMatchers.is(Reflections.method$PalettedContainer$getAndSet))
@@ -121,16 +120,33 @@ public class BukkitInjector {
.intercept(FieldAccessor.ofField("cesection"))
.method(ElementMatchers.named("ceChunk"))
.intercept(FieldAccessor.ofField("cechunk"))
.method(ElementMatchers.named("ceWorld"))
.intercept(FieldAccessor.ofField("ceworld"))
.method(ElementMatchers.named("cePos"))
.intercept(FieldAccessor.ofField("cepos"))
.make()
.load(BukkitInjector.class.getClassLoader())
.getLoaded();
varHandle$InjectedPalettedContainer$target = Objects.requireNonNull(ReflectionUtils.findVarHandle(clazz$InjectedPalettedContainer, "target", Reflections.clazz$PalettedContainer));
// Level Chunk Section
clazz$InjectedLevelChunkSection = byteBuddy
.subclass(Reflections.clazz$LevelChunkSection)
.name("net.minecraft.world.level.chunk.InjectedLevelChunkSection")
.implement(InjectedHolder.Section.class)
.defineField("cesection", CESection.class, Visibility.PRIVATE)
.defineField("cechunk", CEChunk.class, Visibility.PRIVATE)
.defineField("cepos", SectionPos.class, Visibility.PRIVATE)
.method(ElementMatchers.is(Reflections.method$LevelChunkSection$setBlockState))
.intercept(MethodDelegation.to(SetBlockStateInterceptor.INSTANCE))
.method(ElementMatchers.named("ceSection"))
.intercept(FieldAccessor.ofField("cesection"))
.method(ElementMatchers.named("ceChunk"))
.intercept(FieldAccessor.ofField("cechunk"))
.method(ElementMatchers.named("cePos"))
.intercept(FieldAccessor.ofField("cepos"))
.make()
.load(BukkitInjector.class.getClassLoader())
.getLoaded();
// State Predicate
DynamicType.Unloaded<?> alwaysTrue = byteBuddy
.subclass(Reflections.clazz$StatePredicate)
@@ -388,23 +404,33 @@ public class BukkitInjector {
// }
// }
public synchronized static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEChunk chunk, SectionPos pos) {
public synchronized static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEChunk chunk, SectionPos pos, Consumer<Object> callback) {
try {
Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection);
if (!(container instanceof InjectedPalettedContainerHolder)) {
InjectedPalettedContainerHolder injectedObject;
if (Config.fastPaletteInjection()) {
injectedObject = FastNMS.INSTANCE.createInjectedPalettedContainerHolder(container);
} else {
injectedObject = (InjectedPalettedContainerHolder) Reflections.UNSAFE.allocateInstance(clazz$InjectedPalettedContainer);
varHandle$InjectedPalettedContainer$target.set(injectedObject, container);
if (Config.injectionTarget()) {
Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection);
if (!(container instanceof InjectedHolder.Palette)) {
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.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);
}
} else {
InjectedHolder.Section injectedObject;
if (true) {
injectedObject = FastNMS.INSTANCE.createInjectedLevelChunkSectionHolder(targetSection);
}
injectedObject.ceWorld(chunk.world());
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);
callback.accept(injectedObject);
}
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to inject chunk section", e);
@@ -412,19 +438,30 @@ public class BukkitInjector {
}
public static boolean isSectionInjected(Object section) {
Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(section);
return container instanceof InjectedPalettedContainerHolder;
if (Config.injectionTarget()) {
Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(section);
return container instanceof InjectedHolder.Palette;
} else {
return section instanceof InjectedHolder.Section;
}
}
public synchronized static void uninjectLevelChunkSection(Object section) {
try {
public synchronized static Object uninjectLevelChunkSection(Object section) {
if (Config.injectionTarget()) {
Object states = FastNMS.INSTANCE.field$LevelChunkSection$states(section);
if (states instanceof InjectedPalettedContainerHolder holder) {
Reflections.field$LevelChunkSection$states.set(section, holder.target());
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);
}
}
} else {
if (section instanceof InjectedHolder.Section holder) {
return FastNMS.INSTANCE.constructor$LevelChunkSection(holder);
}
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().severe("Failed to inject chunk section", e);
}
return section;
}
public static class GetRecipeForMethodInterceptor1_20 {
@@ -682,58 +719,78 @@ public class BukkitInjector {
}
}
public static class SetBlockStateInterceptor {
public static final SetBlockStateInterceptor INSTANCE = new SetBlockStateInterceptor();
@RuntimeType
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
InjectedHolder.Section holder = (InjectedHolder.Section) thisObj;
int x = (int) args[0];
int y = (int) args[1];
int z = (int) args[2];
Object newState = args[3];
Object previousState = superMethod.call();
compareAndUpdateBlockState(x, y, z, newState, previousState, holder);
return previousState;
}
}
public static class GetAndSetInterceptor {
public static final GetAndSetInterceptor INSTANCE = new GetAndSetInterceptor();
@RuntimeType
public Object intercept(@This Object thisObj, @AllArguments Object[] args) {
InjectedPalettedContainerHolder holder = (InjectedPalettedContainerHolder) thisObj;
InjectedHolder.Palette holder = (InjectedHolder.Palette) thisObj;
Object targetStates = holder.target();
int x = (int) args[0];
int y = (int) args[1];
int z = (int) args[2];
Object previousState = FastNMS.INSTANCE.method$PalettedContainer$getAndSet(targetStates, x, y, z, args[3]);
try {
Object newState = args[3];
int stateId = BlockStateUtils.blockStateToId(newState);
CESection section = holder.ceSection();
// 如果是原版方块
if (BlockStateUtils.isVanillaBlock(stateId)) {
// 那么应该情况自定义块
ImmutableBlockState previous = section.setBlockState(x, y, z, EmptyBlock.STATE);
// 如果先前不是空气则标记
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);
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);
}
}
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to intercept setBlockState", e);
}
Object newState = args[3];
Object previousState = FastNMS.INSTANCE.method$PalettedContainer$getAndSet(targetStates, x, y, z, newState);
compareAndUpdateBlockState(x, y, z, newState, previousState, holder);
return previousState;
}
}
private void updateLightIfChanged(@This InjectedPalettedContainerHolder thisObj, Object previousBlockState, Object newState, @Nullable Object clientSideNewState, int y, int z, int x) throws ReflectiveOperationException {
int previousLight = BlockStateUtils.getLightEmission(previousBlockState);
int newLight = BlockStateUtils.getLightEmission(newState);
if (previousLight != newLight || (clientSideNewState != null && (BlockStateUtils.isOcclude(newState) != BlockStateUtils.isOcclude(clientSideNewState)))) {
CEWorld world = thisObj.ceWorld();
SectionPos sectionPos = thisObj.cePos();
Set<SectionPos> posSet = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, Math.max(newLight, previousLight));
world.sectionLightUpdated(posSet);
protected static void compareAndUpdateBlockState(int x, int y, int z, Object newState, Object previousState, InjectedHolder holder) {
try {
int stateId = BlockStateUtils.blockStateToId(newState);
CESection section = holder.ceSection();
// 如果是原版方块
if (BlockStateUtils.isVanillaBlock(stateId)) {
// 那么应该情况自定义块
ImmutableBlockState previous = section.setBlockState(x, y, z, EmptyBlock.STATE);
// 如果先前不是空气则标记
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);
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);
}
}
}
} catch (Exception e) {
CraftEngine.instance().logger().warn("Failed to intercept setBlockState", e);
}
}
protected static void updateLightIfChanged(@This InjectedHolder thisObj, Object previousBlockState, Object newState, @Nullable Object clientSideNewState, int y, int z, int x) throws ReflectiveOperationException {
int previousLight = BlockStateUtils.getLightEmission(previousBlockState);
int newLight = BlockStateUtils.getLightEmission(newState);
if (previousLight != newLight || (clientSideNewState != null && (BlockStateUtils.isOcclude(newState) != BlockStateUtils.isOcclude(clientSideNewState)))) {
CEWorld world = thisObj.ceChunk().world();
SectionPos sectionPos = thisObj.cePos();
Set<SectionPos> posSet = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, Math.max(newLight, previousLight));
world.sectionLightUpdated(posSet);
}
}

View File

@@ -1927,7 +1927,6 @@ public class Reflections {
// field$ChunkAccess$blockEntities = targetField;
// }
@Deprecated
public static final Method method$LevelChunkSection$setBlockState = requireNonNull(
ReflectionUtils.getMethod(
clazz$LevelChunkSection, clazz$BlockState, int.class, int.class, int.class, clazz$BlockState, boolean.class

View File

@@ -282,7 +282,11 @@ public class BukkitWorldManager implements WorldManager, Listener {
for (int i = 0; i < ceSections.length; i++) {
CESection ceSection = ceSections[i];
Object section = sections[i];
BukkitInjector.uninjectLevelChunkSection(section);
Object uninjectedSection = BukkitInjector.uninjectLevelChunkSection(section);
if (uninjectedSection != section) {
sections[i] = uninjectedSection;
section = uninjectedSection;
}
if (!ceSection.statesContainer().isEmpty()) {
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
@@ -383,7 +387,9 @@ public class BukkitWorldManager implements WorldManager, Listener {
}
}
}
BukkitInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z));
int finalI = i;
BukkitInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z),
(injected) -> sections[finalI] = injected);
}
if (Config.enableRecipeSystem()) {
@SuppressWarnings("unchecked")