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 d70502472..cb1bc5c41 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/blocks.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/blocks.yml @@ -1,7 +1,7 @@ items: default:chinese_lantern: material: paper - custom-model-data: 3001 + custom-model-data: 3000 data: item-name: "" model: 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 3d38bd5e0..4834bf38d 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/categories.yml @@ -56,4 +56,5 @@ categories: icon: default:chinese_lantern list: - default:chinese_lantern - - default:fairy_flower \ No newline at end of file + - default:fairy_flower + - default:reed \ 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 bb6d97c3f..456f15b57 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/i18n.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/i18n.yml @@ -2,6 +2,7 @@ i18n: en: item.chinese_lantern: "Chinese Lantern" item.fairy_flower: "Fairy Flower" + item.reed: "Reed" item.bench: "Bench" item.table_lamp: "Table Lamp" item.wooden_chair: "Wooden Chair" @@ -36,6 +37,7 @@ i18n: zh_cn: item.chinese_lantern: "灯笼" item.fairy_flower: "仙灵花" + item.reed: "芦苇" item.bench: "长椅" item.table_lamp: "台灯" item.wooden_chair: "木椅" diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/palm_tree.yml b/bukkit-loader/src/main/resources/resources/default/configuration/palm_tree.yml index b3446fb13..d5ce8c5c4 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/palm_tree.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/palm_tree.yml @@ -235,7 +235,7 @@ items: # To prevent errors, we use tree feature from vanilla here feature: minecraft:fancy_oak bone-meal-success-chance: 0.45 - tags: + bottom-block-tags: - minecraft:dirt - minecraft:farmland - minecraft:sand diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/fairy_flower.yml b/bukkit-loader/src/main/resources/resources/default/configuration/plants.yml similarity index 63% rename from bukkit-loader/src/main/resources/resources/default/configuration/fairy_flower.yml rename to bukkit-loader/src/main/resources/resources/default/configuration/plants.yml index 16f034753..ba5ac3ab2 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/fairy_flower.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/plants.yml @@ -1,7 +1,7 @@ items: default:fairy_flower: material: paper - custom-model-data: 3000 + custom-model-data: 3001 data: item-name: "" model: @@ -11,6 +11,18 @@ items: behavior: type: block_item block: default:fairy_flower + default:reed: + material: paper + custom-model-data: 3002 + data: + item-name: "" + model: + template: default:model/simplified_generated + arguments: + path: "minecraft:item/custom/reed" + behavior: + type: liquid_collision_block_item + block: default:reed blocks: default:fairy_flower: settings: @@ -48,4 +60,23 @@ blocks: generation: parent: "minecraft:block/custom/fairy_flower_1" textures: - "0": "minecraft:block/custom/fairy_flower_4" \ No newline at end of file + "0": "minecraft:block/custom/fairy_flower_4" + default:reed: + settings: + template: + - default:hardness/none + - default:sound/grass + overrides: + item: default:reed + behavior: + type: on_liquid_block + liquid-type: water + loot: + template: "default:loot_table/basic" + arguments: + item: default:reed + state: + id: 1 + state: tripwire:1 + model: + path: "minecraft:block/custom/reed" \ No newline at end of file diff --git a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/reed.json b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/reed.json new file mode 100644 index 000000000..63af951fa --- /dev/null +++ b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/reed.json @@ -0,0 +1,35 @@ +{ + "texture_size": [32, 32], + "textures": { + "0": "block/custom/reed", + "particle": "block/custom/reed" + }, + "elements": [ + { + "from": [-0.5, -3, 0.25], + "to": [19.5, 29, 0.25], + "rotation": {"angle": -45, "axis": "y", "origin": [-0.5, -3, 2.25]}, + "faces": { + "north": {"uv": [0, 0, 10, 16], "texture": "#0"}, + "east": {"uv": [0, 0, 0, 16], "texture": "#0"}, + "south": {"uv": [0, 0, 10, 16], "texture": "#0"}, + "west": {"uv": [0, 0, 0, 16], "texture": "#0"}, + "up": {"uv": [0, 0, 0, 10], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 0, 0, 10], "rotation": 90, "texture": "#0"} + } + }, + { + "from": [2, -3, 14.75], + "to": [22, 29, 14.75], + "rotation": {"angle": 45, "axis": "y", "origin": [2, -3, 16.75]}, + "faces": { + "north": {"uv": [0, 0, 10, 16], "texture": "#0"}, + "east": {"uv": [0, 0, 0, 16], "texture": "#0"}, + "south": {"uv": [0, 0, 10, 16], "texture": "#0"}, + "west": {"uv": [0, 0, 0, 16], "texture": "#0"}, + "up": {"uv": [0, 0, 0, 10], "rotation": 270, "texture": "#0"}, + "down": {"uv": [0, 0, 0, 10], "rotation": 90, "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/reed.png b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/reed.png new file mode 100644 index 000000000..282ee6ebd Binary files /dev/null and b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/reed.png differ diff --git a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/reed.png b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/reed.png new file mode 100644 index 000000000..04d930d92 Binary files /dev/null and b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/reed.png differ 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 00605750f..f50ba9570 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 @@ -5,12 +5,12 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.shared.block.EmptyBlockBehavior; public class BukkitBlockBehaviors extends BlockBehaviors { - public static final Key EMPTY = Key.from("craftengine:empty"); public static final Key BUSH_BLOCK = Key.from("craftengine:bush_block"); public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); public static final Key LEAVES_BLOCK = Key.from("craftengine:leaves_block"); public static final Key STRIPPABLE_BLOCK = Key.from("craftengine:strippable_block"); public static final Key SAPLING_BLOCK = Key.from("craftengine:sapling_block"); + public static final Key ON_LIQUID_BLOCK = Key.from("craftengine:on_liquid_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -19,5 +19,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(LEAVES_BLOCK, LeavesBlockBehavior.FACTORY); register(STRIPPABLE_BLOCK, StrippableBlockBehavior.FACTORY); register(SAPLING_BLOCK, SaplingBlockBehavior.FACTORY); + register(ON_LIQUID_BLOCK, OnLiquidBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 52dca81e1..d3013442a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -83,7 +83,9 @@ public class BushBlockBehavior extends BlockBehavior { public static class Factory implements BlockBehaviorFactory { @Override public BlockBehavior create(CustomBlock block, Map arguments) { - if (arguments.containsKey("tags")) { + if (arguments.containsKey("bottom-block-tags")) { + return new BushBlockBehavior(MiscUtils.getAsStringList(arguments.get("bottom-block-tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList()); + } else if (arguments.containsKey("tags")) { return new BushBlockBehavior(MiscUtils.getAsStringList(arguments.get("tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList()); } else { return INSTANCE; @@ -100,7 +102,7 @@ public class BushBlockBehavior extends BlockBehavior { return mayPlaceOn(belowState, world, belowPos); } - private boolean mayPlaceOn(Object belowState, Object world, Object blockPos) throws ReflectiveOperationException { + protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException { for (Object tag : this.tagsCanSurviveOn) { if ((boolean) Reflections.method$BlockStateBase$hasTag.invoke(belowState, tag)) { return true; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java new file mode 100644 index 000000000..1aca9d2bf --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java @@ -0,0 +1,55 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.shared.block.BlockBehavior; + +import java.util.List; +import java.util.Map; + +public class OnLiquidBlockBehavior extends BushBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final boolean onWater; + private final boolean onLava; + + public OnLiquidBlockBehavior(List tagsCanSurviveOn, boolean onWater, boolean onLava) { + super(tagsCanSurviveOn); + this.onWater = onWater; + this.onLava = onLava; + } + + public boolean onWater() { + return this.onWater; + } + + public boolean onLava() { + return this.onLava; + } + + public static class Factory implements BlockBehaviorFactory { + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + List liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water"))); + return new OnLiquidBlockBehavior(List.of(), liquidTypes.contains("water"), liquidTypes.contains("lava")); + } + } + + @Override + protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException { + Object fluidState = Reflections.method$Level$getFluidState.invoke(world, belowPos); + Object fluidStateAbove = Reflections.method$Level$getFluidState.invoke(world, LocationUtils.above(belowPos)); + if (Reflections.method$FluidState$getType.invoke(fluidStateAbove) != Reflections.instance$Fluids$EMPTY) { + return false; + } + if (this.onWater && (Reflections.method$FluidState$getType.invoke(fluidState) == Reflections.instance$Fluids$WATER || Reflections.field$StateHolder$owner.get(belowState) == Reflections.instance$Blocks$ICE)) { + return true; + } + if (this.onLava && Reflections.method$FluidState$getType.invoke(fluidState) == Reflections.instance$Fluids$LAVA) { + return true; + } + return false; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 02442c045..fcbcbba5e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.item; import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior; -import net.momirealms.craftengine.bukkit.item.behavior.BoneMealBehavior; import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior; import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory; @@ -50,7 +49,6 @@ public class BukkitItemManager extends AbstractItemManager { registerVanillaItemExtraBehavior(AxeItemBehavior.INSTANCE, ItemKeys.AXES); registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKETS); registerVanillaItemExtraBehavior(BucketItemBehavior.INSTANCE, ItemKeys.BUCKET); - registerVanillaItemExtraBehavior(BoneMealBehavior.INSTANCE, ItemKeys.BONE_MEAL); } private static BukkitItemManager instance; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java index cc1a448d8..3c95a1d9d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ItemEventListener.java @@ -157,6 +157,8 @@ public class ItemEventListener implements Listener { } for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) { + + InteractionResult result = itemBehavior.useOnBlock(new UseOnContext(player, hand, hitResult)); if (result == InteractionResult.SUCCESS_AND_CANCEL) { event.setCancelled(true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index af2690183..1add69fe2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -79,7 +79,7 @@ public class BlockItemBehavior extends ItemBehavior { BlockPos pos = placeContext.getClickedPos(); BlockPos againstPos = placeContext.getAgainstPos(); - World world = (World) placeContext.getLevel().getHandle(); + World world = (World) placeContext.getLevel().platformWorld(); Location placeLocation = new Location(world, pos.x(), pos.y(), pos.z()); Block bukkitBlock = world.getBlockAt(placeLocation); @@ -151,7 +151,7 @@ public class BlockItemBehavior extends ItemBehavior { Object blockState = state.customBlockState().handle(); Object blockPos = LocationUtils.toBlockPos(context.getClickedPos()); Object voxelShape = Reflections.method$CollisionContext$of.invoke(null, player); - Object world = Reflections.field$CraftWorld$ServerLevel.get(context.getLevel().getHandle()); + Object world = Reflections.field$CraftWorld$ServerLevel.get(context.getLevel().platformWorld()); boolean defaultReturn = ((!this.checkStatePlacement() || (boolean) Reflections.method$BlockStateBase$canSurvive.invoke(blockState, world, blockPos)) && (boolean) Reflections.method$ServerLevel$checkEntityCollision.invoke(world, blockState, player, voxelShape, blockPos, true)); Block block = (Block) Reflections.method$CraftBlock$at.invoke(null, world, blockPos); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealBehavior.java deleted file mode 100644 index f01e85f05..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealBehavior.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.momirealms.craftengine.bukkit.item.behavior; - -import net.momirealms.craftengine.core.entity.player.InteractionResult; -import net.momirealms.craftengine.core.item.behavior.ItemBehavior; -import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; -import net.momirealms.craftengine.core.item.context.UseOnContext; -import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.util.Key; - -import java.nio.file.Path; -import java.util.Map; - -public class BoneMealBehavior extends ItemBehavior { - public static final BoneMealBehavior INSTANCE = new BoneMealBehavior(); - - @Override - public InteractionResult useOnBlock(UseOnContext context) { - return super.useOnBlock(context); - } - - public static class Factory implements ItemBehaviorFactory { - @Override - public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { - return INSTANCE; - } - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java index f11054634..40bed4810 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java @@ -5,16 +5,17 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehaviors; import net.momirealms.craftengine.core.util.Key; public class BukkitItemBehaviors extends ItemBehaviors { - public static final Key EMPTY = Key.from("craftengine:empty"); public static final Key BLOCK_ITEM = Key.from("craftengine:block_item"); + public static final Key ON_LIQUID_BLOCK_ITEM = Key.from("craftengine:liquid_collision_block_item"); public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item"); public static final Key AXE_ITEM = Key.from("craftengine:axe_item"); public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item"); public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item"); public static void init() { - register(EMPTY, (pack, path, args, id) -> EmptyItemBehavior.INSTANCE); + register(EMPTY, EmptyItemBehavior.FACTORY); register(BLOCK_ITEM, BlockItemBehavior.FACTORY); + register(ON_LIQUID_BLOCK_ITEM, LiquidCollisionBlockItemBehavior.FACTORY); register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY); register(AXE_ITEM, AxeItemBehavior.FACTORY); register(WATER_BUCKET_ITEM, WaterBucketItemBehavior.FACTORY); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java index 227cedae8..c8cfe78af 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java @@ -77,7 +77,7 @@ public class FurnitureItemBehavior extends ItemBehavior { // trigger event org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) player.platformPlayer(); - World world = (World) context.getLevel().getHandle(); + World world = (World) context.getLevel().platformWorld(); // get position and rotation for placement Vec3d finalPlacePosition; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java new file mode 100644 index 000000000..194a1bbba --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java @@ -0,0 +1,76 @@ +package net.momirealms.craftengine.bukkit.item.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.world.BlockHitResult; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; + +import java.nio.file.Path; +import java.util.Map; + +public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior { + public static final Factory FACTORY = new Factory(); + private final int offsetY; + + public LiquidCollisionBlockItemBehavior(Key blockId, int offsetY) { + super(blockId); + this.offsetY = offsetY; + } + + @Override + public InteractionResult useOnBlock(UseOnContext context) { + return use(context.getLevel(), context.getPlayer(), context.getHand()); + } + + @Override + public InteractionResult use(World world, Player player, InteractionHand hand) { + try { + Object blockHitResult = Reflections.method$Item$getPlayerPOVHitResult.invoke(null, world.serverWorld(), player.serverPlayer(), Reflections.instance$ClipContext$Fluid$SOURCE_ONLY); + Object blockPos = Reflections.field$BlockHitResul$blockPos.get(blockHitResult); + BlockPos above = new BlockPos(Reflections.field$Vec3i$x.getInt(blockPos), Reflections.field$Vec3i$y.getInt(blockPos) + offsetY, Reflections.field$Vec3i$z.getInt(blockPos)); + Direction direction = Direction.values()[(int) Reflections.method$Direction$ordinal.invoke(Reflections.field$BlockHitResul$direction.get(blockHitResult))]; + boolean miss = Reflections.field$BlockHitResul$miss.getBoolean(blockHitResult); + Vec3d hitPos = LocationUtils.fromVec(Reflections.field$HitResult$location.get(blockHitResult)); + if (miss) { + return super.useOnBlock(new UseOnContext(player, hand, BlockHitResult.miss(hitPos, direction, above))); + } else { + boolean inside = Reflections.field$BlockHitResul$inside.getBoolean(blockHitResult); + return super.useOnBlock(new UseOnContext(player, hand, new BlockHitResult(hitPos, direction, above, inside))); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Error handling use", e); + return InteractionResult.FAIL; + } + } + + public static class Factory implements ItemBehaviorFactory { + @Override + public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { + Object id = arguments.get("block"); + if (id == null) { + throw new IllegalArgumentException("Missing required parameter 'block' for on_liquid_block_item behavior"); + } + int offset = MiscUtils.getAsInt(arguments.getOrDefault("y-offset", 1)); + if (id instanceof Map map) { + BukkitBlockManager.instance().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + return new LiquidCollisionBlockItemBehavior(key, offset); + } else { + return new LiquidCollisionBlockItemBehavior(Key.of(id.toString()), offset); + } + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 4c45def46..821b5ce4d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -344,7 +344,7 @@ public class PacketConsumers { } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); } - }, (World) player.level().getHandle(), (MCUtils.fastFloor(player.x())) >> 4, (MCUtils.fastFloor(player.z())) >> 4); + }, (World) player.level().platformWorld(), (MCUtils.fastFloor(player.x())) >> 4, (MCUtils.fastFloor(player.z())) >> 4); } else { handleSetCreativeSlotPacketOnMainThread(player, packet); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index d6cc5e3bf..dba6359ea 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -16,15 +16,15 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.*; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; import org.jetbrains.annotations.Nullable; import java.lang.ref.Reference; @@ -201,6 +201,31 @@ public class BukkitServerPlayer extends Player { platformPlayer().closeInventory(); } + // TODO DO NOT USE BUKKIT API + @Override + public BlockHitResult rayTrace(double distance, FluidCollisionRule collisionRule) { + RayTraceResult result = platformPlayer().rayTraceBlocks(distance, FluidUtils.toCollisionRule(collisionRule)); + if (result == null) { + Location eyeLocation = platformPlayer().getEyeLocation(); + Location targetLocation = eyeLocation.clone(); + targetLocation.add(eyeLocation.getDirection().multiply(distance)); + return BlockHitResult.miss(new Vec3d(eyeLocation.getX(), eyeLocation.getY(), eyeLocation.getZ()), + Direction.getApproximateNearest(eyeLocation.getX() - targetLocation.getX(), eyeLocation.getY() - targetLocation.getY(), eyeLocation.getZ() - targetLocation.getZ()), + new BlockPos(targetLocation.getBlockX(), targetLocation.getBlockY(), targetLocation.getBlockZ()) + ); + } else { + Vector hitPos = result.getHitPosition(); + Block hitBlock = result.getHitBlock(); + Location hitBlockLocation = hitBlock.getLocation(); + return new BlockHitResult( + new Vec3d(hitPos.getX(), hitPos.getY(), hitPos.getZ()), + DirectionUtils.toDirection(result.getHitBlockFace()), + new BlockPos(hitBlockLocation.getBlockX(), hitBlockLocation.getBlockY(), hitBlockLocation.getBlockZ()), + false + ); + } + } + @Override public void sendPacket(Object packet, boolean immediately) { this.plugin.networkManager().sendPacket(this, packet, immediately); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FluidUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FluidUtils.java new file mode 100644 index 000000000..3af0cadc1 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FluidUtils.java @@ -0,0 +1,24 @@ +package net.momirealms.craftengine.bukkit.util; + +import net.momirealms.craftengine.core.world.FluidCollisionRule; +import org.bukkit.FluidCollisionMode; + +public class FluidUtils { + + private FluidUtils() {} + + public static FluidCollisionMode toCollisionRule(FluidCollisionRule rule) { + switch (rule) { + case NONE -> { + return FluidCollisionMode.NEVER; + } + case ALWAYS -> { + return FluidCollisionMode.ALWAYS; + } + case SOURCE_ONLY -> { + return FluidCollisionMode.SOURCE_ONLY; + } + } + return FluidCollisionMode.NEVER; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java index 4fa7782e9..b960901d0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java @@ -13,6 +13,14 @@ public class LocationUtils { return new Vec3d(loc.getX(), loc.getY(), loc.getZ()); } + public static Vec3d fromVec(Object vec) throws ReflectiveOperationException { + return new Vec3d( + Reflections.field$Vec3$x.getDouble(vec), + Reflections.field$Vec3$y.getDouble(vec), + Reflections.field$Vec3$z.getDouble(vec) + ); + } + public static Object toBlockPos(BlockPos pos) { try { return Reflections.constructor$BlockPos.newInstance(pos.x(), pos.y(), pos.z()); @@ -21,6 +29,14 @@ public class LocationUtils { } } + public static Object above(Object blockPos) throws ReflectiveOperationException { + return toBlockPos( + Reflections.field$Vec3i$x.getInt(blockPos), + Reflections.field$Vec3i$y.getInt(blockPos) + 1, + Reflections.field$Vec3i$z.getInt(blockPos) + ); + } + public static Object toBlockPos(int x, int y, int z) { try { return Reflections.constructor$BlockPos.newInstance(x, y, z); 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 0e474bebd..105899258 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 @@ -1455,6 +1455,12 @@ public class Reflections { ) ); + public static final Method method$Direction$ordinal = requireNonNull( + ReflectionUtils.getMethod( + clazz$Direction, new String[]{"ordinal"} + ) + ); + public static final Method method$Direction$values = requireNonNull( ReflectionUtils.getStaticMethod( clazz$Direction, clazz$Direction.arrayType() @@ -3326,6 +3332,7 @@ public class Reflections { public static final Object instance$Blocks$STONE; public static final Object instance$Blocks$STONE$defaultState; public static final Object instance$Blocks$FIRE; + public static final Object instance$Blocks$ICE; static { try { @@ -3337,6 +3344,8 @@ public class Reflections { Object stone = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "stone"); instance$Blocks$STONE = method$Registry$get.invoke(instance$BuiltInRegistries$BLOCK, stone); instance$Blocks$STONE$defaultState = method$Block$defaultBlockState.invoke(instance$Blocks$STONE); + Object ice = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "ice"); + instance$Blocks$ICE = method$Registry$get.invoke(instance$BuiltInRegistries$BLOCK, ice); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -3862,11 +3871,17 @@ public class Reflections { ); public static final Object instance$Fluids$WATER; + public static final Object instance$Fluids$LAVA; + public static final Object instance$Fluids$EMPTY; static { try { Object waterId = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "water"); instance$Fluids$WATER = method$Registry$get.invoke(instance$BuiltInRegistries$FLUID, waterId); + Object lavaId = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "lava"); + instance$Fluids$LAVA = method$Registry$get.invoke(instance$BuiltInRegistries$FLUID, lavaId); + Object emptyId = method$ResourceLocation$fromNamespaceAndPath.invoke(null, "minecraft", "empty"); + instance$Fluids$EMPTY = method$Registry$get.invoke(instance$BuiltInRegistries$FLUID, emptyId); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } @@ -5015,4 +5030,85 @@ public class Reflections { clazz$ItemStack, clazz$Item ) ); + + public static final Class clazz$BlockHitResult = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.phys.BlockHitResult") + ) + ); + + public static final Class clazz$ClipContext$Fluid = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.level.ClipContext$Fluid") + ) + ); + + public static final Method method$ClipContext$Fluid$values = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$ClipContext$Fluid, clazz$ClipContext$Fluid.arrayType() + ) + ); + + public static final Object instance$ClipContext$Fluid$NONE; + public static final Object instance$ClipContext$Fluid$SOURCE_ONLY; + public static final Object instance$ClipContext$Fluid$ANY; + + static { + try { + Object[] values = (Object[]) method$ClipContext$Fluid$values.invoke(null); + instance$ClipContext$Fluid$NONE = values[0]; + instance$ClipContext$Fluid$SOURCE_ONLY = values[1]; + instance$ClipContext$Fluid$ANY = values[2]; + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public static final Method method$Item$getPlayerPOVHitResult = requireNonNull( + ReflectionUtils.getDeclaredMethod( + clazz$Item, clazz$BlockHitResult, clazz$Level, clazz$Player, clazz$ClipContext$Fluid + ) + ); + + public static final Method method$BlockHitResult$withPosition = requireNonNull( + ReflectionUtils.getMethod( + clazz$BlockHitResult, clazz$BlockHitResult, clazz$BlockPos + ) + ); + + public static final Field field$BlockHitResul$blockPos = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$BlockHitResult, clazz$BlockPos, 0 + ) + ); + + public static final Field field$BlockHitResul$direction = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$BlockHitResult, clazz$Direction, 0 + ) + ); + + public static final Field field$BlockHitResul$miss = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$BlockHitResult, boolean.class, 0 + ) + ); + + public static final Field field$BlockHitResul$inside = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$BlockHitResult, boolean.class, 1 + ) + ); + + public static final Class clazz$HitResult = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.phys.HitResult") + ) + ); + + public static final Field field$HitResult$location = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$HitResult, clazz$Vec3, 0 + ) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java index 6c886d116..b5cddf244 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java @@ -15,7 +15,7 @@ public class BukkitCEWorld extends CEWorld { @Override public void tick() { if (ConfigManager.enableLightSystem()) { - LightUtils.updateChunkLight((org.bukkit.World) world.getHandle(), SectionPosUtils.toMap(super.updatedSectionPositions, world.worldHeight().getMinSection() - 1, world.worldHeight().getMaxSection() + 1)); + LightUtils.updateChunkLight((org.bukkit.World) world.platformWorld(), SectionPosUtils.toMap(super.updatedSectionPositions, world.worldHeight().getMinSection() - 1, world.worldHeight().getMaxSection() + 1)); super.updatedSectionPositions.clear(); } } 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 f4fee5aca..89192c5ac 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 @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -28,36 +29,45 @@ public class BukkitWorld implements World { } @Override - public org.bukkit.World getHandle() { + public org.bukkit.World platformWorld() { return world.get(); } + @Override + public Object serverWorld() { + try { + return Reflections.field$CraftWorld$ServerLevel.get(platformWorld()); + } catch (Exception e) { + throw new RuntimeException("Failed to get server world", e); + } + } + @Override public WorldHeight worldHeight() { if (this.worldHeight == null) { - this.worldHeight = WorldHeight.create(getHandle().getMinHeight(), getHandle().getMaxHeight() - getHandle().getMinHeight()); + this.worldHeight = WorldHeight.create(platformWorld().getMinHeight(), platformWorld().getMaxHeight() - platformWorld().getMinHeight()); } return this.worldHeight; } @Override public WorldBlock getBlockAt(int x, int y, int z) { - return new BukkitWorldBlock(getHandle().getBlockAt(x, y, z)); + return new BukkitWorldBlock(platformWorld().getBlockAt(x, y, z)); } @Override public String name() { - return getHandle().getName(); + return platformWorld().getName(); } @Override public Path directory() { - return getHandle().getWorldFolder().toPath(); + return platformWorld().getWorldFolder().toPath(); } @Override public UUID uuid() { - return getHandle().getUID(); + return platformWorld().getUID(); } @Override @@ -65,16 +75,16 @@ public class BukkitWorld implements World { ItemStack itemStack = (ItemStack) item.load(); if (ItemUtils.isEmpty(itemStack)) return; if (VersionHelper.isVersionNewerThan1_21_2()) { - getHandle().dropItemNaturally(new Location(null, location.x(), location.y(), location.z()), (ItemStack) item.getItem()); + platformWorld().dropItemNaturally(new Location(null, location.x(), location.y(), location.z()), (ItemStack) item.getItem()); } else { - getHandle().dropItemNaturally(new Location(null, location.x() - 0.5, location.y() - 0.5, location.z() - 0.5), (ItemStack) item.getItem()); + platformWorld().dropItemNaturally(new Location(null, location.x() - 0.5, location.y() - 0.5, location.z() - 0.5), (ItemStack) item.getItem()); } } @Override public void dropExp(Vec3d location, int amount) { if (amount <= 0) return; - EntityUtils.spawnEntity(getHandle(), new Location(getHandle(), location.x(), location.y(), location.z()), EntityType.EXPERIENCE_ORB, (e) -> { + EntityUtils.spawnEntity(platformWorld(), new Location(platformWorld(), location.x(), location.y(), location.z()), EntityType.EXPERIENCE_ORB, (e) -> { ExperienceOrb orb = (ExperienceOrb) e; orb.setExperience(amount); }); @@ -82,6 +92,6 @@ public class BukkitWorld implements World { @Override public void playBlockSound(Vec3d location, Key sound, float volume, float pitch) { - getHandle().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundCategory.BLOCKS, volume, pitch); + platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundCategory.BLOCKS, volume, pitch); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java index 8217b0000..5cbc64295 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java @@ -14,6 +14,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Map; public class BlockBehaviors { + public static final Key EMPTY = Key.from("craftengine:empty"); public static void register(Key key, BlockBehaviorFactory factory) { Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK_BEHAVIOR_FACTORY) diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index 67cf0d33f..7465a7fbd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -5,7 +5,9 @@ import net.momirealms.craftengine.core.entity.Entity; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.FluidCollisionRule; import org.jetbrains.annotations.Nullable; public abstract class Player extends Entity implements NetWorkUser { @@ -68,4 +70,6 @@ public abstract class Player extends Entity implements NetWorkUser { public abstract void giveItem(Item item); public abstract void closeInventory(); + + public abstract BlockHitResult rayTrace(double distance, FluidCollisionRule collisionRule); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/EmptyItemBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/EmptyItemBehavior.java index e9ee30aaf..68c0c1e49 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/EmptyItemBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/EmptyItemBehavior.java @@ -1,5 +1,20 @@ package net.momirealms.craftengine.core.item.behavior; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.util.Key; + +import java.nio.file.Path; +import java.util.Map; + public class EmptyItemBehavior extends ItemBehavior { + public static final Factory FACTORY = new Factory(); public static final EmptyItemBehavior INSTANCE = new EmptyItemBehavior(); + + public static class Factory implements ItemBehaviorFactory { + + @Override + public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { + return INSTANCE; + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java index e83921e69..b491baf28 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java @@ -12,6 +12,7 @@ import java.nio.file.Path; import java.util.Map; public class ItemBehaviors { + public static final Key EMPTY = Key.from("craftengine:empty"); public static void register(Key key, ItemBehaviorFactory factory) { Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.ITEM_BEHAVIOR_FACTORY) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 6e30309bf..3af5a0c7b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -320,14 +320,17 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/stripped_palm_log.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/stripped_palm_log_top.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/palm_leaves.png"); - // fairy flower - plugin.saveResource("resources/default/configuration/fairy_flower.yml"); + // plants + plugin.saveResource("resources/default/configuration/plants.yml"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/fairy_flower_1.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/fairy_flower_2.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/fairy_flower_3.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/fairy_flower_4.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/reed.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/fairy_flower.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/reed.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/fairy_flower_1.json"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/reed.json"); // furniture plugin.saveResource("resources/default/configuration/furniture.yml"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/item/custom/table_lamp.json"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergeAltasResolution.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergeAltasResolution.java new file mode 100644 index 000000000..0445a763f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergeAltasResolution.java @@ -0,0 +1,58 @@ +package net.momirealms.craftengine.core.pack.conflict.resolution; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.GsonHelper; +import net.momirealms.craftengine.core.util.Key; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Map; + +public class MergeAltasResolution implements Resolution { + public static final Factory FACTORY = new Factory(); + public static final MergeAltasResolution INSTANCE = new MergeAltasResolution(); + + @Override + public void run(Path existing, Path conflict) { + try { + JsonObject j1 = GsonHelper.readJsonFile(existing).getAsJsonObject(); + JsonObject j2 = GsonHelper.readJsonFile(conflict).getAsJsonObject(); + JsonObject j3 = new JsonObject(); + JsonArray ja1 = j1.getAsJsonArray("sources"); + JsonArray ja2 = j2.getAsJsonArray("sources"); + JsonArray ja3 = new JsonArray(); + HashSet elements = new HashSet<>(); + for (JsonElement je : ja1) { + if (elements.add(je.getAsString())) { + ja3.add(je); + } + } + for (JsonElement je : ja2) { + if (elements.add(je.getAsString())) { + ja3.add(je); + } + } + j3.add("sources", ja3); + GsonHelper.writeJsonFile(j3, existing); + } catch (IOException e) { + CraftEngine.instance().logger().severe("Failed to merge json when resolving file conflicts", e); + } + } + + @Override + public Key type() { + return Resolutions.MERGE_ATLAS; + } + + public static class Factory implements ResolutionFactory { + + @Override + public Resolution create(Map arguments) { + return INSTANCE; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java index cefef34ed..9d65cf9cc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java @@ -12,6 +12,7 @@ import java.util.Map; public class Resolutions { public static final Key RETAIN_MATCHING = Key.of("craftengine:retain_matching"); public static final Key MERGE_JSON = Key.of("craftengine:merge_json"); + public static final Key MERGE_ATLAS = Key.of("craftengine:merge_atlas"); public static final Key CONDITIONAL = Key.of("craftengine:conditional"); public static final Key MERGE_PACK_MCMETA = Key.of("craftengine:merge_pack_mcmeta"); @@ -20,6 +21,7 @@ public class Resolutions { register(MERGE_JSON, MergeJsonResolution.FACTORY); register(CONDITIONAL, ConditionalResolution.FACTORY); register(MERGE_PACK_MCMETA, MergePackMcMetaResolution.FACTORY); + register(MERGE_ATLAS, MergeAltasResolution.FACTORY); } public static void register(Key key, ResolutionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java b/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java index 44d222cd9..0678d4f85 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java @@ -182,6 +182,21 @@ public enum Direction { }; } + public static Direction getApproximateNearest(double x, double y, double z) { + Direction nearestDirection = null; + double maxDotProduct = -Double.MAX_VALUE; + for (Direction direction : Direction.values()) { + double dotProduct = x * direction.vec.x() + + y * direction.vec.y() + + z * direction.vec.z(); + if (dotProduct > maxDotProduct) { + maxDotProduct = dotProduct; + nearestDirection = direction; + } + } + return nearestDirection; + } + public static Direction from3DDataValue(int id) { return BY_3D_DATA[Math.abs(id % BY_3D_DATA.length)]; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/FluidCollisionRule.java b/core/src/main/java/net/momirealms/craftengine/core/world/FluidCollisionRule.java new file mode 100644 index 000000000..7d49f54b9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/FluidCollisionRule.java @@ -0,0 +1,7 @@ +package net.momirealms.craftengine.core.world; + +public enum FluidCollisionRule { + NONE, + SOURCE_ONLY, + ALWAYS +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index 7cabc13a5..3b1cc134e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -8,7 +8,9 @@ import java.util.UUID; public interface World { - Object getHandle(); + Object platformWorld(); + + Object serverWorld(); WorldHeight worldHeight(); diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java b/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java index 64afc437f..caa871ddc 100644 --- a/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java +++ b/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java @@ -24,7 +24,7 @@ import net.momirealms.craftengine.shared.block.*; import org.jetbrains.annotations.NotNull; public class CraftEngineBlock extends Block implements BehaviorHolder, ShapeHolder, NoteBlockIndicator, Fallable, BonemealableBlock { - private static final PaperWeightStoneBlockShape STONE = new PaperWeightStoneBlockShape(Blocks.STONE.defaultBlockState()); + private static final StoneBlockShape STONE = new StoneBlockShape(Blocks.STONE.defaultBlockState()); private boolean isNoteBlock; public ObjectHolder behaviorHolder; public ObjectHolder shapeHolder; diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/PaperWeightStoneBlockShape.java b/server-mod/src/main/java/net/momirealms/craftengine/mod/StoneBlockShape.java similarity index 81% rename from server-mod/src/main/java/net/momirealms/craftengine/mod/PaperWeightStoneBlockShape.java rename to server-mod/src/main/java/net/momirealms/craftengine/mod/StoneBlockShape.java index cc2615820..be7f4aa76 100644 --- a/server-mod/src/main/java/net/momirealms/craftengine/mod/PaperWeightStoneBlockShape.java +++ b/server-mod/src/main/java/net/momirealms/craftengine/mod/StoneBlockShape.java @@ -6,10 +6,10 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.shapes.CollisionContext; import net.momirealms.craftengine.shared.block.BlockShape; -public class PaperWeightStoneBlockShape implements BlockShape { +public class StoneBlockShape implements BlockShape { private final BlockState rawBlockState; - public PaperWeightStoneBlockShape(BlockState rawBlockState) { + public StoneBlockShape(BlockState rawBlockState) { this.rawBlockState = rawBlockState; }