package mcjty.rftools.blocks.environmental; import cpw.mods.fml.common.Optional; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import li.cil.oc.api.machine.Arguments; import li.cil.oc.api.machine.Callback; import li.cil.oc.api.machine.Context; import li.cil.oc.api.network.SimpleComponent; import mcjty.lib.container.InventoryHelper; import mcjty.lib.entity.GenericEnergyReceiverTileEntity; import mcjty.lib.network.Argument; import mcjty.lib.varia.Logging; import mcjty.rftools.blocks.RedstoneMode; import mcjty.rftools.blocks.environmental.modules.EnvironmentModule; import mcjty.rftools.blocks.teleporter.PlayerName; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.ForgeDirection; import java.util.*; @Optional.InterfaceList({ @Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers"), @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheral", modid = "ComputerCraft")}) public class EnvironmentalControllerTileEntity extends GenericEnergyReceiverTileEntity implements ISidedInventory, SimpleComponent, IPeripheral { public static final String CMD_SETRADIUS = "setRadius"; public static final String CMD_SETBOUNDS = "setBounds"; public static final String CMD_RSMODE = "rsMode"; public static final String CMD_SETBLACKLIST = "setBlacklist"; public static final String CMD_ADDPLAYER = "addPlayer"; public static final String CMD_DELPLAYER = "delPlayer"; public static final String CMD_GETPLAYERS = "getPlayers"; public static final String CLIENTCMD_GETPLAYERS = "getPlayers"; public static final String COMPONENT_NAME = "environmental_controller"; private InventoryHelper inventoryHelper = new InventoryHelper(this, EnvironmentalControllerContainer.factory, EnvironmentalControllerContainer.ENV_MODULES); // Cached server modules private List<EnvironmentModule> environmentModules = null; private Set<String> players = new HashSet<String>(); private boolean whitelistMode = false; private int totalRfPerTick = 0; // The total rf per tick for all modules. private int radius = 50; private int miny = 30; private int maxy = 70; private int volume = -1; private boolean active = false; private RedstoneMode redstoneMode = RedstoneMode.REDSTONE_IGNORED; private int powered = 0; private int powerTimeout = 0; public EnvironmentalControllerTileEntity() { super(EnvironmentalConfiguration.ENVIRONMENTAL_MAXENERGY, EnvironmentalConfiguration.ENVIRONMENTAL_RECEIVEPERTICK); } @Override @Optional.Method(modid = "ComputerCraft") public String getType() { return COMPONENT_NAME; } @Override @Optional.Method(modid = "ComputerCraft") public String[] getMethodNames() { return new String[] { "getRedstoneMode", "setRedstoneMode" }; } @Override @Optional.Method(modid = "ComputerCraft") public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException { switch (method) { case 0: return new Object[] { getRedstoneMode().getDescription() }; case 1: return setRedstoneMode((String) arguments[0]); } return new Object[0]; } @Override @Optional.Method(modid = "ComputerCraft") public void attach(IComputerAccess computer) { } @Override @Optional.Method(modid = "ComputerCraft") public void detach(IComputerAccess computer) { } @Override @Optional.Method(modid = "ComputerCraft") public boolean equals(IPeripheral other) { return false; } @Override @Optional.Method(modid = "OpenComputers") public String getComponentName() { return COMPONENT_NAME; } @Callback(doc = "Get the current redstone mode. Values are 'Ignored', 'Off', or 'On'", getter = true) @Optional.Method(modid = "OpenComputers") public Object[] getRedstoneMode(Context context, Arguments args) throws Exception { return new Object[] { getRedstoneMode().getDescription() }; } @Callback(doc = "Set the current redstone mode. Values are 'Ignored', 'Off', or 'On'", setter = true) @Optional.Method(modid = "OpenComputers") public Object[] setRedstoneMode(Context context, Arguments args) throws Exception { String mode = args.checkString(0); return setRedstoneMode(mode); } public boolean isWhitelistMode() { return whitelistMode; } public void setWhitelistMode(boolean w) { whitelistMode = w; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } public boolean isPlayerAffected(EntityPlayer player) { if (whitelistMode) { return players.contains(player.getDisplayName()); } else { return !players.contains(player.getDisplayName()); } } public List<PlayerName> getPlayersAsList() { List<PlayerName> p = new ArrayList<PlayerName>(); for (String player : players) { p.add(new PlayerName(player)); } return p; } public void addPlayer(String player) { if (!players.contains(player)) { players.add(player); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); markDirty(); } } public void delPlayer(String player) { if (players.contains(player)) { players.remove(player); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); markDirty(); } } public boolean isActive() { return active; } public int getTotalRfPerTick() { if (environmentModules == null) { getEnvironmentModules(); } int rfNeeded = (int) (totalRfPerTick * (4.0f - getInfusedFactor()) / 4.0f); if (environmentModules.isEmpty()) { return rfNeeded; } if (rfNeeded < EnvironmentalConfiguration.MIN_USAGE) { rfNeeded = EnvironmentalConfiguration.MIN_USAGE; } return rfNeeded; } public int getVolume() { if (volume == -1) { volume = (int) ((radius * radius * Math.PI) * (maxy-miny + 1)); } return volume; } public int getRadius() { return radius; } public void setRadius(int radius) { this.radius = radius; volume = -1; environmentModules = null; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } public int getMiny() { return miny; } public void setMiny(int miny) { this.miny = miny; volume = -1; environmentModules = null; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } public int getMaxy() { return maxy; } public void setMaxy(int maxy) { this.maxy = maxy; volume = -1; environmentModules = null; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } @Override protected void checkStateServer() { if (powerTimeout > 0) { powerTimeout--; return; } int rf = getEnergyStored(ForgeDirection.DOWN); if (redstoneMode != RedstoneMode.REDSTONE_IGNORED) { boolean rs = powered > 0; if (redstoneMode == RedstoneMode.REDSTONE_OFFREQUIRED) { if (rs) { rf = 0; // Turn of by simulating no power. } } else if (redstoneMode == RedstoneMode.REDSTONE_ONREQUIRED) { if (!rs) { rf = 0; // Turn of by simulating no power. } } } getEnvironmentModules(); int rfNeeded = getTotalRfPerTick(); if (rfNeeded > rf || environmentModules.isEmpty()) { for (EnvironmentModule module : environmentModules) { module.activate(false); } powerTimeout = 20; if (active) { active = false; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } } else { consumeEnergy(rfNeeded); for (EnvironmentModule module : environmentModules) { module.activate(true); module.tick(worldObj, xCoord, yCoord, zCoord, radius, miny, maxy, this); } if (!active) { active = true; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } } } private Object[] setRedstoneMode(String mode) { RedstoneMode redstoneMode = RedstoneMode.getMode(mode); if (redstoneMode == null) { throw new IllegalArgumentException("Not a valid mode"); } setRedstoneMode(redstoneMode); return null; } public void setRedstoneMode(RedstoneMode redstoneMode) { this.redstoneMode = redstoneMode; worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); markDirty(); } public RedstoneMode getRedstoneMode() { return redstoneMode; } @Override public void setPowered(int powered) { if (this.powered != powered) { this.powered = powered; powerTimeout = 0; markDirty(); } } // This is called server side. public List<EnvironmentModule> getEnvironmentModules() { if (environmentModules == null) { int volume = getVolume(); totalRfPerTick = 0; environmentModules = new ArrayList<EnvironmentModule>(); for (int i = 0 ; i < inventoryHelper.getCount() ; i++) { ItemStack itemStack = inventoryHelper.getStackInSlot(i); if (itemStack != null && itemStack.getItem() instanceof EnvModuleProvider) { EnvModuleProvider moduleProvider = (EnvModuleProvider) itemStack.getItem(); Class<? extends EnvironmentModule> moduleClass = moduleProvider.getServerEnvironmentModule(); EnvironmentModule environmentModule; try { environmentModule = moduleClass.newInstance(); } catch (InstantiationException e) { Logging.log("Failed to instantiate controller module!"); continue; } catch (IllegalAccessException e) { Logging.log("Failed to instantiate controller module!"); continue; } environmentModules.add(environmentModule); totalRfPerTick += (int) (environmentModule.getRfPerTick() * volume); } } } return environmentModules; } @Override public int[] getAccessibleSlotsFromSide(int side) { return EnvironmentalControllerContainer.factory.getAccessibleSlots(); } @Override public boolean canInsertItem(int index, ItemStack stack, int side) { return EnvironmentalControllerContainer.factory.isInputSlot(index); } @Override public boolean canExtractItem(int index, ItemStack stack, int side) { return EnvironmentalControllerContainer.factory.isOutputSlot(index); } @Override public int getSizeInventory() { return inventoryHelper.getCount(); } @Override public ItemStack getStackInSlot(int index) { return inventoryHelper.getStackInSlot(index); } @Override public ItemStack decrStackSize(int index, int amount) { environmentModules = null; return inventoryHelper.decrStackSize(index, amount); } @Override public ItemStack getStackInSlotOnClosing(int index) { return null; } @Override public void setInventorySlotContents(int index, ItemStack stack) { inventoryHelper.setInventorySlotContents(getInventoryStackLimit(), index, stack); environmentModules = null; } @Override public String getInventoryName() { return "Environmental Inventory"; } @Override public boolean hasCustomInventoryName() { return false; } @Override public int getInventoryStackLimit() { return 1; } @Override public boolean isUseableByPlayer(EntityPlayer player) { return canPlayerAccess(player); } @Override public void openInventory() { } @Override public void closeInventory() { } @Override public boolean isItemValidForSlot(int index, ItemStack stack) { return true; } @Override public void readFromNBT(NBTTagCompound tagCompound) { super.readFromNBT(tagCompound); totalRfPerTick = tagCompound.getInteger("rfPerTick"); active = tagCompound.getBoolean("active"); powered = tagCompound.getByte("powered"); } @Override public void readRestorableFromNBT(NBTTagCompound tagCompound) { super.readRestorableFromNBT(tagCompound); readBufferFromNBT(tagCompound); radius = tagCompound.getInteger("radius"); miny = tagCompound.getInteger("miny"); maxy = tagCompound.getInteger("maxy"); volume = -1; int m = tagCompound.getByte("rsMode"); redstoneMode = RedstoneMode.values()[m]; whitelistMode = tagCompound.getBoolean("whitelist"); players.clear(); NBTTagList playerList = tagCompound.getTagList("players", Constants.NBT.TAG_STRING); if (playerList != null) { for (int i = 0 ; i < playerList.tagCount() ; i++) { String player = playerList.getStringTagAt(i); players.add(player); } } } private void readBufferFromNBT(NBTTagCompound tagCompound) { NBTTagList bufferTagList = tagCompound.getTagList("Items", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < bufferTagList.tagCount(); i++) { NBTTagCompound nbtTagCompound = bufferTagList.getCompoundTagAt(i); inventoryHelper.setStackInSlot(i + EnvironmentalControllerContainer.SLOT_MODULES, ItemStack.loadItemStackFromNBT(nbtTagCompound)); } environmentModules = null; } @Override public void writeToNBT(NBTTagCompound tagCompound) { super.writeToNBT(tagCompound); tagCompound.setInteger("rfPerTick", totalRfPerTick); tagCompound.setBoolean("active", active); tagCompound.setByte("powered", (byte) powered); } @Override public void writeRestorableToNBT(NBTTagCompound tagCompound) { super.writeRestorableToNBT(tagCompound); writeBufferToNBT(tagCompound); tagCompound.setInteger("radius", radius); tagCompound.setInteger("miny", miny); tagCompound.setInteger("maxy", maxy); tagCompound.setByte("rsMode", (byte) redstoneMode.ordinal()); tagCompound.setBoolean("whitelist", whitelistMode); NBTTagList playerTagList = new NBTTagList(); for (String player : players) { playerTagList.appendTag(new NBTTagString(player)); } tagCompound.setTag("players", playerTagList); } private void writeBufferToNBT(NBTTagCompound tagCompound) { NBTTagList bufferTagList = new NBTTagList(); for (int i = EnvironmentalControllerContainer.SLOT_MODULES; i < inventoryHelper.getCount(); i++) { ItemStack stack = inventoryHelper.getStackInSlot(i); NBTTagCompound nbtTagCompound = new NBTTagCompound(); if (stack != null) { stack.writeToNBT(nbtTagCompound); } bufferTagList.appendTag(nbtTagCompound); } tagCompound.setTag("Items", bufferTagList); } @Override public boolean execute(EntityPlayerMP playerMP, String command, Map<String, Argument> args) { boolean rc = super.execute(playerMP, command, args); if (rc) { return true; } if (CMD_SETRADIUS.equals(command)) { setRadius(args.get("radius").getInteger()); return true; } else if (CMD_SETBOUNDS.equals(command)) { int miny = args.get("miny").getInteger(); int maxy = args.get("maxy").getInteger(); setMiny(miny); setMaxy(maxy); return true; } else if (CMD_RSMODE.equals(command)) { String m = args.get("rs").getString(); setRedstoneMode(RedstoneMode.getMode(m)); return true; } else if (CMD_ADDPLAYER.equals(command)) { addPlayer(args.get("player").getString()); return true; } else if (CMD_DELPLAYER.equals(command)) { delPlayer(args.get("player").getString()); return true; } else if (CMD_SETBLACKLIST.equals(command)) { setWhitelistMode(!args.get("blacklist").getBoolean()); return true; } return false; } @Override public List executeWithResultList(String command, Map<String, Argument> args) { List rc = super.executeWithResultList(command, args); if (rc != null) { return rc; } if (CMD_GETPLAYERS.equals(command)) { return getPlayersAsList(); } return null; } @Override public boolean execute(String command, List list) { boolean rc = super.execute(command, list); if (rc) { return true; } if (CLIENTCMD_GETPLAYERS.equals(command)) { GuiEnvironmentalController.storePlayersForClient(list); return true; } return false; } @Override public boolean shouldRenderInPass(int pass) { return pass == 1; } }