From 3af6f31585f769e02e2dc17e5505185bea4b6a34 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 13:45:51 -0700 Subject: [PATCH 01/34] build.gradle.kts - update SKR --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index b26abc5cd..9cc70d6e4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -46,7 +46,7 @@ dependencies { compileOnly("com.github.SkriptLang:Skript:2.15.0") // SkriptRegistration - implementation("com.github.ShaneBeee:SkriptRegistration:1.2.0") + implementation("com.github.ShaneBeee:SkriptRegistration:1.4.0") // commons-io compileOnly("commons-io:commons-io:2.14.0") From 960c72a9c2dd78cd83d01a39da501092454ae1aa Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 13:49:31 -0700 Subject: [PATCH 02/34] Switch to using SKR Scheduling --- .../java/com/shanebeestudios/skbee/SkBee.java | 4 +- .../skbee/api/bound/BoundConfig.java | 4 +- .../skbee/api/fastboard/FastBoardManager.java | 2 +- .../api/listener/BoundBorderListener.java | 2 +- .../skbee/api/region/RegionUtils.java | 46 -------- .../skbee/api/region/TaskUtils.java | 108 ------------------ .../skbee/api/region/package-info.java | 4 - .../api/region/scheduler/FoliaScheduler.java | 108 ------------------ .../skbee/api/region/scheduler/Scheduler.java | 68 ----------- .../api/region/scheduler/SpigotScheduler.java | 47 -------- .../api/region/scheduler/package-info.java | 5 - .../api/region/scheduler/task/FoliaTask.java | 32 ------ .../api/region/scheduler/task/SpigotTask.java | 31 ----- .../skbee/api/region/scheduler/task/Task.java | 29 ----- .../skbee/api/util/update/UpdateChecker.java | 2 +- .../skbee/api/worldgen/BeeWorldCreator.java | 2 +- .../sections/SecProfileComponent.java | 2 +- .../other/conditions/CondIsOwnedByRegion.java | 2 +- .../other/expressions/ExprTaskID.java | 2 +- .../other/sections/SecRunTaskLater.java | 6 +- .../other/sections/SecWhileRunnable.java | 6 +- .../skbee/elements/registry/type/Types.java | 2 +- .../skbee/elements/testing/type/Types.java | 2 +- 23 files changed, 19 insertions(+), 497 deletions(-) delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/region/RegionUtils.java delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/region/TaskUtils.java delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/region/package-info.java delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/region/scheduler/FoliaScheduler.java delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/region/scheduler/Scheduler.java delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/region/scheduler/SpigotScheduler.java delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/region/scheduler/package-info.java delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/FoliaTask.java delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/SpigotTask.java delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/Task.java diff --git a/src/main/java/com/shanebeestudios/skbee/SkBee.java b/src/main/java/com/shanebeestudios/skbee/SkBee.java index 5f0906f9f..8c1e4b232 100644 --- a/src/main/java/com/shanebeestudios/skbee/SkBee.java +++ b/src/main/java/com/shanebeestudios/skbee/SkBee.java @@ -2,17 +2,17 @@ import ch.njol.skript.test.runner.TestMode; import ch.njol.skript.util.Version; +import com.github.shanebeee.skr.scheduling.TaskUtils; import com.shanebeestudios.skbee.api.bound.Bound; import com.shanebeestudios.skbee.api.bound.BoundConfig; import com.shanebeestudios.skbee.api.command.SkBeeInfo; -import com.shanebeestudios.skbee.api.region.TaskUtils; import com.shanebeestudios.skbee.api.structure.StructureManager; import com.shanebeestudios.skbee.api.util.Util; import com.shanebeestudios.skbee.api.util.update.UpdateChecker; +import com.shanebeestudios.skbee.api.worldgen.BeeWorldConfig; import com.shanebeestudios.skbee.api.wrapper.LazyLocation; import com.shanebeestudios.skbee.config.Config; import com.shanebeestudios.skbee.config.SkBeeMetrics; -import com.shanebeestudios.skbee.api.worldgen.BeeWorldConfig; import com.shanebeestudios.vf.api.VirtualFurnaceAPI; import org.bukkit.Bukkit; import org.bukkit.configuration.serialization.ConfigurationSerialization; diff --git a/src/main/java/com/shanebeestudios/skbee/api/bound/BoundConfig.java b/src/main/java/com/shanebeestudios/skbee/api/bound/BoundConfig.java index 47726c4d5..d059f5d32 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/bound/BoundConfig.java +++ b/src/main/java/com/shanebeestudios/skbee/api/bound/BoundConfig.java @@ -3,8 +3,8 @@ import ch.njol.skript.Skript; import ch.njol.skript.test.runner.TestMode; import com.shanebeestudios.skbee.SkBee; -import com.shanebeestudios.skbee.api.region.TaskUtils; -import com.shanebeestudios.skbee.api.region.scheduler.Scheduler; +import com.github.shanebeee.skr.scheduling.TaskUtils; +import com.github.shanebeee.skr.scheduling.scheduler.Scheduler; import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.World; diff --git a/src/main/java/com/shanebeestudios/skbee/api/fastboard/FastBoardManager.java b/src/main/java/com/shanebeestudios/skbee/api/fastboard/FastBoardManager.java index c7d49aa3d..35783c01a 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/fastboard/FastBoardManager.java +++ b/src/main/java/com/shanebeestudios/skbee/api/fastboard/FastBoardManager.java @@ -1,7 +1,7 @@ package com.shanebeestudios.skbee.api.fastboard; import com.shanebeestudios.skbee.SkBee; -import com.shanebeestudios.skbee.api.region.TaskUtils; +import com.github.shanebeee.skr.scheduling.TaskUtils; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; diff --git a/src/main/java/com/shanebeestudios/skbee/api/listener/BoundBorderListener.java b/src/main/java/com/shanebeestudios/skbee/api/listener/BoundBorderListener.java index 87596b89f..7dd961fd2 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/listener/BoundBorderListener.java +++ b/src/main/java/com/shanebeestudios/skbee/api/listener/BoundBorderListener.java @@ -5,7 +5,7 @@ import com.shanebeestudios.skbee.api.bound.BoundConfig; import com.shanebeestudios.skbee.api.event.bound.BoundEnterEvent; import com.shanebeestudios.skbee.api.event.bound.BoundExitEvent; -import com.shanebeestudios.skbee.api.region.TaskUtils; +import com.github.shanebeee.skr.scheduling.TaskUtils; import com.shanebeestudios.skbee.config.Config; import org.bukkit.Bukkit; import org.bukkit.Location; diff --git a/src/main/java/com/shanebeestudios/skbee/api/region/RegionUtils.java b/src/main/java/com/shanebeestudios/skbee/api/region/RegionUtils.java deleted file mode 100644 index 44f4c7732..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/region/RegionUtils.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.shanebeestudios.skbee.api.region; - -import com.shanebeestudios.skbee.api.util.Util; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.entity.Entity; - -/** - * Utility methods for Folia's threaded regions - */ -public class RegionUtils { - - /** - * Check if an object is owned by the curent region - *

Currently accepts Block/Location/Entity. - * If not running Folia this will just return true

- * - * @param object Object to check - * @return Whether object is running in the current region - */ - public static boolean isOwnedByCurrentRegion(Object object) { - if (!Util.IS_RUNNING_FOLIA) return true; - - if (object instanceof Block block) return Bukkit.isOwnedByCurrentRegion(block); - else if (object instanceof Entity entity) return Bukkit.isOwnedByCurrentRegion(entity); - else if (object instanceof Location location) return Bukkit.isOwnedByCurrentRegion(location); - return true; - } - - /** - * Check if a chunk location is owned by a current region - *

If not running Folia this will just return true

- * - * @param world World of chunk - * @param chunkX Chunk X of chunk - * @param chunkZ Chunk Z of chunk - * @return Whether chunk is running in the current region - */ - public static boolean isOwnedByCurrentRegion(World world, int chunkX, int chunkZ) { - if (!Util.IS_RUNNING_FOLIA) return true; - return Bukkit.isOwnedByCurrentRegion(world, chunkX, chunkZ); - } - -} diff --git a/src/main/java/com/shanebeestudios/skbee/api/region/TaskUtils.java b/src/main/java/com/shanebeestudios/skbee/api/region/TaskUtils.java deleted file mode 100644 index fd450e9c2..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/region/TaskUtils.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.shanebeestudios.skbee.api.region; - -import com.shanebeestudios.skbee.api.region.scheduler.FoliaScheduler; -import com.shanebeestudios.skbee.api.region.scheduler.Scheduler; -import com.shanebeestudios.skbee.api.region.scheduler.SpigotScheduler; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; - -/** - * Utility class for creating {@link Scheduler Schedulers} - *

Intialize before use, {@link #initialize(Plugin, boolean)}

- *

If initialized with `useFoliaSchedulers=true`, will return a {@link FoliaScheduler} - * else will return a {@link SpigotScheduler}

- */ -public class TaskUtils { - - private static Plugin plugin; - private static boolean useFoliaSchedulers; - - /** - * Initialize schedulers - * - * @param plugin Plugin to reference for tasks - * @param useFoliaSchedulers Whether to use Paper/Folia schedulers else Bukkit schedulers - */ - public static void initialize(@NotNull Plugin plugin, boolean useFoliaSchedulers) { - if (TaskUtils.plugin != null) { - throw new IllegalStateException("TaskUtils already initialized!"); - } - TaskUtils.plugin = plugin; - TaskUtils.useFoliaSchedulers = useFoliaSchedulers; - } - - /** - * Get the plugin that these schedulers will use - * - * @return Plugin for schedulers - */ - public static Plugin getPlugin() { - pluginCheck(); - return plugin; - } - - /** - * Get a global scheduler - *

This is used for global World/Server tasks which don't require regions

- *

If running Spigot or Paper (with Paper schedulers disabled) this will use a normal Bukkit Scheduler

- * - * @return Global scheduler - */ - public static Scheduler getGlobalScheduler() { - pluginCheck(); - if (useFoliaSchedulers) return FoliaScheduler.getGlobalScheduler(); - return new SpigotScheduler(); - } - - /** - * Get a regional scheduler based on a location - *

This is used for scheduling tasks at a specific location

- *

If running Spigot or Paper (with Paper schedulers disabled) this will use a normal Bukkit Scheduler

- * - * @param location Location to grab region from - * @return Region scheduler - */ - public static Scheduler getRegionalScheduler(Location location) { - pluginCheck(); - if (useFoliaSchedulers) return FoliaScheduler.getRegionalScheduler(location); - return new SpigotScheduler(); - } - - /** - * Get an entity scheduler - *

This is used for scheduling tasks linked to an entity - * The tasks will move with the entity to whatever region they're in

- *

If running Spigot or Paper (with Paper schedulers disabled) this will use a normal Bukkit Scheduler

- * - * @param entity Entity to attach scheduler to - * @return Entity scheduler - */ - public static Scheduler getEntityScheduler(Entity entity) { - pluginCheck(); - if (useFoliaSchedulers) return FoliaScheduler.getEntityScheduler(entity); - return new SpigotScheduler(); - } - - /** - * Cancel all currently running tasks - */ - public static void cancelTasks() { - pluginCheck(); - if (useFoliaSchedulers) { - Bukkit.getGlobalRegionScheduler().cancelTasks(plugin); - Bukkit.getAsyncScheduler().cancelTasks(plugin); - } else { - Bukkit.getScheduler().cancelTasks(plugin); - } - } - - private static void pluginCheck() { - if (plugin == null) { - throw new IllegalStateException("TaskUtils has not been initialized!"); - } - } - -} diff --git a/src/main/java/com/shanebeestudios/skbee/api/region/package-info.java b/src/main/java/com/shanebeestudios/skbee/api/region/package-info.java deleted file mode 100644 index d76bf6017..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/region/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * General classes related to region based schedulers - */ -package com.shanebeestudios.skbee.api.region; diff --git a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/FoliaScheduler.java b/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/FoliaScheduler.java deleted file mode 100644 index 081b103f4..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/FoliaScheduler.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.shanebeestudios.skbee.api.region.scheduler; - -import com.shanebeestudios.skbee.api.region.TaskUtils; -import com.shanebeestudios.skbee.api.region.scheduler.task.FoliaTask; -import com.shanebeestudios.skbee.api.region.scheduler.task.Task; -import io.papermc.paper.threadedregions.scheduler.AsyncScheduler; -import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler; -import io.papermc.paper.threadedregions.scheduler.RegionScheduler; -import io.papermc.paper.threadedregions.scheduler.ScheduledTask; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.TimeUnit; - -/** - * A {@link Scheduler} based on Folia/Paper regionalized schedulers - */ -public class FoliaScheduler implements Scheduler { - - private static final GlobalRegionScheduler GLOBAL_SCHEDULER = Bukkit.getGlobalRegionScheduler(); - private static final RegionScheduler REGION_SCHEDULER = Bukkit.getRegionScheduler(); - private static final AsyncScheduler ASYNC_SCHEDULER = Bukkit.getAsyncScheduler(); - - public static FoliaScheduler getGlobalScheduler() { - return new FoliaScheduler(null, null); - } - - public static FoliaScheduler getRegionalScheduler(Location location) { - return new FoliaScheduler(null, location); - } - - public static FoliaScheduler getEntityScheduler(Entity entity) { - return new FoliaScheduler(entity, null); - } - - private final @Nullable Entity entity; - private final @Nullable Location location; - - public FoliaScheduler(@Nullable Entity entity, @Nullable Location location) { - this.entity = entity; - this.location = location; - } - - @Override - public FoliaTask runTask(Runnable task) { - ScheduledTask scheduledTask; - if (this.entity != null) { - scheduledTask = this.entity.getScheduler().run(TaskUtils.getPlugin(), t -> task.run(), null); - } else if (this.location != null) { - scheduledTask = REGION_SCHEDULER.run(TaskUtils.getPlugin(), this.location, t -> task.run()); - } else { - scheduledTask = GLOBAL_SCHEDULER.run(TaskUtils.getPlugin(), t -> task.run()); - } - return new FoliaTask(scheduledTask); - } - - @Override - public FoliaTask runTaskAsync(Runnable task) { - ScheduledTask scheduledTask = ASYNC_SCHEDULER.runNow(TaskUtils.getPlugin(), t -> task.run()); - return new FoliaTask(scheduledTask); - } - - @Override - public FoliaTask runTaskLater(Runnable task, long delay) { - if (delay <= 0) delay = 1; - ScheduledTask scheduledTask; - if (this.entity != null) { - scheduledTask = this.entity.getScheduler().runDelayed(TaskUtils.getPlugin(), t -> task.run(), null, delay); - } else if (this.location != null) { - scheduledTask = REGION_SCHEDULER.runDelayed(TaskUtils.getPlugin(), this.location, t -> task.run(), delay); - } else { - scheduledTask = GLOBAL_SCHEDULER.runDelayed(TaskUtils.getPlugin(), t -> task.run(), delay); - } - return new FoliaTask(scheduledTask); - } - - @Override - public Task runTaskLaterAsync(Runnable task, long delay) { - if (delay <= 0) delay = 1; - ScheduledTask scheduledTask = ASYNC_SCHEDULER.runDelayed(TaskUtils.getPlugin(), t -> task.run(), delay * 50, TimeUnit.MILLISECONDS); - return new FoliaTask(scheduledTask); - } - - @Override - public FoliaTask runTaskTimer(Runnable task, long delay, long period) { - if (delay <= 0) delay = 1; - ScheduledTask scheduledTask; - if (this.entity != null) { - scheduledTask = this.entity.getScheduler().runAtFixedRate(TaskUtils.getPlugin(), t -> task.run(), null, delay, period); - } else if (this.location != null) { - scheduledTask = REGION_SCHEDULER.runAtFixedRate(TaskUtils.getPlugin(), this.location, t -> task.run(), delay, period); - } else { - scheduledTask = GLOBAL_SCHEDULER.runAtFixedRate(TaskUtils.getPlugin(), t -> task.run(), delay, period); - } - return new FoliaTask(scheduledTask); - } - - @Override - public Task runTaskTimerAsync(Runnable task, long delay, long period) { - if (delay <= 0) delay = 1; - ScheduledTask scheduledTask = ASYNC_SCHEDULER.runAtFixedRate(TaskUtils.getPlugin(), t -> task.run(), - delay * 50, period * 50, TimeUnit.MILLISECONDS); - return new FoliaTask(scheduledTask); - } - -} diff --git a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/Scheduler.java b/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/Scheduler.java deleted file mode 100644 index 5fa064031..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/Scheduler.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.shanebeestudios.skbee.api.region.scheduler; - -import com.shanebeestudios.skbee.api.region.scheduler.task.Task; - -/** - * Scheduler for scheduling tasks - *

Changes based on Spigot/Paper vs. Folia usage

- * - * @param Underlying task return type - */ -@SuppressWarnings({"unused", "UnusedReturnValue"}) -public interface Scheduler { - - /** - * Run a task on the next tick - * - * @param task Task to run - * @return Instance of scheduler - */ - Task runTask(Runnable task); - - /** - * Run an async task on the next tick - * - * @param task Task to run - * @return Instance of scheduler - */ - Task runTaskAsync(Runnable task); - - /** - * Run a task at a later time - * - * @param task Task to run - * @param delay Delay in ticks - * @return Instance of scheduler - */ - Task runTaskLater(Runnable task, long delay); - - /** - * Run an async task at a later time - * - * @param task Task to run - * @param delay Delay in ticks - * @return Instance of scheduler - */ - Task runTaskLaterAsync(Runnable task, long delay); - - /** - * Run a repeating task - * - * @param task Task to run - * @param delay Delay in ticks to start - * @param period Period in ticks to repeat - * @return Instance of scheduler - */ - Task runTaskTimer(Runnable task, long delay, long period); - - /** - * Run an async repeating task - * - * @param task Task to run - * @param delay Delay in ticks to start - * @param period Period in ticks to repeat - * @return Instance of scheduler - */ - Task runTaskTimerAsync(Runnable task, long delay, long period); - -} diff --git a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/SpigotScheduler.java b/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/SpigotScheduler.java deleted file mode 100644 index 8df3227b9..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/SpigotScheduler.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.shanebeestudios.skbee.api.region.scheduler; - -import com.shanebeestudios.skbee.api.region.TaskUtils; -import com.shanebeestudios.skbee.api.region.scheduler.task.SpigotTask; -import com.shanebeestudios.skbee.api.region.scheduler.task.Task; -import org.bukkit.Bukkit; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; - -/** - * A {@link Scheduler} using the {@link BukkitScheduler} - */ -public class SpigotScheduler implements Scheduler { - - private static final BukkitScheduler SCHEDULER = Bukkit.getScheduler(); - - @Override - public SpigotTask runTask(Runnable task) { - return new SpigotTask(SCHEDULER.runTask(TaskUtils.getPlugin(), task)); - } - - @Override - public SpigotTask runTaskAsync(Runnable task) { - return new SpigotTask(SCHEDULER.runTaskAsynchronously(TaskUtils.getPlugin(), task)); - } - - @Override - public SpigotTask runTaskLater(Runnable task, long delay) { - return new SpigotTask(SCHEDULER.runTaskLater(TaskUtils.getPlugin(), task, delay)); - } - - @Override - public Task runTaskLaterAsync(Runnable task, long delay) { - return new SpigotTask(SCHEDULER.runTaskLaterAsynchronously(TaskUtils.getPlugin(), task, delay)); - } - - @Override - public SpigotTask runTaskTimer(Runnable task, long delay, long period) { - return new SpigotTask(SCHEDULER.runTaskTimer(TaskUtils.getPlugin(), task, delay, period)); - } - - @Override - public Task runTaskTimerAsync(Runnable task, long delay, long period) { - return new SpigotTask(SCHEDULER.runTaskTimerAsynchronously(TaskUtils.getPlugin(), task, delay, period)); - } - -} diff --git a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/package-info.java b/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/package-info.java deleted file mode 100644 index bd9a49a63..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Utility classes for Schedulers - *

