From 5d1d0a6fae8b620e857ac411f296060853f99088 Mon Sep 17 00:00:00 2001 From: ybw0014 Date: Tue, 24 Oct 2023 22:16:53 -0400 Subject: [PATCH] feat: project structure and some machines for testing --- LOCALES.md | 6 + README.md | 37 ++ README.zh_CN.md | 36 ++ pom.xml | 36 +- .../guizhanss/fastmachines/FastMachines.java | 114 ++++++ .../core/recipes/StandardRecipe.java | 66 ++++ .../fastmachines/items/FastMachinesItems.java | 34 ++ .../items/machines/AbstractFastMachine.java | 370 ++++++++++++++++++ .../machines/FastEnhancedCraftingTable.java | 32 ++ .../items/machines/FastOreWasher.java | 31 ++ .../items/machines/FastSmeltery.java | 32 ++ .../items/materials/FastMaterial.java | 24 ++ .../guizhanss/fastmachines/setup/Groups.java | 41 ++ .../guizhanss/fastmachines/setup/Items.java | 45 +++ .../fastmachines/utils/BlockStorageUtils.java | 32 ++ .../guizhanss/fastmachines/utils/Heads.java | 27 ++ .../guizhanss/fastmachines/utils/Keys.java | 21 + .../fastmachines/utils/MachineUtils.java | 51 +++ .../fastmachines/utils/RecipeUtils.java | 186 +++++++++ .../fastmachines/utils/SlimefunItemUtils.java | 23 ++ .../GuizhanSlimefunAddon.java | 55 --- src/main/resources/config.yml | 18 + src/main/resources/lang/en-US.yml | 123 ++++++ src/main/resources/plugin.yml | 8 +- 24 files changed, 1379 insertions(+), 69 deletions(-) create mode 100644 LOCALES.md create mode 100644 README.md create mode 100644 README.zh_CN.md create mode 100644 src/main/java/net/guizhanss/fastmachines/FastMachines.java create mode 100644 src/main/java/net/guizhanss/fastmachines/core/recipes/StandardRecipe.java create mode 100644 src/main/java/net/guizhanss/fastmachines/items/FastMachinesItems.java create mode 100644 src/main/java/net/guizhanss/fastmachines/items/machines/AbstractFastMachine.java create mode 100644 src/main/java/net/guizhanss/fastmachines/items/machines/FastEnhancedCraftingTable.java create mode 100644 src/main/java/net/guizhanss/fastmachines/items/machines/FastOreWasher.java create mode 100644 src/main/java/net/guizhanss/fastmachines/items/machines/FastSmeltery.java create mode 100644 src/main/java/net/guizhanss/fastmachines/items/materials/FastMaterial.java create mode 100644 src/main/java/net/guizhanss/fastmachines/setup/Groups.java create mode 100644 src/main/java/net/guizhanss/fastmachines/setup/Items.java create mode 100644 src/main/java/net/guizhanss/fastmachines/utils/BlockStorageUtils.java create mode 100644 src/main/java/net/guizhanss/fastmachines/utils/Heads.java create mode 100644 src/main/java/net/guizhanss/fastmachines/utils/Keys.java create mode 100644 src/main/java/net/guizhanss/fastmachines/utils/MachineUtils.java create mode 100644 src/main/java/net/guizhanss/fastmachines/utils/RecipeUtils.java create mode 100644 src/main/java/net/guizhanss/fastmachines/utils/SlimefunItemUtils.java delete mode 100644 src/main/java/net/guizhanss/guizhanslimefunaddon/GuizhanSlimefunAddon.java create mode 100644 src/main/resources/lang/en-US.yml diff --git a/LOCALES.md b/LOCALES.md new file mode 100644 index 0000000..d46589c --- /dev/null +++ b/LOCALES.md @@ -0,0 +1,6 @@ +# Locales + +This addon is available in the following languages: + +- English (US) `en-US` +- 简体中文 `zh-CN` diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a61fb8 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# FastMachines + +[English](README.md) | [中文](README.zh_CN.md) + +This Slimefun addon extracts the manual machines from [FinalTECH](https://github.com/ecro-fun/FinalTECH) and made some changes to put them into a separate addon. +Fast machines are Slimefun basic machines, but they cost energy to run and can craft items without recipe to be in order. + +Credit: Final_Root + +## Download + +(WIP) + +## Configuration + +### General Config (config.yml) + +- `auto-update`: Whether to enable auto update from TheBusyBiscuit's builds page. (default: `true`) +- `lang`: The language of the addon, check available languages [here](LOCALES.md). (default: `en-US`) +- `enable-researches`: Whether to enable researches for fast machines. (default: `true`) +- `debug`: Whether to enable debug mode. (default: `false`) +- `fast-machines.use-energy`: Whether to enable energy cost of Fast Machines' crafting. (default: `true`) + +### Item-specific config (/plugins/Slimefun/Items.yml) + +The following settings are available for each individual Fast Machines: + +- `energy-per-use`: The energy cost of each crafting operation. (default: `8`, range: `0` - `33554431`(2^25-1)) + +## Thanks + +Thanks to anyone who helped me during the development of this addon. + +Thanks to [minecraft-heads.com](https://minecraft-heads.com/) for the heads used in this addon. + +[![](https://minecraft-heads.com/images/banners/minecraft-heads_fullbanner_468x60.png)](https://minecraft-heads.com/) + diff --git a/README.zh_CN.md b/README.zh_CN.md new file mode 100644 index 0000000..db64032 --- /dev/null +++ b/README.zh_CN.md @@ -0,0 +1,36 @@ +# FastMachines 快捷机器 + +[English](README.md) | [中文](README.zh_CN.md) + +该粘液科技附属将快速机器的玩法从[乱序技艺](https://github.com/ecro-fun/FinalTECH)中提取出来,并进行了一些改动,使其作为一个单独的附属。 + +鸣谢:Final_Root + +## 下载 + +(WIP) + +## 配置 + +### 通用配置 (config.yml) + +- `auto-update`: 是否启用从TheBusyBiscuit的构建页面进行自动更新(默认值:`true`) +- `lang`: 插件的语言,可在此处查看可用语言[here](LOCALES.md)(默认值:`en-US`) +- `enable-researches`: 是否启用快速机器的研究(默认值:`true`) +- `debug`: 是否启用调试模式(默认值:`false`) +- `fast-machines.use-energy`: 是否启用快速机器的能量消耗(默认值:`true`) + +### 物品特定配置(/plugins/Slimefun/Items.yml) + +以下设置适用于每个独立的快速机器: + +- `energy-per-use`:每个制作操作的能量消耗(默认值:`8`,范围:`0` - `33554431`(2^25-1)) + +## 感谢 + +感谢在开发此插件过程中帮助我的所有人。 + +感谢[minecraft-heads.com](https://minecraft-heads.com/)提供此插件中使用的头颅。 + +[![](https://minecraft-heads.com/images/banners/minecraft-heads_fullbanner_468x60.png)](https://minecraft-heads.com/) + diff --git a/pom.xml b/pom.xml index 9a83b9a..3d20f05 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 net.guizhanss - GuizhanSlimefunAddon + FastMachines UNOFFICIAL jar @@ -45,7 +45,11 @@ org.bstats - net.guizhanss.guizhanslimefunaddon.bstats + net.guizhanss.fastmachines.bstats + + + net.guizhanss.guizhanlib + net.guizhanss.fastmachines.guizhanlib @@ -58,7 +62,8 @@ src/main/resources true - * + *.yml + lang/*.yml @@ -70,8 +75,12 @@ https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - sonatype - https://oss.sonatype.org/content/groups/public/ + sonatype-snapshot + https://s01.oss.sonatype.org/content/repositories/snapshots/ + + + papermc + https://repo.papermc.io/repository/maven-public/ jitpack.io @@ -90,7 +99,7 @@ io.github.Slimefun Slimefun4 - RC-34 + RC-35 provided @@ -103,7 +112,7 @@ org.bstats bstats-bukkit - 3.0.0 + 3.0.1 compile @@ -116,9 +125,16 @@ net.guizhanss - GuizhanLibPlugin - 1.3.1 - provided + GuizhanLib-api + 1.5.0-SNAPSHOT + compile + + + + com.github.MockBukkit + MockBukkit + v1.20-SNAPSHOT + test diff --git a/src/main/java/net/guizhanss/fastmachines/FastMachines.java b/src/main/java/net/guizhanss/fastmachines/FastMachines.java new file mode 100644 index 0000000..7f533d5 --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/FastMachines.java @@ -0,0 +1,114 @@ +package net.guizhanss.fastmachines; + +import java.io.File; +import java.lang.reflect.Method; +import java.util.logging.Level; + +import javax.annotation.Nonnull; + +import com.google.common.base.Preconditions; + +import org.bukkit.plugin.Plugin; + +import io.github.thebusybiscuit.slimefun4.libraries.dough.updater.GitHubBuildsUpdater; + +import net.guizhanss.fastmachines.setup.Items; +import net.guizhanss.guizhanlib.slimefun.addon.AbstractAddon; +import net.guizhanss.guizhanlib.slimefun.addon.AddonConfig; +import net.guizhanss.guizhanlib.slimefun.addon.SlimefunLocalization; +import net.guizhanss.guizhanlib.updater.GuizhanBuildsUpdater; + +import org.bstats.bukkit.Metrics; + +public final class FastMachines extends AbstractAddon { + + private static final String DEFAULT_LANG = "en-US"; + + private SlimefunLocalization localization; + private boolean debugEnabled = false; + + public FastMachines() { + super("ybw0014", "FastMachines", "master", "auto-update"); + } + + @Nonnull + public static SlimefunLocalization getLocalization() { + return inst().localization; + } + + public static void debug(@Nonnull String message, @Nonnull Object... args) { + Preconditions.checkNotNull(message, "message cannot be null"); + + if (inst().debugEnabled) { + inst().getLogger().log(Level.INFO, "[DEBUG] " + message, args); + } + } + + @Nonnull + private static FastMachines inst() { + return getInstance(); + } + + @Override + public void enable() { + log(Level.INFO, "===================="); + log(Level.INFO, " FastMachines "); + log(Level.INFO, " by ybw0014 "); + log(Level.INFO, "===================="); + + // config + AddonConfig config = getAddonConfig(); + + // debug + debugEnabled = config.getBoolean("debug", false); + + // localization + log(Level.INFO, "Loading language..."); + String lang = config.getString("lang", DEFAULT_LANG); + localization = new SlimefunLocalization(this); + localization.addLanguage(lang); + if (!lang.equals(DEFAULT_LANG)) { + localization.addLanguage(DEFAULT_LANG); + } + localization.setPrefix("FM_"); + log(Level.INFO, localization.getString("console.loaded-language"), lang); + + // items + log(Level.INFO, localization.getString("console.loading-items")); + Items.setup(this); + + // researches + if (config.getBoolean("enable-researches", true)) { + // TODO: add researches + } + + setupMetrics(); + } + + @Override + public void disable() { + // nothing to do here for now + } + + private void setupMetrics() { + new Metrics(this, 20046); + } + + @Override + protected void autoUpdate() { + if (getPluginVersion().startsWith("DEV")) { + String path = getGithubUser() + "/" + getGithubRepo() + "/" + getGithubBranch(); + new GitHubBuildsUpdater(this, getFile(), path).start(); + } else if (getPluginVersion().startsWith("Build")) { + try { + // use updater in lib plugin + Class clazz = Class.forName("net.guizhanss.guizhanlibplugin.updater.GuizhanUpdater"); + Method updaterStart = clazz.getDeclaredMethod("start", Plugin.class, File.class, String.class, String.class, String.class); + updaterStart.invoke(null, this, getFile(), getGithubUser(), getGithubRepo(), getGithubBranch()); + } catch (Exception ignored) { + // use updater in lib + new GuizhanBuildsUpdater(this, getFile(), getGithubUser(), getGithubRepo(), getGithubBranch()).start(); + } + } + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/core/recipes/StandardRecipe.java b/src/main/java/net/guizhanss/fastmachines/core/recipes/StandardRecipe.java new file mode 100644 index 0000000..375e4c7 --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/core/recipes/StandardRecipe.java @@ -0,0 +1,66 @@ +package net.guizhanss.fastmachines.core.recipes; + +import java.util.Map; + +import javax.annotation.Nonnull; + +import org.bukkit.World; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; + +import net.guizhanss.fastmachines.utils.RecipeUtils; + +import lombok.Getter; + +/** + * A {@link StandardRecipe} is a recipe that contains only one fixed output {@link ItemStack}. + * + * @author ybw0014 + */ +@Getter +public class StandardRecipe { + private final ItemStack output; + private final Map input; + + public StandardRecipe(ItemStack output, ItemStack... input) { + this.output = output; + this.input = RecipeUtils.calculateItems(input); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StandardRecipe other = (StandardRecipe) o; + return this.input.equals(other.input) && this.output.equals(other.output); + } + + @Override + public int hashCode() { + int result = output.hashCode(); + result = 31 * result + input.hashCode(); + return result; + } + + @Override + public String toString() { + return "StandardRecipe{" + + "output=" + output + + ", input=" + input + + '}'; + } + + /** + * Check whether the output item is disabled in the given {@link World}. + * + * @param world + * The world to check. + * + * @return True if output item is disabled in the given {@link World}. + */ + public boolean isDisabledInWorld(@Nonnull World world) { + SlimefunItem sfItem = SlimefunItem.getByItem(output); + return sfItem != null && sfItem.isDisabledIn(world); + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/items/FastMachinesItems.java b/src/main/java/net/guizhanss/fastmachines/items/FastMachinesItems.java new file mode 100644 index 0000000..a307b3f --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/items/FastMachinesItems.java @@ -0,0 +1,34 @@ +package net.guizhanss.fastmachines.items; + +import org.bukkit.Material; + +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; + +import net.guizhanss.fastmachines.FastMachines; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public final class FastMachinesItems { + // + public static final SlimefunItemStack ETERNAL_FIRE = FastMachines.getLocalization().getItem( + "ETERNAL_FIRE", + Material.IRON_INGOT + ); + // + + // + public static final SlimefunItemStack FAST_ENHANCED_CRAFTING_TABLE = FastMachines.getLocalization().getItem( + "FAST_ENHANCED_CRAFTING_TABLE", + Material.CRAFTING_TABLE + ); + public static final SlimefunItemStack FAST_SMELTERY = FastMachines.getLocalization().getItem( + "FAST_SMELTERY", + Material.FURNACE + ); + public static final SlimefunItemStack FAST_ORE_WASHER = FastMachines.getLocalization().getItem( + "FAST_ORE_WASHER", + Material.CAULDRON + ); + // +} diff --git a/src/main/java/net/guizhanss/fastmachines/items/machines/AbstractFastMachine.java b/src/main/java/net/guizhanss/fastmachines/items/machines/AbstractFastMachine.java new file mode 100644 index 0000000..986fe40 --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/items/machines/AbstractFastMachine.java @@ -0,0 +1,370 @@ +package net.guizhanss.fastmachines.items.machines; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +import com.google.common.base.Preconditions; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon; +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.core.attributes.EnergyNetComponent; +import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType; +import io.github.thebusybiscuit.slimefun4.libraries.dough.blocks.BlockPosition; +import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; + +import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; +import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset; + +import net.guizhanss.fastmachines.FastMachines; +import net.guizhanss.fastmachines.core.recipes.StandardRecipe; +import net.guizhanss.fastmachines.setup.Groups; +import net.guizhanss.fastmachines.utils.BlockStorageUtils; +import net.guizhanss.fastmachines.utils.Heads; +import net.guizhanss.fastmachines.utils.MachineUtils; +import net.guizhanss.guizhanlib.slimefun.machines.TickingMenuBlock; + +/** + * A fast machine is a basic machine but uses energy to fast craft from the given materials. + *

