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

feat(block): 添加瓜藤相关的方块行为并且修复判断方块问题

This commit is contained in:
jhqwqmc
2025-09-23 11:28:58 +08:00
parent bde8ce5d7d
commit d787f0bdfa
15 changed files with 399 additions and 91 deletions

View File

@@ -0,0 +1,110 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.IntegerProperty;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.util.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
public class AttachedStemBlockBehavior extends BushBlockBehavior {
public static final Factory FACTORY = new Factory();
private final Property<HorizontalDirection> facingProperty;
private final Key fruit;
private final Key stem;
public AttachedStemBlockBehavior(CustomBlock customBlock,
int delay,
boolean blacklist,
List<Object> tagsCanSurviveOn,
Set<Object> blockStatesCanSurviveOn,
Set<String> customBlocksCansSurviveOn,
Property<HorizontalDirection> facingProperty,
Key fruit,
Key stem) {
super(customBlock, delay, blacklist, false, tagsCanSurviveOn, blockStatesCanSurviveOn, customBlocksCansSurviveOn);
this.facingProperty = facingProperty;
this.fruit = fruit;
this.stem = stem;
}
@Override
public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable<Object> superMethod) {
return FastNMS.INSTANCE.field$FluidState$isEmpty(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(args[0]));
}
@Override
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
return (VersionHelper.isOrAbove1_20_5() ? args[1] : args[3]).equals(CoreReflections.instance$PathComputationType$AIR)
&& !FastNMS.INSTANCE.field$BlockBehavior$hasCollision(thisBlock) || (boolean) superMethod.call();
}
@Override
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object state = args[0];
HorizontalDirection direction = DirectionUtils.fromNMSDirection(args[updateShape$direction]).toHorizontalDirection();
Object neighborState = args[updateShape$neighborState];
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state);
if (optionalCustomState.isEmpty() || direction != optionalCustomState.get().get(this.facingProperty)) {
return super.updateShape(thisBlock, args, superMethod);
}
Optional<ImmutableBlockState> optionalCustomNeighborState = BlockStateUtils.getOptionalCustomBlockState(neighborState);
if (optionalCustomNeighborState.isPresent()) {
ImmutableBlockState customNeighborState = optionalCustomNeighborState.get();
if (!customNeighborState.owner().value().id().equals(this.fruit)) {
Object stemBlock = resetStemBlock();
if (stemBlock != null) return stemBlock;
}
} else {
if (this.stem.namespace().equals("minecraft")) {
Key neighborBlockId = BlockStateUtils.getBlockOwnerIdFromState(neighborState);
if (!neighborBlockId.equals(this.fruit)) {
Object stemBlock = resetStemBlock();
if (stemBlock != null) return stemBlock;
}
} else {
Object stemBlock = resetStemBlock();
if (stemBlock != null) return stemBlock;
}
}
return super.updateShape(thisBlock, args, superMethod);
}
private Object resetStemBlock() {
Optional<CustomBlock> optionalStemBlock = BukkitBlockManager.instance().blockById(this.stem);
if (optionalStemBlock.isPresent()) {
CustomBlock stemBlock = optionalStemBlock.get();
IntegerProperty ageProperty = (IntegerProperty) stemBlock.getProperty("age");
if (ageProperty == null) return stemBlock.defaultState().customBlockState().literalObject();
return stemBlock.defaultState().with(ageProperty, ageProperty.max).customBlockState().literalObject();
}
return null;
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments, false);
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist");
@SuppressWarnings("unchecked")
Property<HorizontalDirection> facingProperty = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.attached_stem.missing_facing");
Key fruit = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("fruit"), "warning.config.block.behavior.attached_stem.missing_fruit"));
Key stem = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("stem"), "warning.config.block.behavior.attached_stem.missing_stem"));
return new AttachedStemBlockBehavior(block, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), facingProperty, fruit, stem);
}
}
}

View File

@@ -39,6 +39,8 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key FENCE_BLOCK = Key.from("craftengine:fence_block");
public static final Key BUTTON_BLOCK = Key.from("craftengine:button_block");
public static final Key FACE_ATTACHED_HORIZONTAL_DIRECTIONAL_BLOCK = Key.from("craftengine:face_attached_horizontal_directional_block");
public static final Key STEM_BLOCK = Key.from("craftengine:stem_block");
public static final Key ATTACHED_STEM_BLOCK = Key.from("craftengine:attached_stem_block");
public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -76,5 +78,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(FENCE_BLOCK, FenceBlockBehavior.FACTORY);
register(BUTTON_BLOCK, ButtonBlockBehavior.FACTORY);
register(FACE_ATTACHED_HORIZONTAL_DIRECTIONAL_BLOCK, FaceAttachedHorizontalDirectionalBlockBehavior.FACTORY);
register(STEM_BLOCK, StemBlockBehavior.FACTORY);
register(ATTACHED_STEM_BLOCK, AttachedStemBlockBehavior.FACTORY);
}
}

