package mcjty.rftools.blocks.screens; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import mcjty.lib.container.InventoryHelper; import mcjty.lib.entity.GenericTileEntity; import mcjty.lib.network.Argument; import mcjty.lib.network.PacketServerCommand; import mcjty.lib.varia.Coordinate; import mcjty.rftools.blocks.screens.modules.ComputerScreenModule; import mcjty.rftools.blocks.screens.modules.ScreenModule; import mcjty.rftools.blocks.screens.modulesclient.ClientScreenModule; import mcjty.rftools.network.RFToolsMessages; 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.util.AxisAlignedBB; import net.minecraftforge.common.util.Constants; import java.util.*; public class ScreenTileEntity extends GenericTileEntity implements ISidedInventory { public static final String CMD_CLICK = "click"; private InventoryHelper inventoryHelper = new InventoryHelper(this, ScreenContainer.factory, ScreenContainer.SCREEN_MODULES); // This is a map that contains a map from the coordinate of the screen to a map of screen data from the server indexed by slot number, // @todo dimension in the map!!! public static Map<Coordinate, Map<Integer, Object[]>> screenData = new HashMap<Coordinate, Map<Integer, Object[]>>(); // Cached client screen modules private List<ClientScreenModule> clientScreenModules = null; // A list of tags linked to computer modules. private final Map<String,List<ComputerScreenModule>> computerModules = new HashMap<String, List<ComputerScreenModule>>(); private boolean needsServerData = false; private boolean powerOn = false; // True if screen is powered. private boolean connected = false; // True if screen is connected to a controller. private int size = 0; // Size of screen (0 is normal, 1 is large, 2 is huge) private boolean transparent = false; // Transparent screen. private int color = 0; // Color of the screen. public static final int SIZE_NORMAL = 0; public static final int SIZE_LARGE = 1; public static final int SIZE_HUGE = 2; // Cached server screen modules private List<ScreenModule> screenModules = null; private List<ActivatedModule> clickedModules = new ArrayList<ActivatedModule>(); private static class ActivatedModule { int module; int ticks; int x; int y; public ActivatedModule(int module, int ticks, int x, int y) { this.module = module; this.ticks = ticks; this.x = x; this.y = y; } } private int totalRfPerTick = 0; // The total rf per tick for all modules. public long lastTime = 0; public ScreenTileEntity() { } @SideOnly(Side.CLIENT) @Override public AxisAlignedBB getRenderBoundingBox() { return AxisAlignedBB.getBoundingBox(xCoord - 1, yCoord - 1, zCoord - 1, xCoord + size + 1, yCoord + size + 1, zCoord + size + 1); } @Override protected void checkStateClient() { if (clickedModules.isEmpty()) { return; } List<ActivatedModule> newClickedModules = new ArrayList<ActivatedModule>(); for (ActivatedModule cm : clickedModules) { cm.ticks--; if (cm.ticks > 0) { newClickedModules.add(cm); } else { List<ClientScreenModule> modules = getClientScreenModules(); if (cm.module < modules.size()) { modules.get(cm.module).mouseClick(worldObj, cm.x, cm.y, false); } } } clickedModules = newClickedModules; } @Override protected void checkStateServer() { if (clickedModules.isEmpty()) { return; } List<ActivatedModule> newClickedModules = new ArrayList<ActivatedModule>(); for (ActivatedModule cm : clickedModules) { cm.ticks--; if (cm.ticks > 0) { newClickedModules.add(cm); } else { List<ScreenModule> modules = getScreenModules(); if (cm.module < modules.size()) { modules.get(cm.module).mouseClick(worldObj, cm.x, cm.y, false); } } } clickedModules = newClickedModules; } @Override public int[] getAccessibleSlotsFromSide(int side) { return ScreenContainer.factory.getAccessibleSlots(); } @Override public boolean canInsertItem(int index, ItemStack stack, int side) { return ScreenContainer.factory.isInputSlot(index); } @Override public boolean canExtractItem(int index, ItemStack stack, int side) { return ScreenContainer.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) { resetModules(); return inventoryHelper.decrStackSize(index, amount); } private void resetModules() { clientScreenModules = null; screenModules = null; clickedModules.clear(); computerModules.clear(); } public void hitScreenClient(double hitX, double hitY, double hitZ, int side) { float factor = size+1.0f; float dx = 0; float dy = (float) ((-hitY + 1.0) / factor); switch (side) { case 2: dx = (float) ((1.0-hitX) / factor); break; case 3: dx = (float) (hitX / factor); break; case 4: dx = (float) (hitZ / factor); break; case 5: dx = (float) ((1.0 - hitZ) / factor); break; } int x = (int) (dx * 128); int y = (int) (dy * 128); int currenty = 7; int moduleIndex = 0; List<ClientScreenModule> clientScreenModules = getClientScreenModules(); for (ClientScreenModule module : clientScreenModules) { if (module != null) { int height = module.getHeight(); // Check if this module has enough room if (currenty + height <= 124) { if (currenty <= y && y < (currenty + height)) { break; } currenty += height; } } moduleIndex++; } if (moduleIndex >= clientScreenModules.size()) { return; } clientScreenModules.get(moduleIndex).mouseClick(worldObj, x, y - currenty, true); clickedModules.add(new ActivatedModule(moduleIndex, 5, x, y)); RFToolsMessages.INSTANCE.sendToServer(new PacketServerCommand(xCoord, yCoord, zCoord, CMD_CLICK, new Argument("x", x), new Argument("y", y - currenty), new Argument("module", moduleIndex))); } private void hitScreenServer(int x, int y, int module) { List<ScreenModule> screenModules = getScreenModules(); ScreenModule screenModule = screenModules.get(module); if (screenModule != null) { screenModule.mouseClick(worldObj, x, y, true); clickedModules.add(new ActivatedModule(module, 5, x, y)); } } @Override public ItemStack getStackInSlotOnClosing(int index) { return null; } @Override public void setInventorySlotContents(int index, ItemStack stack) { inventoryHelper.setInventorySlotContents(getInventoryStackLimit(), index, stack); resetModules(); } @Override public String getInventoryName() { return "Screen 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); powerOn = tagCompound.getBoolean("powerOn"); connected = tagCompound.getBoolean("connected"); totalRfPerTick = tagCompound.getInteger("rfPerTick"); } @Override public void readRestorableFromNBT(NBTTagCompound tagCompound) { super.readRestorableFromNBT(tagCompound); readBufferFromNBT(tagCompound); if (tagCompound.hasKey("large")) { size = tagCompound.getBoolean("large") ? 1 : 0; } else { size = tagCompound.getInteger("size"); } transparent = tagCompound.getBoolean("transparent"); color = tagCompound.getInteger("color"); } 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 + ScreenContainer.SLOT_MODULES, ItemStack.loadItemStackFromNBT(nbtTagCompound)); } resetModules(); } @Override public void writeToNBT(NBTTagCompound tagCompound) { super.writeToNBT(tagCompound); tagCompound.setBoolean("powerOn", powerOn); tagCompound.setBoolean("connected", connected); tagCompound.setInteger("rfPerTick", totalRfPerTick); } @Override public void writeRestorableToNBT(NBTTagCompound tagCompound) { super.writeRestorableToNBT(tagCompound); writeBufferToNBT(tagCompound); tagCompound.setInteger("size", size); tagCompound.setBoolean("transparent", transparent); tagCompound.setInteger("color", color); } private void writeBufferToNBT(NBTTagCompound tagCompound) { NBTTagList bufferTagList = new NBTTagList(); for (int i = ScreenContainer.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); } public int getColor() { return color; } public void setColor(int color) { this.color = color; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } public void setSize(int size) { this.size = size; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } public void setTransparent(boolean transparent) { this.transparent = transparent; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } public int getSize() { return size; } public boolean isTransparent() { return transparent; } public void setPower(boolean power) { if (powerOn == power) { return; } powerOn = power; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } public boolean isPowerOn() { return powerOn; } public void setConnected(boolean c) { if (connected == c) { return; } connected = c; markDirty(); worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); } public boolean isConnected() { return connected; } public void updateModuleData(int slot, NBTTagCompound tagCompound) { ItemStack stack = inventoryHelper.getStackInSlot(slot); stack.setTagCompound(tagCompound); screenModules = null; clientScreenModules = null; computerModules.clear(); markDirty(); } // This is called client side. public List<ClientScreenModule> getClientScreenModules() { if (clientScreenModules == null) { needsServerData = false; clientScreenModules = new ArrayList<ClientScreenModule>(); for (int i = 0 ; i < inventoryHelper.getCount() ; i++) { ItemStack itemStack = inventoryHelper.getStackInSlot(i); if (itemStack != null && itemStack.getItem() instanceof ModuleProvider) { ModuleProvider moduleProvider = (ModuleProvider) itemStack.getItem(); ClientScreenModule clientScreenModule; try { clientScreenModule = moduleProvider.getClientScreenModule().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); continue; } catch (IllegalAccessException e) { e.printStackTrace(); continue; } clientScreenModule.setupFromNBT(itemStack.getTagCompound(), worldObj.provider.dimensionId, xCoord, yCoord, zCoord); clientScreenModules.add(clientScreenModule); if (clientScreenModule.needsServerData()) { needsServerData = true; } } else { clientScreenModules.add(null); // To keep the indexing correct so that the modules correspond with there slot number. } } } return clientScreenModules; } public boolean isNeedsServerData() { return needsServerData; } public int getTotalRfPerTick() { if (screenModules == null) { getScreenModules(); } return totalRfPerTick; } // This is called server side. public List<ScreenModule> getScreenModules() { if (screenModules == null) { totalRfPerTick = 0; screenModules = new ArrayList<ScreenModule>(); for (int i = 0 ; i < inventoryHelper.getCount() ; i++) { ItemStack itemStack = inventoryHelper.getStackInSlot(i); if (itemStack != null && itemStack.getItem() instanceof ModuleProvider) { ModuleProvider moduleProvider = (ModuleProvider) itemStack.getItem(); ScreenModule screenModule; try { screenModule = moduleProvider.getServerScreenModule().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); continue; } catch (IllegalAccessException e) { e.printStackTrace(); continue; } screenModule.setupFromNBT(itemStack.getTagCompound(), worldObj.provider.dimensionId, xCoord, yCoord, zCoord); screenModules.add(screenModule); totalRfPerTick += screenModule.getRfPerTick(); if (screenModule instanceof ComputerScreenModule) { ComputerScreenModule computerScreenModule = (ComputerScreenModule) screenModule; String tag = computerScreenModule.getTag(); if (!computerModules.containsKey(tag)) { computerModules.put(tag, new ArrayList<ComputerScreenModule>()); } computerModules.get(tag).add(computerScreenModule); } } else { screenModules.add(null); // To keep the indexing correct so that the modules correspond with there slot number. } } } return screenModules; } public List<ComputerScreenModule> getComputerModules(String tag) { return computerModules.get(tag); } public Set<String> getTags() { return computerModules.keySet(); } // This is called server side. public Map<Integer, Object[]> getScreenData(long millis) { Map<Integer, Object[]> map = new HashMap<Integer, Object[]>(); List<ScreenModule> screenModules = getScreenModules(); int moduleIndex = 0; for (ScreenModule module : screenModules) { if (module != null) { Object[] data = module.getData(worldObj, millis); if (data != null) { map.put(moduleIndex, data); } } moduleIndex++; } return map; } @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_CLICK.equals(command)) { int x = args.get("x").getInteger(); int y = args.get("y").getInteger(); int module = args.get("module").getInteger(); hitScreenServer(x, y, module); return true; } return false; } }