+ * Idea from FinalTECH. + * + * @author Final_ROOT + * @author ybw0014 + */ +@SuppressWarnings("ConstantConditions") +public abstract class AbstractFastMachine extends TickingMenuBlock implements EnergyNetComponent { + + // slots + protected static final int[] INPUT_SLOTS = new int[] { + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35 + }; + protected static final int[] OUTPUT_SLOTS = new int[] { + 27, 28, 29, 30, 31, 32, 33, 34, 35 + }; + protected static final int[] PREVIEW_SLOTS = new int[] { + 36, 37, 38, 39, 40, 41, + 45, 46, 47, 48, 49, 50 + }; + protected static final int SCROLL_UP_SLOT = 42; + protected static final int SCROLL_DOWN_SLOT = 51; + protected static final int CHOICE_SLOT = 52; + protected static final int CRAFT_SLOT = 53; + protected static final int CHOICE_INDICATOR_SLOT = 43; + protected static final int INFO_SLOT = 44; + + // constants + protected static final int ITEMS_PER_PAGE = PREVIEW_SLOTS.length; + protected static final String KEY_CHOICE = "choice"; + + // menu items + protected static final ItemStack SCROLL_UP_ITEM = FastMachines.getLocalization().getItem( + "SCROLL_UP", Heads.ARROW_UP.getTexture()); + protected static final ItemStack SCROLL_DOWN_ITEM = FastMachines.getLocalization().getItem( + "SCROLL_DOWN", Heads.ARROW_DOWN.getTexture()); + protected static final ItemStack CHOICE_INDICATOR_ITEM = FastMachines.getLocalization().getItem( + "CHOICE_INDICATOR", Material.YELLOW_STAINED_GLASS_PANE); + protected static final ItemStack INFO_ITEM = FastMachines.getLocalization().getItem( + "INFO", Heads.INFO.getTexture()); + protected static final ItemStack NO_ITEM = FastMachines.getLocalization().getItem( + "NO_ITEM", Material.BARRIER); + + // outputs map + protected static final Map> OUTPUTS_MAP = new HashMap<>(); + + protected final List recipes = new ArrayList<>(); + + // 0 ~ 2^25-1 + private final IntRangeSetting energyPerUse = new IntRangeSetting(this, "energy-per-use", 0, 8, 33554431); + + protected AbstractFastMachine(SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { + super(Groups.MACHINES, item, recipeType, recipe); + + addItemSetting(energyPerUse); + } + + @Nonnull + @Override + public EnergyNetComponentType getEnergyComponentType() { + return EnergyNetComponentType.CONSUMER; + } + + @Override + public int getCapacity() { + return energyPerUse.getValue() * 64; + } + + @Override + protected void setup(@Nonnull BlockMenuPreset preset) { + for (int slot : PREVIEW_SLOTS) { + preset.addItem(slot, ChestMenuUtils.getBackground(), ChestMenuUtils.getEmptyClickHandler()); + } + preset.addItem(CHOICE_INDICATOR_SLOT, CHOICE_INDICATOR_ITEM, ChestMenuUtils.getEmptyClickHandler()); + preset.addItem(INFO_SLOT, INFO_ITEM, ChestMenuUtils.getEmptyClickHandler()); + preset.addItem(CHOICE_SLOT, NO_ITEM, ChestMenuUtils.getEmptyClickHandler()); + preset.addItem(SCROLL_UP_SLOT, SCROLL_UP_ITEM, ChestMenuUtils.getEmptyClickHandler()); + preset.addItem(SCROLL_DOWN_SLOT, SCROLL_DOWN_ITEM, ChestMenuUtils.getEmptyClickHandler()); + preset.addItem(CRAFT_SLOT, getCraftItem(), ChestMenuUtils.getEmptyClickHandler()); + } + + @Override + @ParametersAreNonnullByDefault + protected void onNewInstance(BlockMenu blockMenu, Block block) { + BlockPosition pos = new BlockPosition(block); + blockMenu.addMenuClickHandler(SCROLL_UP_SLOT, (player, i, itemStack, clickAction) -> { + int currentPage = BlockStorageUtils.getInt(pos.toLocation(), "page", 1); + BlockStorageUtils.setInt(pos.toLocation(), "page", currentPage - 1); + updateMenu(block, blockMenu); + return false; + }); + blockMenu.addMenuClickHandler(SCROLL_DOWN_SLOT, (player, i, itemStack, clickAction) -> { + int currentPage = BlockStorageUtils.getInt(pos.toLocation(), "page", 1); + BlockStorageUtils.setInt(pos.toLocation(), "page", currentPage + 1); + updateMenu(block, blockMenu); + return false; + }); + blockMenu.addMenuClickHandler(CRAFT_SLOT, (player, i, itemStack, clickAction) -> { + if (clickAction.isShiftClicked()) { + if (clickAction.isRightClicked()) { + craft(block, blockMenu, Integer.MAX_VALUE); + } else { + craft(block, blockMenu, 64); + } + } else { + if (clickAction.isRightClicked()) { + craft(block, blockMenu, 16); + } else { + craft(block, blockMenu, 1); + } + } + return false; + }); + } + + @Override + @ParametersAreNonnullByDefault + protected void tick(Block block, BlockMenu blockMenu) { + if (blockMenu.hasViewer() && FastMachines.getSlimefunTickCount() % 2 == 0) { + // Calculate machine inputs + findAvailableOutputs(block, blockMenu); + // Display available outputs + updateMenu(block, blockMenu); + } + } + + @Override + protected int[] getInputSlots() { + // Basic machines should not support cargo access + return new int[0]; + } + + @Override + protected int[] getOutputSlots() { + // Basic machines should not support cargo access + return new int[0]; + } + + @Override + public void register(@Nonnull SlimefunAddon addon) { + super.register(addon); + FastMachines.getScheduler().run(2, this::registerRecipes); + } + + @Override + @ParametersAreNonnullByDefault + protected void onBreak(BlockBreakEvent e, BlockMenu menu) { + super.onBreak(e, menu); + Location l = menu.getLocation(); + menu.dropItems(l, INPUT_SLOTS); + } + + /** + * Find all the available outputs based on the given inputs. + * + * @param block + * The {@link Block} of this machine. + * @param blockMenu + * The {@link BlockMenu} of this machine. + */ + @ParametersAreNonnullByDefault + protected void findAvailableOutputs(Block block, BlockMenu blockMenu) { + BlockPosition pos = new BlockPosition(block); + Map machineInputs = MachineUtils.getMachineInputAmount(blockMenu, INPUT_SLOTS); + Map outputs = OUTPUTS_MAP.getOrDefault(pos, new LinkedHashMap<>()); + outputs.clear(); + OUTPUTS_MAP.put(pos, outputs); + + if (machineInputs.isEmpty()) { + return; + } + + FastMachines.debug("current machine location: {0}", pos); + FastMachines.debug("machine inputs: {0}", machineInputs); + + // Fetch available recipes based on inputs + for (var recipe : recipes) { + if (recipe.isDisabledInWorld(block.getWorld())) { + continue; + } + + FastMachines.debug("checking recipe: {0}", recipe); + + // stores the possible maximum output amount + int outputAmount = Integer.MAX_VALUE; + + for (var recipeInputEntry : recipe.getInput().entrySet()) { + + // if the current recipe input isn't in the machine input, just ignore this + if (!machineInputs.containsKey(recipeInputEntry.getKey())) { + outputAmount = 0; + break; + } + + FastMachines.debug("input: {0}, machine amount: {1}", recipeInputEntry.getKey(), + machineInputs.get(recipeInputEntry.getKey())); + FastMachines.debug("recipe amount: {0}", recipeInputEntry.getValue()); + + // check the maximum possible output amount based on inputs + int inputAmount = machineInputs.get(recipeInputEntry.getKey()); + int recipeAmount = recipeInputEntry.getValue(); + outputAmount = Math.min(outputAmount, inputAmount / recipeAmount); + + FastMachines.debug("result amount: {0}", inputAmount / recipeAmount); + } + + // this recipe is available + if (outputAmount > 0) { + FastMachines.debug("recipe is available, output amount: {0}", outputAmount); + outputs.put(recipe, outputAmount); + } + } + + FastMachines.debug("outputs: " + outputs); + } + + @ParametersAreNonnullByDefault + protected void updateMenu(Block block, BlockMenu blockMenu) { + BlockPosition pos = new BlockPosition(block); + + // this shouldn't happen but just in case + if (!OUTPUTS_MAP.containsKey(pos)) { + return; + } + + // preview section + Map outputs = OUTPUTS_MAP.get(pos); + ItemStack[] outputItems = + outputs.keySet().stream().map(StandardRecipe::getOutput).toArray(ItemStack[]::new); + int currentPage = BlockStorageUtils.getInt(pos.toLocation(), "page", 1); + int totalPages = (int) Math.ceil(outputs.size() * 1.0 / ITEMS_PER_PAGE); + if (currentPage < 1) { + currentPage = 1; + BlockStorageUtils.setInt(pos.toLocation(), "page", 1); + } + if (currentPage > totalPages) { + currentPage = totalPages; + BlockStorageUtils.setInt(pos.toLocation(), "page", totalPages); + } + + for (int i = 0; i < ITEMS_PER_PAGE; i++) { + int index = (currentPage - 1) * ITEMS_PER_PAGE + i; + if (totalPages == 0 || index >= outputs.size()) { + blockMenu.replaceExistingItem(PREVIEW_SLOTS[i], ChestMenuUtils.getBackground()); + blockMenu.addMenuClickHandler(PREVIEW_SLOTS[i], ChestMenuUtils.getEmptyClickHandler()); + continue; + } + ItemStack output = outputItems[index].clone(); + blockMenu.replaceExistingItem(PREVIEW_SLOTS[i], output); + blockMenu.addMenuClickHandler(PREVIEW_SLOTS[i], ((player, slot, itemStack, clickAction) -> { + BlockStorageUtils.setInt(pos.toLocation(), KEY_CHOICE, index); + updateChoice(block, blockMenu); + return false; + })); + } + + updateChoice(block, blockMenu); + } + + @ParametersAreNonnullByDefault + protected void updateChoice(Block block, BlockMenu blockMenu) { + BlockPosition pos = new BlockPosition(block); + + // this shouldn't happen but just in case + if (!OUTPUTS_MAP.containsKey(pos)) { + return; + } + + Map outputs = OUTPUTS_MAP.get(pos); + ItemStack[] outputItems = + outputs.keySet().stream().map(StandardRecipe::getOutput).toArray(ItemStack[]::new); + + int choice = BlockStorageUtils.getInt(pos.toLocation(), KEY_CHOICE); + if (choice >= outputs.size()) { + blockMenu.replaceExistingItem(CHOICE_SLOT, NO_ITEM); + } else { + ItemStack output = outputItems[choice].clone(); + blockMenu.replaceExistingItem(CHOICE_SLOT, output); + } + } + + /** + * Craft the given amount of items. + * + * @param amount + * The amount of items to craft. + */ + protected void craft(Block block, BlockMenu blockMenu, int amount) { + Preconditions.checkArgument(amount > 0, "amount must greater than 0"); + + BlockPosition pos = new BlockPosition(block); + + // this shouldn't happen but just in case + if (!OUTPUTS_MAP.containsKey(pos)) { + return; + } + + Map outputs = OUTPUTS_MAP.get(pos); + var outputRecipes = outputs.entrySet().stream().toList(); + + int choice = BlockStorageUtils.getInt(pos.toLocation(), KEY_CHOICE); + if (choice >= outputs.size()) { + return; + } + var recipe = outputRecipes.get(choice); + int maxAmount = recipe.getValue(); + amount = Math.min(maxAmount, amount); + + // check if the machine has enough energy + + } + + /** + * Register available recipes for this machine. + *

+ * Note: this method is called synchronously after server completes loading. + */ + protected abstract void registerRecipes(); + + /** + * Get the item that shows the craft button of this machine. + * + * @return the item that shows the craft button of this machine. + */ + protected abstract ItemStack getCraftItem(); +} diff --git a/src/main/java/net/guizhanss/fastmachines/items/machines/FastEnhancedCraftingTable.java b/src/main/java/net/guizhanss/fastmachines/items/machines/FastEnhancedCraftingTable.java new file mode 100644 index 0000000..674bb02 --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/items/machines/FastEnhancedCraftingTable.java @@ -0,0 +1,32 @@ +package net.guizhanss.fastmachines.items.machines; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; +import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; + +import net.guizhanss.fastmachines.FastMachines; +import net.guizhanss.fastmachines.utils.RecipeUtils; + +public final class FastEnhancedCraftingTable extends AbstractFastMachine { + + private static final ItemStack CRAFT_ITEM = FastMachines.getLocalization().getItem( + "CRAFT", Material.CRAFTING_TABLE); + + public FastEnhancedCraftingTable(SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { + super(item, recipeType, recipe); + } + + @Override + protected void registerRecipes() { + FastMachines.debug("Registering recipes for FastEnhancedCraftingTable"); + RecipeUtils.registerMultiblockMachineRecipes(recipes, SlimefunItems.ENHANCED_CRAFTING_TABLE.getItemId()); + } + + @Override + protected ItemStack getCraftItem() { + return CRAFT_ITEM; + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/items/machines/FastOreWasher.java b/src/main/java/net/guizhanss/fastmachines/items/machines/FastOreWasher.java new file mode 100644 index 0000000..9301b94 --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/items/machines/FastOreWasher.java @@ -0,0 +1,31 @@ +package net.guizhanss.fastmachines.items.machines; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; +import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; + +import net.guizhanss.fastmachines.FastMachines; +import net.guizhanss.fastmachines.utils.RecipeUtils; + +public final class FastOreWasher extends AbstractFastMachine { + + private static final ItemStack CRAFT_ITEM = FastMachines.getLocalization().getItem( + "CRAFT", Material.CAULDRON); + + public FastOreWasher(SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { + super(item, recipeType, recipe); + } + + @Override + protected void registerRecipes() { + RecipeUtils.registerMultiblockMachineRecipes(recipes, SlimefunItems.ORE_WASHER.getItemId()); + } + + @Override + protected ItemStack getCraftItem() { + return CRAFT_ITEM; + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/items/machines/FastSmeltery.java b/src/main/java/net/guizhanss/fastmachines/items/machines/FastSmeltery.java new file mode 100644 index 0000000..ad78178 --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/items/machines/FastSmeltery.java @@ -0,0 +1,32 @@ +package net.guizhanss.fastmachines.items.machines; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; +import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; + +import net.guizhanss.fastmachines.FastMachines; +import net.guizhanss.fastmachines.utils.RecipeUtils; + +public final class FastSmeltery extends AbstractFastMachine { + + private static final ItemStack CRAFT_ITEM = FastMachines.getLocalization().getItem( + "CRAFT", Material.FURNACE); + + public FastSmeltery(SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { + super(item, recipeType, recipe); + } + + @Override + protected void registerRecipes() { + FastMachines.debug("Registering recipes for FastSmeltery"); + RecipeUtils.registerMultiblockMachineRecipes(recipes, SlimefunItems.SMELTERY.getItemId()); + } + + @Override + protected ItemStack getCraftItem() { + return CRAFT_ITEM; + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/items/materials/FastMaterial.java b/src/main/java/net/guizhanss/fastmachines/items/materials/FastMaterial.java new file mode 100644 index 0000000..5266e9b --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/items/materials/FastMaterial.java @@ -0,0 +1,24 @@ +package net.guizhanss.fastmachines.items.materials; + +import javax.annotation.ParametersAreNonnullByDefault; + +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack; +import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.implementation.items.blocks.UnplaceableBlock; +import io.github.thebusybiscuit.slimefun4.libraries.dough.items.CustomItemStack; + +import net.guizhanss.fastmachines.setup.Groups; + +public class FastMaterial extends UnplaceableBlock { + @ParametersAreNonnullByDefault + public FastMaterial(SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) { + super(Groups.MATERIALS, item, recipeType, recipe); + } + + @ParametersAreNonnullByDefault + public FastMaterial(SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe, int outputAmount) { + super(Groups.MATERIALS, item, recipeType, recipe, new CustomItemStack(item, outputAmount)); + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/setup/Groups.java b/src/main/java/net/guizhanss/fastmachines/setup/Groups.java new file mode 100644 index 0000000..68bb82d --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/setup/Groups.java @@ -0,0 +1,41 @@ +package net.guizhanss.fastmachines.setup; + +import org.bukkit.Material; + +import io.github.thebusybiscuit.slimefun4.api.items.groups.NestedItemGroup; +import io.github.thebusybiscuit.slimefun4.api.items.groups.SubItemGroup; + +import net.guizhanss.fastmachines.FastMachines; +import net.guizhanss.fastmachines.utils.Heads; +import net.guizhanss.fastmachines.utils.Keys; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public final class Groups { + public static final NestedItemGroup MAIN = new NestedItemGroup( + Keys.get("fast_machines"), + FastMachines.getLocalization().getItemGroupItem( + "FAST_MACHINES", + Heads.MAIN.getTexture() + ) + ); + + public static final SubItemGroup MATERIALS = new SubItemGroup( + Keys.get("materials"), + MAIN, + FastMachines.getLocalization().getItemGroupItem( + "MATERIALS", + Material.DIAMOND + ) + ); + + public static final SubItemGroup MACHINES = new SubItemGroup( + Keys.get("machines"), + MAIN, + FastMachines.getLocalization().getItemGroupItem( + "MACHINES", + Heads.MAIN.getTexture() + ) + ); +} diff --git a/src/main/java/net/guizhanss/fastmachines/setup/Items.java b/src/main/java/net/guizhanss/fastmachines/setup/Items.java new file mode 100644 index 0000000..cfdd38a --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/setup/Items.java @@ -0,0 +1,45 @@ +package net.guizhanss.fastmachines.setup; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType; +import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems; + +import net.guizhanss.fastmachines.FastMachines; +import net.guizhanss.fastmachines.items.FastMachinesItems; +import net.guizhanss.fastmachines.items.machines.FastSmeltery; +import net.guizhanss.fastmachines.items.materials.FastMaterial; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public final class Items { + public static void setup(FastMachines plugin) { + // + new FastMaterial(FastMachinesItems.ETERNAL_FIRE, RecipeType.MAGIC_WORKBENCH, new ItemStack[] { + null, null, null, + new ItemStack(Material.FLINT_AND_STEEL), new ItemStack(Material.FLINT_AND_STEEL), new ItemStack(Material.FLINT_AND_STEEL), + SlimefunItems.IGNITION_CHAMBER, new ItemStack(Material.NETHERRACK), SlimefunItems.IGNITION_CHAMBER + }).register(plugin); + // + + // +// new FastEnhancedCraftingTable(FastMachinesItems.FAST_ENHANCED_CRAFTING_TABLE, RecipeType.MAGIC_WORKBENCH, new ItemStack[] { +// null, null, null, +// null, new ItemStack(Material.CRAFTING_TABLE), null, +// SlimefunItems.OUTPUT_CHEST, new ItemStack(Material.DISPENSER), null +// }).register(plugin); + new FastSmeltery(FastMachinesItems.FAST_SMELTERY, RecipeType.MAGIC_WORKBENCH, new ItemStack[] { + null, new ItemStack(Material.NETHER_BRICK_FENCE), null, + new ItemStack(Material.NETHER_BRICKS), new ItemStack(Material.DISPENSER), new ItemStack(Material.NETHER_BRICKS), + null, FastMachinesItems.ETERNAL_FIRE, null + }).register(plugin); +// new FastOreWasher(FastMachinesItems.FAST_ORE_WASHER, RecipeType.MAGIC_WORKBENCH, new ItemStack[] { +// null, new ItemStack(Material.GLASS), null, +// null, new ItemStack(Material.CRAFTING_TABLE), null, +// SlimefunItems.OUTPUT_CHEST, new ItemStack(Material.DISPENSER), null +// }).register(plugin); + // + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/utils/BlockStorageUtils.java b/src/main/java/net/guizhanss/fastmachines/utils/BlockStorageUtils.java new file mode 100644 index 0000000..b98715a --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/utils/BlockStorageUtils.java @@ -0,0 +1,32 @@ +package net.guizhanss.fastmachines.utils; + +import javax.annotation.ParametersAreNonnullByDefault; + +import org.bukkit.Location; + +import me.mrCookieSlime.Slimefun.api.BlockStorage; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public final class BlockStorageUtils { + @ParametersAreNonnullByDefault + public static int getInt(Location location, String key) { + return getInt(location, key, 0); + } + + @ParametersAreNonnullByDefault + public static int getInt(Location location, String key, int defaultVal) { + String result = BlockStorage.getLocationInfo(location, key); + if (result != null) { + return Integer.parseInt(result); + } else { + return defaultVal; + } + } + + @ParametersAreNonnullByDefault + public static void setInt(Location location, String key, int value) { + BlockStorage.addBlockInfo(location, key, String.valueOf(value)); + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/utils/Heads.java b/src/main/java/net/guizhanss/fastmachines/utils/Heads.java new file mode 100644 index 0000000..a66cd08 --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/utils/Heads.java @@ -0,0 +1,27 @@ +package net.guizhanss.fastmachines.utils; + +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum Heads { + // https://minecraft-heads.com/custom-heads/decoration/64403-technical-device + MAIN("f1c9de1e420d65c21819e0a0c7ca5817c930052127b44a1334a246997f75e84f"), + // https://minecraft-heads.com/custom-heads/alphabet/11214-quartz-arrow-up + ARROW_UP("a99aaf2456a6122de8f6b62683f2bc2eed9abb81fd5bea1b4c23a58156b669"), + // https://minecraft-heads.com/custom-heads/alphabet/11221-quartz-arrow-down + ARROW_DOWN("3912d45b1c78cc22452723ee66ba2d15777cc288568d6c1b62a545b29c7187"), + // https://minecraft-heads.com/custom-heads/alphabet/23223-information + INFO("16439d2e306b225516aa9a6d007a7e75edd2d5015d113b42f44be62a517e574f"); + + private final String texture; + + public ItemStack getItem() { + return SlimefunUtils.getCustomHead(texture); + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/utils/Keys.java b/src/main/java/net/guizhanss/fastmachines/utils/Keys.java new file mode 100644 index 0000000..13787d0 --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/utils/Keys.java @@ -0,0 +1,21 @@ +package net.guizhanss.fastmachines.utils; + +import javax.annotation.Nonnull; + +import com.google.common.base.Preconditions; + +import org.bukkit.NamespacedKey; + +import net.guizhanss.fastmachines.FastMachines; + +import lombok.experimental.UtilityClass; + +@SuppressWarnings("ConstantConditions") +@UtilityClass +public final class Keys { + public static NamespacedKey get(@Nonnull String name) { + Preconditions.checkArgument(name != null, "name cannot be null"); + + return new NamespacedKey(FastMachines.getInstance(), name); + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/utils/MachineUtils.java b/src/main/java/net/guizhanss/fastmachines/utils/MachineUtils.java new file mode 100644 index 0000000..b652f31 --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/utils/MachineUtils.java @@ -0,0 +1,51 @@ +package net.guizhanss.fastmachines.utils; + +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +import org.bukkit.inventory.ItemStack; + +import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public final class MachineUtils { + /** + * Get the amount map of machine inputs. + * + * @param menu + * The {@link BlockMenu} of machine. + * @param slots + * The slots of machine inputs. + * + * @return The amount map of machine inputs. + */ + @Nonnull + @ParametersAreNonnullByDefault + public static Map getMachineInputAmount(BlockMenu menu, int[] slots) { + return RecipeUtils.calculateItems(getItems(menu, slots)); + } + + /** + * Retrive all the {@link ItemStack} inside given machine slots. + * + * @param menu + * The {@link BlockMenu} of machine. + * @param slots + * The slots of machine. + * + * @return The array of {@link ItemStack} inside given machine slots. + */ + @Nonnull + @ParametersAreNonnullByDefault + public static ItemStack[] getItems(BlockMenu menu, int[] slots) { + ItemStack[] items = new ItemStack[slots.length]; + for (int i = 0; i < slots.length; i++) { + items[i] = menu.getItemInSlot(slots[i]); + } + return items; + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/utils/RecipeUtils.java b/src/main/java/net/guizhanss/fastmachines/utils/RecipeUtils.java new file mode 100644 index 0000000..509cdbf --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/utils/RecipeUtils.java @@ -0,0 +1,186 @@ +package net.guizhanss.fastmachines.utils; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +import com.google.common.base.Preconditions; + +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; +import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem; +import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlockMachine; +import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils; + +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe; + +import net.guizhanss.fastmachines.FastMachines; +import net.guizhanss.fastmachines.core.recipes.StandardRecipe; +import net.guizhanss.fastmachines.items.machines.AbstractFastMachine; + +import lombok.experimental.UtilityClass; + +@UtilityClass +@SuppressWarnings("ConstantConditions") +public final class RecipeUtils { + private static final String MSG_ID_NULL = "id cannot be null"; + private static final String MSG_RECIPE_NULL = "recipes cannot be null"; + + /** + * Calculate the amount of each item in the given array. + * Similar items will be merged by + * {@link SlimefunUtils#isItemSimilar(ItemStack, ItemStack, boolean, boolean, boolean)}. + * + * @param items + * The array of {@link ItemStack}. + * + * @return A {@link Map} that contains the amount of each item. + */ + public static Map calculateItems(@Nonnull ItemStack... items) { + Preconditions.checkArgument(items != null, "items cannot be null"); + Map result = new HashMap<>(); + for (var item : items) { + if (item == null || item.getType().isAir()) { + continue; + } + boolean existingItem = false; + for (var entry : result.entrySet()) { + if (SlimefunUtils.isItemSimilar(item, entry.getKey(), false, false, true)) { + existingItem = true; + result.put(entry.getKey(), entry.getValue() + item.getAmount()); + break; + } + } + if (!existingItem) { + ItemStack itemCopy = item.clone(); + itemCopy.setAmount(1); + result.put(itemCopy, item.getAmount()); + } + } + return result; + } + + /** + * Register recipes from a {@link MultiBlockMachine}. + * + * @param recipes + * The {@link List} instance of {@link StandardRecipe} from a {@link AbstractFastMachine}. + * @param id + * The id of the {@link MultiBlockMachine}. + */ + @ParametersAreNonnullByDefault + public static void registerMultiblockMachineRecipes(List recipes, String id) { + Preconditions.checkArgument(recipes != null, MSG_RECIPE_NULL); + Preconditions.checkArgument(id != null, MSG_ID_NULL); + + SlimefunItem machineItem = SlimefunItem.getById(id); + if (!(machineItem instanceof MultiBlockMachine machine)) { + throw new IllegalArgumentException("must be a multiblock machine"); + } + + // initial recipes + List recipeList = machine.getRecipes(); + + if (recipeList.size() % 2 != 0) { + throw new IllegalArgumentException("The given MultiBlockMachine has illegal recipe list: " + id); + } + + FastMachines.debug("Registering recipes from multiblock: {0}", id); + FastMachines.debug("Total recipes: {0}", recipeList.size() / 2); + for (int i = 0; i < recipeList.size(); i += 2) { + ItemStack[] input = recipeList.get(i); + ItemStack[] output = recipeList.get(i + 1); + if (SlimefunItemUtils.isDisabled(output[0])) { + continue; + } + var recipe = new StandardRecipe(output[0], input); + FastMachines.debug("registering standard recipe: {0}", recipe); + recipes.add(recipe); + } + } + + /** + * Register recipes from a electric machine. + * + * @param recipes + * The {@link List} instance of {@link StandardRecipe} from a {@link AbstractFastMachine}. + * @param id + * The id of the {@link MultiBlockMachine}. + */ + @ParametersAreNonnullByDefault + public static void registerMachineRecipes(List recipes, String id) { + Preconditions.checkArgument(recipes != null, MSG_RECIPE_NULL); + Preconditions.checkArgument(id != null, MSG_ID_NULL); + + SlimefunItem machineItem = SlimefunItem.getById(id); + if (machineItem == null) { + throw new IllegalArgumentException("The given id is not a valid SlimefunItem: " + id); + } + + FastMachines.debug("Registering recipes from machine: {0}", id); + try { + Method method = machineItem.getClass().getMethod("getMachineRecipes"); + List machineRecipes = (List) method.invoke(machineItem); + if (machineRecipes == null) { + FastMachines.debug("Retrieved recipes are null, ignoring."); + return; + } + for (MachineRecipe machineRecipe : machineRecipes) { + if (machineRecipe.getOutput().length > 0) { + ItemStack output = machineRecipe.getOutput()[0]; + if (SlimefunItemUtils.isDisabled(output)) { + continue; + } + + var recipe = new StandardRecipe(machineRecipe.getOutput()[0], machineRecipe.getInput()); + FastMachines.debug("registering standard recipe: {0}", recipe); + recipes.add(recipe); + } + } + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + FastMachines.log(Level.WARNING, "Failed to retrieve machine recipes from {0}, attempting to use backup method.", id); + if (machineItem instanceof RecipeDisplayItem recipeDisplayItem) { + registerDisplayRecipes(recipes, recipeDisplayItem.getDisplayRecipes()); + FastMachines.log(Level.INFO, "Backup method succeeded. You can ignore the above warning."); + } else { + FastMachines.log(Level.SEVERE, "Backup method failed, please report this."); + } + } + } + + /** + * Register recipes from display recipes. + * + * @param recipes + * The {@link List} instance of {@link StandardRecipe} from a {@link AbstractFastMachine}. + * @param displayRecipes + * The display recipes from a {@link RecipeDisplayItem}. + */ + @ParametersAreNonnullByDefault + public static void registerDisplayRecipes(List recipes, List displayRecipes) { + Preconditions.checkArgument(recipes != null, MSG_RECIPE_NULL); + Preconditions.checkArgument(displayRecipes != null, "displayRecipes cannot be null"); + + if (displayRecipes.size() % 2 != 0) { + throw new IllegalArgumentException("The display recipes list is illegal!"); + } + + for (int i = 0; i < displayRecipes.size(); i += 2) { + ItemStack input = displayRecipes.get(i); + ItemStack output = displayRecipes.get(i + 1); + if (SlimefunItemUtils.isDisabled(output)) { + continue; + } + var recipe = new StandardRecipe(output, input); + FastMachines.debug("registering standard recipe: {0}", recipe); + recipes.add(recipe); + } + } +} diff --git a/src/main/java/net/guizhanss/fastmachines/utils/SlimefunItemUtils.java b/src/main/java/net/guizhanss/fastmachines/utils/SlimefunItemUtils.java new file mode 100644 index 0000000..f6c109f --- /dev/null +++ b/src/main/java/net/guizhanss/fastmachines/utils/SlimefunItemUtils.java @@ -0,0 +1,23 @@ +package net.guizhanss.fastmachines.utils; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.bukkit.inventory.ItemStack; + +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public final class SlimefunItemUtils { + public static boolean isDisabled(@Nullable ItemStack item) { + SlimefunItem sfItem = SlimefunItem.getByItem(item); + return sfItem != null && sfItem.isDisabled(); + } + + public static boolean isDisabled(@Nonnull String id) { + SlimefunItem sfItem = SlimefunItem.getById(id); + return sfItem != null && sfItem.isDisabled(); + } +} diff --git a/src/main/java/net/guizhanss/guizhanslimefunaddon/GuizhanSlimefunAddon.java b/src/main/java/net/guizhanss/guizhanslimefunaddon/GuizhanSlimefunAddon.java deleted file mode 100644 index a7b6739..0000000 --- a/src/main/java/net/guizhanss/guizhanslimefunaddon/GuizhanSlimefunAddon.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.guizhanss.guizhanslimefunaddon; - -import java.io.File; -import java.lang.reflect.Method; -import java.util.logging.Level; - -import org.bukkit.plugin.Plugin; - -import io.github.thebusybiscuit.slimefun4.libraries.dough.updater.GitHubBuildsUpdater; - -import net.guizhanss.guizhanlib.slimefun.addon.AbstractAddon; -import net.guizhanss.guizhanlib.updater.GuizhanBuildsUpdater; - -import org.bstats.bukkit.Metrics; - -public final class GuizhanSlimefunAddon extends AbstractAddon { - - public GuizhanSlimefunAddon() { - super("ybw0014", "GuizhanSlimefunAddon", "master", "auto-update"); - } - - @Override - public void enable() { - log(Level.INFO, "===================="); - log(Level.INFO, "GuizhanSlimefunAddon"); - log(Level.INFO, " by ybw0014 "); - log(Level.INFO, "===================="); - } - - @Override - public void disable() { - } - - private void setupMetrics() { - new Metrics(this, 114514); - } - - @Override - protected void autoUpdate() { - if (getPluginVersion().startsWith("DEV")) { - String path = getGithubUser() + "/" + getGithubRepo() + "/" + getGithubBranch(); - new GitHubBuildsUpdater(this, getFile(), path).start(); - } else if (getPluginVersion().startsWith("Build")) { - try { - // use updater in lib plugin - Class clazz = Class.forName("net.guizhanss.guizhanlibplugin.updater.GuizhanUpdater"); - Method updaterStart = clazz.getDeclaredMethod("start", Plugin.class, File.class, String.class, String.class, String.class); - updaterStart.invoke(null, this, getFile(), getGithubUser(), getGithubRepo(), getGithubBranch()); - } catch (Exception ignored) { - // use updater in lib - new GuizhanBuildsUpdater(this, getFile(), getGithubUser(), getGithubRepo(), getGithubBranch()).start(); - } - } - } -} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 3c2f946..57be0e6 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1 +1,19 @@ +# Enable auto update auto-update: true + +# The locale of the plugin. +# Available languages: https://github.com/ybw0014/FastMachines/tree/master/src/main/resources/lang +lang: en-US + +# Enable researches for items in this addon. +enable-researches: true + +# Fast machines related settings. +fast-machines: + # Whether to use energy on crafting. + # Disabling this option will change the recipes of fast machines. + # The energy per use is defined per machine in /plugins/Slimefun/Items.yml + use-energy: true + +# Print debug messages. +debug: false diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml new file mode 100644 index 0000000..8f14fd1 --- /dev/null +++ b/src/main/resources/lang/en-US.yml @@ -0,0 +1,123 @@ +console: + loaded-language: "Loaded language: {0}" + loading-items: "Loading items..." + +categories: + FAST_MACHINES: + name: "&eFast Machines" + MATERIALS: + name: "&eFast Machines &7- &bMaterials" + MACHINES: + name: "&eFast Machines &7- &aMachines" + +items: + # gui items + CHOICE_INDICATOR: + name: "&eChosen item" + lore: + - "&7You have chosen the item below to be made." + SCROLL_UP: + name: "&eScroll up" + lore: + - "&7Click to scroll up possible outputs." + SCROLL_DOWN: + name: "&eScroll down" + lore: + - "&7Click to scroll down possible outputs." + INFO: + name: "&fInformation" + lore: + - "&7Put the materials in the first 4 rows," + - "&7all the available outputs will be shown." + - "" + - "&7Select an item, then click on 'Craft' below." + - "&7The outputs will fill the 4th row." + CRAFT: + name: "&aCraft" + lore: + - "&7Click to craft the selected item." + - "" + - "&7Left Click: 1 time" + - "&7Right Click: 16 times" + - "&7Shift + Left Click: 64 times" + - "&7Shift + Right Click: as many as possible" + - "" + - "&cIf the possible output amount does not satisfy" + - "&cthe requested amount, the crafting will provide" + - "&cmaximum possible amount of the item." + NO_ITEM: + name: "&cNo Item selected" + lore: [] + + # materials + ETERNAL_FIRE: + name: "&4Eternal Fire" + lore: + - "&7The fire that never goes out." + + # machines + FAST_ENHANCED_CRAFTING_TABLE: + name: "&aFast Enhanced Crafting Table" + lore: + - "&7More useful Enhanced Crafting Table." + - "&7Craft without need to put items in order." + FAST_GRIND_STONE: + name: "&aFast Grind Stone" + lore: + - "&7More useful Grind Stone." + - "&7Craft without need to put items in order." + FAST_ARMOR_FORGE: + name: "&aFast Armor Forge" + lore: + - "&7More useful Armor Forge." + - "&7Craft without need to put items in order." + FAST_ORE_CRUSHER: + name: "&aFast Ore Crusher" + lore: + - "&7More useful Armor Forge." + - "&7Craft without need to put items in order." + FAST_COMPRESSOR: + name: "&aFast Compressor" + lore: + - "&7More useful Grind Stone." + - "&7Craft without need to put items in order." + FAST_SMELTERY: + name: "&aFast Smeltery" + lore: + - "&7More useful Smeltery." + - "&7Craft without need to put items in order." + FAST_PRESSURE_CHAMBER: + name: "&aFast Pressure Chamber" + lore: + - "&7More useful Pressure Chamber." + - "&7Craft without need to put items in order." + FAST_MAGIC_WORKBENCH: + name: "&aFast Magic Workbench" + lore: + - "&7More useful Magic Workbench." + - "&7Craft without need to put items in order." + FAST_ORE_WASHER: + name: "&aFast Ore Washer" + lore: + - "&7More useful Ore Washer." + - "&7Craft without need to put items in order." + FAST_TABLE_SAW: + name: "&aFast Table Saw" + lore: + - "&7More useful Table Saw." + - "&7Craft without need to put items in order." + FAST_COMPOSTER: + name: "&aFast Composter" + lore: + - "&7More useful Composter." + - "&7Craft without need to put items in order." + FAST_PANNING_MACHINE: + name: "&aFast Panning Machine" + lore: + - "&7More useful Automated Panning Machine." + - "&7Craft without need to put items in order." + FAST_JUICER: + name: "&aFast Juicer" + lore: + - "&7More useful Juicer." + - "&7Craft without need to put items in order." diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index de8e017..edeaba8 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,8 +1,8 @@ -name: GuizhanSlimefunAddon +name: FastMachines version: '${project.version}' -main: net.guizhanss.guizhanslimefunaddon.GuizhanSlimefunAddon -api-version: 1.14 +main: net.guizhanss.fastmachines.FastMachines +api-version: 1.16 depend: [ Slimefun ] softdepend: [ GuizhanLibPlugin ] authors: [ ybw0014 ] -description: A Slimefun Addon +description: A Slimefun Addon that adds better basic machines.