View File

@@ -77,7 +77,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
return minGrowLight;
}
private static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException {
public static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException {
return (int) CoreReflections.method$BlockAndTintGetter$getRawBrightness.invoke(level, pos, 0);
}

View File

@@ -0,0 +1,154 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
import net.momirealms.craftengine.bukkit.util.KeyUtils;
import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UpdateOption;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.IntegerProperty;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.util.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
public class StemBlockBehavior extends BushBlockBehavior {
public static final Factory FACTORY = new Factory();
private final IntegerProperty ageProperty;
private final Key fruit;
private final Key attachedStem;
private final int minGrowLight;
private final Object tagMayPlaceFruit;
private final Object blockMayPlaceFruit;
public StemBlockBehavior(CustomBlock customBlock,
int delay,
boolean blacklist,
List<Object> tagsCanSurviveOn,
Set<Object> blockStatesCanSurviveOn,
Set<String> customBlocksCansSurviveOn,
IntegerProperty ageProperty,
Key fruit,
Key attachedStem,
int minGrowLight,
Object tagMayPlaceFruit,
Object blockMayPlaceFruit) {
super(customBlock, delay, blacklist, false, tagsCanSurviveOn, blockStatesCanSurviveOn, customBlocksCansSurviveOn);
this.ageProperty = ageProperty;
this.fruit = fruit;
this.attachedStem = attachedStem;
this.minGrowLight = minGrowLight;
this.tagMayPlaceFruit = tagMayPlaceFruit;
this.blockMayPlaceFruit = blockMayPlaceFruit;
}
@Override
public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable<Object> superMethod) {
return FastNMS.INSTANCE.field$FluidState$isEmpty(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(args[0]));
}
@Override
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
return (VersionHelper.isOrAbove1_20_5() ? args[1] : args[3]).equals(CoreReflections.instance$PathComputationType$AIR)
&& !FastNMS.INSTANCE.field$BlockBehavior$hasCollision(thisBlock) || (boolean) superMethod.call();
}
@Override
public void randomTick(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object state = args[0];
Object level = args[1];
Object pos = args[2];
if (CropBlockBehavior.getRawBrightness(level, pos) < this.minGrowLight) return;
ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null);
if (customState == null || customState.isEmpty()) return;
int age = customState.get(ageProperty);
if (age < ageProperty.max) {
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, customState.with(ageProperty, age + 1).customBlockState().literalObject(), 2);
return;
}
Object randomDirection = CoreReflections.instance$Direction$values[RandomUtils.generateRandomInt(2, 6)];
Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, randomDirection);
if (!FastNMS.INSTANCE.method$BlockStateBase$isAir(FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos)))
return;
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, FastNMS.INSTANCE.method$BlockPos$relative(blockPos, CoreReflections.instance$Direction$DOWN));
if (mayPlaceFruit(blockState)) {
Optional<CustomBlock> optionalFruit = BukkitBlockManager.instance().blockById(this.fruit);
Object fruitState = null;
if (optionalFruit.isPresent()) {
fruitState = optionalFruit.get().defaultState().customBlockState().literalObject();
} else if (fruit.namespace().equals("minecraft")) {
fruitState = FastNMS.INSTANCE.method$Block$defaultState(FastNMS.INSTANCE.method$Registry$getValue(
MBuiltInRegistries.BLOCK,
FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", fruit.value())
));
}
Optional<CustomBlock> optionalAttachedStem = BukkitBlockManager.instance().blockById(this.attachedStem);
if (fruitState == null || optionalAttachedStem.isEmpty()) return;
CustomBlock attachedStem = optionalAttachedStem.get();
@SuppressWarnings("unchecked")
Property<HorizontalDirection> facing = (Property<HorizontalDirection>) attachedStem.getProperty("facing");
if (facing == null) return;
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, fruitState, UpdateOption.UPDATE_ALL.flags());
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, attachedStem.defaultState().with(facing, DirectionUtils.fromNMSDirection(randomDirection).toHorizontalDirection()).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags());
}
}
@Override
public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) {
ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[2]).orElse(null);
if (state == null || state.isEmpty()) return false;
return state.get(ageProperty) != ageProperty.max;
}
@Override
public boolean isBoneMealSuccess(Object thisBlock, Object[] args) {
return true;
}
@Override
public void performBoneMeal(Object thisBlock, Object[] args) {
ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[3]).orElse(null);
if (state == null || state.isEmpty()) return;
int min = Math.min(7, state.get(ageProperty) + RandomUtils.generateRandomInt(Math.min(ageProperty.min + 2, ageProperty.max), Math.min(ageProperty.max - 2, ageProperty.max)));
Object blockState = state.with(ageProperty, min).customBlockState().literalObject();
FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], args[2], blockState, 2);
if (min >= ageProperty.max) {
FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$randomTick(blockState, args[0], args[2]);
}
}
private boolean mayPlaceFruit(Object blockState) {
boolean flag1 = tagMayPlaceFruit != null && FastNMS.INSTANCE.method$BlockStateBase$is(blockState, tagMayPlaceFruit);
boolean flag2 = blockMayPlaceFruit != null && FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, blockMayPlaceFruit);
if (tagMayPlaceFruit == null && blockMayPlaceFruit == null) return true;
return flag1 || flag2;
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments, false);
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist");
IntegerProperty ageProperty = (IntegerProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("age"), "warning.config.block.behavior.stem.missing_age");
Key fruit = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("fruit"), "warning.config.block.behavior.stem.missing_fruit"));
Key attachedStem = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("attached-stem"), "warning.config.block.behavior.stem.missing_attached_stem"));
int minGrowLight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("light-requirement", 9), "light-requirement");
Object tagMayPlaceFruit = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("may-place-fruit", "minecraft:dirt").toString())));
Object blockMayPlaceFruit = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("may-place-fruit", "minecraft:farmland").toString())));
return new StemBlockBehavior(block, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), ageProperty, fruit, attachedStem, minGrowLight, tagMayPlaceFruit, blockMayPlaceFruit);
}
}
}

