From 305be2f921407d0a7169025b5580c040df6cb339 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Thu, 20 Mar 2025 00:05:08 +0800 Subject: [PATCH 01/12] Update gradle.properties --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 4366964ee..eb61f868c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.36 +project_version=0.0.35 config_version=15 lang_version=3 project_group=net.momirealms @@ -38,7 +38,7 @@ geantyref_version=1.3.16 zstd_version=1.5.6-9 commons_io_version=2.17.0 sparrow_nbt_version=0.3 -sparrow_util_version=0.27 +sparrow_util_version=0.29 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8 From b290af81f7b8b3151ca97e0ad07c3d2b2448dbcd Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 22 Mar 2025 04:27:20 +0800 Subject: [PATCH 02/12] add on liquid blocks --- .../default/configuration/blocks.yml | 2 +- .../default/configuration/categories.yml | 3 +- .../resources/default/configuration/i18n.yml | 2 + .../default/configuration/palm_tree.yml | 2 +- .../{fairy_flower.yml => plants.yml} | 35 ++++++- .../minecraft/models/block/custom/reed.json | 35 +++++++ .../minecraft/textures/block/custom/reed.png | Bin 0 -> 695 bytes .../minecraft/textures/item/custom/reed.png | Bin 0 -> 1049 bytes .../block/behavior/BukkitBlockBehaviors.java | 3 +- .../block/behavior/BushBlockBehavior.java | 6 +- .../block/behavior/OnLiquidBlockBehavior.java | 55 ++++++++++ .../bukkit/item/BukkitItemManager.java | 2 - .../bukkit/item/ItemEventListener.java | 2 + .../item/behavior/BlockItemBehavior.java | 4 +- .../item/behavior/BoneMealBehavior.java | 27 ----- .../item/behavior/BukkitItemBehaviors.java | 5 +- .../item/behavior/FurnitureItemBehavior.java | 2 +- .../LiquidCollisionBlockItemBehavior.java | 76 ++++++++++++++ .../plugin/network/PacketConsumers.java | 2 +- .../plugin/user/BukkitServerPlayer.java | 29 +++++- .../craftengine/bukkit/util/FluidUtils.java | 24 +++++ .../bukkit/util/LocationUtils.java | 16 +++ .../craftengine/bukkit/util/Reflections.java | 96 ++++++++++++++++++ .../bukkit/world/BukkitCEWorld.java | 2 +- .../craftengine/bukkit/world/BukkitWorld.java | 30 ++++-- .../core/block/behavior/BlockBehaviors.java | 1 + .../core/entity/player/Player.java | 4 + .../core/item/behavior/EmptyItemBehavior.java | 15 +++ .../core/item/behavior/ItemBehaviors.java | 1 + .../core/pack/AbstractPackManager.java | 7 +- .../resolution/MergeAltasResolution.java | 58 +++++++++++ .../pack/conflict/resolution/Resolutions.java | 2 + .../craftengine/core/util/Direction.java | 15 +++ .../core/world/FluidCollisionRule.java | 7 ++ .../craftengine/core/world/World.java | 4 +- .../craftengine/mod/CraftEngineBlock.java | 2 +- ...neBlockShape.java => StoneBlockShape.java} | 4 +- 37 files changed, 518 insertions(+), 62 deletions(-) rename bukkit-loader/src/main/resources/resources/default/configuration/{fairy_flower.yml => plants.yml} (63%) create mode 100644 bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/reed.json create mode 100644 bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/reed.png create mode 100644 bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/reed.png create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealBehavior.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FluidUtils.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/MergeAltasResolution.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/FluidCollisionRule.java rename server-mod/src/main/java/net/momirealms/craftengine/mod/{PaperWeightStoneBlockShape.java => StoneBlockShape.java} (81%) 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 0000000000000000000000000000000000000000..282ee6ebda58f913b3c49297bd61c9621eb20cb3 GIT binary patch literal 695 zcmV;o0!aOdP)Px%aY;l$R9J=0l|OIOKp4iKxV9`A34*BPM&_RosvMM(EDRkH0|@v6bg#t306TjJ zGIZh-bf~%@wNjVP3|-RVwlwNsNReD2h~preG?vWZ+|^FbiG2=;XSvIr@1Ebi_r4e4 zf7i~|YVbGr7sgE*jkQ3X@h3tYAFOjjQUKnQ9v`d+r>4aXF*X7K@OkfO;wI{h&*Oao zu(P$w4z*>42HGsQK`MYGeQp1Wfq-#Ur=}Haxd2pcmKo}&FWwdapz`E(0fVGuLF7>w zfefK;8=pqT(&Wi_03wSojL4BE0tR<|wX(qcK!5!3;s*n;=h)#|PIv)~yG{~GO4ey< z!twxQR^+q(`P4in`&+!2NTA2ZEFY+f`Y5-OhY^*F#ta+YyVLDe}S=^73u=)N?;zDC@GXQ{b z-v9tg^8f(#`kl-GVsw*@mE}OMmcu>}Gu8Amy#~@6+x39_F?E0b$O$koL1`W*`@3}P z!vx!SLZ{fzh8oFi^#&$jEn$66{L;?VO{7|Q-C7Wq__%z?W{{Xh@0sw7` zih|Z*0|3x!yRcms>g6kREQ`czB@JHx9B2ExkVOfyBvLc`uz{kYpr|OYT{kvIT3Hg& z>-%&pa|F(u4gf$FCG`A09M6L+O5vC!!t0+?BggZo5rK*JqhqN70EDKI#XY}I4Tm=- db4d_c^#{%(AF)!*tYZKG002ovPDHLkV1k+aJXin# literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..04d930d927b60e85959df679f5f98445c51ddd74 GIT binary patch literal 1049 zcmaJ=O=uHA6y6eAOSM*nBDR-tduT+ne`&VaC9$U2#zvbOlR$G4H@nkjX?JJcotkZL zErRq?R73?2-V~%r5fnwl_M{#}4;8cr51y(Zf){Vr*)&N#7zcJ|-sAhe_ujlWOWE;L zogF4`{&%h*X+Hb&bfAin zQ$T2@ev#QS!pJQn8we4G=Rt77uyj;$k5(C(jGVSytXdjOD{-1=FovPak#JOrh{I7% zj3#+L#U*%UKoO(Ef*=XJIGC(+6{O9Y(86`DzRQ)Ga{YNQZ4z05j&TXOLTC{95 z&qZviSL5o7KRuTnoQ-61E{~Bly zWP|wE(9e}E;o9Z9S8kNg9_xMEwh;Qf_O 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; } From 0b41d1dc0156356a7026909b9471a8c45b4b6d46 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 22 Mar 2025 04:56:51 +0800 Subject: [PATCH 03/12] fix on 1.20 --- .../resources/default/configuration/plants.yml | 4 ++-- .../models/block/custom/fairy_flower_1.json | 13 ++----------- .../assets/minecraft/models/block/custom/reed.json | 4 +++- .../assets/minecraft/models/item/custom/bench.json | 1 - .../minecraft/models/item/custom/table_lamp.json | 1 - .../minecraft/models/item/custom/wooden_chair.json | 1 - .../craftengine/bukkit/util/Reflections.java | 9 ++++++--- 7 files changed, 13 insertions(+), 20 deletions(-) diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit-loader/src/main/resources/resources/default/configuration/plants.yml index ba5ac3ab2..05a25cdfd 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/plants.yml @@ -39,7 +39,7 @@ blocks: item: default:fairy_flower state: id: 0 - state: tripwire:0 + state: sugar_cane:0 models: - path: "minecraft:block/custom/fairy_flower_1" weight: 100 @@ -77,6 +77,6 @@ blocks: item: default:reed state: id: 1 - state: tripwire:1 + state: sugar_cane: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/fairy_flower_1.json b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fairy_flower_1.json index 44c9adbde..e79d4627e 100644 --- a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fairy_flower_1.json +++ b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fairy_flower_1.json @@ -34,6 +34,7 @@ "from": [7, 28, 7], "to": [9, 30, 9], "rotation": {"angle": 0, "axis": "y", "origin": [7, 28, 7]}, + "shade": false, "faces": { "north": {"uv": [15, 0, 16, 1], "texture": "#0"}, "east": {"uv": [15, 0, 16, 1], "texture": "#0"}, @@ -43,15 +44,5 @@ "down": {"uv": [15, 0, 16, 1], "texture": "#0"} } } - ], - "display": { - "head": { - "translation": [0, 18.5, 0] - }, - "fixed": { - "rotation": [-90, 0, 0], - "translation": [0, 0, -15], - "scale": [2, 2, 2] - } - } + ] } \ 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 index 63af951fa..5f872fc80 100644 --- 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 @@ -1,5 +1,5 @@ { - "texture_size": [32, 32], + "ambientocclusion": false, "textures": { "0": "block/custom/reed", "particle": "block/custom/reed" @@ -8,6 +8,7 @@ { "from": [-0.5, -3, 0.25], "to": [19.5, 29, 0.25], + "shade": false, "rotation": {"angle": -45, "axis": "y", "origin": [-0.5, -3, 2.25]}, "faces": { "north": {"uv": [0, 0, 10, 16], "texture": "#0"}, @@ -21,6 +22,7 @@ { "from": [2, -3, 14.75], "to": [22, 29, 14.75], + "shade": false, "rotation": {"angle": 45, "axis": "y", "origin": [2, -3, 16.75]}, "faces": { "north": {"uv": [0, 0, 10, 16], "texture": "#0"}, diff --git a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/bench.json b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/bench.json index 21bb4288d..881f11a58 100644 --- a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/bench.json +++ b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/bench.json @@ -1,5 +1,4 @@ { - "texture_size": [64, 64], "textures": { "0": "item/custom/bench", "particle": "item/custom/bench" diff --git a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/table_lamp.json b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/table_lamp.json index 25ad38f50..32067b787 100644 --- a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/table_lamp.json +++ b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/table_lamp.json @@ -1,5 +1,4 @@ { - "texture_size": [32, 32], "textures": { "0": "item/custom/table_lamp", "particle": "item/custom/table_lamp" diff --git a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/wooden_chair.json b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/wooden_chair.json index f1ee8e866..81e73f921 100644 --- a/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/wooden_chair.json +++ b/bukkit-loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/item/custom/wooden_chair.json @@ -1,5 +1,4 @@ { - "texture_size": [32, 32], "textures": { "0": "item/custom/wooden_chair", "particle": "item/custom/wooden_chair" 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 105899258..e8c696b66 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 @@ -5033,13 +5033,15 @@ public class Reflections { public static final Class clazz$BlockHitResult = requireNonNull( ReflectionUtils.getClazz( - BukkitReflectionUtils.assembleMCClass("world.phys.BlockHitResult") + BukkitReflectionUtils.assembleMCClass("world.phys.BlockHitResult"), + BukkitReflectionUtils.assembleMCClass("world.phys.MovingObjectPositionBlock") ) ); public static final Class clazz$ClipContext$Fluid = requireNonNull( ReflectionUtils.getClazz( - BukkitReflectionUtils.assembleMCClass("world.level.ClipContext$Fluid") + BukkitReflectionUtils.assembleMCClass("world.level.ClipContext$Fluid"), + BukkitReflectionUtils.assembleMCClass("world.level.RayTrace$FluidCollisionOption") ) ); @@ -5102,7 +5104,8 @@ public class Reflections { public static final Class clazz$HitResult = requireNonNull( ReflectionUtils.getClazz( - BukkitReflectionUtils.assembleMCClass("world.phys.HitResult") + BukkitReflectionUtils.assembleMCClass("world.phys.HitResult"), + BukkitReflectionUtils.assembleMCClass("world.phys.MovingObjectPosition") ) ); From 8b4a0467f09c3c5ca5440bd923725a49a9744151 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 22 Mar 2025 05:11:03 +0800 Subject: [PATCH 04/12] improve debug commands --- .../DebugAppearanceStateUsageCommand.java | 20 ++++++++++++----- .../feature/DebugRealStateUsageCommand.java | 22 ++++++++++++++----- .../feature/DebugTargetBlockCommand.java | 4 ++++ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java index 78ba75961..2aad44aad 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java @@ -44,8 +44,10 @@ public class DebugAppearanceStateUsageCommand extends BukkitCommandFeature appearances = blockManager.blockAppearanceArranger().get(baseBlockId); if (appearances == null) return; int i = 0; - Component component = Component.text(baseBlockId + ": "); - List children = new ArrayList<>(); + Component block = Component.text(baseBlockId + ": "); + plugin().senderFactory().wrap(context.sender()).sendMessage(block); + + List batch = new ArrayList<>(); for (int appearance : appearances) { Component text = Component.text("|"); List reals = blockManager.appearanceToRealStates(appearance); @@ -64,11 +66,19 @@ public class DebugAppearanceStateUsageCommand extends BukkitCommandFeature reals = blockManager.realBlockArranger().get(baseBlockId); if (reals == null) return; int i = 0; - Component component = Component.text(baseBlockId + ": "); - List children = new ArrayList<>(); + Component block = Component.text(baseBlockId + ": "); + plugin().senderFactory().wrap(context.sender()).sendMessage(block); + + List batch = new ArrayList<>(100); for (int real : reals) { ImmutableBlockState state = blockManager.getImmutableBlockStateUnsafe(real); if (state.isEmpty()) { Component hover = Component.text("craftengine:" + baseBlockId.value() + "_" + i).color(NamedTextColor.GREEN); - children.add(Component.text("|").color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover))); + batch.add(Component.text("|").color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover))); } else { Component hover = Component.text("craftengine:" + baseBlockId.value() + "_" + i).color(NamedTextColor.RED); hover = hover.append(Component.newline()).append(Component.text(state.toString()).color(NamedTextColor.GRAY)); - children.add(Component.text("|").color(NamedTextColor.RED).hoverEvent(HoverEvent.showText(hover))); + batch.add(Component.text("|").color(NamedTextColor.RED).hoverEvent(HoverEvent.showText(hover))); } i++; + if (batch.size() == 100) { + plugin().senderFactory().wrap(context.sender()) + .sendMessage(Component.text("").children(batch)); + batch.clear(); + } + } + if (!batch.isEmpty()) { + plugin().senderFactory().wrap(context.sender()) + .sendMessage(Component.text("").children(batch)); + batch.clear(); } - plugin().senderFactory().wrap(context.sender()) - .sendMessage(component.children(children)); }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java index ff3722abd..e86731a62 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java @@ -4,11 +4,13 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.sender.Sender; +import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; @@ -50,6 +52,8 @@ public class DebugTargetBlockCommand extends BukkitCommandFeature if (immutableBlockState != null) { sender.sendMessage(Component.text(immutableBlockState.toString())); } + ImmutableBlockState dataInCache = plugin().worldManager().getWorld(block.getWorld().getUID()).getBlockStateAtIfLoaded(LocationUtils.toBlockPos(block.getLocation())); + sender.sendMessage(Component.text("cache-state: " + !dataInCache.isEmpty())); try { @SuppressWarnings("unchecked") Set tags = (Set) Reflections.field$Holder$Reference$tags.get(holder); From b1e4339b4f14fa076ad1f3527a9b8ddf0f1546ac Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 22 Mar 2025 05:14:10 +0800 Subject: [PATCH 05/12] Update plants.yml --- .../main/resources/resources/default/configuration/plants.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bukkit-loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit-loader/src/main/resources/resources/default/configuration/plants.yml index 05a25cdfd..328001802 100644 --- a/bukkit-loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit-loader/src/main/resources/resources/default/configuration/plants.yml @@ -31,6 +31,7 @@ blocks: - default:sound/grass overrides: item: default:fairy_flower + push-reaction: DESTROY behavior: type: bush_block loot: @@ -68,6 +69,7 @@ blocks: - default:sound/grass overrides: item: default:reed + push-reaction: DESTROY behavior: type: on_liquid_block liquid-type: water From 951a9c321eed27647f8b29df01ded678f0edd0a9 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 22 Mar 2025 17:17:59 +0800 Subject: [PATCH 06/12] prevent illegal chars in anvil --- .../bukkit/item/ItemEventListener.java | 3 +- .../plugin/network/BukkitNetworkManager.java | 2 + .../plugin/network/PacketConsumers.java | 58 ++++++++++++++++++- .../craftengine/bukkit/util/Reflections.java | 26 +++++++++ .../craftengine/core/font/Font.java | 5 ++ .../craftengine/core/font/ImageManager.java | 7 +++ .../core/font/ImageManagerImpl.java | 19 ++++++ .../craftengine/core/plugin/CraftEngine.java | 1 + 8 files changed, 116 insertions(+), 5 deletions(-) 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 3c95a1d9d..c6981358d 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 @@ -29,6 +29,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; @@ -157,8 +158,6 @@ 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/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index a6bd3107a..67591a0a3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -125,6 +125,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener { registerNMSPacketConsumer(PacketConsumers.MOVE_ENTITY, Reflections.clazz$ClientboundMoveEntityPacket$Pos); registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_ENTITY, Reflections.clazz$ServerboundPickItemFromEntityPacket); registerNMSPacketConsumer(PacketConsumers.SOUND, Reflections.clazz$ClientboundSoundPacket); + registerNMSPacketConsumer(PacketConsumers.CHAT, Reflections.clazz$ServerboundChatPacket); + registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, Reflections.clazz$ServerboundRenameItemPacket); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.LEVEL_PARTICLE, this.packetIds.clientboundLevelParticlesPacket()); 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 821b5ce4d..9c4e1ad90 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 @@ -14,6 +14,7 @@ import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.font.ImageManager; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.plugin.network.ConnectionState; @@ -32,9 +33,7 @@ import org.bukkit.util.RayTraceResult; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.function.BiConsumer; public class PacketConsumers { @@ -661,4 +660,57 @@ public class PacketConsumers { CraftEngine.instance().logger().warn("Failed to handle ClientboundSoundPacket", e); } }; + + // we handle it on packet level to prevent it from being captured by plugins (most are chat plugins) + public static final TriConsumer CHAT = (user, event, packet) -> { + try { + String message = (String) Reflections.field$ServerboundChatPacket$message.get(packet); + if (message != null && !message.isEmpty()) { + ImageManager manager = CraftEngine.instance().imageManager(); + if (!manager.isDefaultFontInUse()) return; + char[] chars = message.toCharArray(); + try { + int[] codepoints = CharacterUtils.charsToCodePoints(chars); + for (int codepoint : codepoints) { + if (manager.isIllegalCharacter(codepoint)) { + event.setCancelled(true); + return; + } + } + } catch (Exception ignore) { + } + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundChatPacket", e); + } + }; + + // we handle it on packet level to prevent it from being captured by plugins + public static final TriConsumer RENAME_ITEM = (user, event, packet) -> { + try { + String message = (String) Reflections.field$ServerboundRenameItemPacket$name.get(packet); + if (message != null && !message.isEmpty()) { + ImageManager manager = CraftEngine.instance().imageManager(); + if (!manager.isDefaultFontInUse()) return; + char[] chars = message.toCharArray(); + try { + int[] codepoints = CharacterUtils.charsToCodePoints(chars); + int[] newCodepoints = new int[codepoints.length]; + for (int i = 0; i < codepoints.length; i++) { + int codepoint = codepoints[i]; + if (!manager.isIllegalCharacter(codepoint)) { + newCodepoints[i] = codepoint; + } else { + newCodepoints[i] = '*'; + } + } + String str = new String(newCodepoints, 0, newCodepoints.length); + Reflections.field$ServerboundRenameItemPacket$name.set(packet, str); + } catch (Exception ignore) { + } + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e); + } + }; } 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 e8c696b66..662108a21 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 @@ -5114,4 +5114,30 @@ public class Reflections { clazz$HitResult, clazz$Vec3, 0 ) ); + + public static final Class clazz$ServerboundChatPacket = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundChatPacket"), + BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayInChat") + ) + ); + + public static final Field field$ServerboundChatPacket$message = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerboundChatPacket, String.class, 0 + ) + ); + + public static final Class clazz$ServerboundRenameItemPacket = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundRenameItemPacket"), + BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayInItemName") + ) + ); + + public static final Field field$ServerboundRenameItemPacket$name = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerboundRenameItemPacket, String.class, 0 + ) + ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/Font.java b/core/src/main/java/net/momirealms/craftengine/core/font/Font.java index ffc3f6dd2..eb6ebc802 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/Font.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/Font.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.font; import net.momirealms.craftengine.core.util.Key; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; @@ -19,6 +20,10 @@ public class Font { return this.idToCodepoint.containsKey(codepoint); } + public Collection codepointsInUse() { + return Collections.unmodifiableCollection(this.idToCodepoint.keySet()); + } + public BitmapImage getImageByCodepoint(int codepoint) { return this.idToCodepoint.get(codepoint); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java index c4916334c..ac114d578 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/ImageManager.java @@ -13,11 +13,18 @@ import java.util.function.BiFunction; public interface ImageManager extends Reloadable, ConfigSectionParser { String CONFIG_SECTION_NAME = "images"; + Key DEFAULT_FONT = Key.of("minecraft:default"); default String sectionId() { return CONFIG_SECTION_NAME; } + void delayedLoad(); + + boolean isDefaultFontInUse(); + + boolean isIllegalCharacter(int codepoint); + Collection fontsInUse(); Optional bitmapImageByCodepoint(Key font, int codepoint); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/ImageManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/font/ImageManagerImpl.java index 4c4436362..ace8f47e0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/ImageManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/ImageManagerImpl.java @@ -18,6 +18,7 @@ public class ImageManagerImpl implements ImageManager { private final HashMap fonts = new HashMap<>(); // namespace:id image private final HashMap images = new HashMap<>(); + private final Set illegalChars = new HashSet<>(); private OffsetFont offsetFont; @@ -36,6 +37,24 @@ public class ImageManagerImpl implements ImageManager { public void unload() { this.fonts.clear(); this.images.clear(); + this.illegalChars.clear(); + } + + @Override + public void delayedLoad() { + Optional.ofNullable(this.fonts.get(DEFAULT_FONT)).ifPresent(font -> { + this.illegalChars.addAll(font.codepointsInUse()); + }); + } + + @Override + public boolean isDefaultFontInUse() { + return !this.illegalChars.isEmpty(); + } + + @Override + public boolean isIllegalCharacter(int codepoint) { + return this.illegalChars.contains(codepoint); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 3e173c3e7..2deedf67f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -106,6 +106,7 @@ public abstract class CraftEngine implements Plugin { this.blockManager.delayedLoad(); this.itemBrowserManager.delayedLoad(); this.soundManager.delayedLoad(); + this.imageManager.delayedLoad(); if (ConfigManager.debug()) { this.debugger = (s) -> logger.info("[Debug] " + s.get()); } else { From 2e6eddf17a84e52f70352750328b89565b06790a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 22 Mar 2025 21:13:17 +0800 Subject: [PATCH 07/12] framework for external items --- bukkit-loader/build.gradle.kts | 1 + bukkit/build.gradle.kts | 1 + bukkit/compatibility/build.gradle.kts | 28 ++++++++++++++++ .../item/NeigeItemsProvider.java | 22 +++++++++++++ .../bukkit/item/BukkitItemManager.java | 12 +++++-- .../bukkit/item/ItemEventListener.java | 1 - .../item/factory/ComponentItemFactory.java | 14 +++++++- .../item/factory/UniversalItemFactory.java | 8 ++++- .../feature/DebugTargetBlockCommand.java | 1 - .../plugin/network/PacketConsumers.java | 4 ++- .../craftengine/core/item/AbstractItem.java | 10 ++++-- .../core/item/AbstractItemManager.java | 20 +++++++++++ .../core/item/ExternalItemProvider.java | 11 +++++++ .../craftengine/core/item/Item.java | 4 ++- .../craftengine/core/item/ItemFactory.java | 4 ++- .../craftengine/core/item/ItemManager.java | 4 +++ .../core/item/modifier/ExternalModifier.java | 33 +++++++++++++++++++ .../recipe/CustomSmithingTransformRecipe.java | 2 +- .../craftengine/core/plugin/CraftEngine.java | 2 +- settings.gradle.kts | 1 + 20 files changed, 170 insertions(+), 13 deletions(-) create mode 100644 bukkit/compatibility/build.gradle.kts create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/NeigeItemsProvider.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/ExternalItemProvider.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java diff --git a/bukkit-loader/build.gradle.kts b/bukkit-loader/build.gradle.kts index eef46cabe..fb30824d3 100644 --- a/bukkit-loader/build.gradle.kts +++ b/bukkit-loader/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { implementation(project(":core")) implementation(project(":bukkit")) implementation(project(":bukkit:legacy")) + implementation(project(":bukkit:compatibility")) implementation("net.kyori:adventure-platform-bukkit:${rootProject.properties["adventure_platform_version"]}") implementation("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}") diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 0fab7cd0e..cb9f6441b 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -15,6 +15,7 @@ repositories { dependencies { compileOnly(project(":core")) compileOnly(project(":shared")) + compileOnly(project(":bukkit:compatibility")) compileOnly(project(":bukkit:legacy")) // Anti Grief compileOnly("com.github.Xiao-MoMi:AntiGriefLib:${rootProject.properties["anti_grief_version"]}") diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts new file mode 100644 index 000000000..bc8304b72 --- /dev/null +++ b/bukkit/compatibility/build.gradle.kts @@ -0,0 +1,28 @@ +repositories { + mavenCentral() + maven("https://repo.papermc.io/repository/maven-public/") + maven("https://r.irepo.space/maven/") +} + +dependencies { + compileOnly(project(":core")) + // Platform + compileOnly("dev.folia:folia-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT") + // NeigeItems + compileOnly("pers.neige.neigeitems:NeigeItems:1.21.42") +} + +java { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + withSourcesJar() +} + +tasks.withType { + options.encoding = "UTF-8" + options.release.set(21) + dependsOn(tasks.clean) +} \ No newline at end of file diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/NeigeItemsProvider.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/NeigeItemsProvider.java new file mode 100644 index 000000000..9fe7d0f18 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/NeigeItemsProvider.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.bukkit.compatibility.item; + +import net.momirealms.craftengine.core.item.ExternalItemProvider; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import pers.neige.neigeitems.manager.ItemManager; + +import java.util.Optional; + +public class NeigeItemsProvider implements ExternalItemProvider { + + @Override + public String plugin() { + return "NeigeItems"; + } + + @Override + public ItemStack build(String id, ItemBuildContext context) { + return ItemManager.INSTANCE.getItemStack(id, Optional.ofNullable(context.player()).map(it -> (Player) it.platformPlayer()).orElse(null)); + } +} 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 fcbcbba5e..16a7458ad 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,5 +1,6 @@ package net.momirealms.craftengine.bukkit.item; +import net.momirealms.craftengine.bukkit.compatibility.item.NeigeItemsProvider; import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior; @@ -69,8 +70,15 @@ public class BukkitItemManager extends AbstractItemManager { @Override public void delayedInit() { - Bukkit.getPluginManager().registerEvents(this.itemEventListener, plugin.bootstrap()); - Bukkit.getPluginManager().registerEvents(this.debugStickListener, plugin.bootstrap()); + Bukkit.getPluginManager().registerEvents(this.itemEventListener, this.plugin.bootstrap()); + Bukkit.getPluginManager().registerEvents(this.debugStickListener, this.plugin.bootstrap()); + this.hookExternalPlugins(); + } + + private void hookExternalPlugins() { + if (this.plugin.isPluginEnabled("NeigeItems")) { + registerExternalItemProvider(new NeigeItemsProvider()); + } } @Override 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 c6981358d..cc1a448d8 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 @@ -29,7 +29,6 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerChatEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java index 98db91ca1..e44302c71 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java @@ -299,7 +299,7 @@ public class ComponentItemFactory extends BukkitItemFactory { } @Override - protected ItemWrapper merge(ItemWrapper item1, ItemWrapper item2) { + protected ItemWrapper mergeCopy(ItemWrapper item1, ItemWrapper item2) { Object itemStack1 = item1.getLiteralObject(); Object itemStack2 = item2.getLiteralObject(); try { @@ -311,4 +311,16 @@ public class ComponentItemFactory extends BukkitItemFactory { } return null; } + + @Override + protected void merge(ItemWrapper item1, ItemWrapper item2) { + item1.load(); + Object itemStack1 = item1.getLiteralObject(); + Object itemStack2 = item2.getLiteralObject(); + try { + Reflections.method$ItemStack$applyComponents.invoke(itemStack1, Reflections.method$ItemStack$getComponentsPatch.invoke(itemStack2)); + } catch (Exception e) { + plugin.logger().warn("Failed to merge item", e); + } + } } \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java index 5550598db..c8d3890c4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java @@ -234,11 +234,17 @@ public class UniversalItemFactory extends BukkitItemFactory { } @Override - protected ItemWrapper merge(ItemWrapper item1, ItemWrapper item2) { + protected ItemWrapper mergeCopy(ItemWrapper item1, ItemWrapper item2) { Object itemStack = ItemObject.copy(item2.getLiteralObject()); ItemObject.setCustomDataTag(itemStack, TagCompound.clone(ItemObject.getCustomDataTag(item1.getLiteralObject()))); // one more step than vanilla TagCompound.merge(ItemObject.getCustomDataTag(itemStack), ItemObject.getCustomDataTag(item2.getLiteralObject()), true, true); return new RTagItemWrapper(new RtagItem(ItemObject.asCraftMirror(itemStack)), item2.count()); } + + @Override + protected void merge(ItemWrapper item1, ItemWrapper item2) { + item1.load(); + TagCompound.merge(ItemObject.getCustomDataTag(item1.getLiteralObject()), ItemObject.getCustomDataTag(item2.getLiteralObject()), true, true); + } } \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java index e86731a62..c57ffc6da 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java @@ -10,7 +10,6 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.sender.Sender; -import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; 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 9c4e1ad90..6deef92bc 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 @@ -33,7 +33,9 @@ import org.bukkit.util.RayTraceResult; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.*; +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; import java.util.function.BiConsumer; public class PacketConsumers { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index ae652add7..1d5ffbcbd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -280,7 +280,13 @@ public class AbstractItem, I> implements Item { @SuppressWarnings({"unchecked", "rawtypes"}) @Override - public Item merge(Item another) { - return new AbstractItem<>(this.factory, this.factory.merge(this.item, ((AbstractItem) another).item)); + public Item mergeCopy(Item another) { + return new AbstractItem<>(this.factory, this.factory.mergeCopy(this.item, ((AbstractItem) another).item)); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public void merge(Item another) { + this.factory.merge(this.item, ((AbstractItem) another).item); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index baa2330b1..eb8d76b67 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -23,6 +23,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected static final List VANILLA_ITEMS = new ArrayList<>(); protected static final Map>> VANILLA_ITEM_TAGS = new HashMap<>(); + protected final Map> externalItemProviders = new HashMap<>(); protected final Map>> dataFunctions = new HashMap<>(); protected final Map> customItems = new HashMap<>(); protected final Map>> customItemTags; @@ -47,6 +48,18 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } + @Override + public ExternalItemProvider getExternalItemProvider(String name) { + return this.externalItemProviders.get(name); + } + + @Override + public boolean registerExternalItemProvider(ExternalItemProvider externalItemProvider) { + if (this.externalItemProviders.containsKey(externalItemProvider.plugin())) return false; + this.externalItemProviders.put(externalItemProvider.plugin(), externalItemProvider); + return true; + } + @Override public void unload() { super.clearModelsToGenerate(); @@ -165,6 +178,13 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } private void registerFunctions() { + registerDataFunction((obj) -> { + Map data = MiscUtils.castToMap(obj, false); + String plugin = data.get("plugin").toString(); + String id = data.get("id").toString(); + ExternalItemProvider provider = AbstractItemManager.this.getExternalItemProvider(plugin); + return new ExternalModifier<>(id, Objects.requireNonNull(provider, "Item provider " + plugin + " not found")); + }, "external"); registerDataFunction((obj) -> { String name = obj.toString(); return new DisplayNameModifier<>(name); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ExternalItemProvider.java b/core/src/main/java/net/momirealms/craftengine/core/item/ExternalItemProvider.java new file mode 100644 index 000000000..f5cea3ada --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ExternalItemProvider.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.core.item; + +import org.jetbrains.annotations.Nullable; + +public interface ExternalItemProvider { + + String plugin(); + + @Nullable + I build(String id, ItemBuildContext context); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index 7de763c22..3895da0db 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -117,5 +117,7 @@ public interface Item { Object getLiteralObject(); - Item merge(Item another); + Item mergeCopy(Item another); + + void merge(Item another); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index 8b59f1636..c65a15740 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -112,5 +112,7 @@ public abstract class ItemFactory

, I> protected abstract Optional repairCost(ItemWrapper item); - protected abstract ItemWrapper merge(ItemWrapper item1, ItemWrapper item2); + protected abstract ItemWrapper mergeCopy(ItemWrapper item1, ItemWrapper item2); + + protected abstract void merge(ItemWrapper item1, ItemWrapper item2); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index 8215252ca..3b2b406fb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -51,6 +51,10 @@ public interface ItemManager extends Reloadable, ModelGenerator, ConfigSectio Key customItemId(T itemStack); + ExternalItemProvider getExternalItemProvider(String name); + + boolean registerExternalItemProvider(ExternalItemProvider externalItemProvider); + Optional> getCustomItem(Key key); Optional> getItemBehavior(Key key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java new file mode 100644 index 000000000..296810e37 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java @@ -0,0 +1,33 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.ExternalItemProvider; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.plugin.CraftEngine; + +public class ExternalModifier implements ItemModifier { + private final String id; + private final ExternalItemProvider provider; + + public ExternalModifier(String id, ExternalItemProvider provider) { + this.id = id; + this.provider = provider; + } + + @Override + public String name() { + return "external"; + } + + @SuppressWarnings("unchecked") + @Override + public void apply(Item item, ItemBuildContext context) { + I another = this.provider.build(id, context); + if (another == null) { + CraftEngine.instance().logger().warn("'" + id + "' could not be found in " + provider.plugin()); + return; + } + Item anotherWrapped = (Item) CraftEngine.instance().itemManager().wrap(another); + item.merge(anotherWrapped); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index 8d72de36b..46f9e9909 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -96,7 +96,7 @@ public class CustomSmithingTransformRecipe implements Recipe { Item wrappedResult = (Item) CraftEngine.instance().itemManager().wrap(result); Item finalResult = wrappedResult; if (this.mergeComponents) { - finalResult = base.merge(wrappedResult); + finalResult = base.mergeCopy(wrappedResult); } for (ItemDataProcessor processor : this.processors) { processor.accept(base, wrappedResult, finalResult); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 2deedf67f..931804201 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -127,11 +127,11 @@ public abstract class CraftEngine implements Plugin { // delay the reload so other plugins can register some parsers this.scheduler.sync().runDelayed(() -> { this.registerParsers(); + this.itemManager.delayedInit(); this.reload(); this.guiManager.delayedInit(); this.recipeManager.delayedInit(); this.blockManager.delayedInit(); - this.itemManager.delayedInit(); this.worldManager.delayedInit(); this.packManager.delayedInit(); this.furnitureManager.delayedInit(); diff --git a/settings.gradle.kts b/settings.gradle.kts index 02db6f8bf..cd96a4442 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,7 @@ include(":shared") include(":core") include(":bukkit") include(":bukkit:legacy") +include(":bukkit:compatibility") include(":bukkit-loader") include(":server-mod") pluginManagement { From c09b9877335e7941e58d39a7da3a9ba9616952e8 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 23 Mar 2025 00:28:52 +0800 Subject: [PATCH 08/12] =?UTF-8?q?feat(network):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E9=98=BB=E6=AD=A2=E7=8E=A9=E5=AE=B6=E5=9C=A8=E6=B8=B8=E6=88=8F?= =?UTF-8?q?=E5=86=85=E7=9B=B4=E6=8E=A5=E4=BD=BF=E7=94=A8=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E9=BB=98=E8=AE=A4=E5=AD=97=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 15 ++++ .../plugin/network/PacketConsumers.java | 81 ++++++++++++------- .../plugin/user/BukkitServerPlayer.java | 5 ++ .../craftengine/bukkit/util/Reflections.java | 69 +++++++++++++++- .../core/plugin/network/NetWorkUser.java | 2 + 5 files changed, 142 insertions(+), 30 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 67591a0a3..c37cec1c3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -127,6 +127,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener { registerNMSPacketConsumer(PacketConsumers.SOUND, Reflections.clazz$ClientboundSoundPacket); registerNMSPacketConsumer(PacketConsumers.CHAT, Reflections.clazz$ServerboundChatPacket); registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, Reflections.clazz$ServerboundRenameItemPacket); + registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, Reflections.clazz$ServerboundSignUpdatePacket); registerByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); registerByteBufPacketConsumer(PacketConsumers.LEVEL_PARTICLE, this.packetIds.clientboundLevelParticlesPacket()); @@ -267,6 +268,20 @@ public class BukkitNetworkManager implements NetworkManager, Listener { this.packetsConsumer.accept(player.serverPlayer(), packet); } + public void receivePacket(@NotNull NetWorkUser player, Object packet) { + Channel channel = player.nettyChannel(); + List handlerNames = channel.pipeline().names(); + if (handlerNames.contains("decompress")) { + channel.pipeline().context("decompress").fireChannelRead(packet); + } else { + if (handlerNames.contains("decrypt")) { + channel.pipeline().context("decrypt").fireChannelRead(packet); + } else { + channel.pipeline().context("splitter").fireChannelRead(packet); + } + } + } + private void injectServerChannel(Channel serverChannel) { ChannelPipeline pipeline = serverChannel.pipeline(); ChannelHandler connectionHandler = pipeline.get(CONNECTION_HANDLER_NAME); 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 6deef92bc..806bbb19c 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 @@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.plugin.network; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.ints.IntList; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; @@ -33,9 +35,8 @@ import org.bukkit.util.RayTraceResult; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Map; -import java.util.Objects; +import java.time.Instant; +import java.util.*; import java.util.function.BiConsumer; public class PacketConsumers { @@ -670,17 +671,19 @@ public class PacketConsumers { if (message != null && !message.isEmpty()) { ImageManager manager = CraftEngine.instance().imageManager(); if (!manager.isDefaultFontInUse()) return; - char[] chars = message.toCharArray(); try { - int[] codepoints = CharacterUtils.charsToCodePoints(chars); - for (int codepoint : codepoints) { - if (manager.isIllegalCharacter(codepoint)) { - event.setCancelled(true); - return; - } - } - } catch (Exception ignore) { - } + String str = replaceIllegalString(message, manager); + if (message.equals(str)) return; + event.setCancelled(true); + Object newPacket = Reflections.constructor$ServerboundChatPacket.newInstance( + str, + Reflections.field$ServerboundChatPacket$timeStamp.get(packet), + Reflections.field$ServerboundChatPacket$salt.get(packet), + Reflections.field$ServerboundChatPacket$signature.get(packet), + Reflections.field$ServerboundChatPacket$lastSeenMessages.get(packet) + ); + user.receivePacket(newPacket); + } catch (Exception ignore) {} } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundChatPacket", e); @@ -694,25 +697,49 @@ public class PacketConsumers { if (message != null && !message.isEmpty()) { ImageManager manager = CraftEngine.instance().imageManager(); if (!manager.isDefaultFontInUse()) return; - char[] chars = message.toCharArray(); try { - int[] codepoints = CharacterUtils.charsToCodePoints(chars); - int[] newCodepoints = new int[codepoints.length]; - for (int i = 0; i < codepoints.length; i++) { - int codepoint = codepoints[i]; - if (!manager.isIllegalCharacter(codepoint)) { - newCodepoints[i] = codepoint; - } else { - newCodepoints[i] = '*'; - } - } - String str = new String(newCodepoints, 0, newCodepoints.length); + String str = replaceIllegalString(message, manager); Reflections.field$ServerboundRenameItemPacket$name.set(packet, str); - } catch (Exception ignore) { - } + } catch (Exception ignore) {} } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e); } }; + + // we handle it on packet level to prevent it from being captured by plugins + public static final TriConsumer SIGN_UPDATE = (user, event, packet) -> { + try { + String[] lines = (String[]) Reflections.field$ServerboundSignUpdatePacket$lines.get(packet); + ImageManager manager = CraftEngine.instance().imageManager(); + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + if (line != null && !line.isEmpty()) { + if (!manager.isDefaultFontInUse()) return; + try { + String str = replaceIllegalString(line, manager); + if (line.equals(str)) continue; + lines[i] = str; + } catch (Exception ignore){} + } + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundSignUpdatePacket", e); + } + }; + + private static String replaceIllegalString(String string, ImageManager manager) { + char[] chars = string.toCharArray(); + int[] codepoints = CharacterUtils.charsToCodePoints(chars); + int[] newCodepoints = new int[codepoints.length]; + for (int i = 0; i < codepoints.length; i++) { + int codepoint = codepoints[i]; + if (!manager.isIllegalCharacter(codepoint)) { + newCodepoints[i] = codepoint; + } else { + newCodepoints[i] = '*'; + } + } + return new String(newCodepoints, 0, newCodepoints.length); + } } 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 dba6359ea..1c292d9e3 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 @@ -231,6 +231,11 @@ public class BukkitServerPlayer extends Player { this.plugin.networkManager().sendPacket(this, packet, immediately); } + @Override + public void receivePacket(Object packet) { + this.plugin.networkManager().receivePacket(this, packet); + } + @Override public ConnectionState decoderState() { return decoderState; 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 662108a21..71ffe4d60 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 @@ -7,6 +7,7 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.MessageToByteEncoder; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Location; @@ -26,6 +27,7 @@ import sun.misc.Unsafe; import java.io.BufferedReader; import java.lang.reflect.*; +import java.time.Instant; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; @@ -134,9 +136,9 @@ public class Reflections { ); public static final Constructor constructor$ClientboundSystemChatPacket = requireNonNull( - ReflectionUtils.getConstructor( - clazz$ClientboundSystemChatPacket, clazz$Component, boolean.class - ) + VersionHelper.isVersionNewerThan1_20_4() + ? ReflectionUtils.getConstructor(clazz$ClientboundSystemChatPacket, clazz$Component, boolean.class) + : ReflectionUtils.getConstructor(clazz$ClientboundSystemChatPacket, Component.class, String.class, boolean.class) ); public static final Field field$ClientboundSystemChatPacket$overlay = requireNonNull( @@ -189,6 +191,11 @@ public class Reflections { clazz$ClientboundSystemChatPacket, clazz$Component, 0 ); + public static final Field field$ClientboundSystemChatPacket$adventure$content = + ReflectionUtils.getDeclaredField( + clazz$ClientboundSystemChatPacket, Component.class, 0 + ); + public static final Field field$ClientboundSystemChatPacket$text = ReflectionUtils.getDeclaredField( clazz$ClientboundSystemChatPacket, String.class, 0 @@ -5115,6 +5122,19 @@ public class Reflections { ) ); + public static final Class clazz$MessageSignature = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.chat.MessageSignature") + ) + ); + + public static final Class clazz$LastSeenMessages$Update = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.chat.LastSeenMessages$Update"), + BukkitReflectionUtils.assembleMCClass("network.chat.LastSeenMessages$b") + ) + ); + public static final Class clazz$ServerboundChatPacket = requireNonNull( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundChatPacket"), @@ -5122,12 +5142,42 @@ public class Reflections { ) ); + public static final Constructor constructor$ServerboundChatPacket = requireNonNull( + ReflectionUtils.getConstructor( + clazz$ServerboundChatPacket, String.class, Instant.class, long.class, clazz$MessageSignature, clazz$LastSeenMessages$Update + ) + ); + public static final Field field$ServerboundChatPacket$message = requireNonNull( ReflectionUtils.getDeclaredField( clazz$ServerboundChatPacket, String.class, 0 ) ); + public static final Field field$ServerboundChatPacket$timeStamp = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerboundChatPacket, Instant.class, 0 + ) + ); + + public static final Field field$ServerboundChatPacket$salt = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerboundChatPacket, long.class, 0 + ) + ); + + public static final Field field$ServerboundChatPacket$signature = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerboundChatPacket, clazz$MessageSignature, 0 + ) + ); + + public static final Field field$ServerboundChatPacket$lastSeenMessages = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerboundChatPacket, clazz$LastSeenMessages$Update, 0 + ) + ); + public static final Class clazz$ServerboundRenameItemPacket = requireNonNull( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundRenameItemPacket"), @@ -5140,4 +5190,17 @@ public class Reflections { clazz$ServerboundRenameItemPacket, String.class, 0 ) ); + + public static final Class clazz$ServerboundSignUpdatePacket = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ServerboundSignUpdatePacket"), + BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayInUpdateSign") + ) + ); + + public static final Field field$ServerboundSignUpdatePacket$lines = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerboundSignUpdatePacket, String[].class, 0 + ) + ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index 465c3d88e..3f9c1f21a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -16,6 +16,8 @@ public interface NetWorkUser { void sendPacket(Object packet, boolean immediately); + void receivePacket(Object packet); + @ApiStatus.Internal ConnectionState decoderState(); From 8abcd9cbd03f7a6f8b651ab1660f251381751acc Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Sun, 23 Mar 2025 00:35:19 +0800 Subject: [PATCH 09/12] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8DreceiveP?= =?UTF-8?q?acket=E5=8F=AF=E8=83=BD=E5=87=BA=E7=8E=B0=E7=9A=84=E6=BD=9C?= =?UTF-8?q?=E5=9C=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index c37cec1c3..606f31b5a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -270,15 +270,23 @@ public class BukkitNetworkManager implements NetworkManager, Listener { public void receivePacket(@NotNull NetWorkUser player, Object packet) { Channel channel = player.nettyChannel(); - List handlerNames = channel.pipeline().names(); - if (handlerNames.contains("decompress")) { - channel.pipeline().context("decompress").fireChannelRead(packet); - } else { - if (handlerNames.contains("decrypt")) { - channel.pipeline().context("decrypt").fireChannelRead(packet); + if (channel.isOpen()) { + List handlerNames = channel.pipeline().names(); + if (handlerNames.contains("via-encoder")) { + channel.pipeline().context("via-decoder").fireChannelRead(packet); + } else if (handlerNames.contains("ps_decoder_transformer")) { + channel.pipeline().context("ps_decoder_transformer").fireChannelRead(packet); + } else if (handlerNames.contains("decompress")) { + channel.pipeline().context("decompress").fireChannelRead(packet); } else { - channel.pipeline().context("splitter").fireChannelRead(packet); + if (handlerNames.contains("decrypt")) { + channel.pipeline().context("decrypt").fireChannelRead(packet); + } else { + channel.pipeline().context("splitter").fireChannelRead(packet); + } } + } else { + ((ByteBuf) packet).release(); } } From 554635b0389b21a5ac0d218da782ecb3d3d5b3c3 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 23 Mar 2025 01:02:48 +0800 Subject: [PATCH 10/12] fix some bugs --- .../furniture/FurnitureEventListener.java | 1 - .../entity/furniture/LoadedFurniture.java | 12 ++-- .../item/factory/ComponentItemFactory.java | 1 + .../item/factory/UniversalItemFactory.java | 1 + .../plugin/network/PacketConsumers.java | 63 +++++++++++-------- .../craftengine/bukkit/util/Reflections.java | 4 +- 6 files changed, 44 insertions(+), 38 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java index 79de897cc..8222f585e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/FurnitureEventListener.java @@ -74,7 +74,6 @@ public class FurnitureEventListener implements Listener { this.manager.handleEntityUnload(event.getEntity()); } - @EventHandler(ignoreCancelled = true) public void onPlayerQuit(PlayerQuitEvent event) { Player player = event.getPlayer(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index a39858e62..e4e8071ab 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -81,6 +81,7 @@ public class LoadedFurniture { for (int i = 0; i < interactionEntityIds.size(); ++i) { this.interactionEntityIds[i] = interactionEntityIds.get(i); } + this.resetSpawnPackets(); } private void resetSpawnPackets() { @@ -148,13 +149,6 @@ public class LoadedFurniture { this.location = location; } - public Object spawnPacket() { - if (this.cachedSpawnPacket == null) { - this.resetSpawnPackets(); - } - return this.cachedSpawnPacket; - } - @NotNull public Entity baseEntity() { Entity entity = baseEntity.get(); @@ -286,4 +280,8 @@ public class LoadedFurniture { this.addSeatEntity(seatEntity); seatEntity.addPassenger(player); } + + public @NotNull Object spawnPacket() { + return cachedSpawnPacket; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java index e44302c71..e2e6cff48 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory.java @@ -314,6 +314,7 @@ public class ComponentItemFactory extends BukkitItemFactory { @Override protected void merge(ItemWrapper item1, ItemWrapper item2) { + // load previous changes on nms items item1.load(); Object itemStack1 = item1.getLiteralObject(); Object itemStack2 = item2.getLiteralObject(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java index c8d3890c4..085c997e8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java @@ -244,6 +244,7 @@ public class UniversalItemFactory extends BukkitItemFactory { @Override protected void merge(ItemWrapper item1, ItemWrapper item2) { + // load previous changes on nms items item1.load(); TagCompound.merge(ItemObject.getCustomDataTag(item1.getLiteralObject()), ItemObject.getCustomDataTag(item2.getLiteralObject()), true, true); } 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 806bbb19c..2d75e74ba 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 @@ -3,8 +3,6 @@ package net.momirealms.craftengine.bukkit.plugin.network; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.ints.IntList; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; @@ -35,9 +33,11 @@ import org.bukkit.util.RayTraceResult; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.time.Instant; -import java.util.*; +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; import java.util.function.BiConsumer; +import java.util.function.Consumer; public class PacketConsumers { private static int[] mappings; @@ -671,19 +671,21 @@ public class PacketConsumers { if (message != null && !message.isEmpty()) { ImageManager manager = CraftEngine.instance().imageManager(); if (!manager.isDefaultFontInUse()) return; - try { - String str = replaceIllegalString(message, manager); - if (message.equals(str)) return; + runIfContainsIllegalCharacter(message, manager, (s) -> { event.setCancelled(true); - Object newPacket = Reflections.constructor$ServerboundChatPacket.newInstance( - str, - Reflections.field$ServerboundChatPacket$timeStamp.get(packet), - Reflections.field$ServerboundChatPacket$salt.get(packet), - Reflections.field$ServerboundChatPacket$signature.get(packet), - Reflections.field$ServerboundChatPacket$lastSeenMessages.get(packet) - ); - user.receivePacket(newPacket); - } catch (Exception ignore) {} + try { + Object newPacket = Reflections.constructor$ServerboundChatPacket.newInstance( + s, + Reflections.field$ServerboundChatPacket$timeStamp.get(packet), + Reflections.field$ServerboundChatPacket$salt.get(packet), + Reflections.field$ServerboundChatPacket$signature.get(packet), + Reflections.field$ServerboundChatPacket$lastSeenMessages.get(packet) + ); + user.receivePacket(newPacket); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to create replaced chat packet", e); + } + }); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundChatPacket", e); @@ -697,10 +699,13 @@ public class PacketConsumers { if (message != null && !message.isEmpty()) { ImageManager manager = CraftEngine.instance().imageManager(); if (!manager.isDefaultFontInUse()) return; - try { - String str = replaceIllegalString(message, manager); - Reflections.field$ServerboundRenameItemPacket$name.set(packet, str); - } catch (Exception ignore) {} + runIfContainsIllegalCharacter(message, manager, (s) -> { + try { + Reflections.field$ServerboundRenameItemPacket$name.set(packet, s); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to replace chat", e); + } + }); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e); @@ -712,15 +717,15 @@ public class PacketConsumers { try { String[] lines = (String[]) Reflections.field$ServerboundSignUpdatePacket$lines.get(packet); ImageManager manager = CraftEngine.instance().imageManager(); + if (!manager.isDefaultFontInUse()) return; for (int i = 0; i < lines.length; i++) { String line = lines[i]; if (line != null && !line.isEmpty()) { - if (!manager.isDefaultFontInUse()) return; try { - String str = replaceIllegalString(line, manager); - if (line.equals(str)) continue; - lines[i] = str; - } catch (Exception ignore){} + int lineIndex = i; + runIfContainsIllegalCharacter(line, manager, (s) -> lines[lineIndex] = s); + } catch (Exception ignore) { + } } } } catch (Exception e) { @@ -728,18 +733,22 @@ public class PacketConsumers { } }; - private static String replaceIllegalString(String string, ImageManager manager) { + private static void runIfContainsIllegalCharacter(String string, ImageManager manager, Consumer callback) { char[] chars = string.toCharArray(); int[] codepoints = CharacterUtils.charsToCodePoints(chars); int[] newCodepoints = new int[codepoints.length]; + boolean hasIllegal = false; for (int i = 0; i < codepoints.length; i++) { int codepoint = codepoints[i]; if (!manager.isIllegalCharacter(codepoint)) { newCodepoints[i] = codepoint; } else { newCodepoints[i] = '*'; + hasIllegal = true; } } - return new String(newCodepoints, 0, newCodepoints.length); + if (hasIllegal) { + callback.accept(new String(newCodepoints, 0, newCodepoints.length)); + } } } 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 71ffe4d60..4ed697c8e 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 @@ -136,9 +136,7 @@ public class Reflections { ); public static final Constructor constructor$ClientboundSystemChatPacket = requireNonNull( - VersionHelper.isVersionNewerThan1_20_4() - ? ReflectionUtils.getConstructor(clazz$ClientboundSystemChatPacket, clazz$Component, boolean.class) - : ReflectionUtils.getConstructor(clazz$ClientboundSystemChatPacket, Component.class, String.class, boolean.class) + ReflectionUtils.getConstructor(clazz$ClientboundSystemChatPacket, clazz$Component, boolean.class) ); public static final Field field$ClientboundSystemChatPacket$overlay = requireNonNull( From ad1212558579550a5c70b1f57faf73d500595df5 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 23 Mar 2025 01:24:15 +0800 Subject: [PATCH 11/12] Update config.yml --- bukkit-loader/src/main/resources/config.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bukkit-loader/src/main/resources/config.yml b/bukkit-loader/src/main/resources/config.yml index 125390fb7..e0f09fd16 100644 --- a/bukkit-loader/src/main/resources/config.yml +++ b/bukkit-loader/src/main/resources/config.yml @@ -92,8 +92,6 @@ resource-pack: suffix: "minecraft/items" - type: parent_path_suffix suffix: "minecraft/models/item" - - type: parent_path_suffix - suffix: "minecraft/atlases" resolution: type: merge_json deeply: true @@ -117,6 +115,11 @@ resource-pack: resolution: type: merge_json deeply: false + - term: + type: parent_path_suffix + suffix: "minecraft/atlases" + resolution: + type: merge_atlas item: # Add a tag on item name and lore From 96ae21d4b3daff037e0d465c16aed4509a05f1f8 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 23 Mar 2025 04:34:43 +0800 Subject: [PATCH 12/12] fixed the weird furniture behavior on 1.20 --- .../furniture/BukkitFurnitureManager.java | 31 +------------------ .../entity/furniture/LoadedFurniture.java | 18 ++++------- .../plugin/network/PacketConsumers.java | 7 ++--- .../plugin/user/BukkitServerPlayer.java | 10 ++++++ .../entity/furniture/FurnitureManager.java | 4 --- .../core/plugin/network/NetWorkUser.java | 5 +++ 6 files changed, 25 insertions(+), 50 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index b7cf50a44..60ec4845f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -1,7 +1,5 @@ package net.momirealms.craftengine.bukkit.entity.furniture; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.core.entity.furniture.*; @@ -37,11 +35,6 @@ public class BukkitFurnitureManager implements FurnitureManager { private final Map furnitureByBaseEntityId = new ConcurrentHashMap<>(256, 0.5f); private final Map furnitureByInteractionEntityId = new ConcurrentHashMap<>(512, 0.5f); - private final Map baseEntity2SubEntities = new ConcurrentHashMap<>(256, 0.5f); - - // Delay furniture cache remove for about 4-5 ticks - private static final int DELAYED_TICK = 5; - private final IntSet[] delayedRemove = new IntSet[DELAYED_TICK]; // Event listeners private final Listener dismountListener; private final FurnitureEventListener furnitureEventListener; @@ -56,9 +49,6 @@ public class BukkitFurnitureManager implements FurnitureManager { this.plugin = plugin; this.furnitureEventListener = new FurnitureEventListener(this); this.dismountListener = VersionHelper.isVersionNewerThan1_20_3() ? new DismountListener1_20_3(this) : new DismountListener1_20(this::handleDismount); - for (int i = 0; i < DELAYED_TICK; i++) { - this.delayedRemove[i] = new IntOpenHashSet(); - } instance = this; } @@ -171,18 +161,6 @@ public class BukkitFurnitureManager implements FurnitureManager { } public void tick() { - IntSet first = this.delayedRemove[0]; - for (int i : first) { - // unloaded furniture might be loaded again - LoadedFurniture furniture = getLoadedFurnitureByBaseEntityId(i); - if (furniture == null) - this.baseEntity2SubEntities.remove(i); - } - first.clear(); - for (int i = 1; i < DELAYED_TICK; i++) { - this.delayedRemove[i - 1] = this.delayedRemove[i]; - } - this.delayedRemove[DELAYED_TICK-1] = first; } @Override @@ -224,12 +202,6 @@ public class BukkitFurnitureManager implements FurnitureManager { return Optional.ofNullable(this.byId.get(id)); } - @Nullable - @Override - public int[] getSubEntityIdsByBaseEntityId(int entityId) { - return this.baseEntity2SubEntities.get(entityId); - } - @Override public boolean isFurnitureBaseEntity(int entityId) { return this.furnitureByBaseEntityId.containsKey(entityId); @@ -253,7 +225,6 @@ public class BukkitFurnitureManager implements FurnitureManager { for (int sub : furniture.interactionEntityIds()) { this.furnitureByInteractionEntityId.remove(sub); } - this.delayedRemove[DELAYED_TICK-1].add(id); } } @@ -270,6 +241,7 @@ public class BukkitFurnitureManager implements FurnitureManager { if (previous != null) return; LoadedFurniture furniture = addNewFurniture(display, customFurniture, getAnchorType(entity, customFurniture)); for (Player player : display.getTrackedPlayers()) { + this.plugin.adapt(player).furnitureView().computeIfAbsent(furniture.baseEntityId(), k -> new ArrayList<>()).addAll(furniture.subEntityIds()); this.plugin.networkManager().sendPacket(player, furniture.spawnPacket()); } } @@ -316,7 +288,6 @@ public class BukkitFurnitureManager implements FurnitureManager { private synchronized LoadedFurniture addNewFurniture(ItemDisplay display, CustomFurniture furniture, AnchorType anchorType) { LoadedFurniture loadedFurniture = new LoadedFurniture(display, furniture, anchorType); this.furnitureByBaseEntityId.put(loadedFurniture.baseEntityId(), loadedFurniture); - this.baseEntity2SubEntities.put(loadedFurniture.baseEntityId(), loadedFurniture.subEntityIds()); for (int entityId : loadedFurniture.interactionEntityIds()) { this.furnitureByInteractionEntityId.put(entityId, loadedFurniture); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index e4e8071ab..564769812 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -41,9 +41,9 @@ public class LoadedFurniture { private final WeakReference baseEntity; private final int baseEntityId; // includes elements + interactions - private final int[] subEntityIds; + private final List subEntityIds; // interactions - private final int[] interactionEntityIds; + private final List interactionEntityIds; // seats private final Set occupiedSeats = Collections.synchronizedSet(new HashSet<>()); private final Vector seats = new Vector<>(); @@ -73,14 +73,8 @@ public class LoadedFurniture { interactionEntityIds.add(entityId); this.hitBoxes.put(entityId, hitBox); } - this.subEntityIds = new int[entityIds.size()]; - for (int i = 0; i < entityIds.size(); ++i) { - this.subEntityIds[i] = entityIds.get(i); - } - this.interactionEntityIds = new int[interactionEntityIds.size()]; - for (int i = 0; i < interactionEntityIds.size(); ++i) { - this.interactionEntityIds[i] = interactionEntityIds.get(i); - } + this.subEntityIds = entityIds; + this.interactionEntityIds = interactionEntityIds; this.resetSpawnPackets(); } @@ -229,11 +223,11 @@ public class LoadedFurniture { return baseEntityId; } - public int[] interactionEntityIds() { + public List interactionEntityIds() { return interactionEntityIds; } - public int[] subEntityIds() { + public List subEntityIds() { return this.subEntityIds; } 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 2d75e74ba..7d8048590 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 @@ -33,9 +33,7 @@ import org.bukkit.util.RayTraceResult; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -534,6 +532,7 @@ public class PacketConsumers { int entityId = (int) Reflections.field$ClientboundAddEntityPacket$entityId.get(packet); LoadedFurniture furniture = BukkitFurnitureManager.instance().getLoadedFurnitureByBaseEntityId(entityId); if (furniture != null) { + user.furnitureView().computeIfAbsent(furniture.baseEntityId(), k -> new ArrayList<>()).addAll(furniture.subEntityIds()); user.sendPacket(furniture.spawnPacket(), false); } } @@ -568,7 +567,7 @@ public class PacketConsumers { try { IntList intList = (IntList) Reflections.field$ClientboundRemoveEntitiesPacket$entityIds.get(packet); for (int i = 0, size = intList.size(); i < size; i++) { - int[] entities = BukkitFurnitureManager.instance().getSubEntityIdsByBaseEntityId(intList.getInt(i)); + List entities = user.furnitureView().remove(intList.getInt(i)); if (entities == null) continue; for (int entityId : entities) { intList.add(entityId); 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 1c292d9e3..07e3fccad 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 @@ -29,7 +29,10 @@ import org.jetbrains.annotations.Nullable; import java.lang.ref.Reference; import java.lang.ref.WeakReference; +import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; public class BukkitServerPlayer extends Player { private final Channel channel; @@ -60,6 +63,8 @@ public class BukkitServerPlayer extends Player { private Key lastUsedRecipe = null; + private Map> furnitureView = new ConcurrentHashMap<>(); + public BukkitServerPlayer(BukkitCraftEngine plugin, Channel channel) { this.channel = channel; this.plugin = plugin; @@ -583,6 +588,11 @@ public class BukkitServerPlayer extends Player { return playerRef.get(); } + @Override + public Map> furnitureView() { + return this.furnitureView; + } + public void setResendSound() { resentSoundTick = gameTicks(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java index 639a61bcf..ada46b3c4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.Key; -import javax.annotation.Nullable; import java.util.Optional; public interface FurnitureManager extends Reloadable, ConfigSectionParser { @@ -25,8 +24,5 @@ public interface FurnitureManager extends Reloadable, ConfigSectionParser { Optional getFurniture(Key id); - @Nullable - int[] getSubEntityIdsByBaseEntityId(int entityId); - boolean isFurnitureBaseEntity(int entityId); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index 3f9c1f21a..c70b49362 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -5,6 +5,9 @@ import net.momirealms.craftengine.core.plugin.Plugin; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.ApiStatus; +import java.util.List; +import java.util.Map; + public interface NetWorkUser { boolean isOnline(); @@ -31,4 +34,6 @@ public interface NetWorkUser { Object serverPlayer(); Object platformPlayer(); + + Map> furnitureView(); }