diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml index b979b00a7..613b1a6a9 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/blocks.yml @@ -201,6 +201,75 @@ items#misc: parent: "minecraft:block/cube_all" textures: "all": "minecraft:block/custom/solid_gunpowder_block" + default:copper_coil: + material: nether_brick + custom-model-data: 3004 + data: + item-name: "" + model: + type: "minecraft:model" + path: "minecraft:item/custom/copper_coil" + generation: + parent: "minecraft:block/custom/copper_coil" + behavior: + type: block_item + block: + loot: + template: "default:loot_table/basic" + arguments: + item: default:copper_coil + settings: + template: + - default:sound/metal + - default:pickaxe_power/level_1 + overrides: + hardness: 3.0 + resistance: 4.5 + replaceable: false + is-redstone-conductor: true + is-suffocating: true + instrument: BASEDRUM + map-color: 45 + item: default:copper_coil + behavior: + type: lamp_block + states: + properties: + lit: + type: boolean + default: false + appearances: + off: + state: "cactus:0" + model: + path: "minecraft:block/custom/copper_coil" + generation: + parent: "minecraft:block/cactus" + textures: + "particle": "minecraft:block/custom/copper_coil" + "bottom": "minecraft:block/custom/copper_coil" + "top": "minecraft:block/custom/copper_coil" + "side": "minecraft:block/custom/copper_coil_side" + on: + state: "cactus:1" + model: + path: "minecraft:block/custom/copper_coil_on" + generation: + parent: "minecraft:block/cactus" + textures: + "particle": "minecraft:block/custom/copper_coil_on" + "bottom": "minecraft:block/custom/copper_coil_on" + "top": "minecraft:block/custom/copper_coil_on" + "side": "minecraft:block/custom/copper_coil_on_side" + variants: + lit=false: + appearance: "off" + id: 0 + lit=true: + appearance: "on" + id: 1 + settings: + luminance: 8 recipes#misc: default:chinese_lantern: type: shaped diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml index fd442e990..d111185e9 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml @@ -65,4 +65,6 @@ categories: - default:solid_gunpowder_block - default:ender_pearl_flower_seeds - default:gui_head_size_1 - - default:gui_head_size_4 \ No newline at end of file + - default:gui_head_size_4 + - minecraft:air + - default:copper_coil \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml index 99e6d9705..602c85f0f 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml @@ -34,6 +34,7 @@ i18n: item.netherite_anvil: "Netherite Anvil" item.gunpowder_block: "GunPowder Block" item.solid_gunpowder_block: "Solid GunPowder Block" + item.copper_coil: "Copper Coil" category.default.name: "Default Assets" category.default.lore: "Contains the default configuration of CraftEngine" category.palm_tree: "Palm Tree" @@ -78,6 +79,7 @@ i18n: item.netherite_anvil: "下界合金砧" item.gunpowder_block: "火药粉末" item.solid_gunpowder_block: "凝固火药块" + item.copper_coil: "铜线圈" category.default.name: "默认资产" category.default.lore: "包含了CraftEngine的默认配置" category.palm_tree: "棕榈树" diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil.png new file mode 100644 index 000000000..40f04a5a8 Binary files /dev/null and b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil.png differ diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on.png new file mode 100644 index 000000000..3e59193cb Binary files /dev/null and b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on.png differ diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on_side.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on_side.png new file mode 100644 index 000000000..31b91e1a7 Binary files /dev/null and b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_on_side.png differ diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_side.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_side.png new file mode 100644 index 000000000..859f0234b Binary files /dev/null and b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/copper_coil_side.png differ diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 0ee61b98d..31d995f66 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -239,6 +239,7 @@ warning.config.block.behavior.crop.missing_age: "Issue found in file Issue found in file - The block '' is missing the required 'age' property for 'sugar_cane_block' behavior." warning.config.block.behavior.leaves.missing_persistent: "Issue found in file - The block '' is missing the required 'persistent' property for 'leaves_block' behavior." warning.config.block.behavior.leaves.missing_distance: "Issue found in file - The block '' is missing the required 'distance' property for 'leaves_block' behavior." +warning.config.block.behavior.lamp.missing_lit: "Issue found in file - The block '' is missing the required 'lit' property for 'lamp_block' behavior." warning.config.block.behavior.sapling.missing_stage: "Issue found in file - The block '' is missing the required 'stage' property for 'sapling_block' behavior." warning.config.block.behavior.sapling.missing_feature: "Issue found in file - The block '' is missing the required 'feature' argument for 'sapling_block' behavior." warning.config.block.behavior.strippable.missing_stripped: "Issue found in file - The block '' is missing the required 'stripped' argument for 'strippable_block' behavior." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 1b87ce60b..d9feadebf 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -239,6 +239,7 @@ warning.config.block.behavior.crop.missing_age: "在文件 发 warning.config.block.behavior.sugar_cane.missing_age: "在文件 发现问题 - 方块 '' 的 'sugar_cane_block' 行为缺少必需的 'age' 属性" warning.config.block.behavior.leaves.missing_persistent: "在文件 发现问题 - 方块 '' 的 'leaves_block' 行为缺少必需的 'persistent' 属性" warning.config.block.behavior.leaves.missing_distance: "在文件 发现问题 - 方块 '' 的 'leaves_block' 行为缺少必需的 'distance' 属性" +warning.config.block.behavior.lamp.missing_lit: "在文件 发现问题 - 方块 '' 的 'lamp_block' 行为缺少必需的 'lit' 属性" warning.config.block.behavior.sapling.missing_stage: "在文件 发现问题 - 方块 '' 的 'sapling_block' 行为缺少必需的 'stage' 属性" warning.config.block.behavior.sapling.missing_feature: "在文件 发现问题 - 方块 '' 的 'sapling_block' 行为缺少必需的 'feature' 参数" warning.config.block.behavior.strippable.missing_stripped: "在文件 发现问题 - 方块 '' 的 'strippable_block' 行为缺少必需的 'stripped' 参数" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index 1ebf13dc8..2b36c888f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -17,6 +17,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key SUGARCANE_BLOCK = Key.from("craftengine:sugar_cane_block"); public static final Key CROP_BLOCK = Key.from("craftengine:crop_block"); public static final Key GRASS_BLOCK = Key.from("craftengine:grass_block"); + public static final Key LAMP_BLOCK = Key.from("craftengine:lamp_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -32,5 +33,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(SUGARCANE_BLOCK, SugarCaneBlockBehavior.FACTORY); register(CROP_BLOCK, CropBlockBehavior.FACTORY); register(GRASS_BLOCK, GrassBlockBehavior.FACTORY); + register(LAMP_BLOCK, LampBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java new file mode 100644 index 000000000..56ff8079c --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java @@ -0,0 +1,65 @@ +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.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; +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.Property; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.shared.block.BlockBehavior; + +import java.util.Map; +import java.util.concurrent.Callable; + +public class LampBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final Property litProperty; + + public LampBlockBehavior(CustomBlock block, Property litProperty) { + super(block); + this.litProperty = litProperty; + } + + @Override + public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object blockState = args[0]; + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (state == null || state.isEmpty()) return; + Object world = args[1]; + Object blockPos = args[2]; + if (state.get(this.litProperty) && !FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) { + // TODO Call Event + FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2); + } + } + + @Override + public void neighborChanged(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object blockState = args[0]; + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (state == null || state.isEmpty()) return; + Object world = args[1]; + Object blockPos = args[2]; + boolean lit = state.get(this.litProperty); + if (lit != FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) { + if (lit) { + Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 4); + } else { + // TODO Call Event + FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2); + } + } + } + + @SuppressWarnings("unchecked") + public static class Factory implements BlockBehaviorFactory { + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Property lit = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("lit"), "warning.config.block.behavior.lamp.missing_lit"); + return new LampBlockBehavior(block, lit); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java index 0da9cba81..d6206696d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java @@ -30,6 +30,7 @@ import org.bukkit.event.block.LeavesDecayEvent; import org.jetbrains.annotations.Nullable; import java.util.Map; +import java.util.Optional; import java.util.concurrent.Callable; public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { @@ -78,10 +79,14 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { neighborState = args[2]; } ImmutableBlockState thisState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); - if (thisState != null && thisState.behavior() instanceof LeavesBlockBehavior behavior) { - int distance = behavior.getDistanceAt(neighborState) + 1; - if (distance != 1 || behavior.getDistance(thisState) != distance) { - Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 1); + if (thisState != null) { + Optional optionalBehavior = thisState.behavior().getAs(LeavesBlockBehavior.class); + if (optionalBehavior.isPresent()) { + LeavesBlockBehavior behavior = optionalBehavior.get(); + int distance = behavior.getDistanceAt(neighborState) + 1; + if (distance != 1 || behavior.getDistance(thisState) != distance) { + Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 1); + } } } return blockState; @@ -93,13 +98,17 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { Object level = args[1]; Object blockPos = args[2]; ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); - if (currentState != null && !currentState.isEmpty() && currentState.behavior() instanceof LeavesBlockBehavior behavior) { - ImmutableBlockState newState = behavior.updateDistance(currentState, level, blockPos); - if (newState != currentState) { - if (blockState == newState.customBlockState().handle()) { - Reflections.method$BlockStateBase$updateNeighbourShapes.invoke(blockState, level, blockPos, UpdateOption.UPDATE_ALL.flags(), 512); - } else { - FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); + if (currentState != null && !currentState.isEmpty()) { + Optional optionalBehavior = currentState.behavior().getAs(LeavesBlockBehavior.class); + if (optionalBehavior.isPresent()) { + LeavesBlockBehavior behavior = optionalBehavior.get(); + ImmutableBlockState newState = behavior.updateDistance(currentState, level, blockPos); + if (newState != currentState) { + if (blockState == newState.customBlockState().handle()) { + Reflections.method$BlockStateBase$updateNeighbourShapes.invoke(blockState, level, blockPos, UpdateOption.UPDATE_ALL.flags(), 512); + } else { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); + } } } } @@ -110,25 +119,31 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { Object level = args[1]; Object blockPos = args[2]; ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0])); - if (immutableBlockState != null && immutableBlockState.behavior() instanceof LeavesBlockBehavior behavior && behavior.isDecaying(immutableBlockState)) { - World bukkitWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(level); - BlockPos pos = LocationUtils.fromBlockPos(blockPos); - // call bukkit event - LeavesDecayEvent event = new LeavesDecayEvent(bukkitWorld.getBlockAt(pos.x(), pos.y(), pos.z())); - Bukkit.getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - FastNMS.INSTANCE.method$Level$removeBlock(level, blockPos, false); - if (isWaterLogged(immutableBlockState)) { - bukkitWorld.setBlockData(pos.x(), pos.y(), pos.z(), Material.WATER.createBlockData()); - } - net.momirealms.craftengine.core.world.World world = new BukkitWorld(bukkitWorld); - WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); - ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(DirectContextParameters.POSITION, position); - for (Item item : immutableBlockState.getDrops(builder, world, null)) { - world.dropItemNaturally(position, item); + if (immutableBlockState != null) { + Optional optionalBehavior = immutableBlockState.behavior().getAs(LeavesBlockBehavior.class); + if (optionalBehavior.isPresent()) { + LeavesBlockBehavior behavior = optionalBehavior.get(); + if (behavior.isDecaying(immutableBlockState)) { + World bukkitWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(level); + BlockPos pos = LocationUtils.fromBlockPos(blockPos); + // call bukkit event + LeavesDecayEvent event = new LeavesDecayEvent(bukkitWorld.getBlockAt(pos.x(), pos.y(), pos.z())); + Bukkit.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + FastNMS.INSTANCE.method$Level$removeBlock(level, blockPos, false); + if (isWaterLogged(immutableBlockState)) { + bukkitWorld.setBlockData(pos.x(), pos.y(), pos.z(), Material.WATER.createBlockData()); + } + net.momirealms.craftengine.core.world.World world = new BukkitWorld(bukkitWorld); + WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(DirectContextParameters.POSITION, position); + for (Item item : immutableBlockState.getDrops(builder, world, null)) { + world.dropItemNaturally(position, item); + } + } } } } @@ -164,8 +179,8 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { return (int) Reflections.method$StateHolder$getValue.invoke(blockState, distanceProperty); } else { ImmutableBlockState anotherBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id); - if (!(anotherBlockState.behavior() instanceof LeavesBlockBehavior otherBehavior)) return this.maxDistance; - return otherBehavior.getDistance(anotherBlockState); + Optional optionalAnotherBehavior = anotherBlockState.behavior().getAs(LeavesBlockBehavior.class); + return optionalAnotherBehavior.map(leavesBlockBehavior -> leavesBlockBehavior.getDistance(anotherBlockState)).orElse(this.maxDistance); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java index 60f26221c..a90781574 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java @@ -318,6 +318,9 @@ public class BukkitInjector { .and(ElementMatchers.takesArgument(1, Reflections.clazz$LevelReader).or(ElementMatchers.takesArgument(1, Reflections.clazz$Direction))) .and(ElementMatchers.named("updateShape").or(ElementMatchers.named("a")))) .intercept(MethodDelegation.to(UpdateShapeInterceptor.INSTANCE)) + // neighborChanged + .method(ElementMatchers.is(Reflections.method$BlockBehaviour$neighborChanged)) + .intercept(MethodDelegation.to(NeighborChangedInterceptor.INSTANCE)) // // getFluidState // .method(ElementMatchers.returns(Reflections.clazz$FluidState) // .and(ElementMatchers.takesArgument(0, Reflections.clazz$BlockState))) @@ -1078,6 +1081,20 @@ public class BukkitInjector { } } } + + public static class NeighborChangedInterceptor { + public static final NeighborChangedInterceptor INSTANCE = new NeighborChangedInterceptor(); + + @RuntimeType + public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((BehaviorHolder) thisObj).getBehaviorHolder(); + try { + holder.value().neighborChanged(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run neighborChanged", e); + } + } + } // // public static class PickUpBlockInterceptor { // public static final PickUpBlockInterceptor INSTANCE = new PickUpBlockInterceptor(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 22c58dbbf..9e67f24c6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -6791,4 +6791,16 @@ public class Reflections { } } + public static final Class clazz$Orientation = + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.level.redstone.Orientation", + "world.level.redstone.Orientation" + ); + + public static final Method method$BlockBehaviour$neighborChanged = requireNonNull( + VersionHelper.isOrAbove1_21_2() ? + ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$Orientation, boolean.class) : + Optional.ofNullable(ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$BlockPos, boolean.class)) + .orElse(ReflectionUtils.getMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$BlockPos, boolean.class)) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index 7008c0825..839f8055a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -1,7 +1,10 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.bukkit.util.EntityUtils; +import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.ParticleUtils; +import net.momirealms.craftengine.bukkit.util.SoundUtils; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Context; @@ -15,7 +18,6 @@ import net.momirealms.craftengine.core.world.WorldHeight; import net.momirealms.craftengine.core.world.particle.ParticleData; import org.bukkit.Location; import org.bukkit.Particle; -import org.bukkit.Registry; import org.bukkit.SoundCategory; import org.bukkit.entity.EntityType; import org.bukkit.entity.ExperienceOrb; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java new file mode 100644 index 000000000..21bb9d76d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/UnsafeCompositeBlockBehavior.java @@ -0,0 +1,154 @@ +package net.momirealms.craftengine.core.block.behavior; + +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.context.BlockPlaceContext; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.shared.block.BlockBehavior; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.Callable; + +public class UnsafeCompositeBlockBehavior extends AbstractBlockBehavior { + private final AbstractBlockBehavior[] behaviors; + + public UnsafeCompositeBlockBehavior(CustomBlock customBlock, List behaviors) { + super(customBlock); + this.behaviors = behaviors.toArray(new AbstractBlockBehavior[0]); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getAs(Class tClass) { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (tClass.isInstance(behavior)) { + return Optional.of((T) behavior); + } + } + return Optional.empty(); + } + + @Override + public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { + for (AbstractBlockBehavior behavior : this.behaviors) { + InteractionResult result = behavior.useOnBlock(context, state); + if (result != InteractionResult.PASS) { + return result; + } + } + return super.useOnBlock(context, state); + } + + @Override + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { + for (AbstractBlockBehavior behavior : this.behaviors) { + state = behavior.updateStateForPlacement(context, state); + } + return state; + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + args[0] = behavior.updateShape(thisBlock, args, superMethod); + } + return args[0]; + } + + @Override + public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.tick(thisBlock, args, superMethod); + } + } + + @Override + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.randomTick(thisBlock, args, superMethod); + } + } + + @Override + public Object rotate(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + args[0] = behavior.rotate(thisBlock, args, superMethod); + } + return args[0]; + } + + @Override + public Object mirror(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + args[0] = behavior.mirror(thisBlock, args, superMethod); + } + return args[0]; + } + + @Override + public void performBoneMeal(Object thisBlock, Object[] args) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.performBoneMeal(thisBlock, args); + } + } + + @Override + public void onPlace(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.onPlace(thisBlock, args, superMethod); + } + } + + @Override + public void onLand(Object thisBlock, Object[] args) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.onLand(thisBlock, args); + } + } + + @Override + public void onBrokenAfterFall(Object thisBlock, Object[] args) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.onBrokenAfterFall(thisBlock, args); + } + } + + @Override + public void neighborChanged(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.neighborChanged(thisBlock, args, superMethod); + } + } + + @Override + public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (behavior.isValidBoneMealTarget(thisBlock, args)) { + return true; + } + } + return false; + } + + @Override + public boolean isBoneMealSuccess(Object thisBlock, Object[] args) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (behavior.isBoneMealSuccess(thisBlock, args)) { + return true; + } + } + return false; + } + + @Override + public boolean canSurvive(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (!behavior.canSurvive(thisBlock, args, superMethod)) { + return false; + } + } + return true; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/EmptyItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/EmptyItem.java new file mode 100644 index 000000000..5fcfdbefb --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/EmptyItem.java @@ -0,0 +1,342 @@ +//package net.momirealms.craftengine.core.item; +// +//import com.google.gson.JsonElement; +//import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +//import net.momirealms.craftengine.core.util.Key; +// +//import java.util.List; +//import java.util.Optional; +// +//public class EmptyItem implements Item { +// private final I item; +// +// public EmptyItem(I item) { +// this.item = item; +// } +// +// @Override +// public Item addEnchantment(Enchantment enchantment) { +// return this; +// } +// +// @Override +// public Optional> getCustomItem() { +// return Optional.empty(); +// } +// +// @Override +// public Optional> getItemBehavior() { +// return Optional.empty(); +// } +// +// @Override +// public boolean isCustomItem() { +// return false; +// } +// +// @Override +// public boolean isBlockItem() { +// return false; +// } +// +// @Override +// public Key id() { +// return ItemKeys.AIR; +// } +// +// @Override +// public Key vanillaId() { +// return ItemKeys.AIR; +// } +// +// @Override +// public Optional customId() { +// return Optional.empty(); +// } +// +// @Override +// public Item customId(Key id) { +// return this; +// } +// +// @Override +// public int count() { +// return 0; +// } +// +// @Override +// public Item count(int amount) { +// return this; +// } +// +// @Override +// public Item trim(Trim trim) { +// return this; +// } +// +// @Override +// public Optional trim() { +// return Optional.empty(); +// } +// +// @Override +// public Item customModelData(Integer data) { +// return this; +// } +// +// @Override +// public Optional customModelData() { +// return Optional.empty(); +// } +// +// @Override +// public Item damage(Integer data) { +// return this; +// } +// +// @Override +// public Optional damage() { +// return Optional.empty(); +// } +// +// @Override +// public Item repairCost(Integer data) { +// return this; +// } +// +// @Override +// public Optional repairCost() { +// return Optional.empty(); +// } +// +// @Override +// public Item maxDamage(Integer data) { +// return this; +// } +// +// @Override +// public Optional maxDamage() { +// return Optional.empty(); +// } +// +// @Override +// public Item dyedColor(Integer data) { +// return this; +// } +// +// @Override +// public Optional dyedColor() { +// return Optional.empty(); +// } +// +// @Override +// public Item customName(String displayName) { +// return this; +// } +// +// @Override +// public Optional customName() { +// return Optional.empty(); +// } +// +// @Override +// public Item itemName(String itemName) { +// return this; +// } +// +// @Override +// public Optional itemName() { +// return Optional.empty(); +// } +// +// @Override +// public Item itemModel(String itemModel) { +// return this; +// } +// +// @Override +// public Optional itemModel() { +// return Optional.empty(); +// } +// +// @Override +// public Item tooltipStyle(String tooltipStyle) { +// return this; +// } +// +// @Override +// public Optional tooltipStyle() { +// return Optional.empty(); +// } +// +// @Override +// public Item lore(List lore) { +// return this; +// } +// +// @Override +// public Optional jukeboxSong() { +// return Optional.empty(); +// } +// +// @Override +// public Item jukeboxSong(JukeboxPlayable song) { +// return this; +// } +// +// @Override +// public Optional equippable() { +// return Optional.empty(); +// } +// +// @Override +// public Item equippable(EquipmentData equipmentData) { +// return this; +// } +// +// @Override +// public Optional> lore() { +// return Optional.empty(); +// } +// +// @Override +// public Item unbreakable(boolean unbreakable) { +// return this; +// } +// +// @Override +// public boolean unbreakable() { +// return false; +// } +// +// @Override +// public Item skull(String data) { +// return this; +// } +// +// @Override +// public Optional getEnchantment(Key enchantmentId) { +// return Optional.empty(); +// } +// +// @Override +// public Item setEnchantments(List enchantments) { +// return this; +// } +// +// @Override +// public Item setStoredEnchantments(List enchantments) { +// return this; +// } +// +// @Override +// public Item addStoredEnchantment(Enchantment enchantment) { +// return this; +// } +// +// @Override +// public Item itemFlags(List flags) { +// return this; +// } +// +// @Override +// public Object getTag(Object... path) { +// return null; +// } +// +// @Override +// public Item setTag(Object value, Object... path) { +// return this; +// } +// +// @Override +// public boolean hasTag(Object... path) { +// return false; +// } +// +// @Override +// public boolean removeTag(Object... path) { +// return false; +// } +// +// @Override +// public boolean hasComponent(Object type) { +// return false; +// } +// +// @Override +// public void removeComponent(Object type) { +// } +// +// @Override +// public Object getComponent(Object type) { +// return null; +// } +// +// @Override +// public Object getJavaTypeComponent(Object type) { +// return null; +// } +// +// @Override +// public JsonElement getJsonTypeComponent(Object type) { +// return null; +// } +// +// @Override +// public void setComponent(Object type, Object value) { +// } +// +// @Override +// public void resetComponent(Object type) { +// } +// +// @Override +// public I getItem() { +// return this.item; +// } +// +// @Override +// public I load() { +// return this.item; +// } +// +// @Override +// public int maxStackSize() { +// return 0; +// } +// +// @Override +// public Item maxStackSize(int amount) { +// return this; +// } +// +// @Override +// public Item copyWithCount(int count) { +// return this; +// } +// +// @Override +// public boolean is(Key itemTag) { +// return false; +// } +// +// @Override +// public Object getLiteralObject() { +// return null; +// } +// +// @Override +// public Item mergeCopy(Item another) { +// return this; +// } +// +// @Override +// public void merge(Item another) { +// } +// +// @Override +// public byte[] toByteArray() { +// return new byte[0]; +// } +//} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index de7c072ac..f5fc439c2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -29,6 +29,7 @@ public class ItemKeys { public static final Key BONE_MEAL = Key.of("minecraft:bone_meal"); public static final Key ENCHANTED_BOOK = Key.of("minecraft:enchanted_book"); public static final Key TOTEM_OF_UNDYING = Key.of("minecraft:totem_of_undying"); + public static final Key BARRIER = Key.of("minecraft:barrier"); public static final Key[] AXES = new Key[] { WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java index b18d3f952..839de5886 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java @@ -9,9 +9,6 @@ import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.nio.file.Path; import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; public interface PackManager extends Manageable { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java index c48418575..cbecc4ba5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/GuiElement.java @@ -129,7 +129,7 @@ public interface GuiElement { @Override public Item item() { - return gui().itemAt(index).item(); + return gui().itemAt(this.index).item(); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index 2e9d1e6d0..7fc4915ef 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -1,5 +1,8 @@ package net.momirealms.craftengine.core.plugin.gui.category; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; @@ -243,12 +246,18 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { if (subCategory == null) return null; Item item = this.plugin.itemManager().createWrappedItem(subCategory.icon(), player); if (item == null) { - this.plugin.logger().warn("Can't not find item " + subCategory.icon() + " for category icon"); - return null; + if (!subCategory.icon().equals(ItemKeys.AIR)) { + this.plugin.logger().warn("Can't find item " + subCategory.icon() + " as icon for sub category " + subCategoryId); + item = this.plugin.itemManager().createWrappedItem(ItemKeys.BARRIER, player); + item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); + item.lore(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); + item.load(); + } + } else { + item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); + item.lore(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); + item.load(); } - item.customName(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); - item.lore(subCategory.displayLore().stream().map(lore -> AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(lore, ItemBuildContext.EMPTY.tagResolvers()))).toList()); - item.load(); return new ItemWithAction(item, (element, click) -> { click.cancel(); player.playSound(Constants.SOUND_CLICK_BUTTON); @@ -257,21 +266,35 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } else { Key itemId = Key.of(it); Item item = this.plugin.itemManager().createWrappedItem(itemId, player); - if (item == null) return null; + boolean canGoFurther; + if (item == null) { + if (!itemId.equals(ItemKeys.AIR)) { + this.plugin.logger().warn("Can't find item " + itemId + " for category " + categoryId); + item = this.plugin.itemManager().createWrappedItem(ItemKeys.BARRIER, player); + item.customName(AdventureHelper.componentToJson(Component.text(it).decoration(TextDecoration.ITALIC, TextDecoration.State.FALSE).color(NamedTextColor.RED))); + } + canGoFurther = false; + } else { + canGoFurther = true; + } return new ItemWithAction(item, (e, c) -> { c.cancel(); + Item eItem = e.item(); + if (!canGoFurther) { + return; + } if (player.isCreativeMode() && player.hasPermission(GET_ITEM_PERMISSION)) { if (MIDDLE_CLICK.contains(c.type()) && c.itemOnCursor() == null) { - Item newItem = this.plugin.itemManager().createWrappedItem(e.item().id(), player); + Item newItem = this.plugin.itemManager().createWrappedItem(eItem.id(), player); newItem.count(newItem.maxStackSize()); c.setItemOnCursor(newItem); return; } if (SHIFT_LEFT.equals(c.type())) { - player.giveItem(this.plugin.itemManager().createWrappedItem(e.item().id(), player)); + player.giveItem(this.plugin.itemManager().createWrappedItem(eItem.id(), player)); return; } else if (SHIFT_RIGHT.equals(c.type())) { - Item newItem = this.plugin.itemManager().createWrappedItem(e.item().id(), player); + Item newItem = this.plugin.itemManager().createWrappedItem(eItem.id(), player); newItem.count(newItem.maxStackSize()); player.giveItem(newItem); return; @@ -294,7 +317,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } }); } - }).filter(Objects::nonNull).toList(); + }).toList(); PagedGui.builder() .addIngredients(itemList) diff --git a/gradle.properties b/gradle.properties index 3bb2f44ca..ef3d4750e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.54.8 +project_version=0.0.54.9 config_version=34 lang_version=14 project_group=net.momirealms @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.65.26 +nms_helper_version=0.65.27 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 diff --git a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index 52214c52a..daeeba57c 100644 --- a/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_20_1/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -225,4 +225,16 @@ public class CraftEngineBlock extends Block LOGGER.error(e); } } + + @Override + public void neighborChanged(@NotNull BlockState state, @NotNull Level world, @NotNull BlockPos pos, @NotNull Block sourceBlock, @NotNull BlockPos sourcePos, boolean notify) { + try { + this.behaviorHolder.value().neighborChanged(this, new Object[]{state, world, pos, sourceBlock, sourcePos, notify}, () -> { + super.neighborChanged(state, world, pos, sourceBlock, sourcePos, notify); + return null; + }); + } catch (Exception e) { + LOGGER.error(e); + } + } } diff --git a/server-mod/v1_20_5/build.gradle.kts b/server-mod/v1_20_5/build.gradle.kts index 38964e5ad..bcc393e9d 100644 --- a/server-mod/v1_20_5/build.gradle.kts +++ b/server-mod/v1_20_5/build.gradle.kts @@ -44,7 +44,7 @@ artifacts { tasks { shadowJar { archiveClassifier = "" - archiveFileName = "${rootProject.name}-ignite-mod-${rootProject.properties["project_version"]}+mc1.20.5-1.21.4-mojmap.jar" + archiveFileName = "${rootProject.name}-ignite-mod-${rootProject.properties["project_version"]}+mc1.21.2-1.21.4-mojmap.jar" destinationDirectory.set(file("$rootDir/target")) } } diff --git a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index 4e37a60ef..fdde40516 100644 --- a/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_20_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -12,6 +12,7 @@ import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.Orientation; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.momirealms.craftengine.mod.CraftEnginePlugin; @@ -21,6 +22,7 @@ import net.momirealms.craftengine.shared.block.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class CraftEngineBlock extends Block implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock { @@ -226,4 +228,16 @@ public class CraftEngineBlock extends Block LOGGER.error(e); } } + + @Override + protected void neighborChanged(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { + try { + this.behaviorHolder.value().neighborChanged(this, new Object[]{state, level, pos, neighborBlock, orientation, movedByPiston}, () -> { + super.neighborChanged(state, level, pos, neighborBlock, orientation, movedByPiston); + return null; + }); + } catch (Exception e) { + LOGGER.error(e); + } + } } diff --git a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java index 212e34087..fedc24dd6 100644 --- a/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java +++ b/server-mod/v1_21_5/src/main/java/net/momirealms/craftengine/mod/block/CraftEngineBlock.java @@ -12,6 +12,7 @@ import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.Orientation; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import net.momirealms.craftengine.mod.CraftEnginePlugin; @@ -21,6 +22,7 @@ import net.momirealms.craftengine.shared.block.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class CraftEngineBlock extends Block implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock { @@ -226,4 +228,16 @@ public class CraftEngineBlock extends Block LOGGER.error(e); } } + + @Override + protected void neighborChanged(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { + try { + this.behaviorHolder.value().neighborChanged(this, new Object[]{state, level, pos, neighborBlock, orientation, movedByPiston}, () -> { + super.neighborChanged(state, level, pos, neighborBlock, orientation, movedByPiston); + return null; + }); + } catch (Exception e) { + LOGGER.error(e); + } + } } diff --git a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java index 24e08c8b3..5c4987cab 100644 --- a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java +++ b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java @@ -1,9 +1,18 @@ package net.momirealms.craftengine.shared.block; +import java.util.Optional; import java.util.concurrent.Callable; public abstract class BlockBehavior { + @SuppressWarnings("unchecked") + public Optional getAs(Class tClass) { + if (tClass.isInstance(this)) { + return Optional.of((T) this); + } + return Optional.empty(); + } + public Object rotate(Object thisBlock, Object[] args, Callable superMethod) throws Exception { return superMethod.call(); } @@ -16,6 +25,10 @@ public abstract class BlockBehavior { return superMethod.call(); } + public void neighborChanged(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + superMethod.call(); + } + public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { superMethod.call(); }