View File

@@ -381,4 +381,14 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior
}
FallOnBlockBehavior.super.updateEntityMovementAfterFallOn(thisBlock, args, superMethod);
}
}
@Override
public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
for (AbstractBlockBehavior behavior : this.behaviors) {
if (!behavior.propagatesSkylightDown(thisBlock, args, superMethod)) {
return false;
}
}
return (boolean) superMethod.call();
}
}

View File

@@ -170,6 +170,9 @@ public final class BlockGenerator {
// stepOn
.method(ElementMatchers.is(CoreReflections.method$Block$stepOn))
.intercept(MethodDelegation.to(StepOnInterceptor.INSTANCE))
// propagatesSkylightDown
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$propagatesSkylightDown))
.intercept(MethodDelegation.to(PropagatesSkylightDownInterceptor.INSTANCE))
;
// 1.21.5+
if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) {
@@ -760,4 +763,19 @@ public final class BlockGenerator {
}
}
}
public static class PropagatesSkylightDownInterceptor {
public static final PropagatesSkylightDownInterceptor INSTANCE = new PropagatesSkylightDownInterceptor();
@RuntimeType
public boolean intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
try {
return holder.value().propagatesSkylightDown(thisObj, args, superMethod);
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to run propagatesSkylightDown", e);
return false;
}
}
}
}

View File

