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

注入blockstate

This commit is contained in:
XiaoMoMi
2025-06-27 18:03:50 +08:00
parent fdd1b88e0b
commit 4564bfdb5f
8 changed files with 104 additions and 16 deletions

View File

@@ -320,7 +320,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
for (Object block : (Iterable<Object>) MBuiltInRegistries.BLOCK) {
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(block);
if (affectedBlockSounds.contains(soundType)) {
Object state = getOnlyBlockState(block);
Object state = FastNMS.INSTANCE.method$Block$defaultState(block);
if (BlockStateUtils.isVanillaBlock(state)) {
affectedBlocks.add(block);
}
@@ -792,7 +792,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
CoreReflections.method$Holder$Reference$bindValue.invoke(blockHolder, newRealBlock);
CoreReflections.field$Holder$Reference$tags.set(blockHolder, Set.of());
newBlockState = getOnlyBlockState(newRealBlock);
newBlockState = FastNMS.INSTANCE.method$Block$defaultState(newRealBlock);
CoreReflections.method$IdMapper$add.invoke(CoreReflections.instance$Block$BLOCK_STATE_REGISTRY, newBlockState);
if (isNoteBlock) {
@@ -838,13 +838,6 @@ public class BukkitBlockManager extends AbstractBlockManager {
return blockProperties;
}
private Object getOnlyBlockState(Object newBlock) throws IllegalAccessException {
Object stateDefinition = CoreReflections.field$Block$StateDefinition.get(newBlock);
@SuppressWarnings("unchecked")
ImmutableList<Object> states = (ImmutableList<Object>) CoreReflections.field$StateDefinition$states.get(stateDefinition);
return states.get(0);
}
@SuppressWarnings("unchecked")
private void deceiveBukkit() {
try {

View File

@@ -108,6 +108,7 @@ public class BukkitCraftEngine extends CraftEngine {
if (super.blockManager != null) return;
try {
BlockGenerator.init();
BlockStateGenerator.init();
super.blockManager = new BukkitBlockManager(this);
} catch (Exception e) {
throw new InjectionException("Error injecting blocks", e);

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.plugin.injector;
import com.google.common.collect.ImmutableList;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.description.modifier.Visibility;
@@ -30,6 +31,7 @@ import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.util.concurrent.Callable;
import java.util.function.BiConsumer;
import java.util.function.Function;
public final class BlockGenerator {
private static final BukkitBlockShape STONE_SHAPE =
@@ -201,6 +203,12 @@ public final class BlockGenerator {
field$CraftEngineBlock$shape.set(newBlockInstance, shapeHolder);
field$CraftEngineBlock$isNoteBlock.set(newBlockInstance, replacedBlock.equals(BlockKeys.NOTE_BLOCK));
field$CraftEngineBlock$isTripwire.set(newBlockInstance, replacedBlock.equals(BlockKeys.TRIPWIRE));
Object stateDefinitionBuilder = CoreReflections.constructor$StateDefinition$Builder.newInstance(newBlockInstance);
Object stateDefinition = CoreReflections.method$StateDefinition$Builder$create.invoke(stateDefinitionBuilder,
(Function<Object, Object>) FastNMS.INSTANCE::method$Block$defaultState, BlockStateGenerator.instance$StateDefinition$Factory);
CoreReflections.field$Block$StateDefinition.set(newBlockInstance, stateDefinition);
CoreReflections.field$Block$defaultBlockState.set(newBlockInstance, ((ImmutableList<?>) CoreReflections.field$StateDefinition$states.get(stateDefinition)).getFirst());
return newBlockInstance;
}

View File

@@ -0,0 +1,58 @@
package net.momirealms.craftengine.bukkit.plugin.injector;
import com.mojang.serialization.MapCodec;
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.matcher.ElementMatchers;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.core.block.CustomBlockState;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public final class BlockStateGenerator {
private static MethodHandle constructor$CraftEngineBlockState;
public static Object instance$StateDefinition$Factory;
public static void init() throws ReflectiveOperationException {
ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17);
String packageWithName = BlockStateGenerator.class.getName();
String generatedStateClassName = packageWithName.substring(0, packageWithName.lastIndexOf('.')) + ".CraftEngineBlockState";
DynamicType.Builder<?> stateBuilder = byteBuddy
.subclass(CoreReflections.clazz$BlockState, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
.name(generatedStateClassName)
.implement(CustomBlockState.class);
Class<?> clazz$CraftEngineBlock = stateBuilder.make().load(BlockStateGenerator.class.getClassLoader()).getLoaded();
constructor$CraftEngineBlockState = MethodHandles.publicLookup().in(clazz$CraftEngineBlock)
.findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class))
.asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class));
String generatedFactoryClassName = packageWithName.substring(0, packageWithName.lastIndexOf('.')) + ".CraftEngineStateFactory";
DynamicType.Builder<?> factoryBuilder = byteBuddy
.subclass(Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING)
.name(generatedFactoryClassName)
.implement(CoreReflections.clazz$StateDefinition$Factory)
.method(ElementMatchers.named("create"))
.intercept(MethodDelegation.to(CreateStateInterceptor.INSTANCE));
Class<?> clazz$Factory = factoryBuilder.make().load(BlockStateGenerator.class.getClassLoader()).getLoaded();
instance$StateDefinition$Factory = ReflectionUtils.getTheOnlyConstructor(clazz$Factory).newInstance();
}
public static class CreateStateInterceptor {
public static final CreateStateInterceptor INSTANCE = new CreateStateInterceptor();
@RuntimeType
public Object intercept(@AllArguments Object[] args) throws Throwable {
return constructor$CraftEngineBlockState.invoke(args[0], args[1], args[2]);
}
}
}

View File

@@ -22,6 +22,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import static java.util.Objects.requireNonNull;
@@ -1152,6 +1153,28 @@ public final class CoreReflections {
)
);
public static final Class<?> clazz$StateDefinition$Builder = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.level.block.state.BlockStateList$a",
"world.level.block.state.StateDefinition$Builder"
)
);
public static final Class<?> clazz$StateDefinition$Factory = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.level.block.state.BlockStateList$b",
"world.level.block.state.StateDefinition$Factory"
)
);
public static final Constructor<?> constructor$StateDefinition$Builder = requireNonNull(
ReflectionUtils.getTheOnlyConstructor(clazz$StateDefinition$Builder)
);
public static final Method method$StateDefinition$Builder$create = requireNonNull(
ReflectionUtils.getMethod(clazz$StateDefinition$Builder, clazz$StateDefinition, Function.class, clazz$StateDefinition$Factory)
);
public static final Field field$Block$StateDefinition = requireNonNull(
ReflectionUtils.getDeclaredField(clazz$Block, clazz$StateDefinition, 0)
);
@@ -1572,8 +1595,8 @@ public final class CoreReflections {
}
}
public static final Method method$Block$defaultBlockState = requireNonNull(
ReflectionUtils.getMethod(clazz$Block, clazz$BlockState)
public static final Field field$Block$defaultBlockState = requireNonNull(
ReflectionUtils.getDeclaredField(clazz$Block, clazz$BlockState, 0)
);
public static final Method method$Entity$getOnPos = requireNonNull(
@@ -3503,4 +3526,5 @@ public final class CoreReflections {
throw new RuntimeException(e);
}
}
}

View File

@@ -27,14 +27,14 @@ public final class MBlocks {
static {
try {
AIR = getById("air");
AIR$defaultState = CoreReflections.method$Block$defaultBlockState.invoke(AIR);
AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR);
FIRE = getById("fire");
SOUL_FIRE = getById("soul_fire");
STONE = getById("stone");
STONE$defaultState = CoreReflections.method$Block$defaultBlockState.invoke(STONE);
STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE);
ICE = getById("ice");
SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass");
SHORT_GRASS$defaultState = CoreReflections.method$Block$defaultBlockState.invoke(SHORT_GRASS);
SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS);
SHULKER_BOX = getById("shulker_box");
COMPOSTER = getById("composter");
} catch (ReflectiveOperationException e) {