package advancedsystemsmanager.flow; import advancedsystemsmanager.api.execution.ICommand; import advancedsystemsmanager.api.gui.IGuiElement; import advancedsystemsmanager.api.network.IPacketProvider; import advancedsystemsmanager.api.network.IPacketSync; import advancedsystemsmanager.flow.elements.TextBoxLogic; import advancedsystemsmanager.flow.menus.Menu; import advancedsystemsmanager.flow.menus.MenuResult; import advancedsystemsmanager.client.gui.GuiManager; import advancedsystemsmanager.helpers.CollisionHelper; import advancedsystemsmanager.tileentities.manager.Settings; import advancedsystemsmanager.network.ASMPacket; import advancedsystemsmanager.network.PacketHandler; import advancedsystemsmanager.registry.CommandRegistry; import advancedsystemsmanager.registry.ConnectionOption; import advancedsystemsmanager.registry.ConnectionSet; import advancedsystemsmanager.registry.ThemeHandler; import advancedsystemsmanager.tileentities.manager.TileEntityManager; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.client.gui.GuiScreen; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.StatCollector; import net.minecraftforge.common.util.Constants; import org.lwjgl.opengl.GL11; import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class FlowComponent implements Comparable<FlowComponent>, IGuiElement, IPacketSync, IPacketProvider { public static final int COMPONENT_START_X = 100; public static final int COMPONENT_START_Y = 50; public static final int COMPONENT_SRC_X = 136; public static final int COMPONENT_SRC_Y = 30; public static final int COMPONENT_SRC_W = 45; public static final int COMPONENT_SRC_H = 10; public static final int COMPONENT_SIZE_W = 90; public static final int COMPONENT_SIZE_H = 20; public static final int COMPONENT_SIZE_LARGE_W = 128; public static final int COMPONENT_SIZE_LARGE_H = 152; public static final int COMPONENT_SRC_LARGE_X = 72; public static final int COMPONENT_SRC_LARGE_Y = 30; public static final int COMPONENT_SRC_LARGE_W = 64; public static final int COMPONENT_SRC_LARGE_H = 76; public static final int DRAGGABLE_SIZE = 6; public static final int ARROW_X = -15; public static final int ARROW_Y = 5; public static final int ARROW_SIZE_W = 15; public static final int ARROW_SIZE_H = 8; public static final int ARROW_SRC_X = 70; public static final int ARROW_SRC_Y = 2; public static final int MENU_AREA_OFFSET_X = 1; public static final int MENU_AREA_OFFSET_Y = 19; public static final int MENU_AREA_SRC_X = 136; public static final int MENU_AREA_SRC_Y = 40; public static final int MENU_AREA_SRC_W = 63; public static final int MENU_AREA_SRC_H = 66; public static final int MENU_AREA_SIZE_W = 126; public static final int MENU_AREA_SIZE_H = 132; public static final int MENU_ITEM_SIZE_W = MENU_AREA_SIZE_W; public static final int MENU_ITEM_SIZE_H = 13; public static final int MENU_ITEM_SRC_X = COMPONENT_SRC_LARGE_X; public static final int MENU_ITEM_SRC_Y = 106; public static final int MENU_X = MENU_AREA_OFFSET_X; public static final int MENU_Y = MENU_AREA_OFFSET_Y; public static final int MENU_SIZE_H = 132; public static final int MENU_ITEM_CAPACITY = 5; public static final int MENU_ARROW_X = 109; public static final int MENU_ARROW_Y = 2; public static final int MENU_ARROW_SIZE_W = 9; public static final int MENU_ARROW_SIZE_H = 9; public static final int MENU_ARROW_SRC_X = 0; public static final int MENU_ARROW_SRC_Y = 40; public static final int MENU_ITEM_TEXT_X = 5; public static final int MENU_ITEM_TEXT_Y = 3; public static final int CONNECTION_SIZE_W = 4; public static final int CONNECTION_SIZE_H = 4; public static final int CONNECTION_SRC_X = 0; public static final int CONNECTION_SRC_Y = 58; public static final int CONNECTION_SRC_Y_SIDE = 245; public static final int ERROR_X = 2; public static final int ERROR_Y = 8; public static final int ERROR_SIZE_W = 2; public static final int ERROR_SIZE_H = 10; public static final int ERROR_SRC_X = 42; public static final int ERROR_SRC_Y = 212; public static final int NODE_SRC_X = COMPONENT_SRC_X; public static final int NODE_SRC_Y = 23; public static final int NODE_SIZE = 4; public static final int MAX_NODES = 15; public static final int CURSOR_X = -1; public static final int CURSOR_Y = -4; public static final int CURSOR_Z = 5; public static final int TEXT_X = 7; public static final int TEXT_Y = 10; public static final int TEXT_HEIGHT = 10; public static final int EDIT_SRC_X = 32; public static final int EDIT_SRC_Y = 189; public static final int EDIT_X = 103; public static final int EDIT_Y = 6; public static final int EDIT_X_SMALL = 105; public static final int EDIT_Y_TOP = 2; public static final int EDIT_Y_BOT = 11; public static final int EDIT_SIZE = 9; public static final int EDIT_SIZE_SMALL = 7; public static final int TEXT_SPACE = 135; public static final int TEXT_SPACE_SHORT = 65; public static final int TEXT_MAX_LENGTH = 31; public static final String NBT_POS_X = "X"; public static final String NBT_POS_Y = "Y"; public static final String NBT_TYPE = "T"; public static final String NBT_CONNECTION = "C"; public static final String NBT_INTERVAL = "I"; public static final String NBT_MENUS = "M"; public static final String NBT_NAME = "Na"; public static final String NBT_PARENT = "P"; private static final String NBT_ID = "ID"; private static final String NBT_SET = "S"; public int x; public int y; public int mouseDragX; public int mouseDragY; public int mouseStartX; public int mouseStartY; public int resetTimer; public boolean isDragging; public boolean isLarge; public List<Menu> menus; public int openMenuId; public ConnectionSet connectionSet; public ICommand type; public TileEntityManager manager; public int id; public Connection[] connections; public int currentInterval; public boolean isEditing; public TextBoxLogic textBox; public String name; public FlowComponent parent; public List<FlowComponent> childrenInputNodes; public List<FlowComponent> childrenOutputNodes; public boolean isInventoryListDirty = true; public boolean isLoading; public String cachedName; public String cachedShortName; public int parentLoadId = -1; public int overrideX = -1; public int overrideY = -1; List<String> errors = new ArrayList<String>(); private List<IPacketSync> networkSyncList = new ArrayList<IPacketSync>(); public FlowComponent(TileEntityManager manager, ICommand type) { this(manager, COMPONENT_START_X, COMPONENT_START_Y, type); } public FlowComponent(TileEntityManager manager, int x, int y, ICommand type) { this(manager, x, y, manager.getNextFreeID(), type); } public FlowComponent(TileEntityManager manager, int x, int y, int id, ICommand type) { this.x = x; this.y = y; this.connectionSet = type.getSets()[0]; this.type = type; this.manager = manager; this.id = id; menus = new ArrayList<Menu>(); type.getMenus(this, menus); if (type.getSets().length > 1) menus.add(new MenuResult(this)); openMenuId = -1; connections = new Connection[connectionSet.getConnections().length]; textBox = new TextBoxLogic(this, TEXT_MAX_LENGTH, TEXT_SPACE) { @Override public boolean readData(ASMPacket packet) { super.readData(packet); setComponentName(text); return false; } }; childrenInputNodes = new ArrayList<FlowComponent>(); childrenOutputNodes = new ArrayList<FlowComponent>(); } public static FlowComponent readFromNBT(TileEntityManager manager, NBTTagCompound nbtTagCompound, boolean pickup) { FlowComponent component = null; try { int x = nbtTagCompound.getShort(NBT_POS_X); int y = nbtTagCompound.getShort(NBT_POS_Y); int typeId = nbtTagCompound.getByte(NBT_TYPE); int id = nbtTagCompound.getInteger(NBT_ID); component = new FlowComponent(manager, x, y, id, CommandRegistry.getCommand(typeId)); component.setConnectionSet(component.getType().getSets()[nbtTagCompound.getByte(NBT_SET)]); component.isLoading = true; if (nbtTagCompound.hasKey(NBT_NAME)) { component.name = nbtTagCompound.getString(NBT_NAME); } else { component.name = null; } if (nbtTagCompound.hasKey(NBT_PARENT)) { component.parentLoadId = nbtTagCompound.getInteger(NBT_PARENT); } NBTTagList connections = nbtTagCompound.getTagList(NBT_CONNECTION, 10); for (int i = 0; i < connections.tagCount(); i++) { Connection.readFromNBT(component.connections, connections.getCompoundTagAt(i), id); } if (nbtTagCompound.hasKey(NBT_INTERVAL, Constants.NBT.TAG_SHORT)) { component.currentInterval = nbtTagCompound.getShort(NBT_INTERVAL); } NBTTagList menuTagList = nbtTagCompound.getTagList(NBT_MENUS, 10); int menuId = 0; for (int i = 0; i < menuTagList.tagCount() && i < component.menus.size(); i++) { NBTTagCompound menuTag = menuTagList.getCompoundTagAt(i); component.menus.get(menuId).readFromNBT(menuTag, pickup); menuId++; } return component; } finally { if (component != null) { component.isLoading = false; } } } public ICommand getType() { return type; } public void removeConnection(int id) { Connection connection = connections[id]; if (connection != null) { sendConnectionData(id, false, 0, 0); connection.deleteConnection(manager); } } private void sendConnectionData(int connectionId, boolean add, int targetComponent, int targetConnection) { ASMPacket packet = getSyncPacket(); packet.writeByte(networkSyncList.size() + 1); packet.writeByte(connectionId); packet.writeBoolean(add); if (add) { packet.writeVarIntToBuffer(targetComponent); packet.writeByte(targetConnection); } packet.sendServerPacket(); } @Override @SideOnly(Side.CLIENT) public ASMPacket getSyncPacket() { return PacketHandler.getComponentPacket(this); } @Override public void registerSyncable(IPacketSync networkSync) { networkSync.setId(networkSyncList.size()); networkSyncList.add(networkSync); } @Override @SideOnly(Side.CLIENT) public void sendPacketToServer(ASMPacket packet) { packet.sendServerPacket(); } public static void moveComponents(FlowComponent component, FlowComponent parent, boolean moveCluster) { if (moveCluster) { List<FlowComponent> cluster = new ArrayList<FlowComponent>(); findCluster(cluster, component, parent); for (FlowComponent flowComponent : cluster) { flowComponent.setParent(parent); if (parent != null) { for (int i = 0; i < flowComponent.getConnectionSet().getConnections().length; i++) { Connection connection = flowComponent.getConnection(i); if (connection != null && (connection.getInputId() == parent.getId() || connection.getOutputId() == parent.getId())) { flowComponent.removeConnection(i); } } } } } else if (!component.equals(parent)) { component.setParent(parent); component.deleteConnections(); } } public static void findCluster(List<FlowComponent> components, FlowComponent component, FlowComponent parent) { if (!components.contains(component) && !component.equals(parent)) { components.add(component); for (int i = 0; i < component.getConnectionSet().getConnections().length; i++) { Connection connection = component.getConnection(i); if (connection != null) { findCluster(components, component.getManager().getFlowItem(connection.getOutputId() == component.getId() ? connection.getInputId() : connection.getOutputId()), parent); } } } } public int getCurrentInterval() { return currentInterval; } public void setCurrentInterval(int currentInterval) { this.currentInterval = currentInterval; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public void update(float partial) { //no need for this to be precise, can ignore the partial time if (resetTimer > 0) { if (resetTimer == 1) { x = mouseStartX; y = mouseStartY; } resetTimer--; } for (Menu menu : menus) { menu.update(partial); } } @SideOnly(Side.CLIENT) public void draw(GuiManager gui, int mX, int mY, int zLevel) { GL11.glPushMatrix(); GL11.glTranslatef(0, 0, zLevel); gui.drawScaledColouredTexture(x, y, getComponentWidth(), getComponentHeight(), isLarge ? COMPONENT_SRC_LARGE_X : COMPONENT_SRC_X, isLarge ? COMPONENT_SRC_LARGE_Y : COMPONENT_SRC_Y, isLarge ? COMPONENT_SRC_LARGE_W : COMPONENT_SRC_W, isLarge ? COMPONENT_SRC_LARGE_H : COMPONENT_SRC_H, type.getColour()); int internalX = mX - x; int internalY = mY - y; int srcArrowY = isLarge ? 0 : 1; gui.drawTexture(x + getComponentWidth() + ARROW_X, y + ARROW_Y, ARROW_SRC_X, ARROW_SRC_Y + ARROW_SIZE_H * srcArrowY, ARROW_SIZE_W, ARROW_SIZE_H); if (isLarge) { gui.drawScaledColouredTexture(x + MENU_AREA_OFFSET_X, y + MENU_AREA_OFFSET_Y, MENU_AREA_SIZE_W, MENU_AREA_SIZE_H, MENU_AREA_SRC_X, MENU_AREA_SRC_Y, MENU_AREA_SRC_W, MENU_AREA_SRC_H, ThemeHandler.theme.commands.menuArea.getColour()); for (int i = 0; i < menus.size(); i++) { Menu menu = menus.get(i); if (!menu.isVisible()) { if (openMenuId == i) { openMenuId = -1; } continue; } int itemX = getMenuAreaX(); int itemY = y + getMenuItemY(i); gui.drawScaledColouredTexture(itemX, itemY, MENU_ITEM_SIZE_W, MENU_ITEM_SIZE_H, MENU_ITEM_SRC_X, MENU_ITEM_SRC_Y, MENU_ITEM_SIZE_W * 0.5f, MENU_ITEM_SIZE_H * 0.5f, (i == openMenuId ? ThemeHandler.theme.menus.selectedTitleBackground : ThemeHandler.theme.menus.titleBackground).getColour()); int srcItemArrowY = i == openMenuId ? 0 : 1; gui.drawTexture(itemX + getComponentWidth() + ARROW_X, itemY + ARROW_Y, ARROW_SRC_X, ARROW_SRC_Y + ARROW_SIZE_H * srcItemArrowY, ARROW_SIZE_W, ARROW_SIZE_H); gui.drawString(menu.getName(), x + MENU_X + MENU_ITEM_TEXT_X, y + getMenuItemY(i) + MENU_ITEM_TEXT_Y, 0xFF404040); if (i == openMenuId) { GL11.glPushMatrix(); GL11.glTranslatef(itemX, getMenuAreaY(i), 0); menu.draw(gui, mX - itemX, mY - getMenuAreaY(i)); GL11.glPopMatrix(); } } } boolean hasConnection = false; for (int i = 0; i < connectionSet.getConnections().length; i++) { ConnectionOption connection = connectionSet.getConnections()[i]; int[] location = connectionSet.getConnectionLocation(i, this); if (location == null) { continue; } int connectionWidth = 4; int connectionHeight = 4; boolean connectionMouseover = CollisionHelper.inBounds(location[0], location[1], connectionWidth, connectionHeight, mX, mY); Connection current = manager.getCurrentlyConnecting(); if (current != null && current.getInputId() == id && current.getInputConnection() == i) { gui.drawLines(new int[]{location[0] + connectionWidth / 2, location[1] + connectionHeight / 2, overrideX != -1 ? overrideX : mX, overrideY != -1 ? overrideY : mY}, ThemeHandler.theme.lines.getColour()); } Connection connectedConnection = connections[i]; if (connectedConnection != null) { hasConnection = true; if (connectedConnection.getInputId() == id) { FlowComponent other = manager.getFlowItem(connectedConnection.getOutputId()); if (other == null) { continue; } int[] otherLocation = other.getConnectionLocationFromId(connectedConnection.getOutputConnection()); if (otherLocation == null) { continue; } int startX = location[0] + connectionWidth / 2; int startY = location[1] + connectionHeight / 2; int endX = otherLocation[0] + connectionWidth / 2; int endY = otherLocation[1] + connectionHeight / 2; GL11.glPushMatrix(); GL11.glTranslatef(0, 0, -zLevel); List<Point> nodes = connectedConnection.getNodes(); int[] points = new int[nodes.size() * 2 + 4]; int j = 0; points[j++] = startX; points[j++] = startY; for (Point node : nodes) { points[j++] = node.getX(); points[j++] = node.getY(); } points[j++] = endX; points[j] = endY; gui.drawLines(points, ThemeHandler.theme.lines.getColour()); for (Point node : nodes) { int x = node.getX() - NODE_SIZE / 2; int y = node.getY() - NODE_SIZE / 2; boolean selected = connectedConnection.getSelectedNode() == null && CollisionHelper.inBounds(x, y, NODE_SIZE, NODE_SIZE, mX, mY); gui.drawColouredTexture(x, y, NODE_SRC_X, NODE_SRC_Y, NODE_SIZE, NODE_SIZE, (selected ? ThemeHandler.theme.commands.connectionNodes.mouseover : ThemeHandler.theme.commands.connectionNodes.colour).getColour()); } GL11.glPopMatrix(); } } gui.drawColouredTexture(location[0], location[1], connection.getType().getX(), connection.getType().getY(), connectionWidth, connectionHeight, connection.getColour(connectionMouseover)); } errors.clear(); if (hasConnection || getConnectionSet().getConnections().length == 0) { for (Menu menu : menus) { if (menu.isVisible()) { menu.addErrors(errors); } } } if (!errors.isEmpty()) { int srcErrorY = CollisionHelper.inBounds(x + ERROR_X, y + ERROR_Y, ERROR_SIZE_W, ERROR_SIZE_H, mX, mY) ? 1 : 0; gui.drawTexture(x + ERROR_X, y + ERROR_Y, ERROR_SRC_X, ERROR_SRC_Y + srcErrorY * ERROR_SIZE_H, ERROR_SIZE_W, ERROR_SIZE_H); } if (!isEditing || isLarge) { String name = getName(); if (!isLarge) { name = getShortName(gui, name); } gui.drawString(name, x + TEXT_X, y + TEXT_Y - (!isLarge ? TEXT_Y / 2 : 0), 1F, isEditing ? 0x707020 : 0x404040); } if (isEditing) { gui.drawString(getShortName(gui, getName()), x + TEXT_X, y + TEXT_Y, 1F, 0x207020); } if (name != null && Settings.isCommandTypes() && !GuiScreen.isCtrlKeyDown()) { gui.drawCenteredString(getType().getName(), x + DRAGGABLE_SIZE, y + 3, 1F, getComponentWidth() - DRAGGABLE_SIZE - ARROW_SIZE_W, 0x707070); } if (isLarge) { if (isEditing) { gui.drawCursor(x + TEXT_X + (int)((textBox.getCursorPosition(gui) + CURSOR_X)), y + TEXT_Y + (int)(CURSOR_Y), CURSOR_Z, 1F, 0xFFFFFFFF); for (int i = 0; i < 2; i++) { int buttonX = x + EDIT_X_SMALL; int buttonY = y + (i == 0 ? EDIT_Y_TOP : EDIT_Y_BOT); int srcXButton = CollisionHelper.inBounds(buttonX, buttonY, EDIT_SIZE_SMALL, EDIT_SIZE_SMALL, mX, mY) ? 1 : 0; int srcYButton = i; gui.drawTexture(buttonX, buttonY, EDIT_SRC_X + srcXButton * EDIT_SIZE_SMALL, EDIT_SRC_Y + EDIT_SIZE + EDIT_SIZE_SMALL * srcYButton, EDIT_SIZE_SMALL, EDIT_SIZE_SMALL); } } else { int buttonX = x + EDIT_X; int buttonY = y + EDIT_Y; int srcXButton = CollisionHelper.inBounds(buttonX, buttonY, EDIT_SIZE, EDIT_SIZE, mX, mY) ? 1 : 0; gui.drawTexture(buttonX, buttonY, EDIT_SRC_X + srcXButton * EDIT_SIZE, EDIT_SRC_Y, EDIT_SIZE, EDIT_SIZE); } } GL11.glPopMatrix(); } @SideOnly(Side.CLIENT) public void drawMouseOver(GuiManager gui, int mX, int mY) { for (int i = 0; i < connectionSet.getConnections().length; i++) { ConnectionOption connection = connectionSet.getConnections()[i]; int[] location = connectionSet.getConnectionLocation(i, this); if (location == null) { continue; } if (CollisionHelper.inBounds(location[0], location[1], CONNECTION_SIZE_W, CONNECTION_SIZE_H, mX, mY)) { gui.drawMouseOver(connection.getName(this, (connection.isInput() ? i : i - connectionSet.getInputs())), mX, mY); } } if (isLarge) { for (int i = 0; i < menus.size(); i++) { Menu menu = menus.get(i); if (menu.isVisible() && i == openMenuId) { GL11.glPushMatrix(); GL11.glTranslatef(getMenuAreaX(), getMenuAreaY(i), 0); menu.drawMouseOver(gui, mX - getMenuAreaX(), mY - getMenuAreaY(i)); GL11.glPopMatrix(); break; } } } if (!errors.isEmpty()) { if (CollisionHelper.inBounds(x + ERROR_X, y + ERROR_Y, ERROR_SIZE_W, ERROR_SIZE_H, mX, mY)) { String str = ""; for (int i = 0; i < errors.size(); i++) { if (i != 0) { str += "\n\n"; } str += StatCollector.translateToLocal(errors.get(i)); } gui.drawMouseOver(str, mX, mY); } } } @SideOnly(Side.CLIENT) public boolean onKeyStroke(GuiManager gui, char c, int k) { if (isLarge && isEditing) { textBox.onKeyStroke(gui, c, k); return true; } else return isLarge && openMenuId != -1 && menus.get(openMenuId).onKeyStroke(gui, c, k); } public boolean onClick(int mX, int mY, int button) { if (CollisionHelper.inBounds(x, y, getComponentWidth(), getComponentHeight(), mX, mY)) { int internalX = mX - x; int internalY = mY - y; if (internalX <= DRAGGABLE_SIZE && internalY <= DRAGGABLE_SIZE) { mouseStartX = mouseDragX = mX; mouseStartY = mouseDragY = mY; isDragging = true; } else if (isLarge && !isEditing && CollisionHelper.inBounds(EDIT_X, EDIT_Y, EDIT_SIZE, EDIT_SIZE, internalX, internalY)) { isEditing = true; textBox.setTextAndCursor(getName()); } else if (isLarge && isEditing && CollisionHelper.inBounds(EDIT_X_SMALL, EDIT_Y_TOP, EDIT_SIZE_SMALL, EDIT_SIZE_SMALL, internalX, internalY)) { isEditing = false; name = textBox.getText(); if (name.equals("")) { name = null; } textBox.setText(null); } else if (isLarge && isEditing && CollisionHelper.inBounds(EDIT_X_SMALL, EDIT_Y_BOT, EDIT_SIZE_SMALL, EDIT_SIZE_SMALL, internalX, internalY)) { isEditing = false; textBox.setText(null); } else if (isLarge && isEditing && CollisionHelper.inBounds(TEXT_X, TEXT_Y, TEXT_SPACE, TEXT_HEIGHT, internalX, internalY)) { if (button == 1) { textBox.setTextAndCursor(""); } } else if (inArrowBounds(internalX, internalY) || (Settings.isLargeOpenHitBox() && internalY < COMPONENT_SIZE_H)) { if (!isLarge && type.getCommandType() == ICommand.CommandType.GROUP && Settings.isQuickGroupOpen() && !GuiScreen.isShiftKeyDown()) { manager.setSelectedGroup(this); } else { isLarge = !isLarge; } } else if (!Settings.isLargeOpenHitBox() && internalY < COMPONENT_SIZE_H) { mouseStartX = mouseDragX = mX; mouseStartY = mouseDragY = mY; isDragging = true; } else if (isLarge) { for (int i = 0; i < menus.size(); i++) { Menu menu = menus.get(i); if (menu.isVisible()) { if (inMenuArrowBounds(i, internalX, internalY) || (Settings.isLargeOpenHitBoxMenu() && internalY >= getMenuItemY(i) && internalY <= getMenuItemY(i) + MENU_ITEM_SIZE_H)) { if (openMenuId == i) { openMenuId = -1; } else { openMenuId = i; } return true; } if (i == openMenuId) { menu.onClick(mX - getMenuAreaX(), mY - getMenuAreaY(i), button); } } } } return true; } else { for (int i = 0; i < connectionSet.getConnections().length; i++) { ConnectionOption connection = connectionSet.getConnections()[i]; int[] location = getConnectionLocationFromId(i); if (location == null) { continue; } Connection selected = connections[i]; if ((selected == null || selected.getSelected() == -1) && CollisionHelper.inBounds(location[0], location[1], CONNECTION_SIZE_W, CONNECTION_SIZE_H, mX, mY)) { Connection current = manager.getCurrentlyConnecting(); if (button == 1 && current == null) { if (selected != null) { if (selected.getNodes().size() < MAX_NODES) { int id = connectionSet.connections[i].isInput() ? selected.getNodes().size() : 0; selected.addAndSelectNode(mX, mY, id); sendConnectionNodeData(i, id, 1, mX, mY); } } } else { if (current == null) { if (connections[i] != null) { removeConnection(i); } manager.setCurrentlyConnecting(new Connection(id, i)); } else if (current.getInputId() == this.id && current.getInputConnection() == i) { manager.setCurrentlyConnecting(null); } else if (current.getInputId() != id) { FlowComponent connectTo = manager.getFlowItem(current.getInputId()); ConnectionOption connectToOption = connectTo.connectionSet.getConnections()[current.getInputConnection()]; if (connectToOption.isInput() != connection.isInput()) { if (checkForLoops(current)) { return true; } if (connections[i] != null) { removeConnection(i); } if (connection.isInput()) { current.setOutputId(id); current.setOutputConnection(i); connectTo.addConnection(current.inputConnection, current, true); } else { current.setInputId(id); current.setInputConnection(i); addConnection(i, current, true); } manager.setCurrentlyConnecting(null); } } } return true; } else if (selected != null) { List<Point> nodes = selected.getNodes(); for (int j = 0; j < nodes.size(); j++) { Point node = nodes.get(j); int x = node.getX() - NODE_SIZE / 2; int y = node.getY() - NODE_SIZE / 2; if (CollisionHelper.inBounds(x, y, NODE_SIZE, NODE_SIZE, mX, mY)) { if (button == 0) { selected.setSelected(j); } else if (button == 1) { if (GuiScreen.isShiftKeyDown()) { selected.getNodes().remove(j); sendConnectionNodeData(i, j, 0, 0, 0); } else if (selected.getNodes().size() < MAX_NODES && selected.getSelectedNode() == null) { selected.addAndSelectNode(mX, mY, j + 1); sendConnectionNodeData(i, j + 1, 1, mX, mY); } } return true; } } } } return false; } } public boolean isVisible() { return isVisible(getManager().getSelectedGroup()); } public boolean isVisible(FlowComponent selectedComponent) { return (selectedComponent == null && parent == null) || (parent != null && parent.equals(selectedComponent)); } public TileEntityManager getManager() { return manager; } public int getComponentWidth() { return isLarge ? COMPONENT_SIZE_LARGE_W : COMPONENT_SIZE_W; } public int getComponentHeight() { return isLarge ? COMPONENT_SIZE_LARGE_H : COMPONENT_SIZE_H; } public int getMenuAreaX() { return x + MENU_X; } public int getMenuItemY(int id) { int ret = MENU_Y; for (int i = 0; i < id; i++) { if (menus.get(i).isVisible()) { ret += MENU_ITEM_SIZE_H - 1; if (openMenuId == i) { ret += getMenuOpenSize() - 1; } } } return ret; } public int getMenuAreaY(int i) { return y + getMenuItemY(i) + MENU_ITEM_SIZE_H; } public int[] getConnectionLocationFromId(int id) { return connectionSet.getConnectionLocation(id, this); } public ConnectionSet getConnectionSet() { return connectionSet; } public void setConnectionSet(ConnectionSet connectionSet) { if (this.connections != null && this.connectionSet != null && !isLoading) { int oldLength = this.connectionSet.getConnections().length; int newLength = connectionSet.getConnections().length; for (int i = 0; i < Math.min(oldLength, newLength); i++) { Connection connection = connections[i]; if (connection != null && this.connectionSet.getConnections()[i].isInput() != connectionSet.getConnections()[i].isInput()) { removeConnection(i); } } for (int i = newLength; i < oldLength; i++) { Connection connection = connections[i]; if (connection != null) { removeConnection(i); } } this.connections = Arrays.copyOf(connections, connectionSet.getConnections().length); } this.connectionSet = connectionSet; } @SideOnly(Side.CLIENT) public String getName() { return textBox.getText() == null ? name == null || GuiScreen.isCtrlKeyDown() ? StatCollector.translateToLocal(getType().getName()) : name : textBox.getText(); } public String getShortName(GuiManager gui, String name) { if (!name.equals(cachedName)) { cachedShortName = ""; for (char c : StatCollector.translateToLocal(name).toCharArray()) { if (gui.getStringWidth(cachedShortName + c) > TEXT_SPACE_SHORT) { break; } cachedShortName += c; } } cachedName = name; return cachedShortName; } public static int getMenuOpenSize() { return MENU_SIZE_H - MENU_ITEM_CAPACITY * (MENU_ITEM_SIZE_H - 1); } public void addConnection(int id, Connection connection, boolean sync) { if (sync && getManager().getWorldObj() != null && getManager().getWorldObj().isRemote) { sendConnectionData(id, true, connection.getOutputId(), connection.getOutputConnection()); } connection.setConnection(manager); } public boolean checkForLoops(Connection connection) { return checkForLoops(new ArrayList<Integer>(Arrays.asList(id)), connection.getInputId()); } public boolean checkForLoops(List<Integer> usedComponents, int id) { if (usedComponents.contains(id)) { return true; } usedComponents.add(id); FlowComponent currentComponent = manager.getFlowItem(id); for (int i = 0; i < currentComponent.connections.length; i++) { if (!currentComponent.connectionSet.isInput(i)) { Connection c = currentComponent.getConnection(i); if (c != null) { if (checkForLoops(usedComponents, c.getOutputId())) { return true; } } } } return false; } public void removeAllConnections() { for (int i = 0; i < connectionSet.getConnections().length; i++) { Connection connection = connections[i]; if (connection != null) { removeConnection(i); } } } public void deleteConnections() { for (Connection connection : connections) { if (connection != null) connection.deleteConnection(manager); } } public void onDrag(int mX, int mY, int button) { followMouse(mX, mY, button); for (int i = 0; i < menus.size(); i++) { Menu menu = menus.get(i); menu.onDrag(mX - getMenuAreaX(), mY - getMenuAreaY(i), i == openMenuId); } for (int i = 0; i < connectionSet.getConnections().length; i++) { Connection connection = connections[i]; if (connection != null) { connection.update(mX, mY); } } } @SideOnly(Side.CLIENT) public void followMouse(int mX, int mY, int button) { if (isDragging) { int startX = x; int startY = y; x += mX - mouseDragX; y += mY - mouseDragY; if (GuiScreen.isShiftKeyDown()) { adjustToGrid(10); mouseDragX = x; mouseDragY = y; } else { mouseDragX = mX; mouseDragY = mY; } if (button == 2) { List<FlowComponent> connected = new ArrayList<FlowComponent>(); findCluster(connected, this, null); for (FlowComponent component : connected) { component.shiftNodes(x - startX, y - startY); if (!component.equals(this)) component.shiftLocation(x - startX, y - startY); } } } } public void shiftNodes(int dx, int dy) { for (Connection connection : connections) { if (connection != null && connection.getInputId() == id) { for (Point point : connection.getNodes()) { point.x += dx; point.y += dy; } } } } public void shiftLocation(int dx, int dy) { x += dx; y += dy; } public void onRelease(int mX, int mY, int button) { followMouse(mX, mY, button); if (isDragging) { sendLocationData(button == 2); } for (int i = 0; i < menus.size(); i++) { Menu menu = menus.get(i); menu.onRelease(mX - getMenuAreaX(), mY - getMenuAreaY(i), button, isLarge && i == openMenuId); } for (int i = 0; i < connectionSet.getConnections().length; i++) { Connection connection = connections[i]; if (connection != null) { Point node; if ((node = connection.getSelectedNode()) != null) { connection.update(mX, mY); sendConnectionNodeData(i, connection.getSelected(), 2, node.getX(), node.getY()); connection.setSelected(-1); return; } } } } public void postRelease() { isDragging = false; } public void adjustEverythingToGrid(int grid) { adjustToGrid(grid); for (Connection connection : connections) { if (connection != null) { connection.adjustAllToGrid(grid); } } } public void adjustToGrid(int grid) { x = Math.round(x / grid) * grid; y = Math.round(y / grid) * grid; } public boolean inArrowBounds(int internalX, int internalY) { return CollisionHelper.inBounds(getComponentWidth() + ARROW_X, ARROW_Y, ARROW_SIZE_W, ARROW_SIZE_H, internalX, internalY); } public boolean inMenuArrowBounds(int i, int internalX, int internalY) { return CollisionHelper.inBounds(MENU_X + MENU_ARROW_X, getMenuItemY(i) + MENU_ARROW_Y, MENU_ARROW_SIZE_W, MENU_ARROW_SIZE_H, internalX, internalY); } public List<Menu> getMenus() { return menus; } public Menu getMenu(int menu) { return menus.get(menu); } public FlowComponent copy() { FlowComponent copy = new FlowComponent(manager, x, y, id, type); copy.name = name; for (int i = 0; i < menus.size(); i++) { Menu menu = menus.get(i); copy.menus.get(i).copyFrom(menu); } for (int i = 0; i < connectionSet.getConnections().length; i++) { Connection connection = connections[i]; if (connection != null) { copy.connections[i] = connection.copy(); } } return copy; } public Connection getConnection(int i) { return connections[i]; } public boolean isBeingMoved() { return isDragging; } public void removeParent(int idToRemove) { if (parent != null && parent.getId() == idToRemove) { setParent(null); } } public int getId() { return id; } public void setId(int id) { this.id = id; } public void linkAfterLoad() { if (parentLoadId != -1) { setParent(getManager().getFlowItem(parentLoadId)); } else { setParent(null); } for (Connection connection : connections) { if (connection != null) { connection.setConnection(manager); } } } public void writeToNBT(NBTTagCompound nbtTagCompound, boolean pickup) { nbtTagCompound.setShort(NBT_POS_X, (short)x); nbtTagCompound.setShort(NBT_POS_Y, (short)y); nbtTagCompound.setByte(NBT_TYPE, (byte)type.getId()); nbtTagCompound.setInteger(NBT_ID, id); for (int i = 0; i < type.getSets().length; i++) { if (type.getSets()[i] == getConnectionSet()) { nbtTagCompound.setByte(NBT_SET, (byte)i); break; } } if (name != null) { nbtTagCompound.setString(NBT_NAME, name); } if (parent != null) { nbtTagCompound.setInteger(NBT_PARENT, parent.getId()); } nbtTagCompound.setTag(NBT_CONNECTION, getConnectionNBT()); if (this.type.getCommandType() == ICommand.CommandType.TRIGGER) { nbtTagCompound.setShort(NBT_INTERVAL, (short)currentInterval); } NBTTagList menuTagList = new NBTTagList(); for (Menu menu : menus) { NBTTagCompound menuTag = new NBTTagCompound(); menu.writeToNBT(menuTag, pickup); menuTagList.appendTag(menuTag); } nbtTagCompound.setTag(NBT_MENUS, menuTagList); } public NBTTagList getConnectionNBT() { NBTTagList connections = new NBTTagList(); for (int i = 0; i < connectionSet.getConnections().length & i < this.connections.length; i++) { Connection connection = this.connections[i]; if (connection != null && connection.getInputId() == id) { NBTTagCompound connectionTag = new NBTTagCompound(); connection.writeToNBT(connectionTag); connections.appendTag(connectionTag); } } return connections; } public boolean isOpen() { return isLarge; } public void setOpen(boolean b) { isLarge = b; openMenuId = -1; } public void close() { isLarge = false; } public void setConnection(int i, Connection connection) { connections[i] = connection; } public void clearConnections() { connections = new Connection[connections.length]; } public String getComponentName() { return name; } public void setComponentName(String name) { this.name = name; } public FlowComponent getParent() { return parent; } public void setParent(FlowComponent parent) { type.moveComponent(this, this.parent, parent); this.parent = parent; } @Override public int hashCode() { return id; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; FlowComponent component = (FlowComponent)o; return id == component.id; } public List<FlowComponent> getChildrenOutputNodes() { return childrenOutputNodes; } public List<FlowComponent> getChildrenInputNodes() { return childrenInputNodes; } // public void setNameEdited(boolean b) // { // isEditing = b; // if (b) // { // textBox.setTextAndCursor(""); // } else // { // textBox.setText(null); // } // } // // public void refreshEditing(String name) // { // textBox.setTextAndCursor(name); // } // // public boolean isNameBeingEdited() // { // return isEditing; // } // // public int getOverrideY() // { // return overrideY; // } // // public void setOverrideY(int overrideY) // { // this.overrideY = overrideY; // } // // public int getOverrideX() // { // return overrideX; // } // // public void setOverrideX(int overrideX) // { // this.overrideX = overrideX; // } @Override public int compareTo(@Nonnull FlowComponent o) { return id == o.id ? 0 : id < o.id ? -1 : 1; } // public int getOpenMenuId() // { // return openMenuId; // } // // public void setOpenMenuId(int openMenuId) // public void setOpenMenuId(int openMenuId) // { // this.openMenuId = openMenuId; // } public void resetPosition() { resetTimer = 20; } public boolean isInventoryListDirty() { return isInventoryListDirty; } public void setInventoryListDirty(boolean inventoryListDirty) { isInventoryListDirty = inventoryListDirty; } public void doScroll(int scroll) { if (isLarge) { if (openMenuId != -1) { menus.get(openMenuId).doScroll(scroll); } } } public void onGuiClosed() { for (Menu menu : menus) { menu.onGuiClosed(); } } public Connection[] getConnections() { return connections; } @Override public boolean readData(ASMPacket packet) { int id = packet.readUnsignedByte(); if (id < networkSyncList.size()) { return networkSyncList.get(id).readData(packet); } else { switch (id - networkSyncList.size()) { case 0: int newX = packet.readShort(); int newY = packet.readShort(); if (packet.readBoolean()) { newX -= x; newY -= y; List<FlowComponent> connected = new ArrayList<FlowComponent>(); findCluster(connected, this, null); for (FlowComponent component : connected) { component.shiftLocation(newX, newY); component.shiftNodes(newX, newY); } } else { x = newX; y = newY; } break; case 1: int connectionId = packet.readByte(); if (packet.readBoolean()) { Connection connection = new Connection(this.id, connectionId, packet.readVarIntFromBuffer(), packet.readByte()); connection.setConnection(manager); } else { connections[connectionId].deleteConnection(manager); } break; case 2: connectionId = packet.readByte(); Connection connection = connections[connectionId]; int nodeId = Math.min(packet.readByte(), connection.nodes.size()); switch (packet.readByte()) { case 0: connection.nodes.remove(nodeId); break; case 1: connection.nodes.add(nodeId, new Point()); case 2: Point point = connection.nodes.get(nodeId); point.setX(packet.readShort()); point.setY(packet.readShort()); break; } break; case 3: int parentId = packet.readVarIntFromBuffer(); FlowComponent newParent = parentId == -1 ? null : manager.getFlowItem(parentId); moveComponents(this, newParent, packet.readBoolean()); break; } return false; } } private void sendLocationData(boolean moveConnected) { ASMPacket packet = PacketHandler.getComponentPacket(this); packet.writeByte(networkSyncList.size()); packet.writeShort(x); packet.writeShort(y); packet.writeBoolean(moveConnected); packet.sendServerPacket(); } public void sendConnectionNodeData(int connectionId, int nodeId, int action, int x, int y) { ASMPacket packet = getSyncPacket(); packet.writeByte(networkSyncList.size() + 2); packet.writeByte(connectionId); packet.writeByte(nodeId); packet.writeByte(action); if (action != 0) { packet.writeShort(x); packet.writeShort(y); } packet.sendServerPacket(); } public void sendNewParentData(FlowComponent parent, boolean shift) { ASMPacket packet = getSyncPacket(); packet.writeByte(networkSyncList.size() + 3); packet.writeVarIntToBuffer(parent == null ? -1 : parent.id); packet.writeBoolean(shift); packet.sendServerPacket(); } }