Created
October 20, 2014 06:07
-
-
Save SpaceManiac/d3333d8a8dfb73ce7c95 to your computer and use it in GitHub Desktop.
Double-speed furnace implementation, comments note how to make normal-speed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.platymuus.bukkit.endmachines.machines; | |
import com.platymuus.bukkit.endmachines.MachineDescription; | |
import org.bukkit.*; | |
import org.bukkit.configuration.ConfigurationSection; | |
import org.bukkit.entity.Player; | |
import org.bukkit.event.EventHandler; | |
import org.bukkit.event.Listener; | |
import org.bukkit.event.inventory.InventoryClickEvent; | |
import org.bukkit.event.inventory.InventoryCloseEvent; | |
import org.bukkit.event.inventory.InventoryMoveItemEvent; | |
import org.bukkit.event.inventory.InventoryType; | |
import org.bukkit.event.player.PlayerInteractEvent; | |
import org.bukkit.inventory.*; | |
import org.bukkit.scheduler.BukkitRunnable; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.Set; | |
/** | |
* Furnace which acts at double the normal speed. | |
*/ | |
public class FurnaceUpgrade extends Machine { | |
public static final MachineDescription DESCRIPTION = new MachineDescription("furnace", "End Furnace", FurnaceUpgrade.class) | |
.shape("S/S", "SxS", "nnn") | |
.ingredient('S', Material.ENDER_STONE) | |
.ingredient('/', Material.BLAZE_ROD) | |
.ingredient('x', Material.PAPER) | |
.ingredient('n', Material.NETHERRACK); | |
private static final int INPUT = 0; | |
private static final int FUEL = 1; | |
private static final int OUTPUT = 2; | |
private final FurnaceListener listener = new FurnaceListener(); | |
private final SmeltTask task = new SmeltTask(); | |
private final Inventory inventory = Bukkit.getServer().createInventory(null, InventoryType.FURNACE, "End Furnace"); | |
private int cookTime = 0; // Up to 200, in ticks | |
private int burnTime = 0; // Remaining burn ticks, out of fuelTicks | |
private int fuelTicks = 0; // Max fuel ticks | |
private int flameTime = 0; // For vfx only | |
@Override | |
public boolean construct(PlayerInteractEvent event) { | |
return matchesType(event, Material.FURNACE) || matchesType(event, Material.BURNING_FURNACE); | |
} | |
@Override | |
public void destroy() { | |
keepInventoryEmpty(inventory); | |
if (getBlock().getState() instanceof InventoryHolder) { | |
Inventory inv = ((InventoryHolder) getBlock().getState()).getInventory(); | |
inv.setContents(inventory.getContents()); | |
inventory.clear(); | |
} else { | |
// you messed it up so no items back for you | |
} | |
} | |
@Override | |
public void activate() { | |
register(listener); | |
task.runTaskTimer(getPlugin(), 0, 1); | |
} | |
@Override | |
public void deactivate() { | |
unregister(listener); | |
task.cancel(); | |
listener.close(); | |
} | |
@Override | |
public void loadData(ConfigurationSection data) { | |
for (int i = 0; i < inventory.getSize(); ++i) { | |
inventory.setItem(i, data.getItemStack("item" + i)); | |
} | |
cookTime = data.getInt("cookTime", 0); | |
burnTime = data.getInt("burnTime", 0); | |
fuelTicks = data.getInt("fuelTicks", 0); | |
} | |
@Override | |
public void saveData(ConfigurationSection data) { | |
for (int i = 0; i < inventory.getSize(); ++i) { | |
data.set("item" + i, inventory.getItem(i)); | |
} | |
data.set("cookTime", cookTime); | |
data.set("burnTime", burnTime); | |
data.set("fuelTicks", fuelTicks); | |
} | |
private class FurnaceListener implements Listener { | |
private final Set<InventoryView> openViews = new HashSet<InventoryView>(); | |
@EventHandler(ignoreCancelled = true) | |
public void handleInteract(PlayerInteractEvent event) { | |
if (shouldInteract(event)) { | |
openViews.add(event.getPlayer().openInventory(inventory)); | |
event.setCancelled(true); | |
update(); | |
} | |
} | |
@EventHandler | |
public void handleClick(InventoryClickEvent event) { | |
if (!openViews.contains(event.getView())) { | |
return; | |
} | |
if (event.isShiftClick()) { | |
// There's a nasty crash bug with shift-clicking atm so let's avoid it. | |
if (event.getWhoClicked() instanceof Player) { | |
((Player) event.getWhoClicked()).sendMessage(PREFIX + ChatColor.RED + "Shift-clicking in End Furnaces is broken"); | |
} | |
event.setCancelled(true); | |
return; | |
} | |
if (event.getRawSlot() == OUTPUT && event.getCursor() != null && event.getCursor().getType() != Material.AIR) { | |
// Only allow taking things /out/ of the result slot | |
event.setCancelled(true); | |
ItemStack output = inventory.getItem(OUTPUT), cursor = event.getCursor(); | |
if (output != null && canStack(output, event.getCursor())) { | |
int toAdd = Math.min(cursor.getType().getMaxStackSize() - cursor.getAmount(), output.getAmount()); | |
cursor.setAmount(cursor.getAmount() + toAdd); | |
output.setAmount(output.getAmount() - toAdd); | |
if (output.getAmount() <= 0) { | |
inventory.setItem(OUTPUT, null); | |
} | |
} | |
} | |
} | |
@EventHandler | |
public void handleClose(InventoryCloseEvent event) { | |
if (openViews.contains(event.getView())) { | |
openViews.remove(event.getView()); | |
} | |
} | |
@EventHandler(ignoreCancelled = true) | |
public void handleHopper(InventoryMoveItemEvent event) { | |
// this doesn't work yet. | |
// the hopper has to be trying to pull items in the first place, | |
// which it won't be if we keep it empty as we do currently | |
if (!(getBlock().getState() instanceof InventoryHolder)) return; | |
Inventory realInv = ((InventoryHolder) getBlock().getState()).getInventory(); | |
if (event.getSource() == realInv) { | |
event.setCancelled(true); | |
// move one item from our result slot to the target | |
ItemStack item = inventory.getItem(OUTPUT).clone(); | |
item.setAmount(item.getAmount() - 1); | |
inventory.setItem(OUTPUT, item.getAmount() > 0 ? item.clone() : null); | |
item.setAmount(1); | |
addItems(event.getDestination(), item); | |
} | |
} | |
public void close() { | |
for (InventoryView v : openViews) { | |
v.close(); | |
} | |
openViews.clear(); | |
} | |
public void update() { | |
for (InventoryView v : openViews) { | |
v.setProperty(InventoryView.Property.COOK_TIME, cookTime); | |
v.setProperty(InventoryView.Property.BURN_TIME, burnTime); | |
v.setProperty(InventoryView.Property.TICKS_FOR_CURRENT_FUEL, fuelTicks); | |
} | |
} | |
} | |
private class SmeltTask extends BukkitRunnable { | |
private ItemStack output; | |
private Material cachedInput; | |
public void run() { | |
// this is basically the furnace code | |
keepInventoryEmpty(inventory); | |
// make some flaming effects | |
if (++flameTime >= 30) { | |
Location loc = getLocation(); | |
loc.getWorld().playEffect(loc.clone().add(0.5, 0.5, 0.5), Effect.MOBSPAWNER_FLAMES, 0); | |
flameTime = 0; | |
} | |
// if there's nothing at all to burn, just sit there, for efficiency | |
if (inventory.getItem(FUEL) == null && burnTime == 0) return; | |
// nothing wll make burnTime forcibly zero | |
// cookTime will forcibly be 0 if burnTime is 0 or input and output are incompatible | |
// cache the input->output mapping so we don't have to constantly search for it | |
ItemStack input = inventory.getItem(INPUT); | |
if (cachedInput != (input == null ? null : input.getType())) { | |
cachedInput = (input == null ? null : input.getType()); | |
output = findOutput(inventory.getItem(INPUT)); | |
} | |
boolean goodOutput = output != null && canStackAmount(output, inventory.getItem(OUTPUT)); | |
// run down the burn timer | |
burnTime -= 1; | |
if (burnTime <= 0) { | |
if (goodOutput) { | |
// add to burn time - 10 would be 20 if the furnace was normal speed | |
burnTime = fuelTicks = (int)(10 * findFuel(inventory.getItem(FUEL))); | |
if (burnTime > 0) { | |
// consume fuel | |
int amt = inventory.getItem(FUEL).getAmount(); | |
if (amt <= 1) { | |
inventory.setItem(FUEL, null); | |
} else { | |
inventory.getItem(FUEL).setAmount(amt - 1); | |
} | |
} | |
} else { | |
burnTime = 0; | |
} | |
} | |
byte data = getBlock().getData(); | |
if (burnTime == 0 || !goodOutput) { | |
// no fuel burning or invalid output | |
cookTime = 0; | |
// make furnace off | |
getBlock().setType(Material.FURNACE); | |
} else { | |
cookTime += 2; // On normal furnace, this would be a 1 | |
if (cookTime >= 200) { | |
cookTime = 0; | |
// produce output | |
if (inventory.getItem(OUTPUT) == null) { | |
inventory.setItem(OUTPUT, output); | |
} else { | |
inventory.getItem(OUTPUT).setAmount(inventory.getItem(OUTPUT).getAmount() + output.getAmount()); | |
} | |
// consume input | |
int amt = inventory.getItem(INPUT).getAmount(); | |
if (amt <= 1) { | |
inventory.setItem(INPUT, null); | |
} else { | |
inventory.getItem(INPUT).setAmount(amt - 1); | |
} | |
// play a little particle effect | |
getLocation().getWorld().playEffect(getLocation(), Effect.ENDER_SIGNAL, 0); | |
} | |
// make furnace on | |
getBlock().setType(Material.BURNING_FURNACE); | |
} | |
getBlock().setData(data); | |
listener.update(); | |
} | |
private double findFuel(ItemStack fuel) { | |
if (fuel == null) return 0; | |
switch (fuel.getType()) { | |
case LAVA_BUCKET: | |
return 1000; | |
case BLAZE_ROD: | |
return 120; | |
case COAL: | |
return 80; | |
case LOG: | |
case LOG_2: | |
case WOOD: | |
case WOOD_PLATE: | |
case FENCE: | |
case FENCE_GATE: | |
case WOOD_STAIRS: | |
case TRAP_DOOR: | |
case WORKBENCH: | |
case BOOKSHELF: | |
case CHEST: | |
case JUKEBOX: | |
case NOTE_BLOCK: | |
case HUGE_MUSHROOM_1: | |
case HUGE_MUSHROOM_2: | |
return 15; | |
case WOOD_AXE: | |
case WOOD_SPADE: | |
case WOOD_PICKAXE: | |
case WOOD_HOE: | |
case WOOD_SWORD: | |
return 10; | |
case WOOD_STEP: | |
return 7.5; | |
case STICK: | |
case SAPLING: | |
return 5; | |
default: | |
return 0; | |
} | |
} | |
private ItemStack findOutput(ItemStack input) { | |
if (input == null || input.getType() == Material.AIR) return null; | |
Iterator<Recipe> iter = Bukkit.getServer().recipeIterator(); | |
while (iter.hasNext()) { | |
Recipe r = iter.next(); | |
if (r instanceof FurnaceRecipe) { | |
FurnaceRecipe fr = (FurnaceRecipe) r; | |
// Intentionally ignore durability values to align with CraftBukkit behaviour | |
if (fr.getInput().getType() == input.getType()) { | |
return fr.getResult(); | |
} | |
} | |
} | |
return null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment