package mcjty.rftools.blocks.screens; 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.entity.GenericEnergyReceiverTileEntity; import mcjty.lib.network.Argument; import mcjty.lib.varia.Coordinate; import mcjty.rftools.blocks.screens.modules.ComputerScreenModule; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.ForgeDirection; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @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 ScreenControllerTileEntity extends GenericEnergyReceiverTileEntity implements SimpleComponent, IPeripheral { public static final String CMD_SCAN = "scan"; public static final String CMD_DETACH = "detach"; public static final String COMPONENT_NAME = "screen_controller"; private List<Coordinate> connectedScreens = new ArrayList<Coordinate>(); private int tickCounter = 20; public ScreenControllerTileEntity() { super(ScreenConfiguration.CONTROLLER_MAXENERGY, ScreenConfiguration.CONTROLLER_RECEIVEPERTICK); } @Override @Optional.Method(modid = "ComputerCraft") public String getType() { return COMPONENT_NAME; } @Override @Optional.Method(modid = "ComputerCraft") public String[] getMethodNames() { return new String[] { "getScreenCount", "getScreenIndex", "getScreenCoordinate", "addText", "setText", "clearText" }; } @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[] { connectedScreens.size() }; case 1: return getScreenIndex(new Coordinate(((Double) arguments[0]).intValue(), ((Double) arguments[1]).intValue(), ((Double) arguments[2]).intValue())); case 2: Coordinate c = connectedScreens.get(((Double) arguments[0]).intValue()); return new Object[] { c.getX(), c.getY(), c.getZ() }; case 3: return addText((String) arguments[0], (String) arguments[1], ((Double) arguments[2]).intValue()); case 4: return setText((String) arguments[0], (String) arguments[1], ((Double) arguments[2]).intValue()); case 5: return clearText((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 amount of screens controlled by this controller", getter = true) @Optional.Method(modid = "OpenComputers") public Object[] getScreenCount(Context context, Arguments args) throws Exception { return new Object[] { connectedScreens.size() }; } @Callback(doc = "Get a table with coordinates (every coordinate is a table indexed with 'x', 'y', and 'z') for all connected screens", getter = true) @Optional.Method(modid = "OpenComputers") public Object[] getScreens(Context context, Arguments args) throws Exception { List<Map<String,Integer>> result = new ArrayList<Map<String, Integer>>(); for (Coordinate screen : connectedScreens) { Map<String,Integer> coordinate = new HashMap<String, Integer>(); coordinate.put("x", screen.getX()); coordinate.put("y", screen.getY()); coordinate.put("z", screen.getZ()); result.add(coordinate); } return new Object[] { result }; } @Callback(doc = "Given a screen coordinate (table indexed by 'x', 'y', and 'z') return the index of that screen", getter = true) @Optional.Method(modid = "OpenComputers") public Object[] getScreenIndex(Context context, Arguments args) throws Exception { Map screen = args.checkTable(0); if (!screen.containsKey("x") || !screen.containsKey("y") || !screen.containsKey("z")) { throw new IllegalArgumentException("Screen map doesn't contain the right x,y,z coordinate!"); } Coordinate recC = new Coordinate(((Double) screen.get("x")).intValue(), ((Double) screen.get("y")).intValue(), ((Double) screen.get("z")).intValue()); return getScreenIndex(recC); } private Object[] getScreenIndex(Coordinate coordinate) { int i = 0; for (Coordinate connectedScreen : connectedScreens) { if (connectedScreen.equals(coordinate)) { return new Object[] { i }; } i++; } return null; } @Callback(doc = "Given a screen index return the coordinate (table indexed by 'x', 'y', and 'z') of that screen", getter = true) @Optional.Method(modid = "OpenComputers") public Object[] getScreenCoordinate(Context context, Arguments args) throws Exception { int index = args.checkInteger(0); if (index < 0 || index >= connectedScreens.size()) { throw new IllegalArgumentException("Screen index out of range!"); } Coordinate screen = connectedScreens.get(index); Map<String,Integer> coordinate = new HashMap<String, Integer>(); coordinate.put("x", screen.getX()); coordinate.put("y", screen.getY()); coordinate.put("z", screen.getZ()); return new Object[] { coordinate }; } @Callback(doc = "Add text to all screens listening to the given 'tag'. Parameters are: 'tag', 'text' and 'color' (RGB value)") @Optional.Method(modid = "OpenComputers") public Object[] addText(Context context, Arguments args) throws Exception { String tag = args.checkString(0); String text = args.checkString(1); int color = args.checkInteger(2); return addText(tag, text, color); } @Callback(doc = "Set text to all screens listening to the given 'tag'. Parameters are: 'tag', 'text' and 'color' (RGB value)") @Optional.Method(modid = "OpenComputers") public Object[] setText(Context context, Arguments args) throws Exception { String tag = args.checkString(0); String text = args.checkString(1); int color = args.checkInteger(2); clearText(tag); return addText(tag, text, color); } private Object[] setText(String tag, String text, int color) { clearText(tag); return addText(tag, text, color); } private Object[] addText(String tag, String text, int color) { for (Coordinate screen : connectedScreens) { TileEntity te = worldObj.getTileEntity(screen.getX(), screen.getY(), screen.getZ()); if (te instanceof ScreenTileEntity) { ScreenTileEntity screenTileEntity = (ScreenTileEntity) te; List<ComputerScreenModule> computerScreenModules = screenTileEntity.getComputerModules(tag); if (computerScreenModules != null) { for (ComputerScreenModule screenModule : computerScreenModules) { screenModule.addText(text, color); } } } } return null; } @Callback(doc = "Clear text to all screens listening to the given 'tag'. The 'tag' is the only parameter") @Optional.Method(modid = "OpenComputers") public Object[] clearText(Context context, Arguments args) throws Exception { String tag = args.checkString(0); return clearText(tag); } private Object[] clearText(String tag) { for (Coordinate screen : connectedScreens) { TileEntity te = worldObj.getTileEntity(screen.getX(), screen.getY(), screen.getZ()); if (te instanceof ScreenTileEntity) { ScreenTileEntity screenTileEntity = (ScreenTileEntity) te; List<ComputerScreenModule> computerScreenModules = screenTileEntity.getComputerModules(tag); if (computerScreenModules != null) { for (ComputerScreenModule screenModule : computerScreenModules) { screenModule.clearText(); } } } } return null; } @Callback(doc = "Get a table of all tags supported by all connected screens", getter = true) @Optional.Method(modid = "OpenComputers") public Object[] getTags(Context context, Arguments args) throws Exception { List<String> tags = new ArrayList<String>(); for (Coordinate screen : connectedScreens) { TileEntity te = worldObj.getTileEntity(screen.getX(), screen.getY(), screen.getZ()); if (te instanceof ScreenTileEntity) { ScreenTileEntity screenTileEntity = (ScreenTileEntity) te; tags.addAll(screenTileEntity.getTags()); } } return new Object[] { tags }; } @Override public void readFromNBT(NBTTagCompound tagCompound) { super.readFromNBT(tagCompound); int[] xes = tagCompound.getIntArray("screensx"); int[] yes = tagCompound.getIntArray("screensy"); int[] zes = tagCompound.getIntArray("screensz"); connectedScreens.clear(); for (int i = 0 ; i < xes.length ; i++) { connectedScreens.add(new Coordinate(xes[i], yes[i], zes[i])); } } @Override public void readRestorableFromNBT(NBTTagCompound tagCompound) { super.readRestorableFromNBT(tagCompound); } @Override public void writeToNBT(NBTTagCompound tagCompound) { super.writeToNBT(tagCompound); int[] xes = new int[connectedScreens.size()]; int[] yes = new int[connectedScreens.size()]; int[] zes = new int[connectedScreens.size()]; for (int i = 0 ; i < connectedScreens.size() ; i++) { Coordinate c = connectedScreens.get(i); xes[i] = c.getX(); yes[i] = c.getY(); zes[i] = c.getZ(); } tagCompound.setIntArray("screensx", xes); tagCompound.setIntArray("screensy", yes); tagCompound.setIntArray("screensz", zes); } @Override public void writeRestorableToNBT(NBTTagCompound tagCompound) { super.writeRestorableToNBT(tagCompound); } @Override protected void checkStateServer() { tickCounter--; if (tickCounter > 0) { return; } tickCounter = 20; int rf = getEnergyStored(ForgeDirection.DOWN); int rememberRf = rf; boolean fixesAreNeeded = false; for (Coordinate c : connectedScreens) { TileEntity te = worldObj.getTileEntity(c.getX(), c.getY(), c.getZ()); if (te instanceof ScreenTileEntity) { ScreenTileEntity screenTileEntity = (ScreenTileEntity) te; int rfModule = screenTileEntity.getTotalRfPerTick() * 20; if (rfModule > rf) { screenTileEntity.setPower(false); } else { rf -= rfModule; screenTileEntity.setPower(true); } } else { // This coordinate is no longer a valid screen. We need to update. fixesAreNeeded = true; } } if (rf < rememberRf) { consumeEnergy(rememberRf - rf); } if (fixesAreNeeded) { List<Coordinate> newScreens = new ArrayList<Coordinate>(); for (Coordinate c : connectedScreens) { TileEntity te = worldObj.getTileEntity(c.getX(), c.getY(), c.getZ()); if (te instanceof ScreenTileEntity) { newScreens.add(c); } } connectedScreens = newScreens; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } } private void scan() { detach(); int radius = 32 + (int) (getInfusedFactor() * 32); for (int y = yCoord - 16 ; y <= yCoord + 16 ; y++) { if (y >= 0 && y < 256) { for (int x = xCoord - radius; x <= xCoord + radius; x++) { for (int z = zCoord - radius; z <= zCoord + radius; z++) { TileEntity te = worldObj.getTileEntity(x, y, z); if (te instanceof ScreenTileEntity) { if (!((ScreenTileEntity) te).isConnected()) { connectedScreens.add(new Coordinate(x, y, z)); ((ScreenTileEntity) te).setConnected(true); } } } } } } markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } public void detach() { for (Coordinate c : connectedScreens) { TileEntity te = worldObj.getTileEntity(c.getX(), c.getY(), c.getZ()); if (te instanceof ScreenTileEntity) { ((ScreenTileEntity) te).setPower(false); ((ScreenTileEntity) te).setConnected(false); } } connectedScreens.clear(); markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } public List<Coordinate> getConnectedScreens() { return connectedScreens; } @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_SCAN.equals(command)) { scan(); return true; } else if (CMD_DETACH.equals(command)) { detach(); return true; } return false; } }