diff --git a/src/main/java/com/artillexstudios/axminions/command/AxMinionsCommand.java b/src/main/java/com/artillexstudios/axminions/command/AxMinionsCommand.java index 5f7cb27..e44f121 100644 --- a/src/main/java/com/artillexstudios/axminions/command/AxMinionsCommand.java +++ b/src/main/java/com/artillexstudios/axminions/command/AxMinionsCommand.java @@ -41,11 +41,11 @@ public final class AxMinionsCommand { .withPermission("axminions.command.debug.spawn") .executesPlayer((sender, args) -> { Location location = LocationUtils.toBlockCenter(sender.getLocation()); - MinionData data = new MinionData(0, MinionTypes.parse("miner"), new Level(1, 20, new Skin("cool", Map.ofEntries(Map.entry(EquipmentSlot.BOOTS, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_BOOTS))), Map.entry(EquipmentSlot.LEGGINGS, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_LEGGINGS))), Map.entry(EquipmentSlot.CHEST_PLATE, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_CHESTPLATE))), Map.entry(EquipmentSlot.HELMET, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_HELMET))), Map.entry(EquipmentSlot.MAIN_HAND, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_PICKAXE))), Map.entry(EquipmentSlot.OFF_HAND, WrappedItemStack.wrap(new ItemStack(Material.AIR)))))), new ItemStack(Material.DIAMOND_HOE), new Skin("cool", Map.ofEntries(Map.entry(EquipmentSlot.BOOTS, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_BOOTS))), Map.entry(EquipmentSlot.LEGGINGS, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_LEGGINGS))), Map.entry(EquipmentSlot.CHEST_PLATE, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_CHESTPLATE))), Map.entry(EquipmentSlot.HELMET, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_HELMET))), Map.entry(EquipmentSlot.MAIN_HAND, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_PICKAXE))), Map.entry(EquipmentSlot.OFF_HAND, WrappedItemStack.wrap(new ItemStack(Material.AIR))))), new HashMap<>()); + MinionData data = new MinionData(0, MinionTypes.parse("miner"), new Level(1, 80, new Skin("cool", Map.ofEntries(Map.entry(EquipmentSlot.BOOTS, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_BOOTS))), Map.entry(EquipmentSlot.LEGGINGS, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_LEGGINGS))), Map.entry(EquipmentSlot.CHEST_PLATE, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_CHESTPLATE))), Map.entry(EquipmentSlot.HELMET, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_HELMET))), Map.entry(EquipmentSlot.MAIN_HAND, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_PICKAXE))), Map.entry(EquipmentSlot.OFF_HAND, WrappedItemStack.wrap(new ItemStack(Material.AIR)))))), new ItemStack(Material.DIAMOND_HOE), new Skin("cool", Map.ofEntries(Map.entry(EquipmentSlot.BOOTS, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_BOOTS))), Map.entry(EquipmentSlot.LEGGINGS, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_LEGGINGS))), Map.entry(EquipmentSlot.CHEST_PLATE, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_CHESTPLATE))), Map.entry(EquipmentSlot.HELMET, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_HELMET))), Map.entry(EquipmentSlot.MAIN_HAND, WrappedItemStack.wrap(new ItemStack(Material.DIAMOND_PICKAXE))), Map.entry(EquipmentSlot.OFF_HAND, WrappedItemStack.wrap(new ItemStack(Material.AIR))))), new HashMap<>()); Minion minion = new Minion(location, data); minion.spawn(); MinionArea area = MinionWorldCache.getArea(location.getWorld()); - area.load(minion); + MinionWorldCache.add(minion); area.startTicking(location.getChunk()); }) ) diff --git a/src/main/java/com/artillexstudios/axminions/exception/MinionTickFailException.java b/src/main/java/com/artillexstudios/axminions/exception/MinionTickFailException.java index 8980050..602b541 100644 --- a/src/main/java/com/artillexstudios/axminions/exception/MinionTickFailException.java +++ b/src/main/java/com/artillexstudios/axminions/exception/MinionTickFailException.java @@ -1,6 +1,7 @@ package com.artillexstudios.axminions.exception; public class MinionTickFailException extends IllegalStateException { + // We don't always care about the stacktrace public static final MinionTickFailException INSTANCE = new MinionTickFailException(); public MinionTickFailException() { diff --git a/src/main/java/com/artillexstudios/axminions/minions/Minion.java b/src/main/java/com/artillexstudios/axminions/minions/Minion.java index 5dcd38c..1469e8b 100644 --- a/src/main/java/com/artillexstudios/axminions/minions/Minion.java +++ b/src/main/java/com/artillexstudios/axminions/minions/Minion.java @@ -22,6 +22,7 @@ public final class Minion { private final AtomicBoolean needsSaving = new AtomicBoolean(false); private int tick = 0; private int armTick = 0; + private boolean ticking = false; private MinionData minionData; public Minion(Location location, MinionData data) { @@ -40,7 +41,7 @@ public final class Minion { if (Config.SHOW_HAND_ANIMATION) { if (this.armTick >= 20) return; ArmorStandMeta meta = (ArmorStandMeta) this.entity.meta(); - meta.metadata().set(Accessors.RIGHT_ARM_ROTATION, new EulerAngle((double) (-2 + this.armTick) / 10, 0, 0)); + meta.metadata().set(Accessors.RIGHT_ARM_ROTATION, new EulerAngle((-2 + ((double) this.armTick / 10)), 0, 0)); this.armTick += 2; } return; @@ -48,7 +49,6 @@ public final class Minion { this.tick = 0; if (Config.SHOW_HAND_ANIMATION & this.minionData.type().tick(this)) { - // TODO: Animation this.armTick = 0; } } @@ -74,6 +74,10 @@ public final class Minion { return this.minionData.skin(); } + public MinionType type() { + return this.minionData.type(); + } + public void spawn() { this.entity.spawn(); } @@ -90,6 +94,14 @@ public final class Minion { return this.location; } + public boolean ticking() { + return this.ticking; + } + + public void ticking(boolean ticking) { + this.ticking = ticking; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/com/artillexstudios/axminions/minions/MinionWorldCache.java b/src/main/java/com/artillexstudios/axminions/minions/MinionWorldCache.java index df4ddea..1b26922 100644 --- a/src/main/java/com/artillexstudios/axminions/minions/MinionWorldCache.java +++ b/src/main/java/com/artillexstudios/axminions/minions/MinionWorldCache.java @@ -1,6 +1,7 @@ package com.artillexstudios.axminions.minions; import com.artillexstudios.axminions.utils.LogUtils; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.bukkit.World; import java.util.Collection; @@ -8,6 +9,7 @@ import java.util.IdentityHashMap; public final class MinionWorldCache { private static final IdentityHashMap worlds = new IdentityHashMap<>(); + private static final ObjectArrayList minions = new ObjectArrayList<>(); public static void loadArea(World world) { if (worlds.containsKey(world)) { @@ -18,6 +20,18 @@ public final class MinionWorldCache { worlds.put(world, new MinionArea()); } + public static void add(Minion minion) { + minions.add(minion); + MinionArea area = worlds.get(minion.location().getWorld()); + area.load(minion); + } + + public static void remove(Minion minion) { + minions.remove(minion); + MinionArea area = worlds.get(minion.location().getWorld()); + area.remove(minion); + } + public static MinionArea getArea(World world) { return worlds.get(world); } @@ -26,6 +40,10 @@ public final class MinionWorldCache { return worlds.remove(world); } + public static ObjectArrayList minions() { + return minions; + } + public static Collection worlds() { return worlds.values(); } diff --git a/src/main/java/com/artillexstudios/axminions/minions/actions/CompiledAction.java b/src/main/java/com/artillexstudios/axminions/minions/actions/CompiledAction.java index 7484660..db25820 100644 --- a/src/main/java/com/artillexstudios/axminions/minions/actions/CompiledAction.java +++ b/src/main/java/com/artillexstudios/axminions/minions/actions/CompiledAction.java @@ -98,12 +98,12 @@ public final class CompiledAction { try { effect.dispatch(minion, collected); } catch (MinionTickFailException exception) { - LogUtils.warn("An unexpected error occurred while ticking minion {} at {}!", minion, minion.location(), exception); + LogUtils.warn("An unexpected error occurred while ticking minion {} at {}!", minion.type().name(), minion.location(), exception); throw exception; } } }); - // TODO: Return false if the actions can't be ran + return true; } } diff --git a/src/main/java/com/artillexstudios/axminions/minions/actions/effects/implementation/BreakEffect.java b/src/main/java/com/artillexstudios/axminions/minions/actions/effects/implementation/BreakEffect.java index 4d500cb..be8ed30 100644 --- a/src/main/java/com/artillexstudios/axminions/minions/actions/effects/implementation/BreakEffect.java +++ b/src/main/java/com/artillexstudios/axminions/minions/actions/effects/implementation/BreakEffect.java @@ -6,7 +6,6 @@ import com.artillexstudios.axminions.minions.actions.effects.Effect; import com.artillexstudios.axminions.utils.ItemCollection; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Registry; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; @@ -29,7 +28,7 @@ public class BreakEffect extends Effect { World world = argument.getWorld(); if (world == null) { - throw MinionTickFailException.INSTANCE; + throw new MinionTickFailException("World is null!"); } world.setBlockData(argument, AIR); diff --git a/src/main/java/com/artillexstudios/axminions/minions/actions/effects/implementation/DropAtMinionEffect.java b/src/main/java/com/artillexstudios/axminions/minions/actions/effects/implementation/DropAtMinionEffect.java index 3be6c91..4fadcaa 100644 --- a/src/main/java/com/artillexstudios/axminions/minions/actions/effects/implementation/DropAtMinionEffect.java +++ b/src/main/java/com/artillexstudios/axminions/minions/actions/effects/implementation/DropAtMinionEffect.java @@ -1,5 +1,6 @@ package com.artillexstudios.axminions.minions.actions.effects.implementation; +import com.artillexstudios.axminions.exception.MinionTickFailException; import com.artillexstudios.axminions.minions.Minion; import com.artillexstudios.axminions.minions.actions.effects.Effect; import com.artillexstudios.axminions.utils.ItemCollection; @@ -18,7 +19,7 @@ public class DropAtMinionEffect extends Effect { public ItemCollection run(Minion minion, ItemCollection argument) { World world = minion.location().getWorld(); if (world == null) { - return ItemCollection.EMPTY; + throw new MinionTickFailException("World is null!"); } for (ItemStack itemStack : argument.items()) { diff --git a/src/main/java/com/artillexstudios/axminions/minions/ticker/BukkitMinionTicker.java b/src/main/java/com/artillexstudios/axminions/minions/ticker/BukkitMinionTicker.java index b2618d2..86bd338 100644 --- a/src/main/java/com/artillexstudios/axminions/minions/ticker/BukkitMinionTicker.java +++ b/src/main/java/com/artillexstudios/axminions/minions/ticker/BukkitMinionTicker.java @@ -4,53 +4,38 @@ import com.artillexstudios.axapi.scheduler.ScheduledTask; import com.artillexstudios.axapi.scheduler.Scheduler; import com.artillexstudios.axminions.jfr.MinionTickEvent; import com.artillexstudios.axminions.minions.Minion; -import com.artillexstudios.axminions.minions.MinionArea; import com.artillexstudios.axminions.minions.MinionTicker; import com.artillexstudios.axminions.minions.MinionWorldCache; -import com.artillexstudios.axminions.utils.ChunkPos; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -// TODO: Add a list with all minions, add a ticking boolean to minions public final class BukkitMinionTicker implements MinionTicker { - private static ScheduledTask task; + private ScheduledTask task; @Override public void start() { - task = Scheduler.get().runTimer(() -> { + this.task = Scheduler.get().runTimer(() -> { MinionTickEvent event = new MinionTickEvent(); event.begin(); - for (MinionArea world : MinionWorldCache.worlds()) { - world.forEachPos(position -> { - if (!position.isTicking()) return; - tickChunk(position); - }); + final ObjectArrayList minions = MinionWorldCache.minions(); + final int minionSize = minions.size(); + for (int i = 0; i < minionSize; i++) { + final Minion minion = minions.get(i); + if (!minion.ticking()) { + continue; + } + + minion.tick(); } event.commit(); }, 1, 1); } - private static void tickChunk(ChunkPos position) { - ObjectArrayList minions = position.minions(); - int minionSize = minions.size(); - if (minionSize == 0) return; - - Minion first = minions.get(0); - Scheduler.get().executeAt(first.location(), () -> { - // We already have the first, why not tick it? - first.tick(); - - for (int i = 1; i < minionSize; i++) { - Minion minion = minions.get(i); - minion.tick(); - } - }); - } @Override public void cancel() { - if (task != null && !task.isCancelled()) { - task.cancel(); + if (this.task != null && !this.task.isCancelled()) { + this.task.cancel(); } } } diff --git a/src/main/java/com/artillexstudios/axminions/minions/ticker/FoliaMinionTicker.java b/src/main/java/com/artillexstudios/axminions/minions/ticker/FoliaMinionTicker.java index a7d0f6a..a3d036b 100644 --- a/src/main/java/com/artillexstudios/axminions/minions/ticker/FoliaMinionTicker.java +++ b/src/main/java/com/artillexstudios/axminions/minions/ticker/FoliaMinionTicker.java @@ -1,16 +1,55 @@ package com.artillexstudios.axminions.minions.ticker; +import com.artillexstudios.axapi.scheduler.ScheduledTask; +import com.artillexstudios.axapi.scheduler.Scheduler; +import com.artillexstudios.axminions.jfr.MinionTickEvent; +import com.artillexstudios.axminions.minions.Minion; +import com.artillexstudios.axminions.minions.MinionArea; import com.artillexstudios.axminions.minions.MinionTicker; +import com.artillexstudios.axminions.minions.MinionWorldCache; +import com.artillexstudios.axminions.utils.ChunkPos; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; public final class FoliaMinionTicker implements MinionTicker { + private ScheduledTask task; @Override public void start() { + this.task = Scheduler.get().runTimer(() -> { + MinionTickEvent event = new MinionTickEvent(); + event.begin(); + for (MinionArea world : MinionWorldCache.worlds()) { + world.forEachPos(position -> { + if (!position.isTicking()) return; + tickChunk(position); + }); + } + event.commit(); + }, 1, 1); + } + + private void tickChunk(ChunkPos position) { + ObjectArrayList minions = position.minions(); + int minionSize = minions.size(); + if (minionSize == 0) return; + + Minion first = minions.get(0); + Scheduler.get().executeAt(first.location(), () -> { + // We already have the first, why not tick it? + first.tick(); + + for (int i = 1; i < minionSize; i++) { + Minion minion = minions.get(i); + minion.tick(); + } + }); } @Override public void cancel() { - + if (this.task != null && !this.task.isCancelled()) { + this.task.cancel(); + } } } diff --git a/src/main/java/com/artillexstudios/axminions/utils/ChunkPos.java b/src/main/java/com/artillexstudios/axminions/utils/ChunkPos.java index ec1c103..82b0291 100644 --- a/src/main/java/com/artillexstudios/axminions/utils/ChunkPos.java +++ b/src/main/java/com/artillexstudios/axminions/utils/ChunkPos.java @@ -9,6 +9,10 @@ public record ChunkPos(int x, int z, AtomicBoolean ticking, ObjectArrayList