mirror of
https://github.com/StarWishsama/Slimefun4.git
synced 2024-09-20 03:35:51 +00:00
Created abstract auto crafter framework
This commit is contained in:
parent
5a0a52baab
commit
0aa5a999d4
@ -0,0 +1,257 @@
|
|||||||
|
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.crafters;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import io.github.thebusybiscuit.cscorelib2.inventory.InvUtils;
|
||||||
|
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
|
||||||
|
import io.github.thebusybiscuit.slimefun4.api.items.ItemState;
|
||||||
|
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
|
||||||
|
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
|
||||||
|
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
|
||||||
|
import io.papermc.lib.PaperLib;
|
||||||
|
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
|
||||||
|
import me.mrCookieSlime.Slimefun.Lists.RecipeType;
|
||||||
|
import me.mrCookieSlime.Slimefun.Objects.Category;
|
||||||
|
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem;
|
||||||
|
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer;
|
||||||
|
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
|
||||||
|
import me.mrCookieSlime.Slimefun.api.SlimefunItemStack;
|
||||||
|
|
||||||
|
public abstract class AbstractAutoCrafter extends SlimefunItem implements EnergyNetComponent {
|
||||||
|
|
||||||
|
private int energyConsumedPerTick = -1;
|
||||||
|
private int energyCapacity = -1;
|
||||||
|
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
public AbstractAutoCrafter(Category category, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
|
||||||
|
super(category, item, recipeType, recipe);
|
||||||
|
|
||||||
|
addItemHandler(onRightClick());
|
||||||
|
addItemHandler(new BlockTicker() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick(Block b, SlimefunItem item, Config data) {
|
||||||
|
AbstractAutoCrafter.this.tick(b, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSynchronized() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private BlockUseHandler onRightClick() {
|
||||||
|
return e -> e.getClickedBlock().ifPresent(b -> onRightClick(e.getPlayer(), b));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void tick(@Nonnull Block b, @Nonnull Config data) {
|
||||||
|
AbstractRecipe recipe = getSelectedRecipe(b);
|
||||||
|
|
||||||
|
if (recipe == null || getCharge(b.getLocation(), data) < getEnergyConsumption()) {
|
||||||
|
// No valid recipe selected, abort...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block chest = b.getRelative(BlockFace.DOWN);
|
||||||
|
|
||||||
|
if (chest.getType() == Material.CHEST || chest.getType() == Material.TRAPPED_CHEST) {
|
||||||
|
BlockState state = PaperLib.getBlockState(chest, false).getState();
|
||||||
|
|
||||||
|
if (state instanceof InventoryHolder) {
|
||||||
|
Inventory inv = ((InventoryHolder) state).getInventory();
|
||||||
|
|
||||||
|
if (craft(inv, recipe)) {
|
||||||
|
removeCharge(b.getLocation(), getEnergyConsumption());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the currently selected {@link AbstractRecipe} for the given
|
||||||
|
* {@link Block}.
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
* The {@link Block}
|
||||||
|
*
|
||||||
|
* @return The currently selected {@link AbstractRecipe} or null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public abstract AbstractRecipe getSelectedRecipe(@Nonnull Block b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called when a {@link Player} right clicks the {@link AbstractAutoCrafter}.
|
||||||
|
* Use it to choose the {@link AbstractRecipe}.
|
||||||
|
*
|
||||||
|
* @param p
|
||||||
|
* The {@link Player} who clicked
|
||||||
|
* @param b
|
||||||
|
* The {@link Block} which was clicked
|
||||||
|
*/
|
||||||
|
protected abstract void onRightClick(@Nonnull Player p, @Nonnull Block b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks whether the given {@link Predicate} matches the provided {@link ItemStack}.
|
||||||
|
*
|
||||||
|
* @param item
|
||||||
|
* The {@link ItemStack} to check
|
||||||
|
* @param predicate
|
||||||
|
* The {@link Predicate}
|
||||||
|
*
|
||||||
|
* @return Whether the {@link Predicate} matches the {@link ItemStack}
|
||||||
|
*/
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
protected boolean matches(ItemStack item, Predicate<ItemStack> predicate) {
|
||||||
|
return predicate.test(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
protected boolean matchesAny(Inventory inv, Map<Integer, Integer> itemQuantities, Predicate<ItemStack> predicate) {
|
||||||
|
for (int slot = 0; slot < inv.getSize(); slot++) {
|
||||||
|
ItemStack item = inv.getItem(slot);
|
||||||
|
|
||||||
|
if (item != null) {
|
||||||
|
int amount = itemQuantities.getOrDefault(slot, item.getAmount());
|
||||||
|
|
||||||
|
if (amount > 0 && matches(item, predicate)) {
|
||||||
|
// Update our local quantity map
|
||||||
|
itemQuantities.put(slot, amount - 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean craft(@Nonnull Inventory inv, @Nonnull AbstractRecipe recipe) {
|
||||||
|
Validate.notNull(inv, "The Inventory must not be null");
|
||||||
|
Validate.notNull(recipe, "The Recipe shall not be null");
|
||||||
|
|
||||||
|
if (InvUtils.fits(inv, recipe.getResult())) {
|
||||||
|
Map<Integer, Integer> itemQuantities = new HashMap<>();
|
||||||
|
|
||||||
|
for (Predicate<ItemStack> predicate : recipe.getInputs()) {
|
||||||
|
// Check if any Item matches the Predicate
|
||||||
|
if (!matchesAny(inv, itemQuantities, predicate)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove ingredients
|
||||||
|
for (Map.Entry<Integer, Integer> entry : itemQuantities.entrySet()) {
|
||||||
|
ItemStack item = inv.getItem(entry.getKey());
|
||||||
|
|
||||||
|
// Double-check to be extra safe
|
||||||
|
if (item != null) {
|
||||||
|
item.setAmount(entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All Predicates have found a match
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the max amount of electricity this machine can hold.
|
||||||
|
*
|
||||||
|
* @return The max amount of electricity this Block can store.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int getCapacity() {
|
||||||
|
return energyCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the amount of energy that is consumed per operation.
|
||||||
|
*
|
||||||
|
* @return The rate of energy consumption
|
||||||
|
*/
|
||||||
|
public int getEnergyConsumption() {
|
||||||
|
return energyConsumedPerTick;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This sets the energy capacity for this machine.
|
||||||
|
* This method <strong>must</strong> be called before registering the item
|
||||||
|
* and only before registering.
|
||||||
|
*
|
||||||
|
* @param capacity
|
||||||
|
* The amount of energy this machine can store
|
||||||
|
*
|
||||||
|
* @return This method will return the current instance of {@link AContainer}, so that can be chained.
|
||||||
|
*/
|
||||||
|
public final AbstractAutoCrafter setCapacity(int capacity) {
|
||||||
|
Validate.isTrue(capacity > 0, "The capacity must be greater than zero!");
|
||||||
|
|
||||||
|
if (getState() == ItemState.UNREGISTERED) {
|
||||||
|
this.energyCapacity = capacity;
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("You cannot modify the capacity after the Item was registered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the energy consumed by this machine per tick.
|
||||||
|
*
|
||||||
|
* @param energyConsumption
|
||||||
|
* The energy consumed per tick
|
||||||
|
*
|
||||||
|
* @return This method will return the current instance of {@link AContainer}, so that can be chained.
|
||||||
|
*/
|
||||||
|
public final AbstractAutoCrafter setEnergyConsumption(int energyConsumption) {
|
||||||
|
Validate.isTrue(energyConsumption > 0, "The energy consumption must be greater than zero!");
|
||||||
|
Validate.isTrue(energyCapacity > 0, "You must specify the capacity before you can set the consumption amount.");
|
||||||
|
Validate.isTrue(energyConsumption <= energyCapacity, "The energy consumption cannot be higher than the capacity (" + energyCapacity + ')');
|
||||||
|
|
||||||
|
this.energyConsumedPerTick = energyConsumption;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register(@Nonnull SlimefunAddon addon) {
|
||||||
|
this.addon = addon;
|
||||||
|
|
||||||
|
if (getCapacity() <= 0) {
|
||||||
|
warn("The capacity has not been configured correctly. The Item was disabled.");
|
||||||
|
warn("Make sure to call '" + getClass().getSimpleName() + "#setEnergyCapacity(...)' before registering!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getEnergyConsumption() <= 0) {
|
||||||
|
warn("The energy consumption has not been configured correctly. The Item was disabled.");
|
||||||
|
warn("Make sure to call '" + getClass().getSimpleName() + "#setEnergyConsumption(...)' before registering!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getCapacity() > 0 && getEnergyConsumption() > 0) {
|
||||||
|
super.register(addon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final EnergyNetComponentType getEnergyComponentType() {
|
||||||
|
return EnergyNetComponentType.CONSUMER;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package io.github.thebusybiscuit.slimefun4.implementation.items.electric.crafters;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.RecipeChoice;
|
||||||
|
import org.bukkit.inventory.ShapedRecipe;
|
||||||
|
import org.bukkit.inventory.ShapelessRecipe;
|
||||||
|
|
||||||
|
public class AbstractRecipe {
|
||||||
|
|
||||||
|
private final Collection<Predicate<ItemStack>> inputs;
|
||||||
|
private final ItemStack result;
|
||||||
|
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
public AbstractRecipe(Collection<Predicate<ItemStack>> inputs, ItemStack result) {
|
||||||
|
Validate.notEmpty(inputs, "The input predicates cannot be null or an empty array");
|
||||||
|
Validate.notNull(result, "The recipe result must not be null!");
|
||||||
|
|
||||||
|
this.inputs = inputs;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractRecipe(@Nonnull ShapelessRecipe recipe) {
|
||||||
|
this(new ArrayList<>(recipe.getChoiceList()), recipe.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractRecipe(@Nonnull ShapedRecipe recipe) {
|
||||||
|
this(getChoices(recipe), recipe.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private static Collection<Predicate<ItemStack>> getChoices(@Nonnull ShapedRecipe recipe) {
|
||||||
|
List<Predicate<ItemStack>> choices = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String row : recipe.getShape()) {
|
||||||
|
for (char c : row.toCharArray()) {
|
||||||
|
RecipeChoice choice = recipe.getChoiceMap().get(c);
|
||||||
|
|
||||||
|
if (choice != null) {
|
||||||
|
choices.add(choice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return choices;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public Collection<Predicate<ItemStack>> getInputs() {
|
||||||
|
return inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public ItemStack getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -141,6 +141,7 @@ public abstract class AContainer extends SlimefunItem implements InventoryBlock,
|
|||||||
*
|
*
|
||||||
* @return The max amount of electricity this Block can store.
|
* @return The max amount of electricity this Block can store.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int getCapacity() {
|
public int getCapacity() {
|
||||||
return energyCapacity;
|
return energyCapacity;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user