@@ -12,7 +12,6 @@ import net.bytebuddy.implementation.FieldAccessor;
import net.bytebuddy.implementation.MethodDelegation;
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.matcher.ElementMatchers;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
@@ -23,15 +22,16 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlockState
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MLootContextParams;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
import net.momirealms.craftengine.core.block.*;
import net.momirealms.craftengine.core.block.BlockSettings;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.DelegatingBlockState;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.ObjectHolder;
import net.momirealms.craftengine.core.registry.Holder;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.World;
@@ -42,8 +42,6 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
public final class BlockStateGenerator {
private static MethodHandle constructor$CraftEngineBlockState;
@@ -87,11 +85,11 @@ public final class BlockStateGenerator {
Class<?> clazz$CraftEngineBlock = stateBuilder.make().load(BlockStateGenerator.class.getClassLoader()).getLoaded();
constructor$CraftEngineBlockState = VersionHelper.isOrAbove1_20_5() ?
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)) :
.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)) :
MethodHandles.publicLookup().in(clazz$CraftEngineBlock)
.findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class))
.asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class));
.findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class))
.asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class));
String generatedFactoryClassName = packageWithName.substring(0, packageWithName.lastIndexOf('.')) + ".CraftEngineStateFactory";
DynamicType.Builder<?> factoryBuilder = byteBuddy
@@ -210,10 +208,12 @@ public final class BlockStateGenerator {
DelegatingBlockState customState = (DelegatingBlockState) thisObj;
ImmutableBlockState thisState = customState.blockState();
if (thisState == null) return false;
if (!(args[0] instanceof DelegatingBlock delegatingBlock)) return false;
BlockBehavior behavior = delegatingBlock.behaviorDelegate().value();
if (behavior == null) return false;
return behavior.block().equals(thisState.owner().value());
if (FastNMS.INSTANCE.method$Block$defaultState(args[0]) instanceof DelegatingBlockState holder) {
ImmutableBlockState holderState = holder.blockState();
if (holderState == null) return false;
return holderState.owner().equals(thisState.owner());
}
return false;
}
}
@@ -226,13 +226,15 @@ public final class BlockStateGenerator {
DelegatingBlockState customState = (DelegatingBlockState) thisObj;
ImmutableBlockState thisState = customState.blockState();
if (thisState == null) return false;
CustomBlock thisBlock = thisState.owner().value();
Holder<CustomBlock> owner = thisState.owner();
for (Object holder : (Iterable<Object>) args[0]) {
Object block = FastNMS.INSTANCE.method$Holder$value(holder);
if (!(block instanceof DelegatingBlock delegatingBlock)) continue;
BlockBehavior behavior = delegatingBlock.behaviorDelegate().value();
if (behavior == null) continue;
if (behavior.block().equals(thisBlock)) return true;
if (block == null) continue;
if (!(FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState customHolder))
continue;
ImmutableBlockState holderState = customHolder.blockState();
if (holderState == null) continue;
return holderState.owner().equals(owner);
}
return false;
}
@@ -243,15 +245,17 @@ public final class BlockStateGenerator {
@RuntimeType
public boolean intercept(@This Object thisObj, @AllArguments Object[] args) {
Object block = FastNMS.INSTANCE.method$Holder$value(args[0]);
if (!(block instanceof DelegatingBlock delegatingBlock)) return false;
BlockBehavior behavior = delegatingBlock.behaviorDelegate().value();
if (behavior == null) return false;
DelegatingBlockState customState = (DelegatingBlockState) thisObj;
ImmutableBlockState thisState = customState.blockState();
if (thisState == null) return false;
CustomBlock thisBlock = thisState.owner().value();
return behavior.block().equals(thisBlock);
Object block = FastNMS.INSTANCE.method$Holder$value(args[0]);
if (block == null) return false;
if (FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState holder) {
ImmutableBlockState holderState = holder.blockState();
if (holderState == null) return false;
return holderState.owner().equals(thisState.owner());
}
return false;
}
}
@@ -260,17 +264,19 @@ public final class BlockStateGenerator {
@RuntimeType
public boolean intercept(@This Object thisObj, @AllArguments Object[] args) {
Object block = FastNMS.INSTANCE.method$HolderGetter$getResourceKey(MBuiltInRegistries.BLOCK, args[0])
.map(FastNMS.INSTANCE::method$Holder$value)
.orElse(null);
if (!(block instanceof DelegatingBlock delegatingBlock)) return false;
BlockBehavior behavior = delegatingBlock.behaviorDelegate().value();
if (behavior == null) return false;
DelegatingBlockState customState = (DelegatingBlockState) thisObj;
ImmutableBlockState thisState = customState.blockState();
if (thisState == null) return false;
CustomBlock thisBlock = thisState.owner().value();
return behavior.block().equals(thisBlock);
Object block = FastNMS.INSTANCE.method$HolderGetter$getResourceKey(MBuiltInRegistries.BLOCK, args[0])
.map(FastNMS.INSTANCE::method$Holder$value)
.orElse(null);
if (block == null) return false;
if (FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState holder) {
ImmutableBlockState holderState = holder.blockState();
if (holderState == null) return false;
return holderState.owner().equals(thisState.owner());
}
return false;
}
}

View File

