/* * CraftBook Copyright (C) 2010-2017 sk89q <http://www.sk89q.com> * CraftBook Copyright (C) 2011-2017 me4502 <http://www.me4502.com> * CraftBook Copyright (C) Contributors * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program. If not, * see <http://www.gnu.org/licenses/>. */ package com.sk89q.craftbook.sponge.mechanics; import com.google.inject.Inject; import com.me4502.modularframework.module.Module; import com.me4502.modularframework.module.guice.ModuleConfiguration; import com.sk89q.craftbook.core.util.ConfigValue; import com.sk89q.craftbook.core.util.CraftBookException; import com.sk89q.craftbook.core.util.PermissionNode; import com.sk89q.craftbook.core.util.documentation.DocumentationProvider; import com.sk89q.craftbook.sponge.CraftBookPlugin; import com.sk89q.craftbook.sponge.mechanics.types.SpongeSignMechanic; import com.sk89q.craftbook.sponge.st.SelfTriggeringMechanic; import com.sk89q.craftbook.sponge.st.SpongeSelfTriggerManager; import com.sk89q.craftbook.sponge.util.BlockUtil; import com.sk89q.craftbook.sponge.util.SignUtil; import com.sk89q.craftbook.sponge.util.SpongePermissionNode; import com.sk89q.craftbook.sponge.util.data.CraftBookKeys; import com.sk89q.craftbook.sponge.util.data.mutable.LastPowerData; import ninja.leaping.configurate.ConfigurationNode; import org.spongepowered.api.block.BlockTypes; import org.spongepowered.api.block.tileentity.Sign; import org.spongepowered.api.block.tileentity.carrier.Chest; import org.spongepowered.api.data.key.Keys; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.block.InteractBlockEvent; import org.spongepowered.api.event.block.NotifyNeighborBlockEvent; import org.spongepowered.api.event.cause.NamedCause; import org.spongepowered.api.event.filter.cause.First; import org.spongepowered.api.event.filter.cause.Named; import org.spongepowered.api.item.ItemType; import org.spongepowered.api.item.ItemTypes; import org.spongepowered.api.item.inventory.Inventory; import org.spongepowered.api.item.inventory.ItemStack; import org.spongepowered.api.service.permission.PermissionDescription; import org.spongepowered.api.text.Text; import org.spongepowered.api.util.Tuple; import org.spongepowered.api.world.LocatableBlock; import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; @Module(id = "cookingpot", name = "CookingPot", onEnable="onInitialize", onDisable="onDisable") public class CookingPot extends SpongeSignMechanic implements SelfTriggeringMechanic, DocumentationProvider { @Inject @ModuleConfiguration public ConfigurationNode config; private SpongePermissionNode createPermissions = new SpongePermissionNode("craftbook.cookingpot", "Allows the user to create Cooking Pots", PermissionDescription.ROLE_USER); private SpongePermissionNode refuelPermissions = new SpongePermissionNode("craftbook.cookingpot.refuel", "Allows the user to refuel Cooking Pots", PermissionDescription.ROLE_USER); private ConfigValue<Boolean> requireFuel = new ConfigValue<>("require-fuel", "Causes the cooking pot to require fuel to cook. Otherwise fuel speeds up cooking.", true); private ConfigValue<Boolean> redstoneFuel = new ConfigValue<>("redstone-fuel", "Allows for a pulsing redstone signal to be used as a fuel source.", false); private ConfigValue<Boolean> superFast = new ConfigValue<>("super-fast", "Removes the cap for 5 fuel to be used per tick, making the cooking pot faster.", false); private ConfigValue<Boolean> cookFoodOnly = new ConfigValue<>("food-only", "Caused the cooking pot to only cook food. Food is defined as anything that gives hunger points.", true); //private List<FurnaceRecipe> recipesCache = new ArrayList<>(); @Override public void onInitialize() throws CraftBookException { createPermissions.register(); refuelPermissions.register(); requireFuel.load(config); redstoneFuel.load(config); superFast.load(config); cookFoodOnly.load(config); // TODO Fill recipesCache - FoodRestorationProperty for determining if food. super.onInitialize(); } @Override public void onDisable() { super.onDisable(); // TODO Clear recipesCache } @Override public boolean verifyLines(Location<World> location, List<Text> lines, @Nullable Player player) { ((SpongeSelfTriggerManager) CraftBookPlugin.inst().getSelfTriggerManager().get()).register(this, location); lines.set(2, Text.of("0")); lines.set(3, requireFuel.getValue() ? Text.of("0") : Text.of("1")); return true; } @Listener public void onPlayerInteract(InteractBlockEvent.Secondary event, @Named(NamedCause.SOURCE) Player player) { event.getTargetBlock().getLocation().ifPresent(location -> { if (isValid(location)) { location.getTileEntity().map(sign -> (Sign) sign).ifPresent(sign -> { ItemStack itemStack = player.getItemInHand(event.getHandType()).filter(stack -> FuelSource.canCookWith(stack.getItem())).orElse(null); if (itemStack != null) { if (refuelPermissions.hasPermission(player)) { int value = FuelSource.getFuelValue(itemStack.getItem()); increaseMultiplier(sign, value); if (itemStack.getQuantity() > 1) { itemStack.setQuantity(itemStack.getQuantity() - 1); player.setItemInHand(event.getHandType(), itemStack); } else { if (itemStack.getItem() == ItemTypes.LAVA_BUCKET) { player.setItemInHand(event.getHandType(), ItemStack.of(ItemTypes.BUCKET, 1)); } else { player.setItemInHand(event.getHandType(), null); } } } else { player.sendMessage(Text.of("You don't have permission to refuel this mechanic!")); } } else { Location<?> chestBlock = SignUtil.getBackBlock(location).add(0, 2, 0); chestBlock.getTileEntity().filter(tileEntity -> tileEntity instanceof Chest).map(tileEntity -> (Chest) tileEntity).ifPresent(chest -> player.openInventory(chest.getInventory(), CraftBookPlugin.spongeInst().getCause().build())); } }); } }); } @Listener public void onBlockUpdate(NotifyNeighborBlockEvent event, @First LocatableBlock source) { if(!redstoneFuel.getValue()) return; if(!SignUtil.isSign(source.getLocation())) return; Location<World> block = source.getLocation(); Sign sign = (Sign) block.getTileEntity().get(); if (isMechanicSign(sign)) { Player player = event.getCause().get(NamedCause.SOURCE, Player.class).orElse(null); if(player != null) { if(!refuelPermissions.hasPermission(player)) { player.sendMessage(Text.of("You don't have permission to refuel this mechanic!")); return; } } int newPower = BlockUtil.getBlockPowerLevel(block).orElse(0); int oldPower = block.get(CraftBookKeys.LAST_POWER).orElse(0); if (newPower != oldPower) { if (newPower > oldPower) { increaseMultiplier(sign, newPower - oldPower); } block.offer(new LastPowerData(newPower)); } } } @Override public void onThink(Location<World> location) { if (!isValid(location)) { ((SpongeSelfTriggerManager) CraftBookPlugin.spongeInst().getSelfTriggerManager().get()).unregister(this, location); return; } int lastTick = 0, oldTick; Sign sign = location.getTileEntity().map(tile -> (Sign) tile).get(); try { lastTick = Math.max(0, Integer.parseInt(SignUtil.getTextRaw(sign, 2))); } catch (Exception e) { List<Text> lines = sign.lines().get(); lines.set(2, Text.of(0)); sign.offer(Keys.SIGN_LINES, lines); } oldTick = lastTick; Location<?> baseBlock = SignUtil.getBackBlock(location); Location<?> chestBlock = baseBlock.add(0, 2, 0); if (chestBlock.getBlockType() == BlockTypes.CHEST || chestBlock.getBlockType() == BlockTypes.TRAPPED_CHEST) { Location<?> fireBlock = baseBlock.add(0, 1, 0); if (fireBlock.getBlockType() == BlockTypes.FIRE) { Chest chest = chestBlock.getTileEntity().map(tile -> (Chest) tile).get(); Inventory inventory = chest.getInventory(); // TODO When recipe API is done - scan furnace recipes from recipesCache. // Tuple<Inventory Stack, Recipe Result> List<Tuple<ItemStack, ItemStack>> items = new ArrayList<>(); if (items.size() > 0) { if (lastTick < 500) { int multiplier = getMultiplier(sign); if (superFast.getValue()) { lastTick += multiplier; } else { lastTick += Math.min(multiplier, 5); } if (multiplier > 0) { setMultiplier(sign, multiplier - 1); } } if (lastTick >= 50) { for (Tuple<ItemStack, ItemStack> item : items) { if (inventory.offer(item.getSecond()).getRejectedItems().isEmpty()) { inventory.query(item.getFirst()).poll(1); lastTick -= 50; } } } } } } if (oldTick != lastTick) { List<Text> lines = sign.lines().get(); lines.set(2, Text.of(lastTick)); sign.offer(Keys.SIGN_LINES, lines); } } public void setMultiplier(Sign sign, int amount) { if(!requireFuel.getValue()) amount = Math.max(amount, 1); List<Text> lines = sign.lines().get(); lines.set(3, Text.of(amount)); sign.offer(Keys.SIGN_LINES, lines); } public void increaseMultiplier(Sign sign, int amount) { setMultiplier(sign, getMultiplier(sign) + amount); } public int getMultiplier(Sign sign) { int multiplier; try { multiplier = Integer.parseInt(SignUtil.getTextRaw(sign, 3)); } catch (Exception e) { multiplier = requireFuel.getValue() ? 0 : 1; setMultiplier(sign, multiplier); } if (multiplier <= 0 && !requireFuel.getValue()) return 1; return Math.max(0, multiplier); } @Override public String[] getValidSigns() { return new String[] { "[Cook]" }; } @Override public SpongePermissionNode getCreatePermission() { return createPermissions; } @Override public String getPath() { return "mechanics/cooking_pot"; } @Override public PermissionNode[] getPermissionNodes() { return new PermissionNode[] { createPermissions, refuelPermissions }; } @Override public ConfigValue<?>[] getConfigurationNodes() { return new ConfigValue<?>[] { requireFuel, redstoneFuel, superFast, cookFoodOnly }; } private enum FuelSource { COAL(ItemTypes.COAL, 40), COALBLOCK(ItemTypes.COAL_BLOCK, 360), LAVA(ItemTypes.LAVA_BUCKET, 6000), BLAZE(ItemTypes.BLAZE_ROD, 500), BLAZEDUST(ItemTypes.BLAZE_POWDER, 250), SNOWBALL(ItemTypes.SNOWBALL, -40), SNOW(ItemTypes.SNOW, -100), ICE(ItemTypes.ICE, -1000); private ItemType item; private int fuelValue; FuelSource(ItemType item, int fuelValue) { this.item = item; this.fuelValue = fuelValue; } public static boolean canCookWith(ItemType item) { for (FuelSource fuelSource : values()) { if (fuelSource.item == item) { return true; } } return false; } public static int getFuelValue(ItemType item) { for (FuelSource fuelSource : values()) { if (fuelSource.item == item) { return fuelSource.fuelValue; } } return 0; } } }