Things will differ based on Spigot/Paper vs. Folia servers

- */ -package com.shanebeestudios.skbee.api.region.scheduler; diff --git a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/FoliaTask.java b/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/FoliaTask.java deleted file mode 100644 index 62f93c089..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/FoliaTask.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.shanebeestudios.skbee.api.region.scheduler.task; - -import io.papermc.paper.threadedregions.scheduler.ScheduledTask; - -/** - * Task wrapper for Folia's {@link ScheduledTask} - */ -public class FoliaTask implements Task { - - private final ScheduledTask scheduledTask; - - public FoliaTask(ScheduledTask scheduledTask) { - this.scheduledTask = scheduledTask; - } - - @Override - public void cancel() { - this.scheduledTask.cancel(); - } - - @Override - public boolean isCancelled() { - return this.scheduledTask.isCancelled(); - } - - @Override - public int getTaskId() { - // ScheduledTask doesn't have an ID?!?!? - return -1; - } - -} diff --git a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/SpigotTask.java b/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/SpigotTask.java deleted file mode 100644 index 6e428f1d8..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/SpigotTask.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.shanebeestudios.skbee.api.region.scheduler.task; - -import org.bukkit.scheduler.BukkitTask; - -/** - * Task wrapper for Bukkit's {@link BukkitTask} - */ -public class SpigotTask implements Task { - - private final BukkitTask bukkitTask; - - public SpigotTask(BukkitTask bukkitTask) { - this.bukkitTask = bukkitTask; - } - - @Override - public void cancel() { - this.bukkitTask.cancel(); - } - - @Override - public boolean isCancelled() { - return this.bukkitTask.isCancelled(); - } - - @Override - public int getTaskId() { - return this.bukkitTask.getTaskId(); - } - -} diff --git a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/Task.java b/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/Task.java deleted file mode 100644 index e89b023ba..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/region/scheduler/task/Task.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.shanebeestudios.skbee.api.region.scheduler.task; - -/** - * Base task to be implemented by server tasks - * - * @param Task type - */ -public interface Task { - - /** - * Cancel this task - */ - void cancel(); - - /** - * Check if this task has been canaclled - * - * @return Whether this task has been cancelled - */ - boolean isCancelled(); - - /** - * Get the ID of this task - * - * @return ID of this task - */ - int getTaskId(); - -} diff --git a/src/main/java/com/shanebeestudios/skbee/api/util/update/UpdateChecker.java b/src/main/java/com/shanebeestudios/skbee/api/util/update/UpdateChecker.java index fda9c1720..a5fa34128 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/util/update/UpdateChecker.java +++ b/src/main/java/com/shanebeestudios/skbee/api/util/update/UpdateChecker.java @@ -6,7 +6,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.shanebeestudios.skbee.SkBee; -import com.shanebeestudios.skbee.api.region.TaskUtils; +import com.github.shanebeee.skr.scheduling.TaskUtils; import com.shanebeestudios.skbee.api.util.Util; import com.shanebeestudios.skbee.config.Config; import org.bukkit.Bukkit; diff --git a/src/main/java/com/shanebeestudios/skbee/api/worldgen/BeeWorldCreator.java b/src/main/java/com/shanebeestudios/skbee/api/worldgen/BeeWorldCreator.java index 9cfc49c8a..09235b55e 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/worldgen/BeeWorldCreator.java +++ b/src/main/java/com/shanebeestudios/skbee/api/worldgen/BeeWorldCreator.java @@ -2,7 +2,7 @@ import ch.njol.skript.Skript; import com.shanebeestudios.skbee.SkBee; -import com.shanebeestudios.skbee.api.region.TaskUtils; +import com.github.shanebeee.skr.scheduling.TaskUtils; import com.shanebeestudios.skbee.api.util.Util; import com.shanebeestudios.skbee.api.util.legacy.LegacyUtils; import io.papermc.paper.math.FinePosition; diff --git a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecProfileComponent.java b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecProfileComponent.java index 286f635db..8d00ed388 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecProfileComponent.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/itemcomponent/sections/SecProfileComponent.java @@ -8,7 +8,7 @@ import ch.njol.util.Kleenean; import com.destroystokyo.paper.profile.ProfileProperty; import com.github.shanebeee.skr.Registration; -import com.shanebeestudios.skbee.api.region.TaskUtils; +import com.github.shanebeee.skr.scheduling.TaskUtils; import com.shanebeestudios.skbee.api.skript.base.Section; import com.shanebeestudios.skbee.api.util.ItemComponentUtils; import com.github.shanebeee.skr.skript.SimpleEntryValidator; diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/conditions/CondIsOwnedByRegion.java b/src/main/java/com/shanebeestudios/skbee/elements/other/conditions/CondIsOwnedByRegion.java index 288c4252b..4812ae86a 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/conditions/CondIsOwnedByRegion.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/conditions/CondIsOwnedByRegion.java @@ -4,7 +4,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.SyntaxStringBuilder; import ch.njol.util.Kleenean; -import com.shanebeestudios.skbee.api.region.RegionUtils; +import com.github.shanebeee.skr.scheduling.RegionUtils; import com.github.shanebeee.skr.Registration; import com.shanebeestudios.skbee.api.skript.base.Condition; import org.bukkit.World; diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprTaskID.java b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprTaskID.java index 6d3183ef3..f4daf0b14 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprTaskID.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprTaskID.java @@ -5,7 +5,7 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; -import com.shanebeestudios.skbee.api.region.scheduler.task.Task; +import com.github.shanebeee.skr.scheduling.scheduler.task.Task; import com.github.shanebeee.skr.Registration; import com.shanebeestudios.skbee.elements.other.sections.SecRunTaskLater; import org.bukkit.event.Event; diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecRunTaskLater.java b/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecRunTaskLater.java index b0835be0b..92bf3b7b1 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecRunTaskLater.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecRunTaskLater.java @@ -12,9 +12,9 @@ import ch.njol.skript.util.Timespan; import ch.njol.skript.variables.Variables; import ch.njol.util.Kleenean; -import com.shanebeestudios.skbee.api.region.TaskUtils; -import com.shanebeestudios.skbee.api.region.scheduler.Scheduler; -import com.shanebeestudios.skbee.api.region.scheduler.task.Task; +import com.github.shanebeee.skr.scheduling.TaskUtils; +import com.github.shanebeee.skr.scheduling.scheduler.Scheduler; +import com.github.shanebeee.skr.scheduling.scheduler.task.Task; import com.github.shanebeee.skr.Registration; import com.shanebeestudios.skbee.config.SkBeeMetrics; import org.bukkit.Location; diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecWhileRunnable.java b/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecWhileRunnable.java index 46c4cf014..37200a5d4 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecWhileRunnable.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecWhileRunnable.java @@ -11,9 +11,9 @@ import ch.njol.skript.util.Timespan; import ch.njol.skript.variables.Variables; import ch.njol.util.Kleenean; -import com.shanebeestudios.skbee.api.region.TaskUtils; -import com.shanebeestudios.skbee.api.region.scheduler.Scheduler; -import com.shanebeestudios.skbee.api.region.scheduler.task.Task; +import com.github.shanebeee.skr.scheduling.TaskUtils; +import com.github.shanebeee.skr.scheduling.scheduler.Scheduler; +import com.github.shanebeee.skr.scheduling.scheduler.task.Task; import com.github.shanebeee.skr.Registration; import com.shanebeestudios.skbee.config.SkBeeMetrics; import org.bukkit.Location; diff --git a/src/main/java/com/shanebeestudios/skbee/elements/registry/type/Types.java b/src/main/java/com/shanebeestudios/skbee/elements/registry/type/Types.java index fc903ae3c..295d8f951 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/registry/type/Types.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/registry/type/Types.java @@ -4,7 +4,7 @@ import ch.njol.skript.lang.ParseContext; import ch.njol.skript.registrations.Classes; import com.github.shanebeee.skr.Registration; -import com.shanebeestudios.skbee.api.region.TaskUtils; +import com.github.shanebeee.skr.scheduling.TaskUtils; import com.shanebeestudios.skbee.api.registry.RegistryHolders; import com.shanebeestudios.skbee.api.util.Util; import io.papermc.paper.registry.RegistryKey; diff --git a/src/main/java/com/shanebeestudios/skbee/elements/testing/type/Types.java b/src/main/java/com/shanebeestudios/skbee/elements/testing/type/Types.java index 6ecdb96d5..f3672e220 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/testing/type/Types.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/testing/type/Types.java @@ -5,7 +5,7 @@ import ch.njol.skript.variables.Variables; import ch.njol.skript.variables.VariablesStorage; import com.shanebeestudios.skbee.api.reflection.ReflectionUtils; -import com.shanebeestudios.skbee.api.region.TaskUtils; +import com.github.shanebeee.skr.scheduling.TaskUtils; import com.github.shanebeee.skr.Registration; import com.shanebeestudios.skbee.api.util.Util; From 6b99b66bbad64b7fa0f92a0f1992bd0c742b5b5a Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 14:15:08 -0700 Subject: [PATCH 03/34] BlockEvents - add event-yield to block explode event --- .../skbee/elements/other/events/other/BlockEvents.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/BlockEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/BlockEvents.java index 8273dcc69..0f21fc106 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/BlockEvents.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/BlockEvents.java @@ -82,8 +82,14 @@ public static void register(Registration reg) { } }) .register(); + reg.newEventValue(BlockExplodeEvent.class, Number.class) + .description("Represents the percentage of blocks to drop from this explosion.") + .patterns("yield") + .converter(BlockExplodeEvent::getYield) + .changer(Changer.ChangeMode.SET, (event, value) -> event.setYield(value.floatValue())) + .register(); reg.newEventValue(BlockExplodeEvent.class, Block[].class) - .description("The blocks which exploded.") + .description("Represents the blocks which exploded.") .patterns("exploded-blocks") .converter(from -> from.blockList().toArray(new Block[0])) .changer(Changer.ChangeMode.SET, (event, value) -> { From b0d566cfd9a3128f09add612856157a51f1a2e58 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 15:24:15 -0700 Subject: [PATCH 04/34] Structure - add structure types --- .../skbee/elements/structure/type/Types.java | 26 ++++++++++++++++++- src/main/resources/lang/english.lang | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/structure/type/Types.java b/src/main/java/com/shanebeestudios/skbee/elements/structure/type/Types.java index 0e9542e2e..94674e4ff 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/structure/type/Types.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/structure/type/Types.java @@ -5,13 +5,17 @@ import ch.njol.skript.lang.ParseContext; import ch.njol.skript.registrations.Classes; import ch.njol.util.coll.CollectionUtils; -import com.shanebeestudios.skbee.SkBee; import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.SkBee; import com.shanebeestudios.skbee.api.structure.StructureManager; import com.shanebeestudios.skbee.api.structure.StructureWrapper; +import com.shanebeestudios.skbee.api.util.Util; +import io.papermc.paper.registry.RegistryKey; import org.bukkit.Bukkit; import org.bukkit.block.structure.Mirror; import org.bukkit.block.structure.StructureRotation; +import org.bukkit.generator.structure.Structure; +import org.bukkit.generator.structure.StructureType; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -91,6 +95,26 @@ public void change(StructureWrapper[] what, Object @Nullable [] delta, ChangeMod .since("1.12.0") .register(); } + + if (Classes.getExactClassInfo(Structure.class) == null) { + reg.newRegistryType(RegistryKey.STRUCTURE, Structure.class, "structure") + .name("Structure - Structure") + .user("structures?") + .description("Represents a structure that can be found in the world, such as a plains village and a mineshaft.", + Util.AUTO_GEN_NOTE) + .since("INSERT VERSION") + .register(); + } + + if (Classes.getExactClassInfo(StructureType.class) == null && Classes.getClassInfoNoError("structuretype") == null) { + reg.newRegistryType(RegistryKey.STRUCTURE_TYPE, StructureType.class, "structuretype") + .name("Structure - Structure Type") + .user("structure ?types?") + .description("Represents the different types of structures that can be found in the world, such as mineshafts, jigsaw, and swamp huts.", + "Requires Skript 2.16+", Util.AUTO_GEN_NOTE) + .since("INSERT VERSION") + .register(); + } } } diff --git a/src/main/resources/lang/english.lang b/src/main/resources/lang/english.lang index f849b90c4..ac01ab0c2 100644 --- a/src/main/resources/lang/english.lang +++ b/src/main/resources/lang/english.lang @@ -83,8 +83,10 @@ types: signedmessage: signed message¦s spellcasterspell: spell¦s statistic: statistic¦s + structure: structure¦s structurerotation: structure rotation¦s structuretemplate: structure template¦s + structuretype: structure type¦s tagresolver: tag resolver¦s tagkey: tag key¦s team: team¦s From 65f747df6af12ffff9f0bef61d56f9055366088e Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 15:29:11 -0700 Subject: [PATCH 05/34] SecStructureLocate - new --- .../StructureElementRegistration.java | 4 + .../sections/SecStructureLocate.java | 152 ++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 src/main/java/com/shanebeestudios/skbee/elements/structure/sections/SecStructureLocate.java diff --git a/src/main/java/com/shanebeestudios/skbee/elements/structure/StructureElementRegistration.java b/src/main/java/com/shanebeestudios/skbee/elements/structure/StructureElementRegistration.java index 0b635cde1..2a6859f54 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/structure/StructureElementRegistration.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/structure/StructureElementRegistration.java @@ -10,6 +10,7 @@ import com.shanebeestudios.skbee.elements.structure.expressions.ExprStructureLastPlacedLocation; import com.shanebeestudios.skbee.elements.structure.expressions.ExprStructureObject; import com.shanebeestudios.skbee.elements.structure.expressions.ExprStructureProperties; +import com.shanebeestudios.skbee.elements.structure.sections.SecStructureLocate; import com.shanebeestudios.skbee.elements.structure.type.Types; public class StructureElementRegistration { @@ -30,6 +31,9 @@ public static void register(Registration reg) { ExprStructureObject.register(reg); ExprStructureProperties.register(reg); + // SECTIONS + SecStructureLocate.register(reg); + // TYPES Types.register(reg); } diff --git a/src/main/java/com/shanebeestudios/skbee/elements/structure/sections/SecStructureLocate.java b/src/main/java/com/shanebeestudios/skbee/elements/structure/sections/SecStructureLocate.java new file mode 100644 index 000000000..be31b2d6a --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/structure/sections/SecStructureLocate.java @@ -0,0 +1,152 @@ +package com.shanebeestudios.skbee.elements.structure.sections; + +import ch.njol.skript.config.SectionNode; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.Trigger; +import ch.njol.skript.lang.TriggerItem; +import ch.njol.skript.registrations.EventValues; +import ch.njol.skript.variables.Variables; +import ch.njol.util.Kleenean; +import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.api.skript.base.Section; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.generator.structure.Structure; +import org.bukkit.generator.structure.StructureType; +import org.bukkit.util.StructureSearchResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class SecStructureLocate extends Section { + + public static class LocateStructureEvent extends Event { + + private final @Nullable StructureSearchResult structureSearchResult; + private final @Nullable CommandSender sender; + + public LocateStructureEvent(@Nullable StructureSearchResult structureSearchResult, @Nullable CommandSender sender) { + this.structureSearchResult = structureSearchResult; + this.sender = sender; + } + + public boolean found() { + return this.structureSearchResult != null; + } + + public @Nullable Structure getStructure() { + if (this.structureSearchResult == null) return null; + return this.structureSearchResult.getStructure(); + } + + public @Nullable Location getLocation() { + if (this.structureSearchResult == null) return null; + return this.structureSearchResult.getLocation(); + } + + public @Nullable CommandSender getSender() { + return this.sender; + } + + @Override + public @NotNull HandlerList getHandlers() { + throw new IllegalStateException(); + } + } + + public static void register(Registration reg) { + reg.newSection(SecStructureLocate.class, + "locate [:unexplored] structure %structure/structuretype% (within|in) radius %number% (around|of) %location%") + .name("Structure - Locate Structure") + .description("Locates a Structure/StructureType within a specified radius around a given location.", + "The `unexplored` option will only find unexplored structures.", + "NOTE: The bigger the radius, the longer it takes to find a structure and the longer this will freeze the main thread.", + "Once the structure is found, the location and structure will be available in the section.") + .examples("locate structure minecraft:village_savanna in radius 5000 around player:", + "\tteleport player to block above highest block at event-location") + .since("INSERT VERSION") + .register(); + + reg.newEventValue(LocateStructureEvent.class, Location.class) + .description("Represents the location of the structure found.") + .converter(LocateStructureEvent::getLocation) + .register(); + reg.newEventValue(LocateStructureEvent.class, Structure.class) + .description("Represents the structure found.") + .converter(LocateStructureEvent::getStructure) + .register(); + reg.newEventValue(LocateStructureEvent.class, CommandSender.class) + .description("Represents the command sender from a parent event.") + .converter(LocateStructureEvent::getSender) + .register(); + reg.newEventValue(LocateStructureEvent.class, boolean.class) + .description("Represents whether a structure was found.") + .patterns("found") + .converter(LocateStructureEvent::found) + .register(); + } + + private Expression structure; + private Expression radius; + private Expression location; + private boolean unexplored; + private Trigger trigger; + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult, + SectionNode sectionNode, List triggerItems) { + this.structure = expressions[0]; + this.radius = (Expression) expressions[1]; + this.location = (Expression) expressions[2]; + this.unexplored = parseResult.hasTag("unexplored"); + this.trigger = loadCode(sectionNode, "locate structure", LocateStructureEvent.class); + return true; + } + + @SuppressWarnings("PatternVariableHidesField") + @Override + protected @Nullable TriggerItem walk(Event event) { + Number single = this.radius.getSingle(event); + if (single == null) return super.walk(event, false); + + int radius = single.intValue(); + Location origin = this.location.getSingle(event); + if (origin == null) return super.walk(event, false); + + Object object = this.structure.getSingle(event); + if (object instanceof Structure structure) { + StructureSearchResult result = origin.getWorld().locateNearestStructure(origin, structure, radius, this.unexplored); + LocateStructureEvent locateStructureEvent = new LocateStructureEvent(result, getSender(event)); + Variables.withLocalVariables(event, locateStructureEvent, () -> { + TriggerItem.walk(this.trigger, locateStructureEvent); + }); + } else if (object instanceof StructureType structureType) { + StructureSearchResult result = origin.getWorld().locateNearestStructure(origin, structureType, radius, this.unexplored); + LocateStructureEvent locateStructureEvent = new LocateStructureEvent(result, getSender(event)); + Variables.withLocalVariables(event, locateStructureEvent, () -> { + TriggerItem.walk(this.trigger, locateStructureEvent); + }); + } + + return super.walk(event, false); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "locate structure " + this.structure.toString(event, debug) + + " within radius " + this.radius.toString(event, debug) + + " around " + this.location.toString(event, debug); + } + + @SuppressWarnings({"deprecation", "removal"}) + private static CommandSender getSender(Event event) { + // TODO use newer methods + return EventValues.getEventValue(event, CommandSender.class, 0); + } + +} From cd53020a2a9c1fa05e10dcea291c21ba5cbfe777 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 15:58:09 -0700 Subject: [PATCH 06/34] SecLocateBiome - add section --- .../other/OtherElementRegistration.java | 2 + .../other/sections/SecLocateBiome.java | 165 ++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecLocateBiome.java diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/OtherElementRegistration.java b/src/main/java/com/shanebeestudios/skbee/elements/other/OtherElementRegistration.java index 391e27768..a1140c55d 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/OtherElementRegistration.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/OtherElementRegistration.java @@ -166,6 +166,7 @@ import com.shanebeestudios.skbee.elements.other.expressions.ExprWorldSpawnLimit; import com.shanebeestudios.skbee.elements.other.expressions.ExprWorldTime; import com.shanebeestudios.skbee.elements.other.sections.SecAttributeModifier; +import com.shanebeestudios.skbee.elements.other.sections.SecLocateBiome; import com.shanebeestudios.skbee.elements.other.sections.SecResourcePack; import com.shanebeestudios.skbee.elements.other.sections.SecRunTaskLater; import com.shanebeestudios.skbee.elements.other.sections.SecSpawnMinecraftEntity; @@ -360,6 +361,7 @@ public static void register(Registration registration) { // SECTIONS SecAttributeModifier.register(registration); + SecLocateBiome.register(registration); SecResourcePack.register(registration); SecRunTaskLater.register(registration); SecSpawnMinecraftEntity.register(registration); diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecLocateBiome.java b/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecLocateBiome.java new file mode 100644 index 000000000..2b580c4af --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/sections/SecLocateBiome.java @@ -0,0 +1,165 @@ +package com.shanebeestudios.skbee.elements.other.sections; + +import ch.njol.skript.config.SectionNode; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.Trigger; +import ch.njol.skript.lang.TriggerItem; +import ch.njol.skript.registrations.EventValues; +import ch.njol.skript.variables.Variables; +import ch.njol.util.Kleenean; +import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.api.skript.base.Section; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.tag.TagKey; +import org.bukkit.Location; +import org.bukkit.Registry; +import org.bukkit.block.Biome; +import org.bukkit.command.CommandSender; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.util.BiomeSearchResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class SecLocateBiome extends Section { + + public static class LocateBiomeEvent extends Event { + + private final @Nullable BiomeSearchResult result; + private final @Nullable CommandSender sender; + + public LocateBiomeEvent(@Nullable BiomeSearchResult result, @Nullable CommandSender sender) { + this.result = result; + this.sender = sender; + } + + public boolean found() { + return this.result != null; + } + + public @Nullable Biome getBiome() { + if (this.result == null) return null; + return this.result.getBiome(); + } + + public @Nullable Location getLocation() { + if (this.result == null) return null; + return this.result.getLocation(); + } + + public @Nullable CommandSender getSender() { + return this.sender; + } + + @Override + public @NotNull HandlerList getHandlers() { + throw new IllegalStateException(); + } + } + + public static void register(Registration reg) { + reg.newSection(SecLocateBiome.class, + "locate biome %biomes/tagkeys% (within|in) radius %number% (around|of) %location%") + .name("Locate Biome") + .description("Locates a biome within a specified radius around a given location.", + "This accepts a single biome, list of biomes or a biome registry tag key.", + "NOTE: The bigger the radius, the longer it takes to find a biome and the longer this will freeze the main thread.", + "Once the biome is found, the location and biome will be available in the section.", + "NOTE: While it might not be deemed thread safe, this does work off the main thread, use with caution.") + .examples("locate biome beer:plains/temperate_plains in radius 5000 around player:", + "\tteleport player to block above highest block at event-location", + "", + "# Async Example", + "async run task 0 ticks later:", + "\tlocate biome (biome registry tag key \"minecraft:is_beach\") in radius 5000 around player:", + "\t\t# Pass back to the main thread so we can teleport the player", + "\t\twait 1 tick", + "\t\tteleport player to block above highest block at event-location") + .since("INSERT VERSION") + .register(); + + reg.newEventValue(LocateBiomeEvent.class, Location.class) + .description("Represents the location of the biome found.") + .converter(LocateBiomeEvent::getLocation) + .register(); + reg.newEventValue(LocateBiomeEvent.class, Biome.class) + .description("Represents the biome found.") + .converter(LocateBiomeEvent::getBiome) + .register(); + reg.newEventValue(LocateBiomeEvent.class, CommandSender.class) + .description("Represents the command sender from a parent event.") + .converter(LocateBiomeEvent::getSender) + .register(); + reg.newEventValue(LocateBiomeEvent.class, boolean.class) + .description("Represents whether a biome was found.") + .patterns("found") + .converter(LocateBiomeEvent::found) + .register(); + } + + private Expression biome; + private Expression radius; + private Expression location; + private Trigger trigger; + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult, + SectionNode sectionNode, List triggerItems) { + this.biome = expressions[0]; + this.radius = (Expression) expressions[1]; + this.location = (Expression) expressions[2]; + this.trigger = loadCode(sectionNode, "locate biome", LocateBiomeEvent.class); + return true; + } + + @SuppressWarnings({"UnstableApiUsage", "unchecked", "PatternVariableHidesField"}) + @Override + protected @Nullable TriggerItem walk(Event event) { + Number single = this.radius.getSingle(event); + if (single == null) return super.walk(event, false); + + int radius = single.intValue(); + Location origin = this.location.getSingle(event); + if (origin == null) return super.walk(event, false); + + List biomes = new ArrayList<>(); + Registry registry = RegistryAccess.registryAccess().getRegistry(RegistryKey.BIOME); + for (Object object : this.biome.getArray(event)) { + if (object instanceof Biome biome) { + biomes.add(biome); + } else if (object instanceof TagKey tagKey) { + if (tagKey.registryKey() != RegistryKey.BIOME) continue; + + biomes.addAll(registry.getTagValues((TagKey) tagKey)); + + } + } + BiomeSearchResult result = origin.getWorld().locateNearestBiome(origin, radius, biomes.toArray(new Biome[0])); + LocateBiomeEvent locateStructureEvent = new LocateBiomeEvent(result, getSender(event)); + Variables.withLocalVariables(event, locateStructureEvent, () -> { + TriggerItem.walk(this.trigger, locateStructureEvent); + }); + + return super.walk(event, false); + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "locate biome " + this.biome.toString(event, debug) + + " within radius " + this.radius.toString(event, debug) + + " around " + this.location.toString(event, debug); + } + + @SuppressWarnings({"deprecation", "removal"}) + private static CommandSender getSender(Event event) { + // TODO use newer methods + return EventValues.getEventValue(event, CommandSender.class, 0); + } + +} From 181923d3051dff298e2a18eeb251d681b523367c Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 16:04:30 -0700 Subject: [PATCH 07/34] build.gradle.kts - update SKR --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 9cc70d6e4..d79dbe235 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -46,7 +46,7 @@ dependencies { compileOnly("com.github.SkriptLang:Skript:2.15.0") // SkriptRegistration - implementation("com.github.ShaneBeee:SkriptRegistration:1.4.0") + implementation("com.github.ShaneBeee:SkriptRegistration:1.4.1") // commons-io compileOnly("commons-io:commons-io:2.14.0") From 1283eb28c516aa854f91aafc74bece8be1d679bd Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 20:25:30 -0700 Subject: [PATCH 08/34] RegistryHolder - add method to get value - also some javadoc work --- .../skbee/api/registry/RegistryHolder.java | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/api/registry/RegistryHolder.java b/src/main/java/com/shanebeestudios/skbee/api/registry/RegistryHolder.java index ce14b10af..030350e31 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/registry/RegistryHolder.java +++ b/src/main/java/com/shanebeestudios/skbee/api/registry/RegistryHolder.java @@ -4,10 +4,12 @@ import ch.njol.skript.registrations.Classes; import io.papermc.paper.registry.RegistryAccess; import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; import io.papermc.paper.registry.tag.Tag; import io.papermc.paper.registry.tag.TagKey; import org.bukkit.Keyed; import org.bukkit.Registry; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.lang.converter.Converter; @@ -16,7 +18,7 @@ import java.util.List; /** - * Holder class for registry elements + * Holder class for {@link Registry} elements * * @param Type of registry * @param Return type from registry (may differ from F) @@ -39,20 +41,35 @@ public class RegistryHolder { this.reverser = reverser; } + /** + * Get the RegistryKey that belongs to this {@link Registry}. + * + * @return RegistryKey + */ public RegistryKey getRegistryKey() { return registryKey; } + /** + * Get the type of class returned by this {@link Registry}. + * + * @return Class type + */ public Class getReturnType() { return returnType; } + /** + * Get the name of this {@link Registry}. + * + * @return Registry name + */ public String getRegistryName() { return registryName; } /** - * Get all values from this {@link Registry} + * Get all values from this {@link Registry}. *

May be converted

* * @return List of values from the registry @@ -72,7 +89,7 @@ public List getValues() { } /** - * Get all values of a TagKey + * Get all values of a TagKey from this {@link Registry}. * * @param tagKey TagKey to get values from * @return Values from tagkey @@ -95,6 +112,24 @@ public List getTagValues(TagKey tagKey) { return values; } + /** + * Get the value of a TypedKey from this {@link Registry}. + * + * @param typedKey TypedKey to get value from + * @return Value from registry + */ + @SuppressWarnings("unchecked") + public @Nullable T getValue(TypedKey typedKey) { + Registry registry = RegistryAccess.registryAccess().getRegistry(this.registryKey); + F f = registry.get(typedKey); + if (f == null) return null; + + if (this.converter != null) { + return this.converter.convert(f); + } + return (T) f; + } + /** * Get the original value from the registry. * @@ -114,6 +149,10 @@ public List getTagValues(TagKey tagKey) { } } + /** + * @hidden + */ + @ApiStatus.Internal public String getDocString() { ClassInfo info = Classes.getExactClassInfo(this.returnType); String className = info != null ? info.getDocName() : "unsupported"; From 96195716fec341a12f33102243ce469678eb9956 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 20:28:11 -0700 Subject: [PATCH 09/34] ExprRegistryValue --- .../registry/RegistryElementRegistration.java | 2 + .../expression/ExprRegistryValue.java | 102 ++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 src/main/java/com/shanebeestudios/skbee/elements/registry/expression/ExprRegistryValue.java diff --git a/src/main/java/com/shanebeestudios/skbee/elements/registry/RegistryElementRegistration.java b/src/main/java/com/shanebeestudios/skbee/elements/registry/RegistryElementRegistration.java index d3575f7f2..fd4e2f3a4 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/registry/RegistryElementRegistration.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/registry/RegistryElementRegistration.java @@ -4,6 +4,7 @@ import com.shanebeestudios.skbee.elements.registry.expression.ExprRegistryTagKeyFrom; import com.shanebeestudios.skbee.elements.registry.expression.ExprRegistryTagKeyValues; import com.shanebeestudios.skbee.elements.registry.expression.ExprRegistryTagKeys; +import com.shanebeestudios.skbee.elements.registry.expression.ExprRegistryValue; import com.shanebeestudios.skbee.elements.registry.expression.ExprRegistryValues; import com.shanebeestudios.skbee.elements.registry.type.Types; @@ -14,6 +15,7 @@ public static void register(Registration reg) { ExprRegistryTagKeyFrom.register(reg); ExprRegistryTagKeys.register(reg); ExprRegistryTagKeyValues.register(reg); + ExprRegistryValue.register(reg); ExprRegistryValues.register(reg); // TYPES diff --git a/src/main/java/com/shanebeestudios/skbee/elements/registry/expression/ExprRegistryValue.java b/src/main/java/com/shanebeestudios/skbee/elements/registry/expression/ExprRegistryValue.java new file mode 100644 index 000000000..f6f09869a --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/registry/expression/ExprRegistryValue.java @@ -0,0 +1,102 @@ +package com.shanebeestudios.skbee.elements.registry.expression; + +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.Literal; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import com.github.shanebeee.skr.Registration; +import com.github.shanebeee.skr.Utils; +import com.shanebeestudios.skbee.api.registry.RegistryHolder; +import com.shanebeestudios.skbee.api.registry.RegistryHolders; +import com.shanebeestudios.skbee.api.skript.base.SimpleExpression; +import com.shanebeestudios.skbee.config.SkBeeMetrics; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import org.bukkit.NamespacedKey; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; + +public class ExprRegistryValue extends SimpleExpression { + + public static void register(Registration reg) { + reg.newSimpleExpression(ExprRegistryValue.class, Object.class, + "value of %string/typedkey/namespacedkey% (in|from) %registrykey%", + "%registrykey% value [of] %string/typedkey/namespacedkey%") + .name("Registry - Registry Value") + .description("Get the value of a registry entry by key.") + .examples("set {_v} to value of \"minecraft:plains\" in biome registry", + "set {_v} to value of \"minecraft:diamond_sword\" from item registry", + "set {_v} to block registry value of \"minecraft:stone\"") + .since("INSERT VERSION") + .register(); + } + + private Expression key; + private Expression> registryKey; + private Class returnType = null; + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + SkBeeMetrics.Features.REGISTRY.used(); + this.key = expressions[matchedPattern]; + this.registryKey = (Expression>) expressions[matchedPattern == 0 ? 1 : 0]; + if (this.registryKey instanceof Literal> literal) { + this.returnType = RegistryHolders.getRegistryHolder(literal.getSingle()).getReturnType(); + } + return true; + } + + @SuppressWarnings({"ReassignedVariable", "unchecked", "rawtypes"}) + @Override + protected Object @Nullable [] get(Event event) { + RegistryKey registryKey = this.registryKey.getSingle(event); + if (registryKey == null) return null; + + RegistryHolder registryHolder = RegistryHolders.getRegistryHolder(registryKey); + if (this.returnType == null) { + this.returnType = registryHolder.getReturnType(); + } + + TypedKey typedKey = null; + Object o = this.key.getSingle(event); + if (o instanceof TypedKey tk) { + typedKey = tk; + } else if (o instanceof String string) { + NamespacedKey namespacedKey = Utils.getNamespacedKey(string, false); + if (namespacedKey != null) { + typedKey = TypedKey.create(registryKey, namespacedKey); + } + } else if (o instanceof NamespacedKey nsk) { + typedKey = TypedKey.create(registryKey, nsk); + } + if (typedKey == null) return null; + + List values = new ArrayList<>(); + values.add(registryHolder.getValue((TypedKey) typedKey)); + + return values.toArray((Object[]) Array.newInstance(this.returnType, values.size())); + + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + if (this.returnType == null) return Object.class; + return this.returnType; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "value of " + this.key.toString(event, debug) + " from " + this.registryKey.toString(event, debug); + } + +} From 0439d9924d147154a300c46703c96ab8933bb89f Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 20:50:36 -0700 Subject: [PATCH 10/34] build.gradle.kts - update SKR --- build.gradle.kts | 2 +- .../shanebeestudios/skbee/elements/other/type/PlayerTypes.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index d79dbe235..c5a7f6c80 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -46,7 +46,7 @@ dependencies { compileOnly("com.github.SkriptLang:Skript:2.15.0") // SkriptRegistration - implementation("com.github.ShaneBeee:SkriptRegistration:1.4.1") + implementation("com.github.ShaneBeee:SkriptRegistration:1.4.2") // commons-io compileOnly("commons-io:commons-io:2.14.0") diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/type/PlayerTypes.java b/src/main/java/com/shanebeestudios/skbee/elements/other/type/PlayerTypes.java index 2a609d982..2f8343c1b 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/type/PlayerTypes.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/type/PlayerTypes.java @@ -38,7 +38,7 @@ public static void register(Registration reg) { status.add(value.name().toLowerCase() + "[" + value.intermediate() + "]"); } status.sort(String::compareTo); - reg.newEnumType(ResourcePackStatus.class, "resourcepackstatus") + reg.newEnumType(ResourcePackStatus.class, "resourcepackstatus", info -> info.usage(StringUtils.join(status, ", "))) .name("ResourcePack - Status") .user("resource ?pack ?status(es)?") .description("Represents the status of a resource pack request.", @@ -46,7 +46,6 @@ public static void register(Registration reg) { "(Whether, after receiving this status, further status events might occur), " + "this is not actually part of the pattern.", Util.AUTO_GEN_NOTE) - .usage(StringUtils.join(status, ", ")) .since("3.21.0") .register(); } From ca53cdee771cea28d44281c80520ac077b141cac Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 21:02:36 -0700 Subject: [PATCH 11/34] ExprMerchant - add copy option - Ref #966 --- .../villager/expressions/ExprMerchant.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/villager/expressions/ExprMerchant.java b/src/main/java/com/shanebeestudios/skbee/elements/villager/expressions/ExprMerchant.java index 7ca597ee5..76aa9b026 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/villager/expressions/ExprMerchant.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/villager/expressions/ExprMerchant.java @@ -15,20 +15,23 @@ public class ExprMerchant extends SimpleExpression { public static void register(Registration reg) { reg.newSimpleExpression(ExprMerchant.class, Merchant.class, - "[new ]merchant named %string%") + "[new ]merchant named %string% [to (copy|clone) %-merchant%]") .name("Merchant - Create") - .description("Creates a new Merchant object with a title.") + .description("Creates a new Merchant object with a title.", + "You can optionally clone another merchant's recipes.") .examples("set {_merch} to new merchant named \"Le-Merchant\"") .since("1.17.0") .register(); } private Expression name; + private Expression copy; @SuppressWarnings({"unchecked"}) @Override public boolean init(Expression[] exprs, int i, Kleenean kleenean, ParseResult parseResult) { this.name = (Expression) exprs[0]; + this.copy = (Expression) exprs[1]; return true; } @@ -38,6 +41,12 @@ public boolean init(Expression[] exprs, int i, Kleenean kleenean, ParseResult String name = this.name.getSingle(event); if (name != null) { Merchant merchant = Bukkit.createMerchant(name); + if (this.copy != null) { + Merchant copy = this.copy.getSingle(event); + if (copy != null) { + merchant.setRecipes(copy.getRecipes()); + } + } return new Merchant[]{merchant}; } return null; @@ -55,7 +64,8 @@ public boolean isSingle() { @Override public @NotNull String toString(@Nullable Event e, boolean d) { - return "new merchant named " + name.toString(e, d); + String copy = this.copy != null ? " to copy " + this.copy.toString(e, d) : ""; + return "new merchant named " + name.toString(e, d) + copy; } } From 557aabccebc53c332ae26d23ac344af8f846f700 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 21:30:37 -0700 Subject: [PATCH 12/34] Add player statistic increment event - Ref #965 --- .../StatisticElementRegistration.java | 4 ++ .../statistic/events/StatisticEvents.java | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/main/java/com/shanebeestudios/skbee/elements/statistic/events/StatisticEvents.java diff --git a/src/main/java/com/shanebeestudios/skbee/elements/statistic/StatisticElementRegistration.java b/src/main/java/com/shanebeestudios/skbee/elements/statistic/StatisticElementRegistration.java index 4dc2c238c..6724b6523 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/statistic/StatisticElementRegistration.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/statistic/StatisticElementRegistration.java @@ -1,12 +1,16 @@ package com.shanebeestudios.skbee.elements.statistic; import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.elements.statistic.events.StatisticEvents; import com.shanebeestudios.skbee.elements.statistic.expressions.ExprPlayerStatistic; import com.shanebeestudios.skbee.elements.statistic.type.Types; public class StatisticElementRegistration { public static void register(Registration reg) { + // EVENTS + StatisticEvents.register(reg); + // EXPRESSIONS ExprPlayerStatistic.register(reg); diff --git a/src/main/java/com/shanebeestudios/skbee/elements/statistic/events/StatisticEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/statistic/events/StatisticEvents.java new file mode 100644 index 000000000..36f7e9f4b --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/statistic/events/StatisticEvents.java @@ -0,0 +1,65 @@ +package com.shanebeestudios.skbee.elements.statistic.events; + +import ch.njol.skript.aliases.ItemType; +import ch.njol.skript.bukkitutil.EntityUtils; +import ch.njol.skript.entity.EntityData; +import ch.njol.skript.lang.util.SimpleEvent; +import com.github.shanebeee.skr.Registration; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.entity.EntityType; +import org.bukkit.event.player.PlayerStatisticIncrementEvent; +import org.skriptlang.skript.bukkit.lang.eventvalue.EventValue; + +public class StatisticEvents extends SimpleEvent { + + public static void register(Registration reg) { + reg.newEvent(StatisticEvents.class, PlayerStatisticIncrementEvent.class, + "player statistic increment") + .name("Statistic - Increment") + .description("Called when a player statistic is incremented.") + .since("INSERT VERSION") + .register(); + + reg.newEventValue(PlayerStatisticIncrementEvent.class, Statistic.class) + .description("Gets the statistic that is being incremented.") + .converter(PlayerStatisticIncrementEvent::getStatistic) + .register(); + reg.newEventValue(PlayerStatisticIncrementEvent.class, Number.class) + .description("Gets the previous value of the statistic.") + .patterns("value") + .time(EventValue.Time.PAST) + .converter(PlayerStatisticIncrementEvent::getPreviousValue) + .register(); + reg.newEventValue(PlayerStatisticIncrementEvent.class, Number.class) + .description("Gets the new value of the statistic.") + .patterns("value") + .converter(PlayerStatisticIncrementEvent::getNewValue) + .register(); + reg.newEventValue(PlayerStatisticIncrementEvent.class, ItemType.class) + .description("Gets the Material if the statistic is a block or item statistic otherwise returns null.") + .converter(event -> { + Material material = event.getMaterial(); + if (material != null) { + return new ItemType(material); + } + return null; + }) + .register(); + reg.newEventValue(PlayerStatisticIncrementEvent.class, EntityType.class) + .description("Gets the EntityType if the statistic is an entity statistic otherwise returns null.") + .converter(PlayerStatisticIncrementEvent::getEntityType) + .register(); + reg.newEventValue(PlayerStatisticIncrementEvent.class, EntityData.class) + .description("Gets the EntityData if the statistic is an entity statistic otherwise returns null.") + .converter(event -> { + EntityType entityType = event.getEntityType(); + if (entityType != null) { + return EntityUtils.toSkriptEntityData(entityType); + } + return null; + }) + .register(); + } + +} From 046eb3802004383a8e054282717bc4d72cf92b00 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 21:36:19 -0700 Subject: [PATCH 13/34] VillagerEvents - add trade acquire event - Ref #965 --- .../villager/VillagerElementRegistration.java | 4 ++-- ...{SimpleEvents.java => VillagerEvents.java} | 21 ++++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) rename src/main/java/com/shanebeestudios/skbee/elements/villager/event/{SimpleEvents.java => VillagerEvents.java} (76%) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/villager/VillagerElementRegistration.java b/src/main/java/com/shanebeestudios/skbee/elements/villager/VillagerElementRegistration.java index 2a3f8747d..53a56a5bb 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/villager/VillagerElementRegistration.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/villager/VillagerElementRegistration.java @@ -3,7 +3,7 @@ import com.github.shanebeee.skr.Registration; import com.shanebeestudios.skbee.elements.villager.effects.EffOpenMerchant; import com.shanebeestudios.skbee.elements.villager.effects.EffVillagerEffects; -import com.shanebeestudios.skbee.elements.villager.event.SimpleEvents; +import com.shanebeestudios.skbee.elements.villager.event.VillagerEvents; import com.shanebeestudios.skbee.elements.villager.expressions.ExprMerchant; import com.shanebeestudios.skbee.elements.villager.expressions.ExprMerchantRecipe; import com.shanebeestudios.skbee.elements.villager.expressions.ExprMerchantRecipeIngredients; @@ -19,7 +19,7 @@ public static void register(Registration reg) { EffVillagerEffects.register(reg); // EVENTS - SimpleEvents.register(reg); + VillagerEvents.register(reg); // EXPRESSIONS ExprMerchant.register(reg); diff --git a/src/main/java/com/shanebeestudios/skbee/elements/villager/event/SimpleEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/villager/event/VillagerEvents.java similarity index 76% rename from src/main/java/com/shanebeestudios/skbee/elements/villager/event/SimpleEvents.java rename to src/main/java/com/shanebeestudios/skbee/elements/villager/event/VillagerEvents.java index 585e1193d..3357c2cd1 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/villager/event/SimpleEvents.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/villager/event/VillagerEvents.java @@ -1,5 +1,6 @@ package com.shanebeestudios.skbee.elements.villager.event; +import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.lang.util.SimpleEvent; import com.github.shanebeee.skr.Registration; import io.papermc.paper.event.player.PlayerPurchaseEvent; @@ -7,15 +8,16 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; +import org.bukkit.event.entity.VillagerAcquireTradeEvent; import org.bukkit.event.inventory.TradeSelectEvent; import org.bukkit.inventory.Merchant; import org.bukkit.inventory.MerchantInventory; import org.bukkit.inventory.MerchantRecipe; -public class SimpleEvents extends SimpleEvent { +public class VillagerEvents extends SimpleEvent { public static void register(Registration reg) { - reg.newEvent(SimpleEvents.class, TradeSelectEvent.class, "trade select") + reg.newEvent(VillagerEvents.class, TradeSelectEvent.class, "trade select") .name("Trade Select") .description("This event is called whenever a player clicks a new trade on the trades sidebar.", "This event allows the user to get the index of the trade, letting them get the MerchantRecipe via the Merchant.", @@ -47,7 +49,7 @@ public static void register(Registration reg) { }) .register(); - reg.newEvent(SimpleEvents.class, PlayerPurchaseEvent.class, + reg.newEvent(VillagerEvents.class, PlayerPurchaseEvent.class, "player purchase") .name("Player Purchase") .description("Called when a player trades with a standalone merchant/villager GUI. Requires PaperMC.") @@ -67,6 +69,19 @@ public static void register(Registration reg) { return null; }) .register(); + + reg.newEvent(VillagerEvents.class, VillagerAcquireTradeEvent.class, + "villager acquire trade") + .description("Called whenever a villager acquires a new trade.") + .since("INSERT VERSION") + .register(); + + reg.newEventValue(VillagerAcquireTradeEvent.class, MerchantRecipe.class) + .description("Represents the recipe to be acquired.") + .patterns("recipe") + .converter(VillagerAcquireTradeEvent::getRecipe) + .changer(ChangeMode.SET, VillagerAcquireTradeEvent::setRecipe) + .register(); } } From 46e28beb9c299fd26be0e86d74b0db27db768351 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 13 May 2026 22:11:16 -0700 Subject: [PATCH 14/34] PlayerEvents - add player exhaustion event - Ref #965 --- .../other/events/other/PlayerEvents.java | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java index 336777c24..95614c72d 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java @@ -2,7 +2,7 @@ import ch.njol.skript.Skript; import ch.njol.skript.aliases.ItemType; -import ch.njol.skript.classes.Changer; +import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.lang.util.SimpleEvent; import ch.njol.skript.util.Experience; import ch.njol.skript.util.Timespan; @@ -33,6 +33,7 @@ import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.event.Event; +import org.bukkit.event.entity.EntityExhaustionEvent; import org.bukkit.event.entity.PlayerLeashEntityEvent; import org.bukkit.event.inventory.PrepareAnvilEvent; import org.bukkit.event.player.PlayerAttemptPickupItemEvent; @@ -54,6 +55,21 @@ public class PlayerEvents extends SimpleEvent { @SuppressWarnings("UnstableApiUsage") public static void register(Registration reg) { + // EntityExhaustionEvent + reg.newEvent(PlayerEvents.class, EntityExhaustionEvent.class, "player exhaustion") + .name("Player Exhaustion") + .description("Called when a human entity experiences exhaustion.", + "An exhaustion level greater than 4.0 causes a decrease in saturation by 1.") + .since("INSERT VERSION") + .register(); + + reg.newEventValue(EntityExhaustionEvent.class, Number.class) + .description("Represents the amount of exhaustion to add to the player's current exhaustion.") + .patterns("exhaustion") + .converter(EntityExhaustionEvent::getExhaustion) + .changer(ChangeMode.SET, (event, value) -> event.setExhaustion(value.floatValue())) + .register(); + // PlayerAttemptPickupItemEvent reg.newEvent(PlayerEvents.class, PlayerAttemptPickupItemEvent.class, "player attempt item pickup") .name("Player Attempt Item Pickup") @@ -298,13 +314,13 @@ else if (HAS_CONFIG && connection instanceof PlayerConfigurationConnection confi reg.newEventValue(PlayerFailMoveEvent.class, Boolean.class) .description("Whether the player is allowed to move.") .converter(PlayerFailMoveEvent::isAllowed) - .changer(Changer.ChangeMode.SET, PlayerFailMoveEvent::setAllowed) + .changer(ChangeMode.SET, PlayerFailMoveEvent::setAllowed) .register(); reg.newEventValue(PlayerFailMoveEvent.class, Boolean.class) .description("Whether to log warning to console.") .time(EventValue.Time.FUTURE) .converter(PlayerFailMoveEvent::getLogWarning) - .changer(Changer.ChangeMode.SET, PlayerFailMoveEvent::setLogWarning) + .changer(ChangeMode.SET, PlayerFailMoveEvent::setLogWarning) .register(); // Player Leash Entity Event @@ -343,7 +359,7 @@ else if (HAS_CONFIG && connection instanceof PlayerConfigurationConnection confi reg.newEventValue(PlayerPickupExperienceEvent.class, Experience.class) .description("Represents the experience picked up (This is Skript's version of XP).") .converter(event -> new Experience(event.getExperienceOrb().getExperience())) - .changer(Changer.ChangeMode.SET, (event, value) -> { + .changer(ChangeMode.SET, (event, value) -> { if (value == null) return; event.getExperienceOrb().setExperience(value.getXP()); }) @@ -351,7 +367,7 @@ else if (HAS_CONFIG && connection instanceof PlayerConfigurationConnection confi reg.newEventValue(PlayerPickupExperienceEvent.class, Number.class) .description("represents the experience picked up as a number.") .converter(event -> event.getExperienceOrb().getExperience()) - .changer(Changer.ChangeMode.SET, (event, value) -> { + .changer(ChangeMode.SET, (event, value) -> { if (value == null) return; event.getExperienceOrb().setExperience(value.intValue()); }) @@ -426,12 +442,12 @@ else if (HAS_CONFIG && connection instanceof PlayerConfigurationConnection confi reg.newEventValue(PlayerShearEntityEvent.class, ItemStack[].class) .description("Get a list of drops for this shearing.") .converter(event -> event.getDrops().toArray(new ItemStack[0])) - .changer(Changer.ChangeMode.SET, (event, value) -> event.setDrops(Arrays.asList(value))) + .changer(ChangeMode.SET, (event, value) -> event.setDrops(Arrays.asList(value))) .register(); reg.newEventValue(PlayerShearEntityEvent.class, ItemType[].class) .description("Get a list of drops for this shearing.") .converter(event -> event.getDrops().stream().map(ItemType::new).toArray(ItemType[]::new)) - .changer(Changer.ChangeMode.SET, (event, value) -> { + .changer(ChangeMode.SET, (event, value) -> { List items = new ArrayList<>(); for (ItemType itemType : value) { items.add(itemType.getRandom()); From 78e9b2e6e0e4073a77533d1492f23756c704a912 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Thu, 14 May 2026 06:09:15 -0700 Subject: [PATCH 15/34] VillagerEvents - missing name --- .../skbee/elements/villager/event/VillagerEvents.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/villager/event/VillagerEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/villager/event/VillagerEvents.java index 3357c2cd1..0bf516873 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/villager/event/VillagerEvents.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/villager/event/VillagerEvents.java @@ -72,6 +72,7 @@ public static void register(Registration reg) { reg.newEvent(VillagerEvents.class, VillagerAcquireTradeEvent.class, "villager acquire trade") + .name("Villager Acquire Trade") .description("Called whenever a villager acquires a new trade.") .since("INSERT VERSION") .register(); From 0b19c37e25319a58ffd389b19fbfd3217ef8eda4 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Thu, 14 May 2026 06:40:05 -0700 Subject: [PATCH 16/34] EntityEvents - add lunge event - Ref #965 --- .../skbee/api/util/legacy/LegacyUtils.java | 3 +++ .../other/events/other/EntityEvents.java | 22 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/shanebeestudios/skbee/api/util/legacy/LegacyUtils.java b/src/main/java/com/shanebeestudios/skbee/api/util/legacy/LegacyUtils.java index c73e4ac24..a5df5d63b 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/util/legacy/LegacyUtils.java +++ b/src/main/java/com/shanebeestudios/skbee/api/util/legacy/LegacyUtils.java @@ -12,4 +12,7 @@ public class LegacyUtils { public static final boolean IS_RUNNING_MC_26_1_1 = Skript.isRunningMinecraft(26, 1, 1); public static final boolean IS_RUNNING_MC_26_1_2 = Skript.isRunningMinecraft(26, 1, 2); + // Not sure when this was added, maybe 26.1.2?!? + public static final boolean HAS_LUNGE_EVENT = Skript.classExists("io.papermc.paper.event.entity.EntityLungeEvent"); + } diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/EntityEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/EntityEvents.java index 89be4aa16..edee9f466 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/EntityEvents.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/EntityEvents.java @@ -11,7 +11,9 @@ import com.destroystokyo.paper.event.entity.SlimePathfindEvent; import com.github.shanebeee.skr.Registration; import com.shanebeestudios.skbee.api.event.EntityBlockInteractEvent; +import com.shanebeestudios.skbee.api.util.legacy.LegacyUtils; import io.papermc.paper.event.entity.EntityInsideBlockEvent; +import io.papermc.paper.event.entity.EntityLungeEvent; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; @@ -155,11 +157,29 @@ public static void register(Registration reg) { .converter(EntityInsideBlockEvent::getBlock) .register(); + if (LegacyUtils.HAS_LUNGE_EVENT) { + reg.newEvent(EntityEvents.class, EntityLungeEvent.class, "entity lunge") + .name("Entity Lunge") + .description("Called when a living entity tries to lunge with a spear.") + .examples("on entity lunge:", + "\tset event-lunge-power to 5") + .since("INSERT VERSION") + .register(); + + reg.newEventValue(EntityLungeEvent.class, Number.class) + .description("Represents the lunge power, which when initially passed, matches the enchantment level of the item, but can be higher.", + "If set higher than 3, the power of the lunge will continue to scale like normal, as if the max enchantment level is higher.") + .patterns("power", "lunge-power") + .converter(EntityLungeEvent::getLungePower) + .changer(Changer.ChangeMode.SET, (event, value) -> event.setLungePower(value.intValue())) + .register(); + } + // Entity Pathfind Event reg.newEvent(EntityEvents.class, new Class[]{EntityPathfindEvent.class, SlimePathfindEvent.class}, "entity start[s] pathfinding") .name("Entity Pathfind") .description("Called when an Entity decides to start moving towards a location. This event does not fire for the entities " + - "actual movement. Only when it is choosing to start moving to a location. Requires Paper.") + "actual movement. Only when it is choosing to start moving to a location.") .examples("on entity starts pathfinding:", "\tif event-entity is a sheep:", "\t\tcancel event") From 45061e2b8c363b55743684e8b1b06f2d2797bb50 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Thu, 14 May 2026 06:47:44 -0700 Subject: [PATCH 17/34] PlayerEvents - add item cooldown event - Ref #965 --- .../other/events/other/PlayerEvents.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java index 95614c72d..c6894ddbd 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java @@ -6,6 +6,7 @@ import ch.njol.skript.lang.util.SimpleEvent; import ch.njol.skript.util.Experience; import ch.njol.skript.util.Timespan; +import ch.njol.skript.util.Timespan.TimePeriod; import ch.njol.skript.util.slot.Slot; import com.destroystokyo.paper.event.player.PlayerElytraBoostEvent; import com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent; @@ -22,6 +23,7 @@ import io.papermc.paper.event.packet.PlayerChunkUnloadEvent; import io.papermc.paper.event.player.PlayerCustomClickEvent; import io.papermc.paper.event.player.PlayerFailMoveEvent; +import io.papermc.paper.event.player.PlayerItemGroupCooldownEvent; import io.papermc.paper.event.player.PlayerStopUsingItemEvent; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.nbt.api.BinaryTagHolder; @@ -346,6 +348,25 @@ else if (HAS_CONFIG && connection instanceof PlayerConfigurationConnection confi .converter(PlayerLeashEntityEvent::getLeashHolder) .register(); + // Player Item Group Cooldown Event + reg.newEvent(PlayerEvents.class, PlayerItemGroupCooldownEvent.class, + "player item group cooldown", "player item cooldown") + .name("Player Item Group Cooldown") + .description("Fired when a player receives an item cooldown.") + .since("INSERT VERSION") + .register(); + + reg.newEventValue(PlayerItemGroupCooldownEvent.class, Timespan.class) + .description("Represents the cooldown.") + .converter(event -> new Timespan(TimePeriod.TICK, event.getCooldown())) + .changer(ChangeMode.SET, (event, timespan) -> event.setCooldown((int) timespan.getAs(TimePeriod.TICK))) + .register(); + reg.newEventValue(PlayerItemGroupCooldownEvent.class, NamespacedKey.class) + .description("Represents the cooldown group as defined by an item's UseCooldownComponent.") + .patterns("cooldown-group", "group") + .converter(PlayerItemGroupCooldownEvent::getCooldownGroup) + .register(); + // Player Pickup XP Event reg.newEvent(PlayerEvents.class, PlayerPickupExperienceEvent.class, "player pickup (experience|xp) [orb]") @@ -479,7 +500,7 @@ else if (HAS_CONFIG && connection instanceof PlayerConfigurationConnection confi .register(); reg.newEventValue(PlayerStopUsingItemEvent.class, Timespan.class) .description("The span of time the item was held for.") - .converter(event -> new Timespan(Timespan.TimePeriod.TICK, event.getTicksHeldFor())) + .converter(event -> new Timespan(TimePeriod.TICK, event.getTicksHeldFor())) .register(); } From 1e3c32ba62ab7f5d224dd093dc4cb737def91166 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Thu, 14 May 2026 07:02:40 -0700 Subject: [PATCH 18/34] PlayerEvents - add player velocity event - Ref #965 --- .../other/events/other/PlayerEvents.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java index c6894ddbd..21e12b033 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java @@ -40,8 +40,10 @@ import org.bukkit.event.inventory.PrepareAnvilEvent; import org.bukkit.event.player.PlayerAttemptPickupItemEvent; import org.bukkit.event.player.PlayerShearEntityEvent; +import org.bukkit.event.player.PlayerVelocityEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.skriptlang.skript.bukkit.lang.eventvalue.EventValue; @@ -503,6 +505,22 @@ else if (HAS_CONFIG && connection instanceof PlayerConfigurationConnection confi .converter(event -> new Timespan(TimePeriod.TICK, event.getTicksHeldFor())) .register(); + // Player Velocity Event + reg.newEvent(PlayerEvents.class, PlayerVelocityEvent.class, + "player velocity", "player velocity change", "player velocity changed") + .name("Player Velocity") + .description("Called when a player's velocity changes.") + .examples("on player velocity changed:", + "\tset event-velocity to vector(0, 10, 0)") + .since("INSERT VERSION") + .register(); + + reg.newEventValue(PlayerVelocityEvent.class, Vector.class) + .description("Represents the velocity vector that will be sent to the player.") + .patterns("velocity") + .converter(PlayerVelocityEvent::getVelocity) + .changer(ChangeMode.SET, PlayerVelocityEvent::setVelocity) + .register(); } From bd4b1e7f84d7ef257aac455650851ea2de75c5cc Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Thu, 14 May 2026 09:58:35 -0700 Subject: [PATCH 19/34] SecExprMusicalInstrument - add --- .../registry/RegistryElementRegistration.java | 2 + .../expression/SecExprMusicalInstrument.java | 163 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 src/main/java/com/shanebeestudios/skbee/elements/registry/expression/SecExprMusicalInstrument.java diff --git a/src/main/java/com/shanebeestudios/skbee/elements/registry/RegistryElementRegistration.java b/src/main/java/com/shanebeestudios/skbee/elements/registry/RegistryElementRegistration.java index fd4e2f3a4..ffbc514f3 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/registry/RegistryElementRegistration.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/registry/RegistryElementRegistration.java @@ -6,6 +6,7 @@ import com.shanebeestudios.skbee.elements.registry.expression.ExprRegistryTagKeys; import com.shanebeestudios.skbee.elements.registry.expression.ExprRegistryValue; import com.shanebeestudios.skbee.elements.registry.expression.ExprRegistryValues; +import com.shanebeestudios.skbee.elements.registry.expression.SecExprMusicalInstrument; import com.shanebeestudios.skbee.elements.registry.type.Types; public class RegistryElementRegistration { @@ -17,6 +18,7 @@ public static void register(Registration reg) { ExprRegistryTagKeyValues.register(reg); ExprRegistryValue.register(reg); ExprRegistryValues.register(reg); + SecExprMusicalInstrument.register(reg); // TYPES Types.register(reg); diff --git a/src/main/java/com/shanebeestudios/skbee/elements/registry/expression/SecExprMusicalInstrument.java b/src/main/java/com/shanebeestudios/skbee/elements/registry/expression/SecExprMusicalInstrument.java new file mode 100644 index 000000000..1aa6b96b1 --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/registry/expression/SecExprMusicalInstrument.java @@ -0,0 +1,163 @@ +package com.shanebeestudios.skbee.elements.registry.expression; + +import ch.njol.skript.config.SectionNode; +import ch.njol.skript.expressions.base.SectionExpression; +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.lang.TriggerItem; +import ch.njol.skript.util.Timespan; +import ch.njol.util.Kleenean; +import com.github.shanebeee.skr.Registration; +import com.github.shanebeee.skr.Utils; +import com.github.shanebeee.skr.skript.SimpleEntryValidator; +import com.shanebeestudios.skbee.api.wrapper.ComponentWrapper; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import io.papermc.paper.registry.data.InstrumentRegistryEntry; +import net.kyori.adventure.text.Component; +import org.bukkit.MusicInstrument; +import org.bukkit.NamespacedKey; +import org.bukkit.Sound; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; +import org.skriptlang.skript.lang.entry.EntryContainer; +import org.skriptlang.skript.lang.entry.EntryValidator; + +import java.util.List; + +@SuppressWarnings("UnstableApiUsage") +public class SecExprMusicalInstrument extends SectionExpression { + + private static EntryValidator VALIDATOR; + + @SuppressWarnings("unchecked") + public static void register(Registration reg) { + VALIDATOR = SimpleEntryValidator.builder() + .addOptionalEntry("description", new Class[]{String.class, ComponentWrapper.class, Component.class}) + .addRequiredEntry("sound_event", new Class[]{String.class, TypedKey.class, NamespacedKey.class}) + .addOptionalEntry("use_duration", Timespan.class) + .addOptionalEntry("range", Number.class) + .build(); + + reg.newSimpleExpression(SecExprMusicalInstrument.class, MusicInstrument.class, + "new [music] instrument") + .validator(VALIDATOR) + .name("Registry - Instrument") + .description("Create a new instrument with specified properties.", + "This can be used in the [**Instrument Component**](https://minecraft.wiki/w/Data_component_format#instrument).", + "See [**Instrument Definition**](https://minecraft.wiki/w/Instrument_definition) on McWiki for more information.") + .examples("set {_m} to new instrument:", + "\tdescription: formatted \"Toot Toot\"", + "\tsound_event: \"minecraft:entity.ender_dragon.death\"", + "\tuse_duration: 1 second", + "\trange: 10", + "", + "set {_i} to 1 of goat horn", + "apply instrument component to {_i}:", + "\tinstrument: {_m}") + .since("INSERT VERSION") + .register(); + } + + private Expression description; + private Expression soundEvent; + private Expression useDuration; + private Expression range; + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int pattern, Kleenean delayed, ParseResult result, + @Nullable SectionNode node, @Nullable List triggerItems) { + EntryContainer container = VALIDATOR.validate(node); + if (container == null) return false; + + this.description = (Expression) container.getOptional("description", false); + this.soundEvent = (Expression) container.getOptional("sound_event", false); + this.useDuration = (Expression) container.getOptional("use_duration", false); + this.range = (Expression) container.getOptional("range", false); + return true; + } + + @SuppressWarnings("unchecked") + @Override + protected MusicInstrument @Nullable [] get(Event event) { + TypedKey soundEvent; + Object o = this.soundEvent.getSingle(event); + switch (o) { + case String s -> { + NamespacedKey namespacedKey = Utils.getNamespacedKey(s, false); + if (namespacedKey != null) { + soundEvent = TypedKey.create(RegistryKey.SOUND_EVENT, namespacedKey); + } else { + soundEvent = null; + } + } + case NamespacedKey namespacedKey -> soundEvent = TypedKey.create(RegistryKey.SOUND_EVENT, namespacedKey); + case TypedKey typedKey when typedKey.registryKey() == RegistryKey.SOUND_EVENT -> + soundEvent = (TypedKey) typedKey; + case null, default -> { + return null; + } + } + if (soundEvent == null) { + return null; + } + + MusicInstrument musicInstrument = MusicInstrument.create(factory -> { + Component description = Component.empty(); + if (this.description != null) { + Object object = this.description.getSingle(event); + if (object instanceof String string) { + description = Component.text(string); + } else if (object instanceof Component component) { + description = component; + } else if (object instanceof ComponentWrapper cw) { + description = cw.getComponent(); + } + } + + InstrumentRegistryEntry.Builder empty = factory.empty(); + if (description != null) { + empty.description(description); + } + + empty.soundEvent(soundEvent); + + float range = 256; + if (this.range != null) { + Number single = this.range.getSingle(event); + if (single != null) { + range = single.floatValue(); + } + } + empty.range(Math.max(0, range)); + + float duration = 7; + if (this.useDuration != null) { + Timespan timespan = this.useDuration.getSingle(event); + if (timespan != null) { + duration = (float) timespan.getAs(Timespan.TimePeriod.TICK) / 20; + } + } + empty.duration(Math.max(0, duration)); + }); + + return new MusicInstrument[]{musicInstrument}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return MusicInstrument.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "new music instrument"; + } + +} From 6bd0e97a35ec43ac834f530cf51fbcdc3ef291ea Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Fri, 15 May 2026 16:13:37 -0700 Subject: [PATCH 20/34] WeightedList - add weighted list elements --- .../skbee/api/util/WeightedList.java | 73 ++++++++++++++++ .../other/OtherElementRegistration.java | 8 ++ .../effects/EffWeightedListAddEntry.java | 69 +++++++++++++++ .../expressions/ExprWeightedListCreate.java | 58 +++++++++++++ .../ExprWeightedListRandomElement.java | 84 +++++++++++++++++++ .../elements/other/type/CustomTypes.java | 47 +++++++++++ 6 files changed, 339 insertions(+) create mode 100644 src/main/java/com/shanebeestudios/skbee/api/util/WeightedList.java create mode 100644 src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffWeightedListAddEntry.java create mode 100644 src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprWeightedListCreate.java create mode 100644 src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprWeightedListRandomElement.java create mode 100644 src/main/java/com/shanebeestudios/skbee/elements/other/type/CustomTypes.java diff --git a/src/main/java/com/shanebeestudios/skbee/api/util/WeightedList.java b/src/main/java/com/shanebeestudios/skbee/api/util/WeightedList.java new file mode 100644 index 000000000..f1ec119ea --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/api/util/WeightedList.java @@ -0,0 +1,73 @@ +package com.shanebeestudios.skbee.api.util; + +import java.util.List; +import java.util.Random; +import java.util.TreeMap; + +/** + * A weighted list that allows for random selection based on entry weights. + * + * @param The type of elements in the list. + */ +public class WeightedList { + + private final TreeMap weightMap = new TreeMap<>(); + private final Random random = new Random(); + private double total = 0; + + /** + * Add an entry to the weighted list with a specified weight. + * + * @param entry The entry to add. + * @param weight The weight of the entry. + * @throws IllegalArgumentException if weight is not positive. + */ + public void add(T entry, int weight) { + if (weight <= 0) { + throw new IllegalArgumentException("Weight must be positive"); + } + this.total += weight; + this.weightMap.put(this.total, entry); + } + + /** + * Get the next entry from the weighted list based on weights. + * + * @return The next entry or null if the list is empty. + */ + public T nextEntry() { + if (this.total == 0) { + return null; + } + double randomValue = this.random.nextDouble() * this.total; + return this.weightMap.higherEntry(randomValue).getValue(); + } + + /** + * Get all entries in the weighted list. + * + * @return An unmodifiable list of entries. + */ + public List getEntries() { + return List.copyOf(this.weightMap.values()); + } + + /** + * Check if the weighted list is empty. + * + * @return True if the list is empty, false otherwise. + */ + public boolean isEmpty() { + return this.weightMap.isEmpty(); + } + + /** + * Get the number of entries in the weighted list. + * + * @return The number of entries. + */ + public int size() { + return this.weightMap.size(); + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/OtherElementRegistration.java b/src/main/java/com/shanebeestudios/skbee/elements/other/OtherElementRegistration.java index a1140c55d..769e0aafc 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/OtherElementRegistration.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/OtherElementRegistration.java @@ -51,6 +51,7 @@ import com.shanebeestudios.skbee.elements.other.effects.EffTaskStop; import com.shanebeestudios.skbee.elements.other.effects.EffTransferCookieStore; import com.shanebeestudios.skbee.elements.other.effects.EffUpdateRecipeResources; +import com.shanebeestudios.skbee.elements.other.effects.EffWeightedListAddEntry; import com.shanebeestudios.skbee.elements.other.events.AsyncEvents; import com.shanebeestudios.skbee.elements.other.events.EvtDamageByBlock; import com.shanebeestudios.skbee.elements.other.events.EvtEntitiesLoad; @@ -161,6 +162,8 @@ import com.shanebeestudios.skbee.elements.other.expressions.ExprTickingState; import com.shanebeestudios.skbee.elements.other.expressions.ExprTransferCookie; import com.shanebeestudios.skbee.elements.other.expressions.ExprTranslationKey; +import com.shanebeestudios.skbee.elements.other.expressions.ExprWeightedListCreate; +import com.shanebeestudios.skbee.elements.other.expressions.ExprWeightedListRandomElement; import com.shanebeestudios.skbee.elements.other.expressions.ExprWorldAutoSave; import com.shanebeestudios.skbee.elements.other.expressions.ExprWorldHeight; import com.shanebeestudios.skbee.elements.other.expressions.ExprWorldSpawnLimit; @@ -175,6 +178,7 @@ import com.shanebeestudios.skbee.elements.other.structures.StructTagAliases; import com.shanebeestudios.skbee.elements.other.type.BlockTypes; import com.shanebeestudios.skbee.elements.other.type.Comps; +import com.shanebeestudios.skbee.elements.other.type.CustomTypes; import com.shanebeestudios.skbee.elements.other.type.EntityTypes; import com.shanebeestudios.skbee.elements.other.type.EventTypes; import com.shanebeestudios.skbee.elements.other.type.Functions; @@ -239,6 +243,7 @@ public static void register(Registration registration) { EffTaskStop.register(registration); EffTransferCookieStore.register(registration); EffUpdateRecipeResources.register(registration); + EffWeightedListAddEntry.register(registration); // EVENTS BlockEvents.register(registration); @@ -354,6 +359,8 @@ public static void register(Registration registration) { ExprTickingState.register(registration); ExprTransferCookie.register(registration); ExprTranslationKey.register(registration); + ExprWeightedListCreate.register(registration); + ExprWeightedListRandomElement.register(registration); ExprWorldAutoSave.register(registration); ExprWorldHeight.register(registration); ExprWorldSpawnLimit.register(registration); @@ -375,6 +382,7 @@ public static void register(Registration registration) { Comps.register(registration); Functions.register(registration); BlockTypes.register(registration); + CustomTypes.register(registration); EntityTypes.register(registration); EventTypes.register(registration); ItemTypes.register(registration); diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffWeightedListAddEntry.java b/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffWeightedListAddEntry.java new file mode 100644 index 000000000..256a936f2 --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffWeightedListAddEntry.java @@ -0,0 +1,69 @@ +package com.shanebeestudios.skbee.elements.other.effects; + +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.skript.util.LiteralUtils; +import ch.njol.util.Kleenean; +import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.api.skript.base.Effect; +import com.shanebeestudios.skbee.api.util.WeightedList; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@SuppressWarnings("rawtypes") +public class EffWeightedListAddEntry extends Effect { + + public static void register(Registration reg) { + reg.newEffect(EffWeightedListAddEntry.class, + "add %object% to %weightedlist% with weight %number%") + .name("WeightedList - Add Entry") + .description("Adds an entry to a weighted list with a specified weight.", + "Weight must be greater than 0.") + .examples("set {_loot} to new weighted list", + "add 1 of salmon to {_loot} with weight 5", + "add 1 of cod to {_loot} with weight 7", + "add stone sword of unbreaking 3 to {_loot} with weight 1", + "add 3 of cooked chicken to {_loot} with weight 2", + "add 4 of string to {_loot} with weight 15", + "", + "set {_random} to random weighted element of {_loot}", + "set {_random::*} to 5 random weighted elements of {_loot}\n") + .since("INSERT VERSION") + .register(); + } + + private Expression object; + private Expression weightedList; + private Expression weight; + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + this.object = LiteralUtils.defendExpression(expressions[0]); + this.weightedList = (Expression) expressions[1]; + this.weight = (Expression) expressions[2]; + return LiteralUtils.canInitSafely(this.object); + } + + @SuppressWarnings("unchecked") + @Override + protected void execute(Event event) { + Object object = this.object.getSingle(event); + WeightedList list = this.weightedList.getSingle(event); + Number number = this.weight.getSingle(event); + if (object == null || list == null || number == null) { + return; + } + int weight = number.intValue(); + if (weight > 0) { + list.add(object, weight); + } + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "add " + this.object.toString(event, debug) + " to " + this.weightedList.toString(event, debug) + + " with weight " + this.weight.toString(event, debug); + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprWeightedListCreate.java b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprWeightedListCreate.java new file mode 100644 index 000000000..7f1a7d64c --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprWeightedListCreate.java @@ -0,0 +1,58 @@ +package com.shanebeestudios.skbee.elements.other.expressions; + +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.api.skript.base.SimpleExpression; +import com.shanebeestudios.skbee.api.util.WeightedList; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@SuppressWarnings("rawtypes") +public class ExprWeightedListCreate extends SimpleExpression { + + public static void register(Registration reg) { + reg.newSimpleExpression(ExprWeightedListCreate.class, WeightedList.class, + "[a] new weighted[ ]list") + .name("WeightedList - Create") + .description("Creates a new weighted list for use with other WeightedList expressions.") + .examples("set {_loot} to new weighted list", + "add 1 of salmon to {_loot} with weight 5", + "add 1 of cod to {_loot} with weight 7", + "add stone sword of unbreaking 3 to {_loot} with weight 1", + "add 3 of cooked chicken to {_loot} with weight 2", + "add 4 of string to {_loot} with weight 15", + "", + "set {_random} to random weighted element of {_loot}", + "set {_random::*} to 5 random weighted elements of {_loot}\n") + .since("INSERT VERSION") + .register(); + } + + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + return true; + } + + @Override + protected WeightedList @Nullable [] get(Event event) { + return new WeightedList[]{new WeightedList<>()}; + } + + @Override + public boolean isSingle() { + return true; + } + + @Override + public Class getReturnType() { + return WeightedList.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + return "new weighted list"; + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprWeightedListRandomElement.java b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprWeightedListRandomElement.java new file mode 100644 index 000000000..2b2d8e073 --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/expressions/ExprWeightedListRandomElement.java @@ -0,0 +1,84 @@ +package com.shanebeestudios.skbee.elements.other.expressions; + +import ch.njol.skript.lang.Expression; +import ch.njol.skript.lang.SkriptParser.ParseResult; +import ch.njol.util.Kleenean; +import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.api.skript.base.SimpleExpression; +import com.shanebeestudios.skbee.api.util.WeightedList; +import org.bukkit.event.Event; +import org.jetbrains.annotations.Nullable; + +@SuppressWarnings("rawtypes") +public class ExprWeightedListRandomElement extends SimpleExpression { + + public static void register(Registration reg) { + reg.newCombinedExpression(ExprWeightedListRandomElement.class, Object.class, + "[%-number%] random weighted element[s] (of|from) %weightedlist%") + .name("WeightedList - Random Element") + .description("Returns a random element from the provided weighted list.", + "Optionally you can include an amount of multiple random weighted elements from the list.") + .examples("set {_loot} to new weighted list", + "add 1 of salmon to {_loot} with weight 5", + "add 1 of cod to {_loot} with weight 7", + "add stone sword of unbreaking 3 to {_loot} with weight 1", + "add 3 of cooked chicken to {_loot} with weight 2", + "add 4 of string to {_loot} with weight 15", + "", + "set {_random} to random weighted element of {_loot}", + "set {_random::*} to 5 random weighted elements of {_loot}\n") + .since("INSERT VERSION") + .register(); + } + + private Expression amount; + private Expression weightedList; + + @SuppressWarnings("unchecked") + @Override + public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { + this.amount = (Expression) expressions[0]; + this.weightedList = (Expression) expressions[1]; + return true; + } + + @Override + protected Object @Nullable [] get(Event event) { + WeightedList list = this.weightedList.getSingle(event); + if (list == null) { + return null; + } + + if (this.amount != null) { + Number number = this.amount.getSingle(event); + if (number == null) { + return null; + } + int amount = number.intValue(); + Object[] results = new Object[amount]; + for (int i = 0; i < amount; i++) { + results[i] = list.nextEntry(); + } + return results; + } + + return new Object[]{list.nextEntry()}; + } + + @Override + public boolean isSingle() { + return this.amount == null; + } + + @Override + public Class getReturnType() { + return Object.class; + } + + @Override + public String toString(@Nullable Event event, boolean debug) { + String amount = this.amount != null ? this.amount.toString(event, debug) + " " : ""; + return amount + "random weighted element[s] from " + this.weightedList.toString(event, debug); + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/type/CustomTypes.java b/src/main/java/com/shanebeestudios/skbee/elements/other/type/CustomTypes.java new file mode 100644 index 000000000..072a62380 --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/type/CustomTypes.java @@ -0,0 +1,47 @@ +package com.shanebeestudios.skbee.elements.other.type; + +import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.api.util.WeightedList; +import org.jetbrains.annotations.NotNull; +import org.skriptlang.skript.lang.properties.Property; +import org.skriptlang.skript.lang.properties.handlers.base.ConditionPropertyHandler; +import org.skriptlang.skript.lang.properties.handlers.base.ExpressionPropertyHandler; + +@SuppressWarnings({"UnstableApiUsage", "rawtypes"}) +public class CustomTypes { + + public static void register(Registration reg) { + reg.newType(WeightedList.class, "weightedlist") + .user("weighted ?lists?") + .name("WeightedList") + .description("A weighted list that allows for random selection based on entry weights.") + .since("INSERT VERSION") + .property(Property.SIZE, "The amount of elements in a weighted list.", new WeightedListSize()) + .property(Property.NUMBER, "The amount of elements in a weighted list.", new WeightedListSize()) + .property(Property.AMOUNT, "The amount of elements in a weighted list.", new WeightedListSize()) + .property(Property.IS_EMPTY, "Whether the weighted list is empty.", new WeightedListEmpty()) + .register(); + } + + private static class WeightedListSize implements ExpressionPropertyHandler { + + @Override + public Number convert(WeightedList list) { + return list.size(); + } + + @Override + public @NotNull Class returnType() { + return Number.class; + } + } + + private static class WeightedListEmpty implements ConditionPropertyHandler { + + @Override + public boolean check(WeightedList propertyHolder) { + return propertyHolder.isEmpty(); + } + } + +} From f4f82e588954e31c8e831dda2f75febca6ea419e Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Fri, 15 May 2026 16:16:39 -0700 Subject: [PATCH 21/34] WeightedList - forgot lang --- src/main/resources/lang/english.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/lang/english.lang b/src/main/resources/lang/english.lang index ac01ab0c2..8baabe63c 100644 --- a/src/main/resources/lang/english.lang +++ b/src/main/resources/lang/english.lang @@ -103,6 +103,7 @@ types: typedkey: typed key¦s vibration: vibration¦s @- villagertype: villager type¦s + weightedlist: weighted list¦s worldborder: world border¦s worldcreator: world creator worldtype: world type¦s @- From 5105c549f962ac0f2aa173eef4f8fed5a99ab3e4 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Fri, 15 May 2026 16:37:27 -0700 Subject: [PATCH 22/34] EffWeightedListAddEntry - more patterns --- .../elements/other/effects/EffWeightedListAddEntry.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffWeightedListAddEntry.java b/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffWeightedListAddEntry.java index 256a936f2..65cb593c3 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffWeightedListAddEntry.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/effects/EffWeightedListAddEntry.java @@ -15,7 +15,8 @@ public class EffWeightedListAddEntry extends Effect { public static void register(Registration reg) { reg.newEffect(EffWeightedListAddEntry.class, - "add %object% to %weightedlist% with weight %number%") + "add %object% to %weightedlist% with [a] weight [of] %number%", + "add %object% with [a] weight [of] %number% to %weightedlist%") .name("WeightedList - Add Entry") .description("Adds an entry to a weighted list with a specified weight.", "Weight must be greater than 0.") @@ -40,8 +41,8 @@ public static void register(Registration reg) { @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { this.object = LiteralUtils.defendExpression(expressions[0]); - this.weightedList = (Expression) expressions[1]; - this.weight = (Expression) expressions[2]; + this.weightedList = (Expression) expressions[matchedPattern + 1]; + this.weight = (Expression) expressions[matchedPattern == 0 ? 2 : 1]; return LiteralUtils.canInitSafely(this.object); } From 74a313f47032464c1d1572ccaab3b155ff87d346 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 18 May 2026 05:55:44 -0700 Subject: [PATCH 23/34] ExprStructureEntities - add option to return snapshots - Ref #968 --- .../expressions/ExprStructureEntities.java | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/structure/expressions/ExprStructureEntities.java b/src/main/java/com/shanebeestudios/skbee/elements/structure/expressions/ExprStructureEntities.java index 5082db064..d1fce11ba 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/structure/expressions/ExprStructureEntities.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/structure/expressions/ExprStructureEntities.java @@ -7,17 +7,23 @@ import com.shanebeestudios.skbee.api.skript.base.SimpleExpression; import com.shanebeestudios.skbee.api.structure.StructureWrapper; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntitySnapshot; import org.bukkit.event.Event; import org.jetbrains.annotations.Nullable; -public class ExprStructureEntities extends SimpleExpression { +import java.util.ArrayList; +import java.util.List; + +public class ExprStructureEntities extends SimpleExpression { public static void register(Registration reg) { - reg.newCombinedExpression(ExprStructureEntities.class, Entity.class, - "structure template entities of %structuretemplate%") + reg.newCombinedExpression(ExprStructureEntities.class, Object.class, + "structure template entities of %structuretemplate%", + "structure template entity snapshots of %structuretemplate%") .name("Structure - Template Entities") .description("Get a list of entities in a structure template.", - "This cannot be modified.") + "Optionally you can return entity snapshots instead of entities.", + "These cannot be modified.") .examples("loop structure template entities of {_structure}:", "set {_size} to size of structure template entities of {_structure}") .since("3.23.0") @@ -25,18 +31,28 @@ public static void register(Registration reg) { } private Expression structure; + private boolean snapshots; @SuppressWarnings("unchecked") @Override public boolean init(Expression[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) { this.structure = (Expression) expressions[0]; + this.snapshots = matchedPattern == 1; return true; } + @SuppressWarnings("UnstableApiUsage") @Override - protected Entity @Nullable [] get(Event event) { + protected Object @Nullable [] get(Event event) { StructureWrapper structure = this.structure.getSingle(event); if (structure == null) return null; + if (this.snapshots) { + List snapshotList = new ArrayList<>(); + for (Entity entity : structure.getBukkitStructure().getEntities()) { + snapshotList.add(entity.createSnapshot()); + } + return snapshotList.toArray(new EntitySnapshot[0]); + } return structure.getBukkitStructure().getEntities().toArray(new Entity[0]); } @@ -46,13 +62,15 @@ public boolean isSingle() { } @Override - public Class getReturnType() { + public Class getReturnType() { + if (this.snapshots) return EntitySnapshot.class; return Entity.class; } @Override public String toString(@Nullable Event event, boolean debug) { - return "structure template entities of " + this.structure.toString(event, debug); + String type = this.snapshots ? "entity snapshots" : "entities"; + return "structure template " + type + " of " + this.structure.toString(event, debug); } } From 9fe360d696abdce5321debf2f853ead9548a775f Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 18 May 2026 06:09:38 -0700 Subject: [PATCH 24/34] EntityEvents - add entity dye event - Ref #965 --- .../other/events/other/EntityEvents.java | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/EntityEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/EntityEvents.java index edee9f466..d8de801dd 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/EntityEvents.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/EntityEvents.java @@ -1,7 +1,8 @@ package com.shanebeestudios.skbee.elements.other.events.other; -import ch.njol.skript.classes.Changer; +import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.lang.util.SimpleEvent; +import ch.njol.skript.util.SkriptColor; import ch.njol.skript.util.Timespan; import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent; import com.destroystokyo.paper.event.entity.EntityPathfindEvent; @@ -12,8 +13,10 @@ import com.github.shanebeee.skr.Registration; import com.shanebeestudios.skbee.api.event.EntityBlockInteractEvent; import com.shanebeestudios.skbee.api.util.legacy.LegacyUtils; +import io.papermc.paper.event.entity.EntityDyeEvent; import io.papermc.paper.event.entity.EntityInsideBlockEvent; import io.papermc.paper.event.entity.EntityLungeEvent; +import org.bukkit.DyeColor; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; @@ -89,12 +92,12 @@ public static void register(Registration reg) { reg.newEventValue(EntityAirChangeEvent.class, Number.class) .description("The amount of air the entity will have left (measured in ticks).") .converter(EntityAirChangeEvent::getAmount) - .changer(Changer.ChangeMode.SET, (event, value) -> + .changer(ChangeMode.SET, (event, value) -> event.setAmount(value != null ? value.intValue() : 0)) .register(); reg.newEventValue(EntityAirChangeEvent.class, Timespan.class) .converter(event -> new Timespan(Timespan.TimePeriod.TICK, Math.max(event.getAmount(), 0))) - .changer(Changer.ChangeMode.SET, (event, value) -> { + .changer(ChangeMode.SET, (event, value) -> { int amount = value != null ? (int) value.getAs(Timespan.TimePeriod.TICK) : 0; event.setAmount(amount); }) @@ -138,6 +141,34 @@ public static void register(Registration reg) { .converter(EntityChangeBlockEvent::getBlockData) .register(); + // Entity Dye Event + reg.newEvent(EntityEvents.class, EntityDyeEvent.class, "entity dye") + .name("Entity Dye") + .description("Called when an entity is dyed.", + "Currently, this is called for Sheep being dyed, and Wolf/Cat collars being dyed.") + .examples("on entity dye:", + "\tif event-entity is a sheep:", + "\t\tif event-dye is red:", + "\t\t\tcancel event") + .since("INSERT VERSION") + .register(); + + reg.newEventValue(EntityDyeEvent.class, Player.class) + .description("Returns the player dyeing the entity, if available.") + .converter(EntityDyeEvent::getPlayer) + .register(); + + reg.newEventValue(EntityDyeEvent.class, SkriptColor.class) + .description("The color that the entity was dyed with.") + .patterns("dye") + .converter(event -> SkriptColor.fromDyeColor(event.getColor())) + .changer(ChangeMode.SET, (event, value) -> { + DyeColor dyeColor = value.asDyeColor(); + if (dyeColor == null) return; + event.setColor(dyeColor); + }) + .register(); + // EntityInsideBlockEvent reg.newEvent(EntityEvents.class, EntityInsideBlockEvent.class, "entity inside block") .name("Entity Inside Block") @@ -171,7 +202,7 @@ public static void register(Registration reg) { "If set higher than 3, the power of the lunge will continue to scale like normal, as if the max enchantment level is higher.") .patterns("power", "lunge-power") .converter(EntityLungeEvent::getLungePower) - .changer(Changer.ChangeMode.SET, (event, value) -> event.setLungePower(value.intValue())) + .changer(ChangeMode.SET, (event, value) -> event.setLungePower(value.intValue())) .register(); } From 4b62c3e1c477debbf8889fdba142bc5bbc0a5680 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 18 May 2026 06:42:45 -0700 Subject: [PATCH 25/34] BlockEvents - add block lock check event --- .../other/events/other/BlockEvents.java | 61 +++++++++++++++++-- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/BlockEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/BlockEvents.java index 0f21fc106..43299373a 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/BlockEvents.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/BlockEvents.java @@ -1,9 +1,14 @@ package com.shanebeestudios.skbee.elements.other.events.other; import ch.njol.skript.aliases.ItemType; -import ch.njol.skript.classes.Changer; +import ch.njol.skript.bukkitutil.SoundUtils; +import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.lang.util.SimpleEvent; import com.github.shanebeee.skr.Registration; +import io.papermc.paper.event.block.BlockLockCheckEvent; +import net.kyori.adventure.sound.Sound; +import net.kyori.adventure.text.Component; +import org.bukkit.NamespacedKey; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; @@ -86,33 +91,77 @@ public static void register(Registration reg) { .description("Represents the percentage of blocks to drop from this explosion.") .patterns("yield") .converter(BlockExplodeEvent::getYield) - .changer(Changer.ChangeMode.SET, (event, value) -> event.setYield(value.floatValue())) + .changer(ChangeMode.SET, (event, value) -> event.setYield(value.floatValue())) .register(); reg.newEventValue(BlockExplodeEvent.class, Block[].class) .description("Represents the blocks which exploded.") .patterns("exploded-blocks") .converter(from -> from.blockList().toArray(new Block[0])) - .changer(Changer.ChangeMode.SET, (event, value) -> { + .changer(ChangeMode.SET, (event, value) -> { event.blockList().clear(); if (value != null && value.length > 0) { event.blockList().addAll(List.of(value)); } }) - .changer(Changer.ChangeMode.ADD, (event, value) -> { + .changer(ChangeMode.ADD, (event, value) -> { if (value != null) { for (Block block : value) { event.blockList().add(block); } } }) - .changer(Changer.ChangeMode.REMOVE, (event, value) -> { + .changer(ChangeMode.REMOVE, (event, value) -> { if (value != null) { for (Block block : value) { event.blockList().remove(block); } } }) - .changer(Changer.ChangeMode.DELETE, (event, value) -> event.blockList().clear()) + .changer(ChangeMode.DELETE, (event, value) -> event.blockList().clear()) + .register(); + + // Block Lock Check Event + reg.newEvent(BlockEvents.class, BlockLockCheckEvent.class, "block lock check") + .name("Block Lock Check") + .description("Called when the server tries to check the lock on a lockable block entity.") + .register(); + + reg.newEventValue(BlockLockCheckEvent.class, Player.class) + .description("Get the player involved this lock check.") + .converter(BlockLockCheckEvent::getPlayer) + .register(); + reg.newEventValue(BlockLockCheckEvent.class, ItemStack.class) + .description("Represents the item used to check the lock.") + .converter(BlockLockCheckEvent::getKeyItem) + .changer(ChangeMode.SET, BlockLockCheckEvent::setKeyItem) + .register(); + reg.newEventValue(BlockLockCheckEvent.class, Component.class) + .description("Represents the locked message that will be sent if the player cannot open the block.") + .patterns("locked-message", "locked message") + .converter(BlockLockCheckEvent::getLockedMessage) + .changer(ChangeMode.SET, BlockLockCheckEvent::setLockedMessage) + .register(); + reg.newEventValue(BlockLockCheckEvent.class, String.class) + .description("Represents the locked sound that will play if the player cannot open the block.") + .converter(event -> { + Sound lockedSound = event.getLockedSound(); + if (lockedSound == null) return null; + + return lockedSound.name().toString(); + }) + .changer(ChangeMode.SET, (event, sound) -> { + NamespacedKey key = SoundUtils.getKey(sound); + if (key == null) return; + + Sound lockedSound = event.getLockedSound(); + + Sound.Source source = lockedSound != null ? lockedSound.source() : Sound.Source.BLOCK; + float volume = lockedSound != null ? lockedSound.volume() : 1.0f; + float pitch = lockedSound != null ? lockedSound.pitch() : 1.0f; + Sound sound1 = Sound.sound(key, source, volume, pitch); + + event.setLockedSound(sound1); + }) .register(); // Moisture Change Event From 5acdf072c87f9dc9be6f3ec8ddf97247513b9e74 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 18 May 2026 06:43:37 -0700 Subject: [PATCH 26/34] SecDynamicRunCommandActionButton - fix doc - Ref #969 --- .../sections/actions/SecDynamicRunCommandActionButton.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/dialog/sections/actions/SecDynamicRunCommandActionButton.java b/src/main/java/com/shanebeestudios/skbee/elements/dialog/sections/actions/SecDynamicRunCommandActionButton.java index fe7f7142a..f27aa3c8d 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/dialog/sections/actions/SecDynamicRunCommandActionButton.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/dialog/sections/actions/SecDynamicRunCommandActionButton.java @@ -57,7 +57,7 @@ public static void register(Registration reg) { "- `width` = The width of the button. Value between 1 and 1024 — Defaults to 150.", "- `template` = The command template including macros that will run when clicked.") .examples("command /message:", - "\trigger:", + "\ttrigger:", "\t\topen multi action dialog to player:", "\t\t\ttitle: \"Send a message:\"", "\t\t\tinputs:", From 85d77c5977fc7f619de48213aa08e1df744c011e Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 18 May 2026 07:08:45 -0700 Subject: [PATCH 27/34] SecSingleOptionInput - fix docs typo - Ref #970 --- .../dialog/sections/inputs/SecSingleOptionInput.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/dialog/sections/inputs/SecSingleOptionInput.java b/src/main/java/com/shanebeestudios/skbee/elements/dialog/sections/inputs/SecSingleOptionInput.java index ccf4f8173..4ac781e0b 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/dialog/sections/inputs/SecSingleOptionInput.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/dialog/sections/inputs/SecSingleOptionInput.java @@ -61,13 +61,13 @@ public static void register(Registration reg) { "\tkey: \"le_key\"", "\tlabel: \"Choose favorite animal\"", "\toptions:", - "\t\tadd options entity:", + "\t\tadd options entry:", "\t\t\tdisplay: \"cat\"", - "\t\tadd options entity:", + "\t\tadd options entry:", "\t\t\tdisplay: \"dog\"", - "\t\tadd options entity:", + "\t\tadd options entry:", "\t\t\tdisplay: \"turtle\"", - "\t\tadd options entity:", + "\t\tadd options entry:", "\t\t\tdisplay: \"spider\"") .since("3.16.0") .register(); From 7e5a17a1109e57c27252e6835e781b17087c7f3b Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 18 May 2026 15:34:09 -0700 Subject: [PATCH 28/34] RecipeUtil - add recipe reloader --- .../skbee/api/recipe/RecipeUtil.java | 52 ++++++++++++++++++- .../recipe/effects/EffCookingRecipe.java | 7 +-- .../recipe/effects/EffCraftingRecipe.java | 10 ++-- .../recipe/effects/EffRemoveRecipe.java | 40 +++++--------- .../recipe/effects/EffStonecuttingRecipe.java | 7 +-- .../recipe/sections/SecRecipeSmithing.java | 1 - 6 files changed, 70 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/api/recipe/RecipeUtil.java b/src/main/java/com/shanebeestudios/skbee/api/recipe/RecipeUtil.java index 7f83dfaf5..3a6df3a70 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/recipe/RecipeUtil.java +++ b/src/main/java/com/shanebeestudios/skbee/api/recipe/RecipeUtil.java @@ -7,11 +7,15 @@ import com.shanebeestudios.skbee.SkBee; import com.shanebeestudios.skbee.api.util.Util; import com.shanebeestudios.skbee.elements.recipe.sections.SecRecipeSmithing; +import io.papermc.paper.event.server.ServerResourcesReloadedEvent; import io.papermc.paper.potion.PotionMix; import org.bukkit.Bukkit; import org.bukkit.Keyed; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.Tag; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; import org.bukkit.inventory.CookingRecipe; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; @@ -39,12 +43,30 @@ public class RecipeUtil { private static final Map CATEGORY_MAP = new HashMap<>(); + private static final Map CUSTOM_RECIPES = new HashMap<>(); static { for (CraftingBookCategory value : CraftingBookCategory.values()) { String name = value.name().toLowerCase(Locale.ROOT); CATEGORY_MAP.put(name, value); } + + Bukkit.getPluginManager().registerEvents(new Listener() { + @EventHandler + private void onServerReloadResources(ServerResourcesReloadedEvent event) { + int count = CUSTOM_RECIPES.size(); + if (count == 0) return; + + String plural = count == 1 ? "" : "s"; + log("Detected server resource reload, re-adding %d custom recipe%s", count, plural); + CUSTOM_RECIPES.forEach((key, recipe) -> { + if (SkBee.isDebug()) { + log("Re-dding custom recipe: '%s'", key); + } + Bukkit.addRecipe(recipe); + }); + } + }, SkBee.getPlugin()); } /** @@ -88,10 +110,32 @@ public static void removeAllMCRecipes() { }); Bukkit.clearRecipes(); recipes.forEach(Bukkit::addRecipe); + if (SkBee.isDebug()) { + log("&aRemoving all Minecraft recipes."); + } } catch (NoSuchElementException ignore) { } } + public static void removeAllRecipes() { + Bukkit.clearRecipes(); + if (SkBee.isDebug()) { + log("&aRemoving all recipes."); + } + CUSTOM_RECIPES.clear(); + } + + public static void removeRecipe(String recipe) { + NamespacedKey key = Util.getNamespacedKey(recipe, false); + if (key != null) { + Bukkit.removeRecipe(key); + CUSTOM_RECIPES.remove(key); + if (SkBee.isDebug()) { + log("&aRemoving recipe: " + recipe); + } + } + } + public static CraftingBookCategory getCraftingBookCategory(String name) { return CATEGORY_MAP.get(name); } @@ -103,7 +147,8 @@ public static CraftingBookCategory getCraftingBookCategory(String name) { * @param recipe Recipe to log * @param ingredients Ingredients of recipe to log */ - public static void logRecipe(Recipe recipe, RecipeChoice... ingredients) { + public static void logRecipe(NamespacedKey key, Recipe recipe, RecipeChoice... ingredients) { + CUSTOM_RECIPES.put(key, recipe); if (!SkBee.isDebug() || TestMode.DEV_MODE) return; if (!(recipe instanceof Keyed)) return; log("&aRegistered new recipe: &7(&b%s&7)", ((Keyed) recipe).getKey().toString()); @@ -122,6 +167,7 @@ public static void logRecipe(Recipe recipe, RecipeChoice... ingredients) { * @param recipe Recipe to log */ public static void logCookingRecipe(CookingRecipe recipe) { + CUSTOM_RECIPES.put(recipe.getKey(), recipe); if (!SkBee.isDebug() || TestMode.DEV_MODE) return; String type = recipe.getClass().getSimpleName().replace("Recipe", "").toLowerCase(Locale.ROOT); log("&aRegistered new %s recipe: &7(&b%s&7)", type, ((Keyed) recipe).getKey().toString()); @@ -142,6 +188,7 @@ public static void logCookingRecipe(CookingRecipe recipe) { * @param recipe Recipe to log */ public static void logShapelessRecipe(ShapelessRecipe recipe) { + CUSTOM_RECIPES.put(recipe.getKey(), recipe); if (!SkBee.isDebug() || TestMode.DEV_MODE) return; log("&aRegistered new shapeless recipe: &7(&b%s&7)", recipe.getKey().toString()); log(" - &7Result: &e%s", recipe.getResult()); @@ -161,6 +208,7 @@ public static void logShapelessRecipe(ShapelessRecipe recipe) { * @param recipe Recipe to log */ public static void logShapedRecipe(ShapedRecipe recipe) { + CUSTOM_RECIPES.put(recipe.getKey(), recipe); if (!SkBee.isDebug() || TestMode.DEV_MODE) return; log("&aRegistered new shaped recipe: &7(&b%s&7)", recipe.getKey().toString()); log(" - &7Result: &e%s", recipe.getResult()); @@ -204,6 +252,7 @@ public static void logBrewingRecipe(PotionMix potionMix) { * @param recipe Recipe to log */ public static void logSmithingRecipe(SmithingTransformRecipe recipe) { + CUSTOM_RECIPES.put(recipe.getKey(), recipe); if (!SkBee.isDebug() || TestMode.DEV_MODE) return; log("&aRegistered new smithing recipe: &7(&b%s&7)", recipe.getKey().toString()); log(" - &7Result: &e%s", recipe.getResult()); @@ -217,6 +266,7 @@ public static void logSmithingRecipe(SmithingTransformRecipe recipe) { } public static void logTransmuteRecipe(TransmuteRecipe recipe) { + CUSTOM_RECIPES.put(recipe.getKey(), recipe); if (!SkBee.isDebug() || TestMode.DEV_MODE) return; log("&aRegistering new transmute recipe: &7(&b%s&7)", recipe.getKey().toString()); log(" - &7Result: &e%s", recipe.getResult().getType().getKey()); diff --git a/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffCookingRecipe.java b/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffCookingRecipe.java index edd5f9169..45b46ca5c 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffCookingRecipe.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffCookingRecipe.java @@ -6,9 +6,8 @@ import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.util.Timespan; import ch.njol.util.Kleenean; -import com.shanebeestudios.skbee.SkBee; -import com.shanebeestudios.skbee.api.recipe.RecipeUtil; import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.api.recipe.RecipeUtil; import com.shanebeestudios.skbee.api.util.Util; import com.shanebeestudios.skbee.config.SkBeeMetrics; import org.bukkit.Bukkit; @@ -132,9 +131,7 @@ private void cookingRecipe(ItemStack result, RecipeChoice ingredient, String gro recipe.setGroup(group); Bukkit.addRecipe(recipe); - if (SkBee.isDebug()) { - RecipeUtil.logCookingRecipe(recipe); - } + RecipeUtil.logCookingRecipe(recipe); } private int getDefaultCookTime(int t) { diff --git a/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffCraftingRecipe.java b/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffCraftingRecipe.java index ea3584fe9..d666d9262 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffCraftingRecipe.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffCraftingRecipe.java @@ -5,9 +5,9 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.util.Kleenean; +import com.github.shanebeee.skr.Registration; import com.shanebeestudios.skbee.SkBee; import com.shanebeestudios.skbee.api.recipe.RecipeUtil; -import com.github.shanebeee.skr.Registration; import com.shanebeestudios.skbee.api.util.Util; import com.shanebeestudios.skbee.config.SkBeeMetrics; import org.bukkit.Bukkit; @@ -169,10 +169,8 @@ private void registerShaped(ItemType item, Object[] ingredients, NamespacedKey k recipe.setIngredient(keyChar[i], recipeChoice); } } - if (SkBee.isDebug()) { - RecipeUtil.logShapedRecipe(recipe); - } Bukkit.addRecipe(recipe); + RecipeUtil.logShapedRecipe(recipe); } private void registerShapeless(ItemType item, Object[] ingredients, NamespacedKey key, String group) { @@ -204,9 +202,7 @@ private void registerShapeless(ItemType item, Object[] ingredients, NamespacedKe } } Bukkit.addRecipe(recipe); - if (SkBee.isDebug()) { - RecipeUtil.logShapelessRecipe(recipe); - } + RecipeUtil.logShapelessRecipe(recipe); } @Override diff --git a/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffRemoveRecipe.java b/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffRemoveRecipe.java index 652918f77..2736fda06 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffRemoveRecipe.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffRemoveRecipe.java @@ -4,12 +4,8 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; -import com.shanebeestudios.skbee.SkBee; -import com.shanebeestudios.skbee.api.recipe.RecipeUtil; import com.github.shanebeee.skr.Registration; -import com.shanebeestudios.skbee.api.util.Util; -import org.bukkit.Bukkit; -import org.bukkit.NamespacedKey; +import com.shanebeestudios.skbee.api.recipe.RecipeUtil; import org.bukkit.event.Event; public class EffRemoveRecipe extends Effect { @@ -44,48 +40,36 @@ public static void register(Registration reg) { @SuppressWarnings("unchecked") @Override public boolean init(Expression[] exprs, int pattern, Kleenean kleenean, SkriptParser.ParseResult parseResult) { - all = pattern == 1; - minecraft = parseResult.mark == 1; - recipes = pattern == 0 ? (Expression) exprs[0] : null; + this.all = pattern == 1; + this.minecraft = parseResult.mark == 1; + this.recipes = pattern == 0 ? (Expression) exprs[0] : null; return true; } @Override protected void execute(Event event) { - if (all) { - if (minecraft) { + if (this.all) { + if (this.minecraft) { RecipeUtil.removeAllMCRecipes(); - if (SkBee.isDebug()) { - RecipeUtil.log("&aRemoving all Minecraft recipes."); - } } else { - Bukkit.clearRecipes(); - if (SkBee.isDebug()) { - RecipeUtil.log("&aRemoving all recipes."); - } + RecipeUtil.removeAllRecipes(); } return; } for (String recipe : this.recipes.getAll(event)) { - NamespacedKey key = Util.getNamespacedKey(recipe, false); - if (key != null) { - Bukkit.removeRecipe(key); - if (SkBee.isDebug()) { - RecipeUtil.log("&aRemoving recipe: " + recipe); - } - } + RecipeUtil.removeRecipe(recipe); } } @Override public String toString(Event e, boolean d) { - if (all) { + if (this.all) { return "remove all minecraft recipes"; - } else if (minecraft) { - return "remove minecraft recipes " + recipes.toString(e, d); + } else if (this.minecraft) { + return "remove minecraft recipes " + this.recipes.toString(e, d); } else { - return "remove custom recipes " + recipes.toString(e, d); + return "remove custom recipes " + this.recipes.toString(e, d); } } diff --git a/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffStonecuttingRecipe.java b/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffStonecuttingRecipe.java index 8a0998fe1..01a3cb53d 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffStonecuttingRecipe.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/recipe/effects/EffStonecuttingRecipe.java @@ -6,9 +6,8 @@ import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser; import ch.njol.util.Kleenean; -import com.shanebeestudios.skbee.SkBee; -import com.shanebeestudios.skbee.api.recipe.RecipeUtil; import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.api.recipe.RecipeUtil; import com.shanebeestudios.skbee.api.util.Util; import com.shanebeestudios.skbee.config.SkBeeMetrics; import org.bukkit.Bukkit; @@ -102,9 +101,7 @@ protected void execute(Event event) { Bukkit.removeRecipe(key); Bukkit.addRecipe(recipe); - if (SkBee.isDebug()) { - RecipeUtil.logRecipe(recipe, recipe.getInputChoice()); - } + RecipeUtil.logRecipe(key, recipe, recipe.getInputChoice()); } @Override diff --git a/src/main/java/com/shanebeestudios/skbee/elements/recipe/sections/SecRecipeSmithing.java b/src/main/java/com/shanebeestudios/skbee/elements/recipe/sections/SecRecipeSmithing.java index 8e5141425..5bd08de57 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/recipe/sections/SecRecipeSmithing.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/recipe/sections/SecRecipeSmithing.java @@ -139,7 +139,6 @@ private void execute(Event event) { Bukkit.removeRecipe(key); Bukkit.addRecipe(recipe); RecipeUtil.logSmithingRecipe(recipe); - } @Override From 2810eff4dc993e75e788336d6522205b8cab5421 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Mon, 18 May 2026 16:24:32 -0700 Subject: [PATCH 29/34] PlayerEvents - add player shear block event - Ref #965 --- .../other/events/other/PlayerEvents.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java index 21e12b033..7976ffbb7 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/events/other/PlayerEvents.java @@ -19,6 +19,7 @@ import io.papermc.paper.connection.PlayerConfigurationConnection; import io.papermc.paper.connection.PlayerConnection; import io.papermc.paper.connection.PlayerGameConnection; +import io.papermc.paper.event.block.PlayerShearBlockEvent; import io.papermc.paper.event.packet.PlayerChunkLoadEvent; import io.papermc.paper.event.packet.PlayerChunkUnloadEvent; import io.papermc.paper.event.player.PlayerCustomClickEvent; @@ -31,6 +32,7 @@ import org.bukkit.Location; import org.bukkit.NamespacedKey; import org.bukkit.OfflinePlayer; +import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.Item; import org.bukkit.entity.Player; @@ -414,6 +416,35 @@ else if (HAS_CONFIG && connection instanceof PlayerConfigurationConnection confi .converter(event -> event.getRecipe().toString()) .register(); + // Player Shear Block Event + reg.newEvent(PlayerEvents.class, PlayerShearBlockEvent.class, "player shear block") + .name("Player Shear Block") + .description("Called when a player uses shears on a block.", + "This event is not called when a player breaks blocks with shears, but rather when a player uses the shears on a block to collect drops from it and/or modify its state.", + "Examples include shearing a pumpkin to turn it into a carved pumpkin or shearing a beehive to get honeycomb.") + .examples("") + .since("INSERT VERSION") + .register(); + + reg.newEventValue(PlayerShearBlockEvent.class, Block.class) + .description("Gets the block being sheared in this event.") + .converter(PlayerShearBlockEvent::getBlock) + .register(); + reg.newEventValue(PlayerShearBlockEvent.class, ItemStack.class) + .description("Gets the item used to shear the block.") + .converter(PlayerShearBlockEvent::getItem) + .register(); + reg.newEventValue(PlayerShearBlockEvent.class, ItemStack[].class) + .description("Gets the resulting drops of this event.") + .patterns("drops") + .converter(event -> event.getDrops().toArray(new ItemStack[0])) + .register(); + reg.newEventValue(PlayerShearBlockEvent.class, EquipmentSlot.class) + .description("Gets the hand used to shear the block.") + .patterns("hand") + .converter(PlayerShearBlockEvent::getHand) + .register(); + // Player Spawn Change Event reg.newEvent(PlayerEvents.class, PlayerSetSpawnEvent.class, "player spawn change") .name("Player Spawn Change") From 1c0bf39456e869af7a25d99e34ab5438c15ec6f0 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 20 May 2026 06:25:16 -0700 Subject: [PATCH 30/34] LazyLocation - use keys --- .../skbee/api/wrapper/LazyLocation.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/api/wrapper/LazyLocation.java b/src/main/java/com/shanebeestudios/skbee/api/wrapper/LazyLocation.java index e31565c34..8b21e1b0a 100644 --- a/src/main/java/com/shanebeestudios/skbee/api/wrapper/LazyLocation.java +++ b/src/main/java/com/shanebeestudios/skbee/api/wrapper/LazyLocation.java @@ -2,6 +2,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.util.NumberConversions; @@ -18,17 +19,24 @@ public class LazyLocation extends Location { private String worldName; + private NamespacedKey worldKey; public LazyLocation(World world, double x, double y, double z, float yaw, float pitch) { super(world, x, y, z, yaw, pitch); - this.worldName = world.getName(); + this.worldKey = world.getKey(); } + @Deprecated(forRemoval = true, since = "INSERT VERSION") public LazyLocation(String worldName, double x, double y, double z, float yaw, float pitch) { super(null, x, y, z, yaw, pitch); this.worldName = worldName; } + public LazyLocation(NamespacedKey worldKey, double x, double y, double z, float yaw, float pitch) { + super(null, x, y, z, yaw, pitch); + this.worldKey = worldKey; + } + public LazyLocation(Location location) { super(location.getWorld(), location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); } @@ -54,9 +62,12 @@ public Location getLocation() { public @NotNull Map serialize() { Map data = super.serialize(); - if (!data.containsKey("world")) { + if (!data.containsKey("world") && this.worldName != null) { data.put("world", this.worldName); } + if (!data.containsKey("world_key") && this.worldKey != null) { + data.put("world_key", this.worldKey.toString()); + } return data; } @@ -74,6 +85,15 @@ public static Location deserialize(@NotNull Map args) { return new LazyLocation(name, NumberConversions.toDouble(args.get("x")), NumberConversions.toDouble(args.get("y")), NumberConversions.toDouble(args.get("z")), NumberConversions.toFloat(args.get("yaw")), NumberConversions.toFloat(args.get("pitch"))); } } + if (args.containsKey("world_key")) { + String name = (String) args.get("world_key"); + NamespacedKey key = NamespacedKey.fromString(name); + assert key != null : "NamespacedKey cannot be null"; + world = Bukkit.getWorld(key); + if (world == null) { + return new LazyLocation(key, NumberConversions.toDouble(args.get("x")), NumberConversions.toDouble(args.get("y")), NumberConversions.toDouble(args.get("z")), NumberConversions.toFloat(args.get("yaw")), NumberConversions.toFloat(args.get("pitch"))); + } + } return new LazyLocation(world, NumberConversions.toDouble(args.get("x")), NumberConversions.toDouble(args.get("y")), NumberConversions.toDouble(args.get("z")), NumberConversions.toFloat(args.get("yaw")), NumberConversions.toFloat(args.get("pitch"))); } From 86268b467f5ccf5efdb1c8324d2e432512f83a98 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 20 May 2026 06:51:31 -0700 Subject: [PATCH 31/34] CondNBTIsBlank - fix registration type --- .../skbee/elements/nbt/conditions/CondNBTIsBlank.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/nbt/conditions/CondNBTIsBlank.java b/src/main/java/com/shanebeestudios/skbee/elements/nbt/conditions/CondNBTIsBlank.java index a23444b93..4f583d833 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/nbt/conditions/CondNBTIsBlank.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/nbt/conditions/CondNBTIsBlank.java @@ -7,7 +7,7 @@ public class CondNBTIsBlank extends PropertyCondition { public static void register(Registration reg) { - reg.newCondition(CondNBTIsBlank.class, "[a[n]] (blank|empty) nbt compound", "nbtcompounds") + reg.newPropertyCondition(CondNBTIsBlank.class, "[a[n]] (blank|empty) nbt compound", "nbtcompounds") .name("NBT - Is Blank Compound") .description("Checks whether or not the provided nbt compounds are empty.") .examples("broadcast whether empty nbt compound is an empty nbt compound", From 8e8ec2f48ec692f00850d4655846714d4c400069 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 20 May 2026 11:35:34 -0700 Subject: [PATCH 32/34] build.gradle.kts - update SKR --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index c5a7f6c80..cbaadcef1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -46,7 +46,7 @@ dependencies { compileOnly("com.github.SkriptLang:Skript:2.15.0") // SkriptRegistration - implementation("com.github.ShaneBeee:SkriptRegistration:1.4.2") + implementation("com.github.ShaneBeee:SkriptRegistration:1.4.3") // commons-io compileOnly("commons-io:commons-io:2.14.0") From fa1ec440c4ceb818624e70a0e13b1f6faf829f45 Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 20 May 2026 11:43:05 -0700 Subject: [PATCH 33/34] Fix some --- .../elements/other/type/EntityTypes.java | 7 ++-- .../skbee/elements/particle/type/Types.java | 41 +++++++++++-------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/shanebeestudios/skbee/elements/other/type/EntityTypes.java b/src/main/java/com/shanebeestudios/skbee/elements/other/type/EntityTypes.java index 29fee704e..c1b7e8516 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/other/type/EntityTypes.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/other/type/EntityTypes.java @@ -2,7 +2,6 @@ import ch.njol.skript.registrations.Classes; import com.github.shanebeee.skr.Registration; -import com.github.shanebeee.skr.skript.RegistryClassInfo; import com.shanebeestudios.skbee.api.util.Util; import org.bukkit.Registry; import org.bukkit.entity.EntityType; @@ -33,10 +32,12 @@ public static void register(Registration reg) { if (Classes.getExactClassInfo(MemoryKey.class) == null) { //noinspection unchecked,rawtypes - Classes.registerClass(RegistryClassInfo.create(Registry.MEMORY_MODULE_TYPE, (Class) MemoryKey.class, "memory") + reg.newRegistryType(Registry.MEMORY_MODULE_TYPE, (Class) MemoryKey.class, "memory") .user("memor(y|ies)") .name("Memory") - .description("Represents the different memories of an entity.", Util.AUTO_GEN_NOTE)); + .description("Represents the different memories of an entity.", Util.AUTO_GEN_NOTE) + .since("3.4.0") + .register(); } else { Util.logLoading("It looks like another addon registered 'memory' already."); Util.logLoading("You may have to use their ItemFlags in SkBee's syntaxes."); diff --git a/src/main/java/com/shanebeestudios/skbee/elements/particle/type/Types.java b/src/main/java/com/shanebeestudios/skbee/elements/particle/type/Types.java index 98f7a1c93..64f61afc1 100644 --- a/src/main/java/com/shanebeestudios/skbee/elements/particle/type/Types.java +++ b/src/main/java/com/shanebeestudios/skbee/elements/particle/type/Types.java @@ -1,14 +1,13 @@ package com.shanebeestudios.skbee.elements.particle.type; -import ch.njol.skript.classes.ClassInfo; import ch.njol.skript.classes.Parser; import ch.njol.skript.lang.ParseContext; import ch.njol.skript.registrations.Classes; import ch.njol.skript.util.Color; import ch.njol.skript.util.SkriptColor; import ch.njol.skript.util.Timespan; -import com.shanebeestudios.skbee.api.particle.ParticleWrapper; import com.github.shanebeee.skr.Registration; +import com.shanebeestudios.skbee.api.particle.ParticleWrapper; import com.shanebeestudios.skbee.api.util.SkriptUtils; import com.shanebeestudios.skbee.api.util.Util; import org.bukkit.Location; @@ -43,8 +42,9 @@ private static void registerTypes(Registration reg) { .register(); if (Classes.getExactClassInfo(DustOptions.class) == null) { - Classes.registerClass(new ClassInfo<>(DustOptions.class, "dustoption") - .name(ClassInfo.NO_DOC).user("dust ?options?") + reg.newType(DustOptions.class, "dustoption") + .noDoc() + .user("dust ?options?") .parser(new Parser<>() { @Override public boolean canParse(ParseContext context) { @@ -73,45 +73,52 @@ public boolean canParse(ParseContext context) { public @NotNull String toVariableNameString(DustOptions o) { return toString(o, 0); } - })); + }) + .register(); } else { Util.logLoading("It looks like another addon registered 'dustoption' already."); Util.logLoading("You may have to use their DustOption in SkBee's syntaxes."); } if (Classes.getExactClassInfo(DustTransition.class) == null) { - Classes.registerClass(new ClassInfo<>(DustTransition.class, "dusttransition") - .name(ClassInfo.NO_DOC).user("dust ?transitions?") - .parser(SkriptUtils.getDefaultParser())); + reg.newType(DustTransition.class, "dusttransition") + .noDoc() + .user("dust ?transitions?") + .parser(SkriptUtils.getDefaultParser()) + .register(); } else { Util.logLoading("It looks like another addon registered 'dusttransition' already."); Util.logLoading("You may have to use their DustTransition in SkBee's syntaxes."); } if (Classes.getExactClassInfo(Vibration.class) == null) { - Classes.registerClass(new ClassInfo<>(Vibration.class, "vibration") - .name(ClassInfo.NO_DOC).user("vibrations?") - .parser(SkriptUtils.getDefaultParser())); + reg.newType(Vibration.class, "vibration") + .noDoc() + .user("vibrations?") + .parser(SkriptUtils.getDefaultParser()) + .register(); } else { Util.logLoading("It looks like another addon registered 'vibration' already."); Util.logLoading("You may have to use their Vibration in SkBee's syntaxes."); } if (Classes.getExactClassInfo(Trail.class) == null) { - Classes.registerClass(new ClassInfo<>(Trail.class, "trail") - .name(ClassInfo.NO_DOC) + reg.newType(Trail.class, "trail") + .noDoc() .user("trails?") - .parser(SkriptUtils.getDefaultParser())); + .parser(SkriptUtils.getDefaultParser()) + .register(); } else { Util.logLoading("It looks like another addon registered 'trail' already."); Util.logLoading("You may have to use their Trail in SkBee's syntaxes."); } if (Classes.getExactClassInfo(Particle.Spell.class) == null) { - Classes.registerClass(new ClassInfo<>(Particle.Spell.class, "particlespell") - .name(ClassInfo.NO_DOC) + reg.newType(Particle.Spell.class, "particlespell") + .noDoc() .user("particle ?spells?") - .parser(SkriptUtils.getDefaultParser())); + .parser(SkriptUtils.getDefaultParser()) + .register(); } else { Util.logLoading("It looks like another addon registered 'particlespell' already."); Util.logLoading("You may have to use their Particle Spell in SkBee's syntaxes."); From 1308b74f1b5020865ac24c2092c0b77f9fe5724d Mon Sep 17 00:00:00 2001 From: ShaneBeee Date: Wed, 20 May 2026 21:58:02 -0700 Subject: [PATCH 34/34] Update SkBee command --- .../java/com/shanebeestudios/skbee/SkBee.java | 4 +- .../skbee/api/command/SkBeeCommand.java | 97 +++++++++++++ .../skbee/api/command/SkBeeInfo.java | 132 ------------------ 3 files changed, 99 insertions(+), 134 deletions(-) create mode 100644 src/main/java/com/shanebeestudios/skbee/api/command/SkBeeCommand.java delete mode 100644 src/main/java/com/shanebeestudios/skbee/api/command/SkBeeInfo.java diff --git a/src/main/java/com/shanebeestudios/skbee/SkBee.java b/src/main/java/com/shanebeestudios/skbee/SkBee.java index 8c1e4b232..0ca6131aa 100644 --- a/src/main/java/com/shanebeestudios/skbee/SkBee.java +++ b/src/main/java/com/shanebeestudios/skbee/SkBee.java @@ -5,7 +5,7 @@ import com.github.shanebeee.skr.scheduling.TaskUtils; import com.shanebeestudios.skbee.api.bound.Bound; import com.shanebeestudios.skbee.api.bound.BoundConfig; -import com.shanebeestudios.skbee.api.command.SkBeeInfo; +import com.shanebeestudios.skbee.api.command.SkBeeCommand; import com.shanebeestudios.skbee.api.structure.StructureManager; import com.shanebeestudios.skbee.api.util.Util; import com.shanebeestudios.skbee.api.util.update.UpdateChecker; @@ -63,7 +63,7 @@ public void onEnable() { // Check if SkriptAddon can actually load this.properlyEnabled = this.addonLoader.canLoadPlugin(); - registerCommand("skbee", new SkBeeInfo(this)); + SkBeeCommand.registerCommand(this); SkBeeMetrics.loadMetrics(this, this.properlyEnabled, skBeeVersion); // Beta check + notice diff --git a/src/main/java/com/shanebeestudios/skbee/api/command/SkBeeCommand.java b/src/main/java/com/shanebeestudios/skbee/api/command/SkBeeCommand.java new file mode 100644 index 000000000..034c1770f --- /dev/null +++ b/src/main/java/com/shanebeestudios/skbee/api/command/SkBeeCommand.java @@ -0,0 +1,97 @@ +package com.shanebeestudios.skbee.api.command; + +import ch.njol.skript.Skript; +import ch.njol.skript.SkriptUpdater; +import com.github.shanebeee.skr.JsonDocGenerator; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.shanebeestudios.skbee.SkBee; +import com.shanebeestudios.skbee.api.util.Util; +import com.shanebeestudios.skbee.config.Config; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; +import io.papermc.paper.plugin.configuration.PluginMeta; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; + +import static com.shanebeestudios.skbee.api.util.Util.sendColMsg; + +public class SkBeeCommand { + + public static void registerCommand(SkBee plugin) { + Config config = plugin.getPluginConfig(); + + LiteralArgumentBuilder command = Commands.literal("skbee") + .requires(context -> context.getSender().hasPermission("skbee.command")) + .then(Commands.literal("info") + .executes(context -> { + info(context.getSource().getSender(), plugin); + return Command.SINGLE_SUCCESS; + })) + .then(Commands.literal("debug") + .then(Commands.literal("enable") + .executes(context -> { + Util.sendMiniPrefixed(context.getSource().getSender(), "Debug mode is now enabled!"); + config.settings_debug = true; + return Command.SINGLE_SUCCESS; + })) + .then(Commands.literal("disable") + .executes(context -> { + Util.sendMiniPrefixed(context.getSource().getSender(), "Debug mode is now disabled!"); + config.settings_debug = false; + return Command.SINGLE_SUCCESS; + })) + .executes(context -> { + String enabled = config.settings_debug ? "enabled" : "disabled"; + Util.sendMiniPrefixed(context.getSource().getSender(), "Debug mode is currently %s", enabled); + return Command.SINGLE_SUCCESS; + })) + .then(Commands.literal("docs") + .executes(context -> { + JsonDocGenerator docs = new JsonDocGenerator(plugin, plugin.getAddonLoader().getRegistration()); + docs.generateDocs(); + return Command.SINGLE_SUCCESS; + })); + + plugin.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, commands -> { + commands.registrar().register(command.build()); + }); + } + + private static void info(CommandSender sender, SkBee plugin) { + PluginMeta pluginMeta = plugin.getPluginMeta(); + sendColMsg(sender, "&7--- [&bSkBee Loading Info&7] ---"); + + // SkBee element info + Util.getDebugs().forEach(debug -> sendColMsg(sender, "- &7" + debug)); + sendColMsg(sender, "&7--- [&bServer Info&7] ---"); + + // Server version + sendColMsg(sender, "&7Server Version: &b" + Bukkit.getName() + " " + Bukkit.getVersion()); + + // Skript version + SkriptUpdater updater = Skript.getInstance().getUpdater(); + String flavor = "&cunknown-flavor"; + if (updater != null) { + flavor = updater.getCurrentRelease().flavor; + if (flavor.equalsIgnoreCase("skriptlang-github")) flavor = "&a" + flavor; + else flavor = "&e" + flavor; + } + sendColMsg(sender, "&7Skript Version: &b%s &7(%s&7)", Skript.getVersion(), flavor); + + // Addon versions + sendColMsg(sender, "&7Skript Addons:"); + Skript.getAddons().forEach(addon -> { + String name = addon.getName(); + if (!name.contains("SkBee")) { + sendColMsg(sender, "&7- &b" + name + " v" + addon.plugin.getPluginMeta().getVersion()); + } + }); + + // SkBee info + sendColMsg(sender, "&7SkBee Version: &b" + pluginMeta.getVersion()); + sendColMsg(sender, "&7SkBee Website: &b" + pluginMeta.getWebsite()); + } + +} diff --git a/src/main/java/com/shanebeestudios/skbee/api/command/SkBeeInfo.java b/src/main/java/com/shanebeestudios/skbee/api/command/SkBeeInfo.java deleted file mode 100644 index 38a8b7ed8..000000000 --- a/src/main/java/com/shanebeestudios/skbee/api/command/SkBeeInfo.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.shanebeestudios.skbee.api.command; - -import ch.njol.skript.Skript; -import ch.njol.skript.SkriptUpdater; -import com.shanebeestudios.skbee.SkBee; -import com.shanebeestudios.skbee.api.property.PropertyPrinter; -import com.github.shanebeee.skr.JsonDocGenerator; -import com.shanebeestudios.skbee.api.util.Util; -import com.shanebeestudios.skbee.config.Config; -import io.papermc.paper.command.brigadier.BasicCommand; -import io.papermc.paper.command.brigadier.CommandSourceStack; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.permissions.PermissionDefault; -import org.bukkit.plugin.PluginDescriptionFile; -import org.bukkit.util.permissions.DefaultPermissions; -import org.jetbrains.annotations.NotNull; -import org.jspecify.annotations.Nullable; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.StringJoiner; - -import static com.shanebeestudios.skbee.api.util.Util.sendColMsg; - -/** - * Base SkBee command - * // TODO I would like to eventually use Paper's proper command system - */ -public class SkBeeInfo implements BasicCommand { - - private final SkBee plugin; - private static final List commands = List.of("info", "debug"); - private static final List debugs = List.of("enable", "disable"); - private final PluginDescriptionFile desc; - private final Config config; - - @SuppressWarnings("deprecation") - public SkBeeInfo(SkBee plugin) { - this.plugin = plugin; - this.desc = plugin.getDescription(); - this.config = plugin.getPluginConfig(); - DefaultPermissions.registerPermission("skbee.admin", "Permission to receive error messages", PermissionDefault.OP); - DefaultPermissions.registerPermission("skbee.command", "Permission to use SkBee's main command", PermissionDefault.OP); - - } - - @Override - public @NotNull Collection suggest(@NotNull CommandSourceStack commandSourceStack, String[] args) { - if (args.length <= 1) { - return commands; - } else if (args.length == 2 && args[0].equalsIgnoreCase("debug")) { - return debugs; - } - return Collections.emptyList(); - } - - @Override - public void execute(CommandSourceStack commandSourceStack, String[] args) { - CommandSender sender = commandSourceStack.getSender(); - if (args.length == 0) { - StringJoiner joiner = new StringJoiner("/"); - commands.forEach(joiner::add); - Util.sendColMsg(sender, "Usage: /skbee <" + joiner + ">"); - } else { - // INFO COMMAND - if (args[0].equalsIgnoreCase("info")) { - sendColMsg(sender, "&7--- [&bSkBee Loading Info&7] ---"); - - // SkBee element info - Util.getDebugs().forEach(debug -> sendColMsg(sender, "- &7" + debug)); - sendColMsg(sender, "&7--- [&bServer Info&7] ---"); - - // Server version - sendColMsg(sender, "&7Server Version: &b" + Bukkit.getName() + " " + Bukkit.getVersion()); - - // Skript version - SkriptUpdater updater = Skript.getInstance().getUpdater(); - String flavor = "&cunknown-flavor"; - if (updater != null) { - flavor = updater.getCurrentRelease().flavor; - if (flavor.equalsIgnoreCase("skriptlang-github")) flavor = "&a" + flavor; - else flavor = "&e" + flavor; - } - sendColMsg(sender, "&7Skript Version: &b%s &7(%s&7)", Skript.getVersion(), flavor); - - // Addon versions - sendColMsg(sender, "&7Skript Addons:"); - Skript.getAddons().forEach(addon -> { - String name = addon.getName(); - if (!name.contains("SkBee")) { - sendColMsg(sender, "&7- &b" + name + " v" + addon.plugin.getPluginMeta().getVersion()); - } - }); - - // SkBee info - sendColMsg(sender, "&7SkBee Version: &b" + desc.getVersion()); - sendColMsg(sender, "&7SkBee Website: &b" + desc.getWebsite()); - } - // DEBUG COMMAND - else if (args[0].equalsIgnoreCase("debug")) { - if (args.length > 1 && args[1].equalsIgnoreCase("enable")) { - Util.sendColMsg(sender, "Debug mode is now &aenabled!"); - this.config.settings_debug = true; - } else if (args.length > 1 && args[1].equalsIgnoreCase("disable")) { - Util.sendColMsg(sender, "Debug mode is now &cdisabled!"); - this.config.settings_debug = false; - } else { - String enabled = this.config.settings_debug ? "&aenabled" : "&cdisabled"; - Util.sendColMsg(sender, "Debug mode is currently %s", enabled); - } - } - // PROPERTY PRINTER - else if (args[0].equalsIgnoreCase("properties")) { - PropertyPrinter.printAll(); - } - - // JSON DOCS - else if (args[0].equalsIgnoreCase("docs")) { - JsonDocGenerator docs = new JsonDocGenerator(this.plugin, this.plugin.getAddonLoader().getRegistration()); - docs.generateDocs(); - } - } - } - - @Override - public @Nullable String permission() { - return "skbee.command"; - } - -}