From f9f5e24ef67c938e5a82e3b79fb88ad49312aef8 Mon Sep 17 00:00:00 2001 From: m1919810 Date: Sun, 28 Sep 2025 02:14:50 +0800 Subject: [PATCH 1/3] feat: automatic recovery of machine progress after server restart for some machines --- .../storage/util/StorageCacheUtils.java | 1 + .../AsyncMachineOperationStartEvent.java | 78 +++++++++++++ .../MachineProcessSerializable.java | 25 ++++ .../core/machines/MachineOperation.java | 8 ++ .../core/machines/MachineProcessor.java | 109 +++++++++++++++++- .../items/electric/machines/AutoAnvil.java | 3 +- .../AbstractEnchantmentMachine.java | 3 +- .../machines/enchanting/BookBinder.java | 3 +- .../operations/CraftingOperation.java | 17 ++- .../CraftingOperationSerializable.java | 35 ++++++ .../slimefun4/utils/SerializingUtils.java | 35 ++++++ 11 files changed, 310 insertions(+), 7 deletions(-) create mode 100644 src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java create mode 100644 src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/MachineProcessSerializable.java create mode 100644 src/main/java/io/github/thebusybiscuit/slimefun4/implementation/operations/CraftingOperationSerializable.java create mode 100644 src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java index 579a11f1ac..adaaccc7b5 100644 --- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java +++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java @@ -301,6 +301,7 @@ public static void executeAfterLoad(ASlimefunDataContainer data, Runnable execut public static void executeAfterLoad(SlimefunBlockData data, Runnable execute, boolean runOnMainThread) { if (data.isDataLoaded()) { + // FIXME: should we care about runOnMainThread argument? execute.run(); return; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java new file mode 100644 index 0000000000..26ef27a0f9 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java @@ -0,0 +1,78 @@ +package io.github.thebusybiscuit.slimefun4.api.events; + +import io.github.bakedlibs.dough.blocks.BlockPosition; +import io.github.thebusybiscuit.slimefun4.core.machines.MachineOperation; +import io.github.thebusybiscuit.slimefun4.core.machines.MachineProcessor; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.bukkit.Bukkit; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class AsyncMachineOperationStartEvent extends Event implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + + private final BlockPosition position; + private final MachineProcessor machineProcessor; + private final MachineOperation machineOperation; + private boolean cancel; + + public AsyncMachineOperationStartEvent( + BlockPosition pos, MachineProcessor processor, T operation) { + super(!Bukkit.isPrimaryThread()); + + this.position = pos; + this.machineProcessor = processor; + this.machineOperation = operation; + } + + /** + * This returns the {@link BlockPosition} of the machine. + * + * @return The {@link BlockPosition} of the machine + */ + @Nonnull + public BlockPosition getPosition() { + return position; + } + + /** + * The {@link MachineProcessor} instance of the machine. + * + * @return The {@link MachineProcessor} instance of the machine + */ + @Nullable public MachineProcessor getProcessor() { + return machineProcessor; + } + + /** + * This returns the used {@link MachineOperation} in the process. + * + * @return The {@link MachineOperation} of the process + */ + @Nullable public MachineOperation getOperation() { + return machineOperation; + } + + @Nonnull + public static HandlerList getHandlerList() { + return handlers; + } + + @Nonnull + @Override + public HandlerList getHandlers() { + return getHandlerList(); + } + + @Override + public boolean isCancelled() { + return this.cancel; + } + + @Override + public void setCancelled(boolean b) { + this.cancel = b; + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/MachineProcessSerializable.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/MachineProcessSerializable.java new file mode 100644 index 0000000000..11b76f9c3c --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/MachineProcessSerializable.java @@ -0,0 +1,25 @@ +package io.github.thebusybiscuit.slimefun4.core.attributes; + +import io.github.bakedlibs.dough.blocks.BlockPosition; +import io.github.thebusybiscuit.slimefun4.core.machines.MachineOperation; + +public interface MachineProcessSerializable extends MachineProcessHolder { + String KEY_PROGRESS_LEFT = "p-tick-left"; + String KEY_OPERATION_INFO = "p-op-info"; + + /** + * this called when a MachineProcessor trys to load a MachineOperation from a blockData by its KEY_OPERATION_INFO value and KEY_PROGRESS_LEFT value + * @param position + * @param output + * @return + */ + T deserialize(BlockPosition position, String output); + + /** + * this called when a MachineProcessor trys to save a MachineOperation when startOperation called, it will store the return value in KEY_OPERATION-INFO + * @param position + * @param operation + * @return + */ + String serialize(BlockPosition position, T operation); +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/machines/MachineOperation.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/machines/MachineOperation.java index fed2120ee3..382b50676c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/machines/MachineOperation.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/machines/MachineOperation.java @@ -2,6 +2,8 @@ import io.github.bakedlibs.dough.blocks.BlockPosition; import io.github.thebusybiscuit.slimefun4.core.attributes.MachineProcessHolder; +import io.github.thebusybiscuit.slimefun4.implementation.operations.CraftingOperation; +import org.bukkit.configuration.ConfigurationSection; /** * This represents a {@link MachineOperation} which is handled @@ -63,4 +65,10 @@ default boolean isFinished() { * Implement to specify behaviour that should happen in this case. */ default void onCancel(BlockPosition position) {} + + public static String TOTAL_TICKS = "total-ticks"; + + default void serializeOperation(ConfigurationSection yaml, CraftingOperation operation) { + yaml.set(TOTAL_TICKS, operation.getTotalTicks()); + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/machines/MachineProcessor.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/machines/MachineProcessor.java index aa45d4329a..90a2696f7b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/machines/MachineProcessor.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/machines/MachineProcessor.java @@ -1,10 +1,15 @@ package io.github.thebusybiscuit.slimefun4.core.machines; +import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunBlockData; +import com.xzavier0722.mc.plugin.slimefun4.storage.util.StorageCacheUtils; import io.github.bakedlibs.dough.blocks.BlockPosition; import io.github.thebusybiscuit.slimefun4.api.events.AsyncMachineOperationFinishEvent; +import io.github.thebusybiscuit.slimefun4.api.events.AsyncMachineOperationStartEvent; import io.github.thebusybiscuit.slimefun4.core.attributes.MachineProcessHolder; +import io.github.thebusybiscuit.slimefun4.core.attributes.MachineProcessSerializable; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -32,6 +37,7 @@ public class MachineProcessor { private final Map machines = new ConcurrentHashMap<>(); private final MachineProcessHolder owner; + private final MachineProcessSerializable optionalSerializer; private ItemStack progressBar; @@ -45,6 +51,8 @@ public MachineProcessor(@Nonnull MachineProcessHolder owner) { Validate.notNull(owner, "The MachineProcessHolder cannot be null."); this.owner = owner; + this.optionalSerializer = + this.owner instanceof MachineProcessSerializable serializable ? serializable : null; } /** @@ -123,13 +131,47 @@ public boolean startOperation(@Nonnull Block b, @Nonnull T operation) { * The {@link MachineOperation} to start * * @return Whether the {@link MachineOperation} was successfully started. This will return false if another - * {@link MachineOperation} has already been started at that {@link BlockPosition}. + * {@link MachineOperation} has already been started at that {@link BlockPosition} or the StartEvent is cancelled. */ public boolean startOperation(@Nonnull BlockPosition pos, @Nonnull T operation) { Validate.notNull(pos, "The BlockPosition must not be null"); Validate.notNull(operation, "The machine operation cannot be null"); + // async Machine Operation Start Event + + var currentOperation = machines.computeIfAbsent(pos, (ps) -> { + // only if the current operation if absent and Event is not cancelled can we put the new operation in the + // map + // other wise it will keep null + var event = new AsyncMachineOperationStartEvent(ps, this, operation); + if (event.callEvent()) { + return operation; + } else { + return null; + } + }); + // if the current Operation is successfully put into the map, returns true + if (currentOperation == operation) { + // serialize and save to blockData + if (optionalSerializer != null) { + SlimefunBlockData blockData = StorageCacheUtils.getBlock(pos.toLocation()); + if (blockData != null) { + StorageCacheUtils.executeAfterLoad( + blockData, + () -> { + blockData.setData( + MachineProcessSerializable.KEY_OPERATION_INFO, + optionalSerializer.serialize(pos, operation)); + blockData.setData( + MachineProcessSerializable.KEY_PROGRESS_LEFT, + String.valueOf(operation.getRemainingTicks())); + }, + false); + } + } + return true; + } - return machines.putIfAbsent(pos, operation) == null; + return false; } /** @@ -171,7 +213,55 @@ public boolean startOperation(@Nonnull BlockPosition pos, @Nonnull T operation) @Nullable public T getOperation(@Nonnull BlockPosition pos) { Validate.notNull(pos, "The BlockPosition must not be null"); - return machines.get(pos); + T value = machines.get(pos); + if (value != null) { + if (optionalSerializer != null) { + // try update the progressLeft field + SlimefunBlockData sfdata = StorageCacheUtils.getBlock(pos.toLocation()); + if (sfdata != null) { + StorageCacheUtils.executeAfterLoad( + sfdata, + () -> sfdata.setData( + MachineProcessSerializable.KEY_PROGRESS_LEFT, + String.valueOf(value.getRemainingTicks())), + false); + } + } + } else { + if (optionalSerializer != null) { + // try load if operation is absent + SlimefunBlockData sfdata = StorageCacheUtils.getBlock(pos.toLocation()); + if (sfdata != null && sfdata.isDataLoaded()) { + // this may not be multithread-safe, but who cares? + String infoYaml = sfdata.getData(MachineProcessSerializable.KEY_OPERATION_INFO); + if (infoYaml != null) { + T operationLoaded; + try { + operationLoaded = Objects.requireNonNull(optionalSerializer.deserialize(pos, infoYaml)); + } finally { + sfdata.removeData(MachineProcessSerializable.KEY_OPERATION_INFO); + } + String progress = sfdata.getData(MachineProcessSerializable.KEY_PROGRESS_LEFT); + int progressTickLeft; + try { + progressTickLeft = + progress == null ? operationLoaded.getTotalTicks() : Integer.parseInt(progress); + } catch (Throwable e) { + progressTickLeft = operationLoaded.getTotalTicks(); + } + operationLoaded.addProgress(operationLoaded.getTotalTicks() - progressTickLeft); + sfdata.setData( + MachineProcessSerializable.KEY_OPERATION_INFO, + optionalSerializer.serialize(pos, operationLoaded)); + sfdata.setData( + MachineProcessSerializable.KEY_PROGRESS_LEFT, + String.valueOf(operationLoaded.getRemainingTicks())); + machines.put(pos, operationLoaded); + } + } + } + } + return value; } /** @@ -215,6 +305,19 @@ public boolean endOperation(@Nonnull Block b) { */ public boolean endOperation(@Nonnull BlockPosition pos) { Validate.notNull(pos, "The BlockPosition cannot be null"); + // remove the serialized data from the blockData + if (optionalSerializer != null) { + SlimefunBlockData sfdata = StorageCacheUtils.getBlock(pos.toLocation()); + if (sfdata != null) { + StorageCacheUtils.executeAfterLoad( + sfdata, + () -> { + sfdata.removeData(MachineProcessSerializable.KEY_PROGRESS_LEFT); + sfdata.removeData(MachineProcessSerializable.KEY_OPERATION_INFO); + }, + false); + } + } T operation = machines.remove(pos); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoAnvil.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoAnvil.java index 075783a9c4..46322c021c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoAnvil.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/AutoAnvil.java @@ -4,6 +4,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; +import io.github.thebusybiscuit.slimefun4.implementation.operations.CraftingOperationSerializable; import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe; @@ -20,7 +21,7 @@ * @author TheBusyBiscuit * */ -public class AutoAnvil extends AContainer { +public class AutoAnvil extends AContainer implements CraftingOperationSerializable { private final int repairFactor; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AbstractEnchantmentMachine.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AbstractEnchantmentMachine.java index b15f3e90d5..01620dc498 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AbstractEnchantmentMachine.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/AbstractEnchantmentMachine.java @@ -8,6 +8,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting; import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import io.github.thebusybiscuit.slimefun4.implementation.operations.CraftingOperationSerializable; import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; @@ -29,7 +30,7 @@ * @see AutoDisenchanter * */ -abstract class AbstractEnchantmentMachine extends AContainer { +abstract class AbstractEnchantmentMachine extends AContainer implements CraftingOperationSerializable { private final ItemSetting useLevelLimit = new ItemSetting<>(this, "use-enchant-level-limit", false); private final IntRangeSetting levelLimit = new IntRangeSetting(this, "enchant-level-limit", 0, 10, Short.MAX_VALUE); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/BookBinder.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/BookBinder.java index 07cf5628d5..79f9c4ba37 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/BookBinder.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/enchanting/BookBinder.java @@ -6,6 +6,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; import io.github.thebusybiscuit.slimefun4.api.items.settings.IntRangeSetting; import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.implementation.operations.CraftingOperationSerializable; import java.util.HashMap; import java.util.Map; import javax.annotation.Nonnull; @@ -24,7 +25,7 @@ * * @author ProfElements */ -public class BookBinder extends AContainer { +public class BookBinder extends AContainer implements CraftingOperationSerializable { private final ItemSetting bypassVanillaMaxLevel = new ItemSetting<>(this, "bypass-vanilla-max-level", false); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/operations/CraftingOperation.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/operations/CraftingOperation.java index 4d91147d6e..96eb849e18 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/operations/CraftingOperation.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/operations/CraftingOperation.java @@ -1,9 +1,11 @@ package io.github.thebusybiscuit.slimefun4.implementation.operations; import io.github.thebusybiscuit.slimefun4.core.machines.MachineOperation; +import io.github.thebusybiscuit.slimefun4.utils.SerializingUtils; import javax.annotation.Nonnull; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe; import org.apache.commons.lang.Validate; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; /** @@ -13,7 +15,8 @@ * */ public class CraftingOperation implements MachineOperation { - + public static String INPUT = "input"; + public static String OUTPUT = "output"; private final ItemStack[] ingredients; private final ItemStack[] results; @@ -36,6 +39,12 @@ public CraftingOperation(@Nonnull ItemStack[] ingredients, @Nonnull ItemStack[] this.totalTicks = totalTicks; } + public CraftingOperation(ConfigurationSection yaml) { + this.totalTicks = yaml.getInt(TOTAL_TICKS); + this.results = SerializingUtils.loadItemStackArray(yaml, OUTPUT); + this.ingredients = SerializingUtils.loadItemStackArray(yaml, INPUT); + } + @Override public void addProgress(int num) { Validate.isTrue(num > 0, "Progress must be positive."); @@ -61,4 +70,10 @@ public int getProgress() { public int getTotalTicks() { return totalTicks; } + + public void serializeOperation(ConfigurationSection yaml, CraftingOperation operation) { + MachineOperation.super.serializeOperation(yaml, operation); + SerializingUtils.saveItemStackArray(yaml, INPUT, getIngredients()); + SerializingUtils.saveItemStackArray(yaml, OUTPUT, getResults()); + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/operations/CraftingOperationSerializable.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/operations/CraftingOperationSerializable.java new file mode 100644 index 0000000000..3ded88a368 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/operations/CraftingOperationSerializable.java @@ -0,0 +1,35 @@ +package io.github.thebusybiscuit.slimefun4.implementation.operations; + +import io.github.bakedlibs.dough.blocks.BlockPosition; +import io.github.thebusybiscuit.slimefun4.core.attributes.MachineProcessSerializable; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; + +public interface CraftingOperationSerializable extends MachineProcessSerializable { + + default CraftingOperation deserialize(BlockPosition position, String output) { + return deserializeOperation(output); + } + + static CraftingOperation deserializeOperation(String yamlStr) { + var yaml = new YamlConfiguration(); + try { + yaml.loadFromString(yamlStr); + } catch (InvalidConfigurationException e) { + return null; + } + return new CraftingOperation(yaml); + } + + /** + * this called when a MachineProcessor trys to save a MachineOperation when startOperation called, it will store the return value in KEY_OPERATION-INFO + * @param position + * @param operation + * @return + */ + default String serialize(BlockPosition position, CraftingOperation operation) { + var yaml = new YamlConfiguration(); + operation.serializeOperation(yaml, operation); + return yaml.saveToString(); + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java new file mode 100644 index 0000000000..32ca14c993 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java @@ -0,0 +1,35 @@ +package io.github.thebusybiscuit.slimefun4.utils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.inventory.ItemStack; + +public class SerializingUtils { + public static ItemStack[] loadItemStackArray(ConfigurationSection yaml, String prefixPath) { + List itemStacks = new ArrayList<>(2); + for (int i = 0; i < 666_666; ++i) { + String keyI = prefixPath + "_" + String.valueOf(i); + if (yaml.contains(keyI)) { + ItemStack stack = yaml.getItemStack(keyI); + // all Exceptions while loading will not be handled + if (stack != null && !stack.getType().isAir()) itemStacks.add(stack); + } else { + break; + } + } + return itemStacks.toArray(ItemStack[]::new); + } + + public static void saveItemStackArray(ConfigurationSection yaml, String prefixPath, ItemStack... itemStacks) { + List results = Arrays.stream(itemStacks) + .filter(Objects::nonNull) + .filter(itemStack -> !itemStack.getType().isAir()) + .toList(); + for (var i = 0; i < results.size(); ++i) { + yaml.set(prefixPath + "_" + String.valueOf(i), results.get(i)); + } + } +} From b5bce4b140af1b9b94189d91fabbbddbfe77cd04 Mon Sep 17 00:00:00 2001 From: m1919810 Date: Fri, 28 Nov 2025 04:59:25 +0800 Subject: [PATCH 2/3] feat: add javadocs --- .../storage/util/StorageCacheUtils.java | 1 - .../AsyncMachineOperationStartEvent.java | 19 +++++++++++++++++++ .../MachineProcessSerializable.java | 5 +++-- .../slimefun4/utils/SerializingUtils.java | 19 ++++++++++++++++++- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java index adaaccc7b5..579a11f1ac 100644 --- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java +++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java @@ -301,7 +301,6 @@ public static void executeAfterLoad(ASlimefunDataContainer data, Runnable execut public static void executeAfterLoad(SlimefunBlockData data, Runnable execute, boolean runOnMainThread) { if (data.isDataLoaded()) { - // FIXME: should we care about runOnMainThread argument? execute.run(); return; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java index 26ef27a0f9..ecbd202669 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java @@ -6,10 +6,18 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.bukkit.Bukkit; +import org.bukkit.block.Block; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +/** + * This {@link Event} is fired whenever an {@link MachineProcessor} wants to start a {@link MachineOperation} when invoking any of the {@link MachineProcessor#startOperation} method + * The event is cancellable, if the event is cancelled, the operation will not be added to the operation map and {@link MachineProcessor#startOperation} will return false + * + * @author m1919810 + * + */ public class AsyncMachineOperationStartEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); @@ -66,11 +74,22 @@ public HandlerList getHandlers() { return getHandlerList(); } + /** + * This returns whether the event is cancelled + * + * @return cancel flag + */ @Override public boolean isCancelled() { return this.cancel; } + /** + * This sets the cancel flag of the event + * If the event is cancelled, the operation will not be added to the operation map and {@link MachineProcessor#startOperation} will return false + * + * @param b new flag + */ @Override public void setCancelled(boolean b) { this.cancel = b; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/MachineProcessSerializable.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/MachineProcessSerializable.java index 11b76f9c3c..c5e210e23c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/MachineProcessSerializable.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/MachineProcessSerializable.java @@ -8,7 +8,7 @@ public interface MachineProcessSerializable extends String KEY_OPERATION_INFO = "p-op-info"; /** - * this called when a MachineProcessor trys to load a MachineOperation from a blockData by its KEY_OPERATION_INFO value and KEY_PROGRESS_LEFT value + * this called when a MachineProcessor trys to load a MachineOperation from a blockData by using the value under the key {@link MachineProcessSerializable#KEY_OPERATION_INFO} as the operation information and {@link MachineProcessSerializable#KEY_PROGRESS_LEFT} as the progress left * @param position * @param output * @return @@ -16,7 +16,8 @@ public interface MachineProcessSerializable extends T deserialize(BlockPosition position, String output); /** - * this called when a MachineProcessor trys to save a MachineOperation when startOperation called, it will store the return value in KEY_OPERATION-INFO + * this called when a MachineProcessor trys to save a MachineOperation when startOperation called, it will store the return value under key {@link MachineProcessSerializable#KEY_OPERATION_INFO} + * * @param position * @param operation * @return diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java index 32ca14c993..4836b95d02 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java @@ -8,9 +8,18 @@ import org.bukkit.inventory.ItemStack; public class SerializingUtils { + /** + * This method load an array of itemStack from a given {@link ConfigurationSection}, + * The structure of the {@link ConfigurationSection} should meet these rules: + * The i-th itemStack is stored under the path "{prefixPath}_{i}" + * The itemStack must be valid , notnull and not empty, or we will skip that itemStack + * @param yaml + * @param prefixPath + * @return + */ public static ItemStack[] loadItemStackArray(ConfigurationSection yaml, String prefixPath) { List itemStacks = new ArrayList<>(2); - for (int i = 0; i < 666_666; ++i) { + for(int i = 0; ; ++i){ String keyI = prefixPath + "_" + String.valueOf(i); if (yaml.contains(keyI)) { ItemStack stack = yaml.getItemStack(keyI); @@ -23,6 +32,14 @@ public static ItemStack[] loadItemStackArray(ConfigurationSection yaml, String p return itemStacks.toArray(ItemStack[]::new); } + /** + * This method save an array of itemStack to a given {@link ConfigurationSection} + * Each element of the array must be notnull and not empty, or we will skip that itemStack + * The saved yaml can be load back to itemStack array using {@link SerializingUtils#loadItemStackArray(ConfigurationSection, String)} + * @param yaml + * @param prefixPath + * @param itemStacks + */ public static void saveItemStackArray(ConfigurationSection yaml, String prefixPath, ItemStack... itemStacks) { List results = Arrays.stream(itemStacks) .filter(Objects::nonNull) From f894661084d4d26f5e9538e7420d0131256fa7c0 Mon Sep 17 00:00:00 2001 From: m1919810 Date: Fri, 28 Nov 2025 04:59:43 +0800 Subject: [PATCH 3/3] feat: spotless --- .../slimefun4/api/events/AsyncMachineOperationStartEvent.java | 1 - .../github/thebusybiscuit/slimefun4/utils/SerializingUtils.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java index ecbd202669..91422e6dc8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/AsyncMachineOperationStartEvent.java @@ -6,7 +6,6 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.bukkit.Bukkit; -import org.bukkit.block.Block; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java index 4836b95d02..64434c3acc 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SerializingUtils.java @@ -19,7 +19,7 @@ public class SerializingUtils { */ public static ItemStack[] loadItemStackArray(ConfigurationSection yaml, String prefixPath) { List itemStacks = new ArrayList<>(2); - for(int i = 0; ; ++i){ + for (int i = 0; ; ++i) { String keyI = prefixPath + "_" + String.valueOf(i); if (yaml.contains(keyI)) { ItemStack stack = yaml.getItemStack(keyI);