diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java index ccc9c42cc..d62099b7b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java @@ -1,5 +1,32 @@ package net.momirealms.craftengine.bukkit.entity.furniture; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.Vector; + +import org.bukkit.Location; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.ItemDisplay; +import org.bukkit.entity.Player; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Quaternionf; +import org.joml.Vector3f; + import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import net.momirealms.craftengine.bukkit.entity.BukkitEntity; @@ -8,7 +35,16 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; -import net.momirealms.craftengine.core.entity.furniture.*; +import net.momirealms.craftengine.core.entity.furniture.AnchorType; +import net.momirealms.craftengine.core.entity.furniture.Collider; +import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; +import net.momirealms.craftengine.core.entity.furniture.ExternalModel; +import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.entity.furniture.FurnitureElement; +import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; +import net.momirealms.craftengine.core.entity.furniture.FurnitureManager; +import net.momirealms.craftengine.core.entity.furniture.HitBox; +import net.momirealms.craftengine.core.entity.furniture.Seat; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.ArrayUtils; import net.momirealms.craftengine.core.util.Key; @@ -16,18 +52,6 @@ import net.momirealms.craftengine.core.util.QuaternionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldPosition; import net.momirealms.craftengine.core.world.collision.AABB; -import org.bukkit.Location; -import org.bukkit.attribute.Attribute; -import org.bukkit.entity.*; -import org.bukkit.persistence.PersistentDataType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.joml.Quaternionf; -import org.joml.Vector3f; - -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.util.*; public class BukkitFurniture implements Furniture { private final Key id; @@ -184,6 +208,12 @@ public class BukkitFurniture implements Furniture { if (!isValid()) { return; } + // Clean up BlockStateHitBoxes before destroying the furniture + for (HitBox hitBox : this.hitBoxes.values()) { + if (hitBox instanceof net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BlockStateHitBox) { + ((net.momirealms.craftengine.bukkit.entity.furniture.hitbox.BlockStateHitBox) hitBox).removePlacedBlock(); + } + } this.baseEntity().remove(); for (Collider entity : this.colliderEntities) { if (entity != null) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BlockStateHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BlockStateHitBox.java new file mode 100644 index 000000000..96ec5c235 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BlockStateHitBox.java @@ -0,0 +1,201 @@ +package net.momirealms.craftengine.bukkit.entity.furniture.hitbox; + +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.bukkit.Material; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.entity.furniture.AbstractHitBox; +import net.momirealms.craftengine.core.entity.furniture.Collider; +import net.momirealms.craftengine.core.entity.furniture.HitBox; +import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; +import net.momirealms.craftengine.core.entity.furniture.HitBoxTypes; +import net.momirealms.craftengine.core.entity.furniture.Seat; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.LazyReference; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; +import net.momirealms.craftengine.core.world.collision.AABB; + +public class BlockStateHitBox extends AbstractHitBox { + public static final Factory FACTORY = new Factory(); + + private final LazyReference lazyBlockState; + private final boolean dropContainer; + private WorldPosition placedPosition; + private BlockStateWrapper originalBlockState; + + public BlockStateHitBox(Seat[] seats, Vector3f position, LazyReference lazyBlockState, + boolean canUseOn, boolean blocksBuilding, boolean canBeHitByProjectile, boolean dropContainer) { + super(seats, position, canUseOn, blocksBuilding, canBeHitByProjectile); + this.lazyBlockState = lazyBlockState; + this.dropContainer = dropContainer; + } + + public LazyReference blockState() { + return lazyBlockState; + } + + public boolean dropContainer() { + return dropContainer; + } + + @Override + public Key type() { + return HitBoxTypes.BLOCKSTATE; + } + + @Override + public void initPacketsAndColliders(int[] entityId, WorldPosition position, Quaternionf conjugated, + BiConsumer packets, Consumer collider, + BiConsumer aabb) { + Vector3f offset = conjugated.transform(new Vector3f(position())); + World world = position.world(); + int blockX = (int) Math.floor(position.x() + offset.x); + int blockY = (int) Math.floor(position.y() + offset.y); + int blockZ = (int) Math.floor(position.z() - offset.z); + + // Store the placed position for later removal + this.placedPosition = new WorldPosition(world, blockX, blockY, blockZ); + + // Store the original block state before placing our block + try { + // Get the bukkit block data from the world + org.bukkit.World bukkitWorld = (org.bukkit.World) world.platformWorld(); + org.bukkit.block.data.BlockData blockData = bukkitWorld.getBlockAt(blockX, blockY, blockZ).getBlockData(); + this.originalBlockState = BlockStateUtils.toPackedBlockState(blockData); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to get original block state", e); + // Fallback to air + this.originalBlockState = CraftEngine.instance().blockManager().createPackedBlockState("minecraft:air"); + } + + // Place the block + BlockStateWrapper blockStateWrapper = lazyBlockState.get(); + if (blockStateWrapper != null) { + world.setBlockAt(blockX, blockY, blockZ, blockStateWrapper, 3); // UPDATE_ALL flags + } + + // If the block can be used on, add AABB for interaction + if (canUseItemOn()) { + aabb.accept(entityId[0], new AABB(blockX, blockY, blockZ, blockX + 1, blockY + 1, blockZ + 1)); + } + } + + @Override + public void initShapeForPlacement(double x, double y, double z, float yaw, Quaternionf conjugated, Consumer aabbs) { + if (blocksBuilding()) { + Vector3f offset = conjugated.transform(new Vector3f(position())); + int blockX = (int) Math.floor(x + offset.x); + int blockY = (int) Math.floor(y + offset.y); + int blockZ = (int) Math.floor(z - offset.z); + aabbs.accept(new AABB(blockX, blockY, blockZ, blockX + 1, blockY + 1, blockZ + 1)); + } + } + + @Override + public int[] acquireEntityIds(Supplier entityIdSupplier) { + return new int[] {entityIdSupplier.get()}; + } + + /** + * Removes the placed block and handles container drops if needed + */ + public void removePlacedBlock() { + if (placedPosition == null) return; + + World world = placedPosition.world(); + int x = (int) placedPosition.x(); + int y = (int) placedPosition.y(); + int z = (int) placedPosition.z(); + + // Drop container contents if the flag is enabled + if (dropContainer) { + dropContainerContents(world, x, y, z); + } + + // Restore the original block state + if (originalBlockState != null) { + world.setBlockAt(x, y, z, originalBlockState, 3); + } else { + // Fallback to air if no original state was stored + BlockStateWrapper airState = CraftEngine.instance().blockManager().createPackedBlockState("minecraft:air"); + if (airState != null) { + world.setBlockAt(x, y, z, airState, 3); + } + } + } + + /** + * Drops the contents of a container block + */ + private void dropContainerContents(World world, int x, int y, int z) { + try { + // Get the bukkit world and block + org.bukkit.World bukkitWorld = (org.bukkit.World) world.platformWorld(); + if (bukkitWorld == null) return; + + org.bukkit.block.Block block = bukkitWorld.getBlockAt(x, y, z); + if (block.getState() instanceof InventoryHolder inventoryHolder) { + org.bukkit.inventory.Inventory inventory = inventoryHolder.getInventory(); + org.bukkit.Location dropLocation = block.getLocation().add(0.5, 0.5, 0.5); + + // Drop all items in the inventory + for (ItemStack itemStack : inventory.getContents()) { + if (itemStack != null && itemStack.getType() != Material.AIR) { + bukkitWorld.dropItemNaturally(dropLocation, itemStack); + } + } + + // Clear the inventory + inventory.clear(); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to drop container contents for BlockStateHitBox", e); + } + } + + public static class Factory implements HitBoxFactory { + + @Override + public HitBox create(Map arguments) { + Vector3f position = net.momirealms.craftengine.core.util.MiscUtils.getAsVector3f( + arguments.getOrDefault("position", "0"), "position"); + + String blockStateString = ResourceConfigUtils.requireNonEmptyStringOrThrow( + arguments.get("block-state"), "warning.config.furniture.hitbox.blockstate.missing_block_state"); + + boolean canUseOn = ResourceConfigUtils.getAsBoolean( + arguments.getOrDefault("can-use-item-on", false), "can-use-item-on"); + boolean blocksBuilding = ResourceConfigUtils.getAsBoolean( + arguments.getOrDefault("blocks-building", true), "blocks-building"); + boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean( + arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile"); + boolean dropContainer = ResourceConfigUtils.getAsBoolean( + arguments.getOrDefault("drop-container", true), "drop-container"); + + LazyReference lazyBlockState = LazyReference.lazyReference( + () -> CraftEngine.instance().blockManager().createPackedBlockState(blockStateString)); + + return new BlockStateHitBox( + HitBoxFactory.getSeats(arguments), + position, + lazyBlockState, + canUseOn, + blocksBuilding, + canBeHitByProjectile, + dropContainer + ); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitHitBoxTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitHitBoxTypes.java index dda752638..0a152f5ca 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitHitBoxTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/BukkitHitBoxTypes.java @@ -11,5 +11,6 @@ public class BukkitHitBoxTypes extends HitBoxTypes { register(SHULKER, ShulkerHitBox.FACTORY); register(HAPPY_GHAST, HappyGhastHitBox.FACTORY); register(CUSTOM, CustomHitBox.FACTORY); + register(BLOCKSTATE, BlockStateHitBox.FACTORY); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java index f77435813..ba595b4f7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java @@ -1,5 +1,8 @@ package net.momirealms.craftengine.core.entity.furniture; +import java.util.Map; +import java.util.Optional; + import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -8,14 +11,12 @@ import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; -import java.util.Map; -import java.util.Optional; - public class HitBoxTypes { public static final Key INTERACTION = Key.of("minecraft:interaction"); public static final Key SHULKER = Key.of("minecraft:shulker"); public static final Key HAPPY_GHAST = Key.of("minecraft:happy_ghast"); public static final Key CUSTOM = Key.of("minecraft:custom"); + public static final Key BLOCKSTATE = Key.of("minecraft:blockstate"); public static void register(Key key, HitBoxFactory factory) { Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.HITBOX_FACTORY) diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index 8613eb5c4..a59629618 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -1,7 +1,40 @@ package net.momirealms.craftengine.core.plugin.context.event; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.function.*; +import net.momirealms.craftengine.core.plugin.context.function.ActionBarFunction; +import net.momirealms.craftengine.core.plugin.context.function.BreakBlockFunction; +import net.momirealms.craftengine.core.plugin.context.function.CancelEventFunction; +import net.momirealms.craftengine.core.plugin.context.function.CommandFunction; +import net.momirealms.craftengine.core.plugin.context.function.CommonFunctions; +import net.momirealms.craftengine.core.plugin.context.function.DropLootFunction; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; +import net.momirealms.craftengine.core.plugin.context.function.LevelerExpFunction; +import net.momirealms.craftengine.core.plugin.context.function.MessageFunction; +import net.momirealms.craftengine.core.plugin.context.function.OpenWindowFunction; +import net.momirealms.craftengine.core.plugin.context.function.ParticleFunction; +import net.momirealms.craftengine.core.plugin.context.function.PlaceBlockFunction; +import net.momirealms.craftengine.core.plugin.context.function.PlaySoundFunction; +import net.momirealms.craftengine.core.plugin.context.function.PotionEffectFunction; +import net.momirealms.craftengine.core.plugin.context.function.RemoveCooldownFunction; +import net.momirealms.craftengine.core.plugin.context.function.RemoveFurnitureFunction; +import net.momirealms.craftengine.core.plugin.context.function.RemovePotionEffectFunction; +import net.momirealms.craftengine.core.plugin.context.function.ReplaceFurnitureFunction; +import net.momirealms.craftengine.core.plugin.context.function.RunFunction; +import net.momirealms.craftengine.core.plugin.context.function.SetCooldownFunction; +import net.momirealms.craftengine.core.plugin.context.function.SetCountFunction; +import net.momirealms.craftengine.core.plugin.context.function.SetFoodFunction; +import net.momirealms.craftengine.core.plugin.context.function.SetSaturationFunction; +import net.momirealms.craftengine.core.plugin.context.function.SpawnFurnitureFunction; +import net.momirealms.craftengine.core.plugin.context.function.SwingHandFunction; +import net.momirealms.craftengine.core.plugin.context.function.TitleFunction; +import net.momirealms.craftengine.core.plugin.context.function.UpdateInteractionFunction; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -12,8 +45,6 @@ import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; -import java.util.*; - public class EventFunctions { static { @@ -39,6 +70,9 @@ public class EventFunctions { register(CommonFunctions.LEVELER_EXP, new LevelerExpFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.SET_COOLDOWN, new SetCooldownFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.REMOVE_COOLDOWN, new RemoveCooldownFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.SPAWN_FURNITURE, new SpawnFurnitureFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.REMOVE_FURNITURE, new RemoveFurnitureFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.REPLACE_FURNITURE, new ReplaceFurnitureFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index 8c0bc6435..f81794979 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -27,4 +27,7 @@ public final class CommonFunctions { public static final Key DROP_LOOT = Key.of("craftengine:drop_loot"); public static final Key SWING_HAND = Key.of("craftengine:swing_hand"); public static final Key LEVELER_EXP = Key.of("craftengine:leveler_exp"); + public static final Key SPAWN_FURNITURE = Key.of("craftengine:spawn_furniture"); + public static final Key REMOVE_FURNITURE = Key.of("craftengine:remove_furniture"); + public static final Key REPLACE_FURNITURE = Key.of("craftengine:replace_furniture"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemoveFurnitureFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemoveFurnitureFunction.java new file mode 100644 index 000000000..7acd7f40d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RemoveFurnitureFunction.java @@ -0,0 +1,60 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.WorldPosition; + +public class RemoveFurnitureFunction extends AbstractConditionalFunction { + private final boolean dropLoot; + private final boolean playSound; + + public RemoveFurnitureFunction(boolean dropLoot, boolean playSound, List> predicates) { + super(predicates); + this.dropLoot = dropLoot; + this.playSound = playSound; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isPresent()) { + // Buscar muebles en el contexto + Optional optionalFurniture = ctx.getOptionalParameter(DirectContextParameters.FURNITURE); + if (optionalFurniture.isPresent()) { + Furniture furniture = optionalFurniture.get(); + if (furniture.isValid()) { + furniture.destroy(); + // TODO: Implementar lógica para dropear loot y reproducir sonidos + // usando this.dropLoot y this.playSound cuando sea necesario + } + } + } + } + + @Override + public Key type() { + return CommonFunctions.REMOVE_FURNITURE; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + boolean dropLoot = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("drop-loot", true), "drop-loot"); + boolean playSound = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("play-sound", true), "play-sound"); + return new RemoveFurnitureFunction<>(dropLoot, playSound, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java new file mode 100644 index 000000000..15a903a51 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ReplaceFurnitureFunction.java @@ -0,0 +1,109 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import net.momirealms.craftengine.core.entity.furniture.AnchorType; +import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; +import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.WorldPosition; + +public class ReplaceFurnitureFunction extends AbstractConditionalFunction { + private final Key newFurnitureId; + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final NumberProvider pitch; + private final NumberProvider yaw; + private final AnchorType anchorType; + private final boolean dropLoot; + private final boolean playSound; + + public ReplaceFurnitureFunction(Key newFurnitureId, NumberProvider x, NumberProvider y, NumberProvider z, + NumberProvider pitch, NumberProvider yaw, AnchorType anchorType, + boolean dropLoot, boolean playSound, List> predicates) { + super(predicates); + this.newFurnitureId = newFurnitureId; + this.x = x; + this.y = y; + this.z = z; + this.pitch = pitch; + this.yaw = yaw; + this.anchorType = anchorType; + this.dropLoot = dropLoot; + this.playSound = playSound; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + Optional optionalOldFurniture = ctx.getOptionalParameter(DirectContextParameters.FURNITURE); + + if (optionalWorldPosition.isPresent() && optionalOldFurniture.isPresent()) { + Furniture oldFurniture = optionalOldFurniture.get(); + + // Obtener la nueva posición o usar la actual del mueble + double xPos = this.x.getDouble(ctx); + double yPos = this.y.getDouble(ctx); + double zPos = this.z.getDouble(ctx); + float pitchValue = this.pitch.getFloat(ctx); + float yawValue = this.yaw.getFloat(ctx); + + WorldPosition newPosition = new WorldPosition(optionalWorldPosition.get().world(), xPos, yPos, zPos, pitchValue, yawValue); + + // Obtener el nuevo mueble + Optional optionalNewFurniture = CraftEngine.instance().furnitureManager().furnitureById(this.newFurnitureId); + if (optionalNewFurniture.isPresent()) { + CustomFurniture newFurniture = optionalNewFurniture.get(); + AnchorType anchor = this.anchorType != null ? this.anchorType : newFurniture.getAnyAnchorType(); + + // Remover el mueble antiguo + if (oldFurniture.isValid()) { + oldFurniture.destroy(); + // TODO: Implementar lógica para dropear loot usando this.dropLoot + } + + // Colocar el nuevo mueble + FurnitureExtraData extraData = FurnitureExtraData.builder().anchorType(anchor).build(); + CraftEngine.instance().furnitureManager().place(newPosition, newFurniture, extraData, this.playSound); + } + } + } + + @Override + public Key type() { + return CommonFunctions.REPLACE_FURNITURE; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + String furnitureIdStr = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("furniture-id"), "warning.config.function.replace_furniture.missing_furniture_id"); + Key furnitureId = Key.of(furnitureIdStr); + NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); + NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); + NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); + NumberProvider pitch = NumberProviders.fromObject(arguments.getOrDefault("pitch", "")); + NumberProvider yaw = NumberProviders.fromObject(arguments.getOrDefault("yaw", "")); + AnchorType anchorType = Optional.ofNullable(arguments.get("anchor-type")).map(o -> AnchorType.valueOf(o.toString().toUpperCase())).orElse(null); + boolean dropLoot = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("drop-loot", true), "drop-loot"); + boolean playSound = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("play-sound", true), "play-sound"); + return new ReplaceFurnitureFunction<>(furnitureId, x, y, z, pitch, yaw, anchorType, dropLoot, playSound, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SpawnFurnitureFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SpawnFurnitureFunction.java new file mode 100644 index 000000000..e18a1e8f4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SpawnFurnitureFunction.java @@ -0,0 +1,93 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import net.momirealms.craftengine.core.entity.furniture.AnchorType; +import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; +import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; + +public class SpawnFurnitureFunction extends AbstractConditionalFunction { + private final Key furnitureId; + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final NumberProvider pitch; + private final NumberProvider yaw; + private final AnchorType anchorType; + private final boolean playSound; + + public SpawnFurnitureFunction(Key furnitureId, NumberProvider x, NumberProvider y, NumberProvider z, + NumberProvider pitch, NumberProvider yaw, AnchorType anchorType, + boolean playSound, List> predicates) { + super(predicates); + this.furnitureId = furnitureId; + this.x = x; + this.y = y; + this.z = z; + this.pitch = pitch; + this.yaw = yaw; + this.anchorType = anchorType; + this.playSound = playSound; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isPresent()) { + World world = optionalWorldPosition.get().world(); + double xPos = this.x.getDouble(ctx); + double yPos = this.y.getDouble(ctx); + double zPos = this.z.getDouble(ctx); + float pitchValue = this.pitch.getFloat(ctx); + float yawValue = this.yaw.getFloat(ctx); + + WorldPosition position = new WorldPosition(world, xPos, yPos, zPos, pitchValue, yawValue); + + Optional optionalFurniture = CraftEngine.instance().furnitureManager().furnitureById(this.furnitureId); + if (optionalFurniture.isPresent()) { + CustomFurniture furniture = optionalFurniture.get(); + AnchorType anchor = this.anchorType != null ? this.anchorType : furniture.getAnyAnchorType(); + FurnitureExtraData extraData = FurnitureExtraData.builder().anchorType(anchor).build(); + CraftEngine.instance().furnitureManager().place(position, furniture, extraData, this.playSound); + } + } + } + + @Override + public Key type() { + return CommonFunctions.SPAWN_FURNITURE; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + String furnitureIdStr = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("furniture-id"), "warning.config.function.spawn_furniture.missing_furniture_id"); + Key furnitureId = Key.of(furnitureIdStr); + NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); + NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); + NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); + NumberProvider pitch = NumberProviders.fromObject(arguments.getOrDefault("pitch", "")); + NumberProvider yaw = NumberProviders.fromObject(arguments.getOrDefault("yaw", "")); + AnchorType anchorType = Optional.ofNullable(arguments.get("anchor-type")).map(o -> AnchorType.valueOf(o.toString().toUpperCase())).orElse(null); + boolean playSound = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("play-sound", true), "play-sound"); + return new SpawnFurnitureFunction<>(furnitureId, x, y, z, pitch, yaw, anchorType, playSound, getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java index 2f49aca37..3b06b968f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/FurnitureParameterProvider.java @@ -1,20 +1,25 @@ package net.momirealms.craftengine.core.plugin.context.parameter; -import net.momirealms.craftengine.core.entity.furniture.Furniture; -import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; -import net.momirealms.craftengine.core.plugin.context.ContextKey; - import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.function.Function; +import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; +import net.momirealms.craftengine.core.plugin.context.ContextKey; + public class FurnitureParameterProvider implements ChainParameterProvider { private static final Map, Function> CONTEXT_FUNCTIONS = new HashMap<>(); static { CONTEXT_FUNCTIONS.put(DirectContextParameters.ID, Furniture::id); CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, Furniture::uuid); CONTEXT_FUNCTIONS.put(DirectContextParameters.ANCHOR_TYPE, Furniture::anchorType); + CONTEXT_FUNCTIONS.put(DirectContextParameters.X, furniture -> furniture.position().x()); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, furniture -> furniture.position().y()); + CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, furniture -> furniture.position().z()); + CONTEXT_FUNCTIONS.put(DirectContextParameters.PITCH, furniture -> furniture.position().yRot()); + CONTEXT_FUNCTIONS.put(DirectContextParameters.YAW, furniture -> furniture.position().xRot()); } @SuppressWarnings("unchecked")