mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-22 16:39:28 +00:00
Merge pull request #388 from jhqwqmc/dev
feat(block): 添加瓜藤相关的方块行为并且修复判断方块问题
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -20,18 +19,16 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlockStateProperties;
|
||||
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.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.util.ReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
@@ -42,8 +39,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;
|
||||
@@ -71,27 +66,15 @@ public final class BlockStateGenerator {
|
||||
.method(ElementMatchers.is(CoreReflections.method$StateHolder$setValue))
|
||||
.intercept(MethodDelegation.to(SetPropertyValueInterceptor.INSTANCE))
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isBlock))
|
||||
.intercept(MethodDelegation.to(IsBlockInterceptor.INSTANCE))
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isHolderSetBlock))
|
||||
.intercept(MethodDelegation.to(IsHolderSetBlockInterceptor.INSTANCE));
|
||||
if (CoreReflections.method$BlockStateBase$isHolderBlock != null) {
|
||||
stateBuilder = stateBuilder
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isHolderBlock))
|
||||
.intercept(MethodDelegation.to(IsHolderBlockInterceptor.INSTANCE));
|
||||
}
|
||||
if (CoreReflections.method$BlockStateBase$isResourceKeyBlock != null) {
|
||||
stateBuilder = stateBuilder
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isResourceKeyBlock))
|
||||
.intercept(MethodDelegation.to(IsResourceKeyBlockInterceptor.INSTANCE));
|
||||
}
|
||||
.intercept(MethodDelegation.to(IsBlockInterceptor.INSTANCE));
|
||||
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,70 +193,15 @@ 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());
|
||||
}
|
||||
}
|
||||
|
||||
public static class IsHolderSetBlockInterceptor {
|
||||
public static final IsHolderSetBlockInterceptor INSTANCE = new IsHolderSetBlockInterceptor();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@RuntimeType
|
||||
public boolean intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
DelegatingBlockState customState = (DelegatingBlockState) thisObj;
|
||||
ImmutableBlockState thisState = customState.blockState();
|
||||
if (thisState == null) return false;
|
||||
CustomBlock thisBlock = thisState.owner().value();
|
||||
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 (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;
|
||||
}
|
||||
}
|
||||
|
||||
public static class IsHolderBlockInterceptor {
|
||||
public static final IsHolderBlockInterceptor INSTANCE = new IsHolderBlockInterceptor();
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
public static class IsResourceKeyBlockInterceptor {
|
||||
public static final IsResourceKeyBlockInterceptor INSTANCE = new IsResourceKeyBlockInterceptor();
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CreateStateInterceptor {
|
||||
public static final CreateStateInterceptor INSTANCE = new CreateStateInterceptor();
|
||||
|
||||
|
||||
@@ -4419,19 +4419,13 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Block)
|
||||
);
|
||||
|
||||
public static final Method method$BlockStateBase$isHolderSetBlock = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$HolderSet)
|
||||
);
|
||||
|
||||
// 1.20.2+
|
||||
public static final Method method$BlockStateBase$isHolderBlock = MiscUtils.requireNonNullIf(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Holder),
|
||||
VersionHelper.isOrAbove1_20_2()
|
||||
);
|
||||
|
||||
// 1.20.3+
|
||||
public static final Method method$BlockStateBase$isResourceKeyBlock = MiscUtils.requireNonNullIf(
|
||||
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$Block, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos)
|
||||
: ReflectionUtils.getDeclaredMethod(clazz$Block, boolean.class, new String[]{"propagatesSkylightDown", "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -85,3 +85,5 @@ minecraft:barrier: 128
|
||||
minecraft:white_bed: 1
|
||||
minecraft:redstone_torch: 1
|
||||
minecraft:redstone_wall_torch: 4
|
||||
minecraft:pumpkin_stem: 8
|
||||
minecraft:attached_pumpkin_stem: 4
|
||||
@@ -0,0 +1,298 @@
|
||||
items:
|
||||
default:honeydew_item:
|
||||
material: apple
|
||||
custom-model-data: 1000
|
||||
data:
|
||||
item-name: <!i><i18n:item.honeydew_item>
|
||||
model:
|
||||
template: default:model/simplified_generated
|
||||
arguments:
|
||||
path: minecraft:item/custom/honeydew_item
|
||||
behavior:
|
||||
type: block_item
|
||||
block: default:honeydew_stem
|
||||
default:honeydew:
|
||||
material: nether_brick
|
||||
custom-model-data: 3023
|
||||
data:
|
||||
item-name: <!i><i18n:item.honeydew>
|
||||
model:
|
||||
path: minecraft:item/custom/honeydew
|
||||
generation:
|
||||
parent: minecraft:block/custom/honeydew
|
||||
behavior:
|
||||
type: block_item
|
||||
block: default:honeydew
|
||||
|
||||
blocks:
|
||||
default:honeydew:
|
||||
loot:
|
||||
pools:
|
||||
- rolls: 1
|
||||
entries:
|
||||
- type: alternatives
|
||||
children:
|
||||
- type: item
|
||||
item: default:honeydew
|
||||
conditions:
|
||||
- type: enchantment
|
||||
predicate: minecraft:silk_touch>=1
|
||||
- type: item
|
||||
item: default:honeydew_item
|
||||
functions:
|
||||
- type: set_count
|
||||
add: false
|
||||
count: 3~7
|
||||
- type: apply_bonus
|
||||
enchantment: minecraft:fortune
|
||||
formula:
|
||||
type: ore_drops
|
||||
- type: limit_count
|
||||
max: 9
|
||||
- type: explosion_decay
|
||||
settings:
|
||||
map-color: 19
|
||||
hardness: 1
|
||||
resistance: 1
|
||||
push-reaction: DESTROY
|
||||
is-suffocating: true
|
||||
is-redstone-conductor: true
|
||||
item: default:honeydew
|
||||
tags:
|
||||
- minecraft:enderman_holdable
|
||||
- minecraft:mineable/axe
|
||||
- minecraft:sword_efficient
|
||||
incorrect-tool-dig-speed: 1
|
||||
state:
|
||||
id: 30
|
||||
state: note_block:30
|
||||
model:
|
||||
template: default:model/cube
|
||||
arguments:
|
||||
model: minecraft:block/custom/honeydew
|
||||
particle_texture: minecraft:block/custom/honeydew
|
||||
down_texture: minecraft:block/custom/honeydew_bottom
|
||||
up_texture: minecraft:block/custom/honeydew_top
|
||||
north_texture: minecraft:block/custom/honeydew
|
||||
east_texture: minecraft:block/custom/honeydew
|
||||
south_texture: minecraft:block/custom/honeydew
|
||||
west_texture: minecraft:block/custom/honeydew
|
||||
default:honeydew_stem:
|
||||
loot:
|
||||
pools:
|
||||
- rolls: 1
|
||||
entries:
|
||||
- type: item
|
||||
item: default:honeydew_item
|
||||
functions:
|
||||
- type: set_count
|
||||
add: false
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: 0
|
||||
count:
|
||||
type: binomial
|
||||
extra: 3
|
||||
probability: 0.06666667
|
||||
- type: set_count
|
||||
add: false
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: 1
|
||||
count:
|
||||
type: binomial
|
||||
extra: 3
|
||||
probability: 0.13333334
|
||||
- type: set_count
|
||||
add: false
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: 2
|
||||
count:
|
||||
type: binomial
|
||||
extra: 3
|
||||
probability: 0.2
|
||||
- type: set_count
|
||||
add: false
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: 3
|
||||
count:
|
||||
type: binomial
|
||||
extra: 3
|
||||
probability: 0.26666668
|
||||
- type: set_count
|
||||
add: false
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: 4
|
||||
count:
|
||||
type: binomial
|
||||
extra: 3
|
||||
probability: 0.33333334
|
||||
- type: set_count
|
||||
add: false
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: 5
|
||||
count:
|
||||
type: binomial
|
||||
extra: 3
|
||||
probability: 0.4
|
||||
- type: set_count
|
||||
add: false
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: 6
|
||||
count:
|
||||
type: binomial
|
||||
extra: 3
|
||||
probability: 0.46666667
|
||||
- type: set_count
|
||||
add: false
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: 7
|
||||
count:
|
||||
type: binomial
|
||||
extra: 3
|
||||
probability: 0.53333336
|
||||
functions:
|
||||
- type: explosion_decay
|
||||
settings:
|
||||
map-color: 7
|
||||
hardness: 0
|
||||
resistance: 0
|
||||
push-reaction: DESTROY
|
||||
is-suffocating: false
|
||||
is-redstone-conductor: false
|
||||
item: default:honeydew_item
|
||||
is-randomly-ticking: true
|
||||
tags:
|
||||
- minecraft:bee_growables
|
||||
- minecraft:crops
|
||||
- minecraft:maintains_farmland
|
||||
behaviors:
|
||||
type: stem_block
|
||||
fruit: default:honeydew
|
||||
attached-stem: default:attached_honeydew_stem
|
||||
blacklist: false
|
||||
bottom-blocks:
|
||||
- minecraft:farmland
|
||||
states:
|
||||
properties:
|
||||
age:
|
||||
type: int
|
||||
default: 0
|
||||
range: 0~7
|
||||
appearances:
|
||||
age=0:
|
||||
state: pumpkin_stem[age=0]
|
||||
age=1:
|
||||
state: pumpkin_stem[age=1]
|
||||
age=2:
|
||||
state: pumpkin_stem[age=2]
|
||||
age=3:
|
||||
state: pumpkin_stem[age=3]
|
||||
age=4:
|
||||
state: pumpkin_stem[age=4]
|
||||
age=5:
|
||||
state: pumpkin_stem[age=5]
|
||||
age=6:
|
||||
state: pumpkin_stem[age=6]
|
||||
age=7:
|
||||
state: pumpkin_stem[age=7]
|
||||
variants:
|
||||
age=0:
|
||||
appearance: age=0
|
||||
id: 0
|
||||
age=1:
|
||||
appearance: age=1
|
||||
id: 1
|
||||
age=2:
|
||||
appearance: age=2
|
||||
id: 2
|
||||
age=3:
|
||||
appearance: age=3
|
||||
id: 3
|
||||
age=4:
|
||||
appearance: age=4
|
||||
id: 4
|
||||
age=5:
|
||||
appearance: age=5
|
||||
id: 5
|
||||
age=6:
|
||||
appearance: age=6
|
||||
id: 6
|
||||
age=7:
|
||||
appearance: age=7
|
||||
id: 7
|
||||
default:attached_honeydew_stem:
|
||||
loot:
|
||||
pools:
|
||||
- rolls: 1
|
||||
entries:
|
||||
- type: item
|
||||
item: default:honeydew_item
|
||||
functions:
|
||||
- type: set_count
|
||||
add: false
|
||||
count:
|
||||
type: binomial
|
||||
extra: 3
|
||||
probability: 0.53333336
|
||||
functions:
|
||||
- type: explosion_decay
|
||||
settings:
|
||||
map-color: 7
|
||||
hardness: 0
|
||||
resistance: 0
|
||||
push-reaction: DESTROY
|
||||
is-suffocating: false
|
||||
is-redstone-conductor: false
|
||||
item: default:honeydew_item
|
||||
is-randomly-ticking: true
|
||||
tags:
|
||||
- minecraft:maintains_farmland
|
||||
behaviors:
|
||||
type: attached_stem_block
|
||||
fruit: default:honeydew
|
||||
stem: default:honeydew_stem
|
||||
blacklist: false
|
||||
bottom-blocks:
|
||||
- minecraft:farmland
|
||||
states:
|
||||
properties:
|
||||
facing:
|
||||
type: horizontal_direction
|
||||
default: north
|
||||
appearances:
|
||||
facing=east:
|
||||
state: attached_pumpkin_stem[facing=east]
|
||||
facing=south:
|
||||
state: attached_pumpkin_stem[facing=south]
|
||||
facing=west:
|
||||
state: attached_pumpkin_stem[facing=west]
|
||||
facing=north:
|
||||
state: attached_pumpkin_stem[facing=north]
|
||||
variants:
|
||||
facing=east:
|
||||
appearance: facing=east
|
||||
id: 0
|
||||
facing=south:
|
||||
appearance: facing=south
|
||||
id: 1
|
||||
facing=west:
|
||||
appearance: facing=west
|
||||
id: 2
|
||||
facing=north:
|
||||
appearance: facing=north
|
||||
id: 3
|
||||
@@ -79,3 +79,5 @@ categories:
|
||||
- default:wooden_chair
|
||||
- default:flower_basket
|
||||
- default:amethyst_torch
|
||||
- default:honeydew_item
|
||||
- default:honeydew
|
||||
@@ -49,6 +49,8 @@ i18n:
|
||||
item.safe_block: Safe Block
|
||||
item.sofa: Sofa
|
||||
item.amethyst_torch: Amethyst Torch
|
||||
item.honeydew_item: Honeydew Slice
|
||||
item.honeydew: Honeydew
|
||||
category.default.name: Default Assets
|
||||
category.default.lore: Contains the default configuration of CraftEngine
|
||||
category.palm_tree: Palm Tree
|
||||
@@ -107,6 +109,8 @@ i18n:
|
||||
item.safe_block: 保险柜
|
||||
item.sofa: 沙发
|
||||
item.amethyst_torch: 紫水晶火把
|
||||
item.honeydew_item: 哈密瓜片
|
||||
item.honeydew: 哈密瓜
|
||||
category.default.name: 默认资产
|
||||
category.default.lore: 包含了CraftEngine的默认配置
|
||||
category.palm_tree: 棕榈树
|
||||
@@ -149,6 +153,9 @@ lang:
|
||||
block_name:default:sofa: Sofa
|
||||
block_name:default:amethyst_torch: Amethyst Torch
|
||||
block_name:default:amethyst_wall_torch: Amethyst Torch
|
||||
block_name:default:honeydew: Honeydew
|
||||
block_name:default:honeydew_stem: Honeydew Stem
|
||||
block_name:default:default:attached_honeydew_stem: Honeydew Stem
|
||||
zh_cn:
|
||||
block_name:default:chinese_lantern: 灯笼
|
||||
block_name:default:netherite_anvil: 下界合金砧
|
||||
@@ -179,3 +186,6 @@ lang:
|
||||
block_name:default:sofa: 沙发
|
||||
block_name:default:amethyst_torch: 紫水晶火把
|
||||
block_name:default:amethyst_wall_torch: 紫水晶火把
|
||||
block_name:default:honeydew: 哈密瓜
|
||||
block_name:default:honeydew_stem: 哈密瓜茎
|
||||
block_name:default:default:attached_honeydew_stem: 哈密瓜茎
|
||||
@@ -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:
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 463 B |
Binary file not shown.
|
After Width: | Height: | Size: 420 B |
Binary file not shown.
|
After Width: | Height: | Size: 493 B |
Binary file not shown.
|
After Width: | Height: | Size: 377 B |
@@ -87,6 +87,8 @@ warning.config.number.uniform.missing_min: "<yellow>Issue found in file <arg:0>
|
||||
warning.config.number.uniform.missing_max: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'max' argument for 'uniform' number.</yellow>"
|
||||
warning.config.number.gaussian.missing_min: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'min' argument for 'gaussian' number.</yellow>"
|
||||
warning.config.number.gaussian.missing_max: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'max' argument for 'gaussian' number.</yellow>"
|
||||
warning.config.number.binomial.missing_extra: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'extra' argument for 'binomial' number.</yellow>"
|
||||
warning.config.number.binomial.missing_probability: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'probability' argument for 'binomial' number.</yellow>"
|
||||
warning.config.condition.all_of.missing_terms: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'terms' argument for 'all_of' condition.</yellow>"
|
||||
warning.config.condition.all_of.invalid_terms_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' has a misconfigured 'all_of' condition, 'terms' should be a map list, current type: '<arg:2>'.</yellow>"
|
||||
warning.config.condition.any_of.missing_terms: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'terms' argument for 'any_of' condition.</yellow>"
|
||||
@@ -328,6 +330,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>"
|
||||
|
||||
@@ -87,6 +87,8 @@ warning.config.number.uniform.missing_min: "<yellow>在文件 <arg:0> 发现问
|
||||
warning.config.number.uniform.missing_max: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'uniform' 数字类型所需的 'max' 参数</yellow>"
|
||||
warning.config.number.gaussian.missing_min: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'gaussian' 数字类型所需的 'min' 参数</yellow>"
|
||||
warning.config.number.gaussian.missing_max: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'gaussian' 数字类型所需的 'max' 参数</yellow>"
|
||||
warning.config.number.binomial.missing_extra: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'binomial' 数字类型所需的 'extra' 参数</yellow>"
|
||||
warning.config.number.binomial.missing_probability: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'binomial' 数字类型所需的 'probability' 参数</yellow>"
|
||||
warning.config.condition.all_of.missing_terms: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'all_of' 条件所需的 'terms' 参数</yellow>"
|
||||
warning.config.condition.all_of.invalid_terms_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'all_of' 条件配置错误, 'terms' 应为映射列表, 当前类型: '<arg:2>'</yellow>"
|
||||
warning.config.condition.any_of.missing_terms: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'any_of' 条件所需的 'terms' 参数</yellow>"
|
||||
@@ -322,6 +324,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>"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package net.momirealms.craftengine.core.loot.function;
|
||||
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.loot.LootConditions;
|
||||
import net.momirealms.craftengine.core.loot.LootContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.Condition;
|
||||
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
|
||||
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class LimitCountFunction<T> extends AbstractLootConditionalFunction<T> {
|
||||
public static final Factory<?> FACTORY = new Factory<>();
|
||||
@Nullable
|
||||
private final NumberProvider min;
|
||||
@Nullable
|
||||
private final NumberProvider max;
|
||||
|
||||
public LimitCountFunction(List<Condition<LootContext>> predicates, @Nullable NumberProvider min, @Nullable NumberProvider max) {
|
||||
super(predicates);
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Key type() {
|
||||
return LootFunctions.LIMIT_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Item<T> applyInternal(Item<T> item, LootContext context) {
|
||||
int amount = item.count();
|
||||
if (min != null) {
|
||||
int minAmount = min.getInt(context);
|
||||
if (amount < minAmount) {
|
||||
item.count(minAmount);
|
||||
}
|
||||
}
|
||||
if (max != null) {
|
||||
int maxAmount = max.getInt(context);
|
||||
if (amount > maxAmount) {
|
||||
item.count(maxAmount);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public static class Factory<A> implements LootFunctionFactory<A> {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public LootFunction<A> create(Map<String, Object> arguments) {
|
||||
Object min = arguments.get("min");
|
||||
Object max = arguments.get("max");
|
||||
List<Condition<LootContext>> conditions = Optional.ofNullable(arguments.get("conditions"))
|
||||
.map(it -> LootConditions.fromMapList((List<Map<String, Object>>) it))
|
||||
.orElse(Collections.emptyList());
|
||||
return new LimitCountFunction<>(conditions, min == null ? null : NumberProviders.fromObject(min), max == null ? null : NumberProviders.fromObject(max));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,14 @@ public class LootFunctions {
|
||||
public static final Key SET_COUNT = Key.from("craftengine:set_count");
|
||||
public static final Key EXPLOSION_DECAY = Key.from("craftengine:explosion_decay");
|
||||
public static final Key DROP_EXP = Key.from("craftengine:drop_exp");
|
||||
public static final Key LIMIT_COUNT = Key.from("craftengine:limit_count");
|
||||
|
||||
static {
|
||||
register(SET_COUNT, SetCountFunction.FACTORY);
|
||||
register(EXPLOSION_DECAY, ExplosionDecayFunction.FACTORY);
|
||||
register(APPLY_BONUS, ApplyBonusCountFunction.FACTORY);
|
||||
register(DROP_EXP, DropExpFunction.FACTORY);
|
||||
register(LIMIT_COUNT, LimitCountFunction.FACTORY);
|
||||
}
|
||||
|
||||
public static <T> void register(Key key, LootFunctionFactory<T> factory) {
|
||||
|
||||
@@ -431,6 +431,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
plugin.saveResource("resources/default/configuration/blocks/topaz_ore.yml");
|
||||
plugin.saveResource("resources/default/configuration/blocks/netherite_anvil.yml");
|
||||
plugin.saveResource("resources/default/configuration/blocks/amethyst_torch.yml");
|
||||
plugin.saveResource("resources/default/configuration/blocks/honeydew.yml");
|
||||
// assets
|
||||
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/font/image/emojis.png");
|
||||
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/chinese_lantern.png");
|
||||
@@ -537,6 +538,10 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_background.png.mcmeta");
|
||||
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png");
|
||||
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png.mcmeta");
|
||||
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png");
|
||||
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png");
|
||||
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_top.png");
|
||||
plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/honeydew_item.png");
|
||||
}
|
||||
|
||||
private TreeMap<ConfigParser, List<CachedConfigSection>> updateCachedConfigFiles() {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package net.momirealms.craftengine.core.plugin.context.number;
|
||||
|
||||
import net.momirealms.craftengine.core.plugin.context.Context;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.RandomUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record BinomialNumberProvider(NumberProvider trials, NumberProvider successProbability) implements NumberProvider {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
|
||||
@Override
|
||||
public float getFloat(Context context) {
|
||||
return getInt(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(Context context) {
|
||||
return getInt(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(Context context) {
|
||||
int trialCount = this.trials.getInt(context);
|
||||
float probability = this.successProbability.getFloat(context);
|
||||
int successCount = 0;
|
||||
|
||||
for (int i = 0; i < trialCount; i++) {
|
||||
if (RandomUtils.generateRandomFloat(0, 1) < probability) {
|
||||
successCount++;
|
||||
}
|
||||
}
|
||||
return successCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Key type() {
|
||||
return NumberProviders.BINOMIAL;
|
||||
}
|
||||
|
||||
public static class Factory implements NumberProviderFactory {
|
||||
|
||||
@Override
|
||||
public NumberProvider create(Map<String, Object> arguments) {
|
||||
Object trials = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("extra"), "warning.config.number.binomial.missing_extra");
|
||||
Object successProbability = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("probability"), "warning.config.number.binomial.missing_probability");
|
||||
return new BinomialNumberProvider(NumberProviders.fromObject(trials), NumberProviders.fromObject(successProbability));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ public class NumberProviders {
|
||||
public static final Key UNIFORM = Key.of("craftengine:uniform");
|
||||
public static final Key EXPRESSION = Key.of("craftengine:expression");
|
||||
public static final Key GAUSSIAN = Key.of("craftengine:gaussian");
|
||||
public static final Key BINOMIAL = Key.of("craftengine:binomial");
|
||||
|
||||
static {
|
||||
register(FIXED, FixedNumberProvider.FACTORY);
|
||||
@@ -25,6 +26,7 @@ public class NumberProviders {
|
||||
register(UNIFORM, UniformNumberProvider.FACTORY);
|
||||
register(GAUSSIAN, GaussianNumberProvider.FACTORY);
|
||||
register(EXPRESSION, ExpressionNumberProvider.FACTORY);
|
||||
register(BINOMIAL, BinomialNumberProvider.FACTORY);
|
||||
}
|
||||
|
||||
public static void register(Key key, NumberProviderFactory factory) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user