@@ -4434,4 +4434,14 @@ public final class CoreReflections {
ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$ResourceKey),
VersionHelper.isOrAbove1_20_3()
);
public static final Method method$BlockBehaviour$propagatesSkylightDown = requireNonNull(
VersionHelper.isOrAbove1_21_2()
? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "e_"}, clazz$BlockState)
: VersionHelper.isOrAbove1_20_5()
? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos)
: VersionHelper.isOrAbove1_20_4()
? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos)
: ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos)
);
}

View File

@@ -6,54 +6,31 @@ import net.momirealms.craftengine.core.util.VersionHelper;
public final class MBlocks {
private MBlocks() {}
public static final Object AIR;
public static final Object AIR$defaultState;
public static final Object STONE;
public static final Object STONE$defaultState;
public static final Object FIRE;
public static final Object SOUL_FIRE;
public static final Object ICE;
public static final Object SHORT_GRASS;
public static final Object SHORT_GRASS$defaultState;
public static final Object SHULKER_BOX;
public static final Object COMPOSTER;
public static final Object SNOW;
public static final Object WATER;
public static final Object WATER$defaultState;
public static final Object TNT;
public static final Object TNT$defaultState;
public static final Object BARRIER;
public static final Object CARVED_PUMPKIN;
public static final Object JACK_O_LANTERN;
public static final Object MELON;
public static final Object PUMPKIN;
public static final Object AIR = getById("air");;
public static final Object AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR);
public static final Object STONE = getById("stone");
public static final Object STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE);
public static final Object FIRE = getById("fire");
public static final Object SOUL_FIRE = getById("soul_fire");
public static final Object ICE = getById("ice");
public static final Object SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass");
public static final Object SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS);
public static final Object SHULKER_BOX = getById("shulker_box");
public static final Object COMPOSTER = getById("composter");
public static final Object SNOW = getById("snow");
public static final Object WATER = getById("water");
public static final Object WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER);
public static final Object TNT = getById("tnt");
public static final Object TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT);
public static final Object BARRIER = getById("barrier");
public static final Object CARVED_PUMPKIN = getById("carved_pumpkin");
public static final Object JACK_O_LANTERN = getById("jack_o_lantern");
public static final Object MELON = getById("melon");
public static final Object PUMPKIN = getById("pumpkin");
public static final Object FARMLAND = getById("farmland");
private static Object getById(String id) {
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, rl);
}
static {
AIR = getById("air");
AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR);
FIRE = getById("fire");
SOUL_FIRE = getById("soul_fire");
STONE = getById("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 = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS);
SHULKER_BOX = getById("shulker_box");
COMPOSTER = getById("composter");
SNOW = getById("snow");
WATER = getById("water");
WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER);
TNT = getById("tnt");
TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT);
BARRIER = getById("barrier");
CARVED_PUMPKIN = getById("carved_pumpkin");
JACK_O_LANTERN = getById("jack_o_lantern");
MELON = getById("melon");
PUMPKIN = getById("pumpkin");
}
}

View File

