diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitFurnitureHitboxTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitFurnitureHitboxTypes.java index 715cb7678..f7fa5e2e1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitFurnitureHitboxTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitFurnitureHitboxTypes.java @@ -10,7 +10,7 @@ public class BukkitFurnitureHitboxTypes extends FurnitureHitBoxTypes { static { register(INTERACTION, InteractionFurnitureHitboxConfig.FACTORY); register(SHULKER, ShulkerFurnitureHitboxConfig.FACTORY); - register(CUSTOM, CustomFurnitureHitboxConfig.FACTORY); + register(CUSTOM, CustomFurnitureHitboxConfig.FACTORY); if (VersionHelper.isOrAbove1_21_6()) { register(HAPPY_GHAST, HappyGhastFurnitureHitboxConfig.FACTORY); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java index 1c4e45ca6..65b0ffd9e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionFurnitureHitbox.java @@ -32,7 +32,7 @@ public class InteractionFurnitureHitbox extends AbstractFurnitureHitBox { int interactionId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet(); this.spawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(List.of( FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( - interactionId, UUID.randomUUID(), position.x, position.y, position.z, 0, position.yRot, + interactionId, UUID.randomUUID(), pos.x, pos.y, pos.z, 0, position.yRot, MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 ), FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(interactionId, config.cachedValues()) 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 19a9aea16..b74926aa9 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 @@ -8,9 +8,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.EventUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; -import net.momirealms.craftengine.core.entity.furniture.FurnitureConfig; -import net.momirealms.craftengine.core.entity.furniture.FurnitureDataAccessor; -import net.momirealms.craftengine.core.entity.furniture.FurnitureVariant; +import net.momirealms.craftengine.core.entity.furniture.*; import net.momirealms.craftengine.core.entity.furniture.hitbox.FurnitureHitBoxConfig; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.Player; @@ -26,10 +24,8 @@ import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.util.Cancellable; -import net.momirealms.craftengine.core.util.ItemUtils; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.plugin.logger.Debugger; +import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; @@ -38,17 +34,17 @@ import org.bukkit.Location; import org.bukkit.World; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; public class FurnitureItemBehavior extends ItemBehavior { public static final Factory FACTORY = new Factory(); + private static final Set ALLOWED_ANCHOR_TYPES = Set.of("wall", "ceiling", "ground"); private final Key id; + private final Map rules; - public FurnitureItemBehavior(Key id) { + public FurnitureItemBehavior(Key id, Map rules) { this.id = id; + this.rules = rules; } public Key furnitureId() { @@ -67,12 +63,24 @@ public class FurnitureItemBehavior extends ItemBehavior { return InteractionResult.FAIL; } + Direction clickedFace = context.getClickedFace(); + AnchorType anchorType = switch (clickedFace) { + case EAST, WEST, NORTH, SOUTH -> AnchorType.WALL; + case UP -> AnchorType.GROUND; + case DOWN -> AnchorType.CEILING; + }; + FurnitureConfig customFurniture = optionalCustomFurniture.get(); - FurnitureVariant variant = customFurniture.anyVariant(); + FurnitureVariant variant = customFurniture.getVariant(anchorType.variantName()); if (variant == null) { return InteractionResult.FAIL; } + Rule rule = this.rules.get(anchorType); + if (rule == null) { + rule = Rule.DEFAULT; + } + Player player = context.getPlayer(); if (player != null && player.isAdventureMode()) { return InteractionResult.FAIL; @@ -80,14 +88,27 @@ public class FurnitureItemBehavior extends ItemBehavior { Vec3d clickedPosition = context.getClickLocation(); + // get position and rotation for placement + Vec3d finalPlacePosition; + double furnitureYaw; + if (anchorType == AnchorType.WALL) { + furnitureYaw = Direction.getYaw(clickedFace); + if (clickedFace == Direction.EAST || clickedFace == Direction.WEST) { + Pair xz = rule.alignmentRule().apply(Pair.of(clickedPosition.y(), clickedPosition.z())); + finalPlacePosition = new Vec3d(clickedPosition.x(), xz.left(), xz.right()); + } else { + Pair xz = rule.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.y())); + finalPlacePosition = new Vec3d(xz.left(), xz.right(), clickedPosition.z()); + } + } else { + furnitureYaw = rule.rotationRule().apply(180 + (player != null ? player.yRot() : 0)); + Pair xz = rule.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.z())); + finalPlacePosition = new Vec3d(xz.left(), clickedPosition.y(), xz.right()); + } + // trigger event org.bukkit.entity.Player bukkitPlayer = player != null ? (org.bukkit.entity.Player) player.platformPlayer() : null; World world = (World) context.getLevel().platformWorld(); - - // get position and rotation for placement - Vec3d finalPlacePosition = clickedPosition; - double furnitureYaw = 180 + (player != null ? player.yRot() : 0); - Location furnitureLocation = new Location(world, finalPlacePosition.x(), finalPlacePosition.y(), finalPlacePosition.z(), (float) furnitureYaw, 0); WorldPosition furniturePos = LocationUtils.toWorldPosition(furnitureLocation); List aabbs = new ArrayList<>(); @@ -162,17 +183,59 @@ public class FurnitureItemBehavior extends ItemBehavior { if (id == null) { throw new LocalizedResourceConfigException("warning.config.item.behavior.furniture.missing_furniture", new IllegalArgumentException("Missing required parameter 'furniture' for furniture_item behavior")); } + Map rulesMap = ResourceConfigUtils.getAsMapOrNull(arguments.get("rules"), "rules"); + Key furnitureId; if (id instanceof Map map) { + Map furnitureSection; if (map.containsKey(key.toString())) { // 防呆 - BukkitFurnitureManager.instance().parser().addPendingConfigSection(new PendingConfigSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false))); + furnitureSection = MiscUtils.castToMap(map.get(key.toString()), false); + BukkitFurnitureManager.instance().parser().addPendingConfigSection(new PendingConfigSection(pack, path, node, key, furnitureSection)); } else { - BukkitFurnitureManager.instance().parser().addPendingConfigSection(new PendingConfigSection(pack, path, node, key, MiscUtils.castToMap(map, false))); + furnitureSection = MiscUtils.castToMap(map, false); + BukkitFurnitureManager.instance().parser().addPendingConfigSection(new PendingConfigSection(pack, path, node, key, furnitureSection)); + } + furnitureId = key; + // 兼容老版本 + if (rulesMap == null) { + Map placementSection = ResourceConfigUtils.getAsMapOrNull(furnitureSection.get("placement"), "placement"); + if (placementSection != null) { + rulesMap = new HashMap<>(); + for (Map.Entry entry : placementSection.entrySet()) { + if (entry.getValue() instanceof Map innerMap) { + if (innerMap.containsKey("rules")) { + Map rules = ResourceConfigUtils.getAsMap(innerMap.get("rules"), "rules"); + if (ALLOWED_ANCHOR_TYPES.contains(entry.getKey())) { + rulesMap.put(entry.getKey(), rules); + } + } + } + } + } } - return new FurnitureItemBehavior(key); } else { - return new FurnitureItemBehavior(Key.of(id.toString())); + furnitureId = Key.of(id.toString()); } + Map rules = new EnumMap<>(AnchorType.class); + if (rulesMap != null) { + for (Map.Entry entry : rulesMap.entrySet()) { + try { + AnchorType type = AnchorType.valueOf(entry.getKey().toUpperCase(Locale.ROOT)); + Map ruleSection = MiscUtils.castToMap(entry.getValue(), true); + rules.put(type, new Rule( + ResourceConfigUtils.getAsEnum(ruleSection.get("alignment"), AlignmentRule.class, AlignmentRule.ANY), + ResourceConfigUtils.getAsEnum(ruleSection.get("rotation"), RotationRule.class, RotationRule.ANY) + )); + } catch (IllegalArgumentException ignored) { + Debugger.FURNITURE.debug(() -> "Invalid anchor type: " + entry.getKey()); + } + } + } + return new FurnitureItemBehavior(furnitureId, rules); } } + + public record Rule(AlignmentRule alignmentRule, RotationRule rotationRule) { + public static final Rule DEFAULT = new Rule(AlignmentRule.ANY, RotationRule.ANY); + } } diff --git a/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml b/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml index 06523d269..66e36f644 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml @@ -6,6 +6,10 @@ items: model: minecraft:item/custom/bench behavior: type: furniture_item + rules: + ground: + rotation: four + alignment: center furniture: settings: item: default:bench @@ -17,8 +21,8 @@ items: loot-spawn-offset: 0.5,0.5,0 elements: - item: default:bench - display-transform: NONE - billboard: FIXED + display-transform: none + billboard: fixed position: 0.5,0,0 translation: 0,0.5,0 shadow-radius: 1 diff --git a/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml b/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml index 15194da75..acfcedb15 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml @@ -7,6 +7,16 @@ items: behavior: type: furniture_item furniture: default:flower_basket + rules: + ground: + rotation: any + alignment: any + wall: + rotation: any + alignment: any + ceiling: + rotation: any + alignment: any default:flower_basket_ground: material: nether_brick model: minecraft:item/custom/flower_basket_ground @@ -27,15 +37,12 @@ furniture: template: default:loot_table/furniture arguments: item: default:flower_basket - placement: + variants: ground: - rules: - rotation: ANY - alignment: ANY elements: - item: default:flower_basket_ground - display-transform: NONE - billboard: FIXED + display-transform: none + billboard: fixed position: 0,0,0 translation: 0,0.5,0 shadow-radius: 0.5 @@ -50,12 +57,10 @@ furniture: height: 0.5 interactive: true wall: - rules: - alignment: ANY elements: - item: default:flower_basket_wall - display-transform: NONE - billboard: FIXED + display-transform: none + billboard: fixed position: 0,0,0.2 translation: 0,0,0 hitboxes: @@ -76,13 +81,10 @@ furniture: height: 0.75 interactive: true ceiling: - rules: - rotation: ANY - alignment: ANY elements: - item: default:flower_basket_ceiling - display-transform: NONE - billboard: FIXED + display-transform: none + billboard: fixed position: 0,-0.46,0 translation: 0,0,0 hitboxes: diff --git a/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml b/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml index fddace996..7ad0017fe 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml @@ -6,18 +6,19 @@ items: model: minecraft:item/custom/wooden_chair behavior: type: furniture_item + rules: + ground: + rotation: any + alignment: any furniture: settings: item: default:wooden_chair sounds: break: minecraft:block.bamboo_wood.break place: minecraft:block.bamboo_wood.place - placement: + variants: ground: loot-spawn-offset: 0,0.4,0 - rules: - rotation: ANY - alignment: ANY elements: - item: default:wooden_chair display-transform: NONE diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AnchorType.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AnchorType.java index b389f52f7..8ec7b6749 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AnchorType.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AnchorType.java @@ -1,21 +1,26 @@ package net.momirealms.craftengine.core.entity.furniture; -@Deprecated(since = "0.0.66") public enum AnchorType { - GROUND(0), - WALL(1), - CEILING(2); + GROUND(0, "ground"), + WALL(1, "wall"), + CEILING(2, "ceiling"); private final int id; + private final String variantName; - AnchorType(int id) { + AnchorType(int id, String variantName) { this.id = id; + this.variantName = variantName; } public int getId() { return id; } + public String variantName() { + return variantName; + } + public static AnchorType byId(int id) { return values()[id]; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index 43a35d7dc..e3be821e6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -36,7 +36,7 @@ public final class ResourceConfigUtils { return defaultValue; } try { - return Enum.valueOf(clazz, o.toString().toUpperCase(Locale.ENGLISH)); + return Enum.valueOf(clazz, o.toString().toUpperCase(Locale.ROOT)); } catch (IllegalArgumentException e) { return defaultValue; }