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 1b26e33b2..89e99122c 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -203,6 +203,51 @@ blocks: crop_item: minecraft:ender_pearl crop_seed: default:ender_pearl_flower_seeds ripe_age: 2 + events: + - on: break + conditions: + - type: match_block_property + properties: + age: 2 + functions: + - type: particle + x: " + 0.5" + y: " + 0.5" + z: " + 0.5" + particle: "minecraft:end_rod" + count: 15 + offset-x: 0.05 + offset-y: 0.05 + offset-z: 0.05 + speed: 0.1 + - type: play_sound + sound: minecraft:entity.enderman.teleport + x: " + 0.5" + y: " + 0.5" + z: " + 0.5" + - on: right_click + conditions: + - type: match_block_property + properties: + age: 2 + - type: "!is_null" + argument: "item_in_hand" + - type: "equals" + value1: "" + value2: "default:ender_pearl_flower_seeds" + functions: + - type: break_block + x: "" + y: "" + z: "" + - type: place_block + x: "" + y: "" + z: "" + block-state: default:ender_pearl_flower[age=0] + - type: set_count + add: true + count: -1 states: properties: age: diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 26a9afbb3..fdfa1323b 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -324,6 +324,12 @@ warning.config.function.place_block.missing_block_state: "Issue found in warning.config.function.set_food.missing_food: "Issue found in file - The config '' is missing the required 'food' argument for 'set_food' function." warning.config.function.set_saturation.missing_saturation: "Issue found in file - The config '' is missing the required 'saturation' argument for 'set_saturation' function." warning.config.function.play_sound.missing_sound: "Issue found in file - The config '' is missing the required 'sound' argument for 'play_sound' function." +warning.config.function.particle.missing_particle: "Issue found in file - The config '' is missing the required 'particle' argument for 'particle' function." +warning.config.function.particle.missing_color: "Issue found in file - The config '' is missing the required 'color' argument for 'particle' function." +warning.config.function.particle.missing_from: "Issue found in file - The config '' is missing the required 'from' argument for 'particle' function." +warning.config.function.particle.missing_to: "Issue found in file - The config '' is missing the required 'to' argument for 'particle' function." +warning.config.function.particle.missing_item: "Issue found in file - The config '' is missing the required 'item' argument for 'particle' function." +warning.config.function.particle.missing_block_state: "Issue found in file - The config '' is missing the required 'block-state' argument for 'particle' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 983dc9e9c..4f15d6a9f 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -324,6 +324,12 @@ warning.config.function.place_block.missing_block_state: "在文件 Issue found in file - The config '' is missing the required 'food' argument for 'set_food' function." warning.config.function.set_saturation.missing_saturation: "Issue found in file - The config '' is missing the required 'saturation' argument for 'set_saturation' function." warning.config.function.play_sound.missing_sound: "Issue found in file - The config '' is missing the required 'sound' argument for 'play_sound' function." +warning.config.function.particle.missing_particle: "Issue found in file - The config '' is missing the required 'particle' argument for 'particle' function." +warning.config.function.particle.missing_color: "Issue found in file - The config '' is missing the required 'color' argument for 'particle' function." +warning.config.function.particle.missing_from: "Issue found in file - The config '' is missing the required 'from' argument for 'particle' function." +warning.config.function.particle.missing_to: "Issue found in file - The config '' is missing the required 'to' argument for 'particle' function." +warning.config.function.particle.missing_item: "Issue found in file - The config '' is missing the required 'item' argument for 'particle' function." +warning.config.function.particle.missing_block_state: "Issue found in file - The config '' is missing the required 'block-state' argument for 'particle' function." warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java index db42cb252..087004c50 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureBreakEvent.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.api.event; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; -import net.momirealms.craftengine.core.entity.furniture.Furniture; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java index b89bb7ba3..a9a523484 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurnitureInteractEvent.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.api.event; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; -import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.player.InteractionHand; import org.bukkit.Location; import org.bukkit.entity.Player; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java index e6f1405c1..8ea0c9645 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/FurniturePlaceEvent.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.api.event; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; -import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.player.InteractionHand; import org.bukkit.Location; import org.bukkit.entity.Player; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index abaf50b8d..1ac765bcd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -293,7 +293,7 @@ public class ItemEventListener implements Listener { Cancellable dummy = Cancellable.dummy(); CustomItem customItem = optionalCustomItem.get(); PlayerOptionalContext context = PlayerOptionalContext.of(this.plugin.adapt(event.getPlayer()), ContextHolder.builder() - .withParameter(DirectContextParameters.CONSUMED_ITEM, wrapped) + .withParameter(DirectContextParameters.ITEM_IN_HAND, wrapped) .withParameter(DirectContextParameters.EVENT, dummy) .withParameter(DirectContextParameters.HAND, event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND) ); 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 d119c2d1c..debbbe0d0 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 @@ -38,6 +38,8 @@ import org.bukkit.block.Block; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; import org.bukkit.persistence.PersistentDataType; import org.bukkit.util.RayTraceResult; import org.jetbrains.annotations.Nullable; @@ -903,4 +905,18 @@ public class BukkitServerPlayer extends Player { public void setSaturation(float saturation) { this.platformPlayer().setSaturation(saturation); } + + @Override + public void addPotionEffect(Key potionEffectType, int duration, int amplifier, boolean ambient, boolean particles) { + PotionEffectType type = Registry.POTION_EFFECT_TYPE.get(KeyUtils.toNamespacedKey(potionEffectType)); + if (type == null) return; + this.platformPlayer().addPotionEffect(new PotionEffect(type, duration, amplifier, ambient, particles)); + } + + @Override + public void removePotionEffect(Key potionEffectType) { + PotionEffectType type = Registry.POTION_EFFECT_TYPE.get(KeyUtils.toNamespacedKey(potionEffectType)); + if (type == null) return; + this.platformPlayer().removePotionEffect(type); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ColorUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ColorUtils.java new file mode 100644 index 000000000..18fcde2d3 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ColorUtils.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.bukkit.util; + +import org.bukkit.Color; + +public final class ColorUtils { + private ColorUtils() {} + + public static Color toBukkit(net.momirealms.craftengine.core.util.Color color) { + return Color.fromARGB(color.a(), color.r(), color.g(), color.b()); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java index dc8c5aeba..e0ba3ccd0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java @@ -1,7 +1,12 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.particle.*; +import org.bukkit.Location; import org.bukkit.Particle; +import org.bukkit.Vibration; +import org.bukkit.World; public final class ParticleUtils { private ParticleUtils() {} @@ -21,4 +26,18 @@ public final class ParticleUtils { public static final Particle HAPPY_VILLAGER = getParticle("HAPPY_VILLAGER"); public static final Particle BUBBLE = getParticle("BUBBLE"); + + public static Object toBukkitParticleData(ParticleData particleData, Context context, World world, double x, double y, double z) { + return switch (particleData) { + case BlockStateData data -> BlockStateUtils.fromBlockData(data.blockState().handle()); + case ColorData data -> ColorUtils.toBukkit(data.color()); + case DustData data -> new Particle.DustOptions(ColorUtils.toBukkit(data.color()), data.size()); + case DustTransitionData data -> new Particle.DustTransition(ColorUtils.toBukkit(data.from()), ColorUtils.toBukkit(data.to()), data.size()); + case ItemStackData data -> data.item().getItem(); + case JavaTypeData data -> data.data(); + case VibrationData data -> new Vibration(new Vibration.Destination.BlockDestination(new Location(world, x + data.destinationX().getDouble(context), y + data.destinationY().getDouble(context), y + data.destinationZ().getDouble(context))), data.arrivalTime().getInt(context)); + case TrailData data -> new Particle.Trail(new Location(world, x + data.targetX().getDouble(context), y + data.targetZ().getDouble(context), z + data.targetZ().getDouble(context)), ColorUtils.toBukkit(data.color()), data.duration().getInt(context)); + default -> null; + }; + } } 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 c1b6949a5..218b01d34 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -1,11 +1,10 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.util.EntityUtils; -import net.momirealms.craftengine.bukkit.util.ItemUtils; -import net.momirealms.craftengine.bukkit.util.SoundUtils; +import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -13,12 +12,17 @@ import net.momirealms.craftengine.core.world.BlockInWorld; import net.momirealms.craftengine.core.world.Position; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldHeight; +import net.momirealms.craftengine.core.world.particle.ParticleData; import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.Registry; import org.bukkit.SoundCategory; import org.bukkit.entity.EntityType; import org.bukkit.entity.ExperienceOrb; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import javax.annotation.Nullable; import java.lang.ref.WeakReference; import java.nio.file.Path; import java.util.UUID; @@ -99,6 +103,14 @@ public class BukkitWorld implements World { platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundCategory.BLOCKS, volume, pitch); } + @Override + public void spawnParticle(Position location, Key particle, int count, double xOffset, double yOffset, double zOffset, double speed, @Nullable ParticleData extraData, @NotNull Context context) { + Particle particleType = Registry.PARTICLE_TYPE.get(KeyUtils.toNamespacedKey(particle)); + if (particleType == null) return; + org.bukkit.World platformWorld = platformWorld(); + platformWorld.spawnParticle(particleType, location.x(), location.y(), location.z(), count, xOffset, yOffset, zOffset, speed, extraData == null ? null : ParticleUtils.toBukkitParticleData(extraData, context, platformWorld, location.x(), location.y(), location.z())); + } + @Override public long time() { return platformWorld().getTime(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/DelayedInitBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/DelayedInitBlockState.java new file mode 100644 index 000000000..253601aaa --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/DelayedInitBlockState.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.core.block; + +import net.momirealms.craftengine.core.plugin.CraftEngine; + +public class DelayedInitBlockState { + private final String state; + private BlockStateWrapper packedBlockState; + + public DelayedInitBlockState(String state) { + this.state = state; + } + + public BlockStateWrapper getState() { + if (this.packedBlockState == null) { + this.packedBlockState = CraftEngine.instance().blockManager().createPackedBlockState(state); + if (this.packedBlockState == null) { + CraftEngine.instance().logger().warn("Could not create block state: " + this.state); + } + } + return this.packedBlockState; + } +} \ No newline at end of file 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 c0132edf8..4a5f8f7a8 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 @@ -124,4 +124,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract float saturation(); public abstract void setSaturation(float saturation); + + public abstract void addPotionEffect(Key potionEffectType, int duration, int amplifier, boolean ambient, boolean particles); + + public abstract void removePotionEffect(Key potionEffectType); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/DelayedInitItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/DelayedInitItem.java new file mode 100644 index 000000000..2e6db264f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/DelayedInitItem.java @@ -0,0 +1,23 @@ +package net.momirealms.craftengine.core.item; + +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Key; + +public class DelayedInitItem { + private final Key itemId; + private Item item; + + public DelayedInitItem(Key itemId) { + this.itemId = itemId; + } + + public Item getItem() { + if (this.item == null) { + this.item = CraftEngine.instance().itemManager().createWrappedItem(this.itemId, null); + if (this.item == null) { + CraftEngine.instance().logger().warn("Could not create item: " + this.itemId); + } + } + return this.item; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index 785a00c6d..af0e99be2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.pack.host.impl; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.Scheduler; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; @@ -30,10 +31,12 @@ public class SelfHostHttpServer { private static SelfHostHttpServer instance; private final Cache oneTimePackUrls = Caffeine.newBuilder() .maximumSize(256) + .scheduler(Scheduler.systemScheduler()) .expireAfterAccess(1, TimeUnit.MINUTES) .build(); private final Cache ipAccessCache = Caffeine.newBuilder() .maximumSize(256) + .scheduler(Scheduler.systemScheduler()) .expireAfterAccess(10, TimeUnit.MINUTES) .build(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java index 9eed4f51b..f85e82333 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java @@ -20,7 +20,6 @@ public abstract class AbstractChainParameterContext extends AbstractCommonContex CHAIN_PARAMETERS.put(DirectContextParameters.MAIN_HAND_ITEM, itemProvider); CHAIN_PARAMETERS.put(DirectContextParameters.OFF_HAND_ITEM, itemProvider); CHAIN_PARAMETERS.put(DirectContextParameters.FURNITURE_ITEM, itemProvider); - CHAIN_PARAMETERS.put(DirectContextParameters.CONSUMED_ITEM, itemProvider); CHAIN_PARAMETERS.put(DirectContextParameters.ITEM_IN_HAND, itemProvider); } 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 ae0c66bd3..b2ce2de15 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 @@ -33,6 +33,8 @@ public class EventFunctions { register(CommonFunctions.SET_FOOD, new SetFoodFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.SET_SATURATION, new SetSaturationFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.PLAY_SOUND, new PlaySoundFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.PARTICLE, new ParticleFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.POTION_EFFECT, new PotionEffectFunction.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/ActionBarFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java index 4e04272f7..9f3781528 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java @@ -14,7 +14,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -import java.util.Optional; public class ActionBarFunction extends AbstractConditionalFunction { private final TextProvider message; @@ -28,9 +27,8 @@ public class ActionBarFunction extends AbstractConditionalF @Override public void runInternal(CTX ctx) { - Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { - owner.ifPresent(it -> { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { it.sendActionBar(AdventureHelper.miniMessage().deserialize(this.message.get(ctx), ctx.tagResolvers())); }); } else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java index 61a4137c4..d85f44950 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommandFunction.java @@ -16,7 +16,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -import java.util.Optional; public class CommandFunction extends AbstractConditionalFunction { private final List command; @@ -33,9 +32,8 @@ public class CommandFunction extends AbstractConditionalFun @Override public void runInternal(CTX ctx) { if (this.asPlayer) { - Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { - owner.ifPresent(it -> { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { for (TextProvider c : this.command) { it.performCommand(c.get(ctx)); } 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 82de72647..e8369e3fa 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 @@ -23,4 +23,5 @@ public final class CommonFunctions { public static final Key SET_SATURATION = Key.of("craftengine:saturation"); 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 PLUGIN_EXP = Key.of("craftengine:plugin_exp"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java index eeee93a4f..8c43e06f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java @@ -15,7 +15,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -import java.util.Optional; public class MessageFunction extends AbstractConditionalFunction { private final List messages; @@ -31,9 +30,8 @@ public class MessageFunction extends AbstractConditionalFun @Override public void runInternal(CTX ctx) { - Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { - owner.ifPresent(it -> { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { for (TextProvider c : this.messages) { it.sendMessage(AdventureHelper.miniMessage().deserialize(c.get(ctx), ctx.tagResolvers()), this.overlay); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java index 53dd47587..9799f63e2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java @@ -35,9 +35,8 @@ public class OpenWindowFunction extends AbstractConditional @Override public void runInternal(CTX ctx) { - Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { - owner.ifPresent(it -> { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { CraftEngine.instance().guiManager().openInventory(it, this.guiType); if (this.optionalTitle != null) { CraftEngine.instance().guiManager().updateInventoryTitle(it, AdventureHelper.miniMessage().deserialize(this.optionalTitle.get(ctx), ctx.tagResolvers())); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java new file mode 100644 index 000000000..098f09d2c --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java @@ -0,0 +1,135 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.block.DelayedInitBlockState; +import net.momirealms.craftengine.core.item.DelayedInitItem; +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.Color; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.Position; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; +import net.momirealms.craftengine.core.world.particle.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ParticleFunction extends AbstractConditionalFunction { + public static final Map, ParticleData>> DATA_TYPES = new HashMap<>(); + + static { + registerParticleData(map -> new BlockStateData( + new DelayedInitBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("block-state"), "warning.config.function.particle.missing_block_state"))), + ParticleTypes.BLOCK, ParticleTypes.FALLING_DUST, ParticleTypes.DUST_PILLAR, ParticleTypes.BLOCK_CRUMBLE, ParticleTypes.BLOCK_MARKER); + registerParticleData(map -> new ColorData( + Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(","))), + ParticleTypes.ENTITY_EFFECT, ParticleTypes.TINTED_LEAVES); + registerParticleData(map -> new JavaTypeData( + ResourceConfigUtils.getAsFloat(map.get("charge"), "charge")), + ParticleTypes.SCULK_CHARGE); + registerParticleData(map -> new JavaTypeData( + ResourceConfigUtils.getAsInt(map.get("shriek"), "shriek")), + ParticleTypes.SHRIEK); + registerParticleData(map -> new DustData( + Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")), + ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")), + ParticleTypes.DUST); + registerParticleData(map -> new DustTransitionData( + Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("from"), "warning.config.function.particle.missing_from").split(",")), + Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("to"), "warning.config.function.particle.missing_to").split(",")), + ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")), + ParticleTypes.DUST_COLOR_TRANSITION); + registerParticleData(map -> new ItemStackData( + new DelayedInitItem(Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("item"), "warning.config.function.particle.missing_item")))), + ParticleTypes.ITEM); + registerParticleData(map -> new VibrationData( + NumberProviders.fromObject(map.getOrDefault("target-x", 0)), + NumberProviders.fromObject(map.getOrDefault("target-y", 0)), + NumberProviders.fromObject(map.getOrDefault("target-z", 0)), + NumberProviders.fromObject(map.getOrDefault("arrival-time", 10))), + ParticleTypes.VIBRATION); + registerParticleData(map -> new TrailData( + NumberProviders.fromObject(map.getOrDefault("target-x", 0)), + NumberProviders.fromObject(map.getOrDefault("target-y", 0)), + NumberProviders.fromObject(map.getOrDefault("target-z", 0)), + Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(",")), + NumberProviders.fromObject(map.getOrDefault("duration", 10))), + ParticleTypes.TRAIL); + } + + public static void registerParticleData(java.util.function.Function, ParticleData> function, Key... types) { + for (Key type : types) { + DATA_TYPES.put(type, function); + } + } + + private final Key particleType; + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final NumberProvider count; + private final NumberProvider xOffset; + private final NumberProvider yOffset; + private final NumberProvider zOffset; + private final NumberProvider speed; + private final ParticleData particleData; + + public ParticleFunction(Key particleType, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider count, + NumberProvider xOffset, NumberProvider yOffset, NumberProvider zOffset, NumberProvider speed, ParticleData particleData, List> predicates) { + super(predicates); + this.particleType = particleType; + this.count = count; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.speed = speed; + this.x = x; + this.y = y; + this.z = z; + this.particleData = particleData; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isPresent()) { + World world = optionalWorldPosition.get().world(); + Position position = new Vec3d(this.x.getDouble(ctx), this.y.getDouble(ctx), this.z.getDouble(ctx)); + world.spawnParticle(position, this.particleType, this.count.getInt(ctx), this.xOffset.getDouble(ctx), this.yOffset.getDouble(ctx), this.zOffset.getDouble(ctx), this.speed.getDouble(ctx), this.particleData, ctx); + } + } + + @Override + public Key type() { + return CommonFunctions.PARTICLE; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Key particleType = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("particle"), "warning.config.function.particle.missing_particle")); + NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); + NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); + NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); + NumberProvider count = NumberProviders.fromObject(arguments.getOrDefault("count", 1)); + NumberProvider xOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-x", 0)); + NumberProvider yOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-y", 0)); + NumberProvider zOffset = NumberProviders.fromObject(arguments.getOrDefault("offset-z", 0)); + NumberProvider speed = NumberProviders.fromObject(arguments.getOrDefault("speed", 0)); + return new ParticleFunction<>(particleType, x, y, z, count, xOffset, yOffset, zOffset, speed, + Optional.ofNullable(ParticleFunction.DATA_TYPES.get(particleType)).map(it -> it.apply(arguments)).orElse(null), getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java index c5fbeae29..b5ee0bbeb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java @@ -1,8 +1,7 @@ package net.momirealms.craftengine.core.plugin.context.function; -import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.block.DelayedInitBlockState; import net.momirealms.craftengine.core.block.UpdateOption; -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; @@ -48,25 +47,6 @@ public class PlaceBlockFunction extends AbstractConditional return CommonFunctions.PLACE_BLOCK; } - public static class DelayedInitBlockState { - private final String state; - private BlockStateWrapper packedBlockState; - - public DelayedInitBlockState(String state) { - this.state = state; - } - - public BlockStateWrapper getState() { - if (this.packedBlockState == null) { - this.packedBlockState = CraftEngine.instance().blockManager().createPackedBlockState(state); - if (this.packedBlockState == null) { - CraftEngine.instance().logger().warn("Could not create block state: " + this.state); - } - } - return this.packedBlockState; - } - } - public static class FactoryImpl extends AbstractFactory { public FactoryImpl(java.util.function.Function, Condition> factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java new file mode 100644 index 000000000..461e838ed --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PotionEffectFunction.java @@ -0,0 +1,69 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.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.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; + +public class PotionEffectFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; + private final Key potionEffectType; + private final NumberProvider duration; + private final NumberProvider amplifier; + private final boolean ambient; + private final boolean particles; + + public PotionEffectFunction(Key potionEffectType, NumberProvider duration, NumberProvider amplifier, boolean ambient, boolean particles, PlayerSelector selector, List> predicates) { + super(predicates); + this.potionEffectType = potionEffectType; + this.duration = duration; + this.amplifier = amplifier; + this.selector = selector; + this.ambient = ambient; + this.particles = particles; + } + + @Override + public void runInternal(CTX ctx) { + if (this.selector == null) { + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { + it.addPotionEffect(this.potionEffectType, this.duration.getInt(ctx), this.amplifier.getInt(ctx), this.ambient, this.particles); + }); + } else { + for (Player target : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(target, ContextHolder.EMPTY)); + target.addPotionEffect(this.potionEffectType, this.duration.getInt(relationalContext), this.amplifier.getInt(relationalContext), this.ambient, this.particles); + } + } + } + + @Override + public Key type() { + return CommonFunctions.POTION_EFFECT; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Key effectType = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("potion-effect"), "warning.config.function.potion_effect.missing_potion_effect")); + NumberProvider duration = NumberProviders.fromObject(arguments.get("duration")); + NumberProvider amplifier = NumberProviders.fromObject(arguments.get("amplifier")); + boolean ambient = (boolean) arguments.getOrDefault("ambient", false); + boolean particles = (boolean) arguments.getOrDefault("particles", true); + return new PotionEffectFunction<>(effectType, duration, amplifier, ambient, particles, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java index fcd05f71a..ebb1705a3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetFoodFunction.java @@ -1,11 +1,12 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.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.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -14,19 +15,28 @@ import java.util.Map; import java.util.Optional; public class SetFoodFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; private final NumberProvider count; private final boolean add; - public SetFoodFunction(NumberProvider count, boolean add, List> predicates) { + public SetFoodFunction(NumberProvider count, boolean add, PlayerSelector selector, List> predicates) { super(predicates); this.count = count; this.add = add; + this.selector = selector; } @Override public void runInternal(CTX ctx) { - Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); - optionalPlayer.ifPresent(player -> player.setFoodLevel(this.add ? player.foodLevel() + this.count.getInt(ctx) : this.count.getInt(ctx))); + if (this.selector == null) { + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + optionalPlayer.ifPresent(player -> player.setFoodLevel(this.add ? player.foodLevel() + this.count.getInt(ctx) : this.count.getInt(ctx))); + } else { + for (Player target : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(target, ContextHolder.EMPTY)); + target.setFoodLevel(this.add ? target.foodLevel() + this.count.getInt(relationalContext) : this.count.getInt(relationalContext)); + } + } } @Override @@ -44,7 +54,7 @@ public class SetFoodFunction extends AbstractConditionalFun public Function create(Map arguments) { Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("food"), "warning.config.function.set_food.missing_food"); boolean add = (boolean) arguments.getOrDefault("add", false); - return new SetFoodFunction<>(NumberProviders.fromObject(value), add, getPredicates(arguments)); + return new SetFoodFunction<>(NumberProviders.fromObject(value), add, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java index 86634543f..7afedc1c5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/SetSaturationFunction.java @@ -1,11 +1,12 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.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.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -14,19 +15,28 @@ import java.util.Map; import java.util.Optional; public class SetSaturationFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; private final NumberProvider count; private final boolean add; - public SetSaturationFunction(NumberProvider count, boolean add, List> predicates) { + public SetSaturationFunction(NumberProvider count, boolean add, PlayerSelector selector, List> predicates) { super(predicates); this.count = count; this.add = add; + this.selector = selector; } @Override public void runInternal(CTX ctx) { - Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); - optionalPlayer.ifPresent(player -> player.setSaturation(this.add ? player.saturation() + this.count.getFloat(ctx) : this.count.getFloat(ctx))); + if (this.selector == null) { + Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); + optionalPlayer.ifPresent(player -> player.setSaturation(this.add ? player.saturation() + this.count.getFloat(ctx) : this.count.getFloat(ctx))); + } else { + for (Player target : this.selector.get(ctx)) { + RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(target, ContextHolder.EMPTY)); + target.setSaturation(this.add ? target.saturation() + this.count.getFloat(relationalContext) : this.count.getFloat(relationalContext)); + } + } } @Override @@ -44,7 +54,7 @@ public class SetSaturationFunction extends AbstractConditio public Function create(Map arguments) { Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("saturation"), "warning.config.function.set_saturation.missing_saturation"); boolean add = (boolean) arguments.getOrDefault("add", false); - return new SetSaturationFunction<>(NumberProviders.fromObject(value), add, getPredicates(arguments)); + return new SetSaturationFunction<>(NumberProviders.fromObject(value), add, PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), getPredicates(arguments)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java index 28900c5a1..43eb8d195 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java @@ -15,7 +15,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -import java.util.Optional; public class TitleFunction extends AbstractConditionalFunction { private final PlayerSelector selector; @@ -38,9 +37,8 @@ public class TitleFunction extends AbstractConditionalFunct @Override public void runInternal(CTX ctx) { - Optional owner = ctx.getOptionalParameter(DirectContextParameters.PLAYER); if (this.selector == null) { - owner.ifPresent(it -> it.sendTitle( + ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> it.sendTitle( AdventureHelper.miniMessage().deserialize(this.main.get(ctx), ctx.tagResolvers()), AdventureHelper.miniMessage().deserialize(this.sub.get(ctx), ctx.tagResolvers()), this.fadeIn.getInt(ctx), this.stay.getInt(ctx), this.fadeOut.getInt(ctx) diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java index 495739c3b..eae49c92b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java @@ -26,7 +26,6 @@ public final class DirectContextParameters { public static final ContextKey LAST_RANDOM = ContextKey.direct("last_random"); public static final ContextKey WORLD = ContextKey.direct("world"); public static final ContextKey> FURNITURE_ITEM = ContextKey.direct("furniture_item"); - public static final ContextKey> CONSUMED_ITEM = ContextKey.direct("consumed_item"); public static final ContextKey> ITEM_IN_HAND = ContextKey.direct("item_in_hand"); public static final ContextKey FALLING_BLOCK = ContextKey.direct("falling_block"); public static final ContextKey EXPLOSION_RADIUS = ContextKey.direct("explosion_radius"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Color.java b/core/src/main/java/net/momirealms/craftengine/core/util/Color.java new file mode 100644 index 000000000..24da61b00 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Color.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.util; + +import java.util.Arrays; + +public class Color { + private static final byte DEFAULT_ALPHA = (byte) 255; + private final byte r; + private final byte g; + private final byte b; + private final byte a; + + public Color(byte r, byte g, byte b, byte a) { + this.b = b; + this.g = g; + this.r = r; + this.a = a; + } + + public Color(byte r, byte g, byte b) { + this(r, g, b, DEFAULT_ALPHA); + } + + public static Color fromString(String[] strings) { + if (strings.length == 3) { + return new Color(Byte.parseByte(strings[0]), Byte.parseByte(strings[1]), Byte.parseByte(strings[2])); + } else if (strings.length == 4) { + return new Color(Byte.parseByte(strings[0]), Byte.parseByte(strings[1]), Byte.parseByte(strings[2]), Byte.parseByte(strings[3])); + } else { + throw new IllegalArgumentException("Invalid color format: " + Arrays.toString(strings)); + } + } + + public byte a() { + return a; + } + + public byte b() { + return b; + } + + public byte g() { + return g; + } + + public byte r() { + return r; + } +} 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 0dacaa8e4..f49424a47 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 @@ -2,10 +2,14 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.particle.ParticleData; +import org.jetbrains.annotations.NotNull; +import javax.annotation.Nullable; import java.nio.file.Path; import java.util.UUID; @@ -43,5 +47,7 @@ public interface World { playBlockSound(location, data.id(), data.volume(), data.pitch()); } + void spawnParticle(Position location, Key particle, int count, double xOffset, double yOffset, double zOffset, double speed, @Nullable ParticleData extraData, @NotNull Context context); + long time(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java new file mode 100644 index 000000000..09a835011 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.block.DelayedInitBlockState; + +public class BlockStateData implements ParticleData { + private final DelayedInitBlockState blockState; + + public BlockStateData(DelayedInitBlockState blockState) { + this.blockState = blockState; + } + + public BlockStateWrapper blockState() { + return blockState.getState(); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/ColorData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ColorData.java new file mode 100644 index 000000000..e2a2b295d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ColorData.java @@ -0,0 +1,15 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.util.Color; + +public class ColorData implements ParticleData { + private final Color color; + + public ColorData(Color color) { + this.color = color; + } + + public Color color() { + return color; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustData.java new file mode 100644 index 000000000..a00b2cc72 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustData.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.util.Color; + +public class DustData implements ParticleData { + private final Color color; + private final float size; + + public DustData(Color color, float size) { + this.color = color; + this.size = size; + } + + public Color color() { + return color; + } + + public float size() { + return size; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustTransitionData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustTransitionData.java new file mode 100644 index 000000000..c4edbd9e2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/DustTransitionData.java @@ -0,0 +1,27 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.util.Color; + +public class DustTransitionData implements ParticleData { + private final Color from; + private final Color to; + private final float size; + + public DustTransitionData(Color from, Color to, float size) { + this.from = from; + this.to = to; + this.size = size; + } + + public Color from() { + return from; + } + + public Color to() { + return to; + } + + public float size() { + return size; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java new file mode 100644 index 000000000..17eaa1fb9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.item.DelayedInitItem; +import net.momirealms.craftengine.core.item.Item; + +public class ItemStackData implements ParticleData { + private final DelayedInitItem item; + + public ItemStackData(DelayedInitItem item) { + this.item = item; + } + + public Item item() { + return item.getItem(); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/JavaTypeData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/JavaTypeData.java new file mode 100644 index 000000000..052e01f3d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/JavaTypeData.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.world.particle; + +public class JavaTypeData implements ParticleData { + private final Object data; + + public JavaTypeData(Object data) { + this.data = data; + } + + public Object data() { + return data; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleData.java new file mode 100644 index 000000000..dfb22cfc3 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleData.java @@ -0,0 +1,4 @@ +package net.momirealms.craftengine.core.world.particle; + +public interface ParticleData { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleTypes.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleTypes.java new file mode 100644 index 000000000..7bd64ca92 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ParticleTypes.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.util.Key; + +public final class ParticleTypes { + private ParticleTypes() {} + + public static final Key ENTITY_EFFECT = Key.of("entity_effect"); + public static final Key DUST = Key.of("dust"); + public static final Key ITEM = Key.of("item"); + public static final Key BLOCK = Key.of("block"); + public static final Key FALLING_DUST = Key.of("falling_dust"); + public static final Key DUST_COLOR_TRANSITION = Key.of("dust_color_transition"); + public static final Key SCULK_CHARGE = Key.of("sculk_charge"); + public static final Key SHRIEK = Key.of("shriek"); + public static final Key TINTED_LEAVES = Key.of("tinted_leaves"); + public static final Key DUST_PILLAR = Key.of("dust_pillar"); + public static final Key BLOCK_CRUMBLE = Key.of("block_crumble"); + public static final Key BLOCK_MARKER = Key.of("block_marker"); + public static final Key TRAIL = Key.of("trail"); + public static final Key VIBRATION = Key.of("vibration"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/TrailData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/TrailData.java new file mode 100644 index 000000000..8ee59c346 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/TrailData.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.util.Color; + +public class TrailData implements ParticleData { + private final NumberProvider targetX; + private final NumberProvider targetY; + private final NumberProvider targetZ; + private final Color color; + private final NumberProvider duration; + + public TrailData(NumberProvider targetX, NumberProvider targetY, NumberProvider targetZ, Color color, NumberProvider duration) { + this.color = color; + this.duration = duration; + this.targetX = targetX; + this.targetY = targetY; + this.targetZ = targetZ; + } + + public Color color() { + return color; + } + + public NumberProvider duration() { + return duration; + } + + public NumberProvider targetX() { + return targetX; + } + + public NumberProvider targetY() { + return targetY; + } + + public NumberProvider targetZ() { + return targetZ; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/VibrationData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/VibrationData.java new file mode 100644 index 000000000..1f8da18a2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/VibrationData.java @@ -0,0 +1,33 @@ +package net.momirealms.craftengine.core.world.particle; + +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; + +public class VibrationData implements ParticleData { + private final NumberProvider destinationX; + private final NumberProvider destinationY; + private final NumberProvider destinationZ; + private final NumberProvider arrivalTime; + + public VibrationData(NumberProvider destinationX, NumberProvider destinationY, NumberProvider destinationZ, NumberProvider arrivalTime) { + this.arrivalTime = arrivalTime; + this.destinationX = destinationX; + this.destinationY = destinationY; + this.destinationZ = destinationZ; + } + + public NumberProvider arrivalTime() { + return arrivalTime; + } + + public NumberProvider destinationX() { + return destinationX; + } + + public NumberProvider destinationY() { + return destinationY; + } + + public NumberProvider destinationZ() { + return destinationZ; + } +}