@@ -12,6 +12,7 @@ public final class MTagKeys {
public static final Object Block$SHULKER_BOXES = create(MRegistries.BLOCK, "shulker_boxes");
public static final Object Block$FENCES = create(MRegistries.BLOCK, "fences");
public static final Object Block$WOODEN_FENCES = create(MRegistries.BLOCK, "wooden_fences");
public static final Object Block$DIRT = create(MRegistries.BLOCK, "dirt");
private static Object create(Object registry, String location) {
Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location);

View File

@@ -48,13 +48,13 @@ templates#models#block:
generation:
parent: minecraft:block/cube_column
textures:
particle: minecraft:block/custom/block_particle
down: minecraft:block/custom/block_down
up: minecraft:block/custom/block_up
north: minecraft:block/custom/block_north
east: minecraft:block/custom/block_east
south: minecraft:block/custom/block_south
west: minecraft:block/custom/block_west
particle: ${particle_texture}
down: ${down_texture}
up: ${up_texture}
north: ${north_texture}
east: ${east_texture}
south: ${south_texture}
west: ${west_texture}
# 2D items
templates#models#2d:

View File

@@ -328,6 +328,12 @@ warning.config.block.behavior.fence.missing_west: "<yellow>Issue found in file <
warning.config.block.behavior.face_attached_horizontal_directional.missing_face: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'face' property for 'face_attached_horizontal_directional_block' behavior.</yellow>"
warning.config.block.behavior.face_attached_horizontal_directional.missing_facing: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'facing' property for 'face_attached_horizontal_directional_block' behavior.</yellow>"
warning.config.block.behavior.button.missing_powered: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'powered' property for 'button_block' behavior.</yellow>"
warning.config.block.behavior.stem.missing_age: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'age' property for 'stem_block' behavior.</yellow>"
warning.config.block.behavior.stem.missing_fruit: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'fruit' argument for 'stem_block' behavior.</yellow>"
warning.config.block.behavior.stem.missing_attached_stem: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'attached_stem' argument for 'stem_block' behavior.</yellow>"
warning.config.block.behavior.attached_stem.missing_facing: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'facing' property for 'attached_stem_block' behavior.</yellow>"
warning.config.block.behavior.attached_stem.missing_fruit: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'fruit' argument for 'attached_stem_block' behavior.</yellow>"
warning.config.block.behavior.attached_stem.missing_stem: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'stem' argument for 'attached_stem_block' behavior.</yellow>"
warning.config.model.generation.missing_parent: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'parent' argument in 'generation' section.</yellow>"
warning.config.model.generation.conflict: "<yellow>Issue found in file <arg:0> - Failed to generate model for '<arg:1>' as two or more configurations attempt to generate different json models with the same path: '<arg:2>'.</yellow>"
warning.config.model.generation.invalid_display_position: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid display position '<arg:2>' in 'generation.display' section. Allowed display positions: [<arg:3>]</yellow>"

View File

@@ -322,6 +322,12 @@ warning.config.block.behavior.fence.missing_west: "<yellow>在文件 <arg:0> 发
warning.config.block.behavior.face_attached_horizontal_directional.missing_face: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'face_attached_horizontal_directional_block' 行为缺少必需的 'face' 属性</yellow>"
warning.config.block.behavior.face_attached_horizontal_directional.missing_facing: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'face_attached_horizontal_directional_block' 行为缺少必需的 'facing' 属性</yellow>"
warning.config.block.behavior.button.missing_powered: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'button_block' 行为缺少必需的 'powered' 属性</yellow>"
warning.config.block.behavior.stem.missing_age: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'stem_block' 行为缺少必需的 'age' 属性</yellow>"
warning.config.block.behavior.stem.missing_fruit: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'stem_block' 行为缺少必需的 'fruit' 选项</yellow>"
warning.config.block.behavior.stem.missing_attached_stem: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'stem_block' 行为缺少必需的 'attached_stem' 选项</yellow>"
warning.config.block.behavior.attached_stem.missing_facing: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'attached_stem_block' 行为缺少必需的 'facing' 属性</yellow>"
warning.config.block.behavior.attached_stem.missing_fruit: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'attached_stem_block' 行为缺少必需的 'fruit' 选项</yellow>"
warning.config.block.behavior.attached_stem.missing_stem: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'attached_stem_block' 行为缺少必需的 'stem' 选项</yellow>"
warning.config.model.generation.missing_parent: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'generation' 段落缺少必需的 'parent' 参数</yellow>"
warning.config.model.generation.conflict: "<yellow>在文件 <arg:0> 发现问题 - 无法为 '<arg:1>' 生成模型 存在多个配置尝试使用相同路径 '<arg:2>' 生成不同的 JSON 模型</yellow>"
warning.config.model.generation.invalid_display_position: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 在 'generation.display' 区域使用了无效的 display 位置类型 '<arg:2>'. 可用展示类型: [<arg:3>]</yellow>"

View File

@@ -184,6 +184,12 @@ public abstract class BlockBehavior {
superMethod.call();
}
// 1.20.1~1.21.1 BlockState state, BlockGetter level, BlockPos pos
// 1.21.2+ BlockState state
public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
return (boolean) superMethod.call();
}
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
return state;
}
@@ -217,4 +223,4 @@ public abstract class BlockBehavior {
}
public abstract CustomBlock block();
}
}

View File

@@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G
# Rule: [major update].[feature update].[bug fix]
project_version=0.0.63.4
config_version=46
lang_version=30
lang_version=31
project_group=net.momirealms
latest_supported_version=1.21.8
@@ -50,7 +50,7 @@ byte_buddy_version=1.17.5
ahocorasick_version=0.6.3
snake_yaml_version=2.5
anti_grief_version=0.20
nms_helper_version=1.0.93
nms_helper_version=1.0.94
evalex_version=3.5.0
reactive_streams_version=1.0.4
amazon_awssdk_version=2.33.1