diff --git a/src/main/java/com/hbm/blocks/ModBlocks.java b/src/main/java/com/hbm/blocks/ModBlocks.java index b80aa0ac7..da38025a0 100644 --- a/src/main/java/com/hbm/blocks/ModBlocks.java +++ b/src/main/java/com/hbm/blocks/ModBlocks.java @@ -22,7 +22,8 @@ import com.hbm.blocks.network.*; import com.hbm.blocks.rail.*; import com.hbm.blocks.test.*; import com.hbm.blocks.turret.*; -import com.hbm.hrist.BlockConduit; +import com.hbm.hrist.BlockConduitBend; +import com.hbm.hrist.BlockConduitStraight; import com.hbm.items.block.*; import com.hbm.items.bomb.ItemPrototypeBlock; import com.hbm.items.special.ItemOreBlock; @@ -1238,6 +1239,7 @@ public class ModBlocks { public static Material materialGas = new MaterialGas(); public static Block conduit_straight; + public static Block conduit_bend; private static void initializeBlock() { @@ -2390,7 +2392,8 @@ public class ModBlocks { logic_block = new LogicBlock().setBlockName("logic_block").setBlockTextureName(RefStrings.MODID + ":logic_block"); - conduit_straight = new BlockConduit().setBlockName("conduit_straight").setBlockTextureName(RefStrings.MODID + ":block_steel"); + conduit_straight = new BlockConduitStraight().setBlockName("conduit_straight").setBlockTextureName(RefStrings.MODID + ":block_steel"); + conduit_bend = new BlockConduitBend().setBlockName("conduit_bend").setBlockTextureName(RefStrings.MODID + ":block_steel"); } private static void registerBlock() { @@ -3546,6 +3549,7 @@ public class ModBlocks { register(logic_block); register(conduit_straight); + register(conduit_bend); } private static void register(Block b) { diff --git a/src/main/java/com/hbm/hrist/BlockConduitBend.java b/src/main/java/com/hbm/hrist/BlockConduitBend.java new file mode 100644 index 000000000..98612ea12 --- /dev/null +++ b/src/main/java/com/hbm/hrist/BlockConduitBend.java @@ -0,0 +1,56 @@ +package com.hbm.hrist; + +import com.hbm.blocks.BlockDummyable; +import com.hbm.hrist.ConduitPiece.ConnectionDefinition; +import com.hbm.util.fauxpointtwelve.BlockPos; +import com.hbm.util.fauxpointtwelve.DirPos; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +// you can think of it like a pipeline +public class BlockConduitBend extends BlockDummyable { + + public BlockConduitBend() { + super(Material.ground); + } + + @Override public TileEntity createNewTileEntity(World world, int meta) { return null; } + @Override public int[] getDimensions() { return new int[] {0, 0, 4, 0, 4, 0}; } + @Override public int getOffset() { return 0; } + + @Override + public void onBlockAdded(World world, int x, int y, int z) { + super.onBlockAdded(world, x, y, z); + int meta = world.getBlockMetadata(x, y, z); + + if(meta >= 12) { + ConduitPiece piece = this.getPiece(world, x, y, z, meta); + ConduitSpace.pushPiece(world, piece, new BlockPos(x, y, z)); + } + } + + @Override + public void breakBlock(World world, int x, int y, int z, Block b, int meta) { + super.breakBlock(world, x, y, z, b, meta); + + if(meta >= 12) { + ConduitSpace.popPiece(world, new BlockPos(x, y, z)); + } + } + + public ConduitPiece getPiece(World world, int x, int y, int z, int meta) { + ForgeDirection dir = ForgeDirection.getOrientation(meta - 10); + ForgeDirection rot = dir.getRotation(ForgeDirection.UP); + DirPos d0 = new DirPos( + x + 0.5 + rot.offsetX * 0.5 + dir.offsetX * 0.5, y, + z + 0.5 + rot.offsetZ * 0.5 + dir.offsetZ * 0.5, dir); + DirPos d1 = new DirPos( + x + 0.5 + rot.offsetX * 4.5 - dir.offsetX * 3.5, y, + z + 0.5 + rot.offsetZ * 4.5 - dir.offsetZ * 3.5, rot); + return new ConduitPiece(new ConnectionDefinition(d0, d1)); + } +} diff --git a/src/main/java/com/hbm/hrist/BlockConduit.java b/src/main/java/com/hbm/hrist/BlockConduitStraight.java similarity index 95% rename from src/main/java/com/hbm/hrist/BlockConduit.java rename to src/main/java/com/hbm/hrist/BlockConduitStraight.java index 2c5380895..f1f9e0e61 100644 --- a/src/main/java/com/hbm/hrist/BlockConduit.java +++ b/src/main/java/com/hbm/hrist/BlockConduitStraight.java @@ -12,9 +12,9 @@ import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; // you can think of it like a pipeline -public class BlockConduit extends BlockDummyable { +public class BlockConduitStraight extends BlockDummyable { - public BlockConduit() { + public BlockConduitStraight() { super(Material.ground); } diff --git a/src/main/java/com/hbm/hrist/ConDbg.java b/src/main/java/com/hbm/hrist/ConDbg.java index e0548bd97..dcbe66074 100644 --- a/src/main/java/com/hbm/hrist/ConDbg.java +++ b/src/main/java/com/hbm/hrist/ConDbg.java @@ -2,6 +2,7 @@ package com.hbm.hrist; import java.util.Map.Entry; +import com.hbm.hrist.ConduitPiece.ConnectionDefinition; import com.hbm.hrist.ConduitSpace.ConduitWorld; import com.hbm.util.ParticleUtil; import com.hbm.util.fauxpointtwelve.BlockPos; @@ -10,25 +11,32 @@ import net.minecraft.world.World; /** Test and debugging tools */ public class ConDbg { - - public static void debugVisualsWorld(World world) { + + public static void debugUpdateWorld(World world) { ConduitWorld cWorld = ConduitSpace.worlds.get(world); if(cWorld == null) return; for(Entry entry : cWorld.pieces.entrySet()) { - BlockPos pos = entry.getValue().definitions[0].connectors[0]; - BlockPos nex = entry.getValue().definitions[0].connectors[1]; - - double x = pos.getX(); - double y = pos.getY() + 0.5; - double z = pos.getZ(); - double dx = nex.getX() - pos.getX(); - double dy = nex.getY() - pos.getY(); - double dz = nex.getZ() - pos.getZ(); - - ParticleUtil.spawnDroneLine(world, x, y, z, dx, dy, dz, 0xff0000, true); + for(ConnectionDefinition def : entry.getValue().definitions) { + ConduitLine line = def.getLine(); + if(line == null) continue; + + BlockPos pos = def.connectors[0]; + BlockPos nex = def.connectors[1]; + + double x = pos.getX(); + double y = pos.getY() + 0.5; + double z = pos.getZ(); + double dx = nex.getX() - pos.getX(); + double dy = nex.getY() - pos.getY(); + double dz = nex.getZ() - pos.getZ(); + + int color = line.hashCode() & 0xFFFFFF; + + ParticleUtil.spawnDroneLine(world, x, y, z, dx, dy, dz, color, true); + } } } } diff --git a/src/main/java/com/hbm/hrist/ConduitConnection.java b/src/main/java/com/hbm/hrist/ConduitConnection.java deleted file mode 100644 index 019985365..000000000 --- a/src/main/java/com/hbm/hrist/ConduitConnection.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.hbm.hrist; - -/** Generated out of multiple ConnectionDefinitions to form a straight segment, ends at a branch */ -public class ConduitConnection { - - protected boolean valid = true; - public ConduitConnection[] connectedTo = new ConduitConnection[2]; // a sausage always has two ends - public int stateKeepAlive; // unclear whether that's a good idea, since it requires the traveling object to be chunk loaded - public ConnectionStatus state = ConnectionStatus.OKAY; - - public boolean isValid() { return this.valid; } - public void invalidate() { this.valid = false; } - - public static enum ConnectionStatus { - OKAY, - BLOCKED - } -} diff --git a/src/main/java/com/hbm/hrist/ConduitLine.java b/src/main/java/com/hbm/hrist/ConduitLine.java new file mode 100644 index 000000000..905455658 --- /dev/null +++ b/src/main/java/com/hbm/hrist/ConduitLine.java @@ -0,0 +1,53 @@ +package com.hbm.hrist; + +import java.util.HashSet; +import java.util.Set; + +import com.hbm.hrist.ConduitPiece.ConnectionDefinition; + +/** Generated out of multiple ConnectionDefinitions to form a straight segment, ends at a branch */ +public class ConduitLine { + + protected boolean valid = true; + public LineEndpoint[] connectedTo = new LineEndpoint[2]; // a sausage always has two ends + public Set constructedFrom = new HashSet(); + public ConnectionStatus state = ConnectionStatus.ONLINE; + + public double cachedDistance = 0; + public boolean hasChanged = true; + + public void setChanged() { this.hasChanged = true; } + + public double getDistance() { + if(this.hasChanged) { + this.cachedDistance = 0; + for(ConnectionDefinition def : constructedFrom) this.cachedDistance += def.distance; + } + return this.cachedDistance; + } + + public boolean isValid() { return this.valid; } + public void invalidate() { this.valid = false; } + + public void destroy() { + for(ConnectionDefinition def : constructedFrom) { + if(def.getLine() == this) { + def.setLine(null); + } + } + this.invalidate(); + } + + public static enum ConnectionStatus { + ONLINE, + OFFLINE + } + + public static class LineEndpoint { + public ConduitLine[] connections; + + public LineEndpoint(ConduitLine... connections) { + this.connections = connections; + } + } +} diff --git a/src/main/java/com/hbm/hrist/ConduitPiece.java b/src/main/java/com/hbm/hrist/ConduitPiece.java index 9ce67dfb5..c96f7a255 100644 --- a/src/main/java/com/hbm/hrist/ConduitPiece.java +++ b/src/main/java/com/hbm/hrist/ConduitPiece.java @@ -6,13 +6,16 @@ import com.hbm.util.fauxpointtwelve.DirPos; public class ConduitPiece { protected boolean valid = true; + + // definitions and lines are always 1:1, definition of index 0 is associated with line of index 0 + // could have probably solved this with a new class, now that i think of it public ConnectionDefinition[] definitions; - public ConduitConnection[] liveConnections; + public ConduitLine[] liveConnections; public ConduitPiece(ConnectionDefinition... defs) { definitions = defs; for(ConnectionDefinition def : defs) def.withParent(this); - liveConnections = new ConduitConnection[defs.length]; + liveConnections = new ConduitLine[defs.length]; } public boolean isValid() { return this.valid; } @@ -20,17 +23,28 @@ public class ConduitPiece { // if a piece goes offline, the entire connection dies with it ad has to be recalculated out of the surviving pieces public void invalidate() { this.valid = false; - for(ConduitConnection con : this.liveConnections) { - if(con != null) con.invalidate(); + for(ConduitLine con : this.liveConnections) { + if(con != null) con.destroy(); } } + /** if it's a switch, then we don't want a line connection there */ + public boolean hasMultipleConnections(DirPos pos) { + int count = 0; + for(ConnectionDefinition def : definitions) { + if(def.connectors[0].equals(pos)) count++; + if(def.connectors[1].equals(pos)) count++; + if(count > 1) return true; + } + return false; + } + /** Describes each branch or connecting line on a piece, building block and not a working instance */ public static class ConnectionDefinition { public ConduitPiece parent; - public DirPos[] connectors = new DirPos[2]; - double distance; + public final DirPos[] connectors = new DirPos[2]; + public final double distance; public ConnectionDefinition(DirPos start, DirPos end) { this(start, end, start.distanceTo(end)); @@ -46,5 +60,20 @@ public class ConduitPiece { this.parent = parent; return this; } + + public ConduitLine getLine() { + if(parent == null) throw new IllegalStateException("Connection def has been initialized with no parent!"); // never happens + for(int i = 0; i < parent.definitions.length; i++) { + if(parent.definitions[i] == this) return parent.liveConnections[i]; + } + return null; + } + + public void setLine(ConduitLine line) { + if(parent == null) throw new IllegalStateException("Connection def has been initialized with no parent!"); // never happens + for(int i = 0; i < parent.definitions.length; i++) { + if(parent.definitions[i] == this) this.parent.liveConnections[i] = line; + } + } } } diff --git a/src/main/java/com/hbm/hrist/ConduitSpace.java b/src/main/java/com/hbm/hrist/ConduitSpace.java index 785b35444..4ae777d6f 100644 --- a/src/main/java/com/hbm/hrist/ConduitSpace.java +++ b/src/main/java/com/hbm/hrist/ConduitSpace.java @@ -1,7 +1,10 @@ package com.hbm.hrist; import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.Map; +import java.util.Set; import com.hbm.hrist.ConduitPiece.ConnectionDefinition; import com.hbm.util.fauxpointtwelve.BlockPos; @@ -29,12 +32,21 @@ public class ConduitSpace { cWorld.pop(cWorld.pieces.get(core), core); } + public static void updateWorld(World world) { + ConduitWorld cWorld = worlds.get(world); + if(cWorld == null) return; + cWorld.update(); + } + public static class ConduitWorld { /** Maps conduit core pos to the actual conduit piece logical unit, for access of the conduit blocks */ - public static Map pieces = new HashMap(); - /** Maps a connection pos to a conduit piece, used for calculating connections */ - public static Map connections = new HashMap(); + public Map pieces = new HashMap(); + /** Maps a connection pos to a conduit piece, used for calculating connections. + * One position can correspond to multiple connection defs, so we have to store the entire piece. */ + public Map connections = new HashMap(); + /** Set of all definitions not yet part of a line */ + public Set orphans = new LinkedHashSet(); public void push(ConduitPiece piece, BlockPos core) { pieces.put(core, piece); @@ -42,9 +54,12 @@ public class ConduitSpace { // for branches, there's some repetition in the keys, but we don't care about that // since this maps to the PIECE, not the CONNECTION for(ConnectionDefinition def : piece.definitions) { - pieces.put(def.connectors[0], piece); - pieces.put(def.connectors[1], piece); + connections.put(def.connectors[0], piece); + connections.put(def.connectors[1], piece); + orphans.add(def); } + + for(ConnectionDefinition con : piece.definitions) orphans.add(con); } public void pop(ConduitPiece piece, BlockPos core) { @@ -55,6 +70,63 @@ public class ConduitSpace { pieces.remove(def.connectors[0]); pieces.remove(def.connectors[1]); } + + for(ConnectionDefinition con : piece.definitions) orphans.remove(con); + + piece.invalidate(); + } + + public void update() { + + Iterator it = orphans.iterator(); + + while(it.hasNext()) { + ConnectionDefinition orphan = it.next(); + ConduitLine line = orphan.getLine(); + + for(DirPos pos : orphan.connectors) { + DirPos connection = pos.flip(); + ConduitPiece connectedPiece = connections.get(connection); + if(connectedPiece == null) continue; // if no piece is actually connected, skip + if(connectedPiece == orphan.parent) continue; // no self-fellating + if(connectedPiece.hasMultipleConnections(connection)) continue; // if this connection leads to a switch, skip + + for(ConnectionDefinition connectedDef : connectedPiece.definitions) { + ConduitLine connectedLine = connectedDef.getLine(); + if(connectedLine == null) continue; + + line = orphan.getLine(); + // if the current line is null + if(line == null) { + if(connectedDef.connectors[0].equals(connection) || connectedDef.connectors[1].equals(connection)) { + orphan.setLine(connectedLine); + } + // if not, merge + } else { + // larger one eats the smaller one for performance + ConduitLine larger = line.constructedFrom.size() > connectedLine.constructedFrom.size() ? line : connectedLine; + ConduitLine smaller = line.constructedFrom.size() > connectedLine.constructedFrom.size() ? connectedLine : line; + + larger.constructedFrom.addAll(smaller.constructedFrom); + for(ConnectionDefinition smallerDef : smaller.constructedFrom) { + smallerDef.setLine(larger); + } + smaller.constructedFrom.clear(); + larger.setChanged(); + smaller.invalidate(); + } + } + } + + if(orphan.getLine() == null) { + ConduitLine newLine = new ConduitLine(); + orphan.setLine(newLine); + newLine.constructedFrom.add(orphan); + newLine.setChanged(); + } + } + + orphans.clear(); } } } diff --git a/src/main/java/com/hbm/main/ModEventHandler.java b/src/main/java/com/hbm/main/ModEventHandler.java index cdab4aec4..f1b9acc09 100644 --- a/src/main/java/com/hbm/main/ModEventHandler.java +++ b/src/main/java/com/hbm/main/ModEventHandler.java @@ -25,6 +25,7 @@ import com.hbm.handler.BossSpawnHandler; import com.hbm.handler.EntityEffectHandler; import com.hbm.hazard.HazardSystem; import com.hbm.hrist.ConDbg; +import com.hbm.hrist.ConduitSpace; import com.hbm.interfaces.IBomb; import com.hbm.interfaces.Spaghetti; import com.hbm.inventory.recipes.loader.SerializableRecipe; @@ -611,9 +612,11 @@ public class ModEventHandler { } EntityRailCarBase.updateMotion(event.world); - + + // Connecton Update + ConduitSpace.updateWorld(event.world); // Connection Debug Tools - ConDbg.debugVisualsWorld(event.world); + ConDbg.debugUpdateWorld(event.world); } } diff --git a/src/main/java/com/hbm/util/fauxpointtwelve/DirPos.java b/src/main/java/com/hbm/util/fauxpointtwelve/DirPos.java index 1f93c6080..5486bb7b1 100644 --- a/src/main/java/com/hbm/util/fauxpointtwelve/DirPos.java +++ b/src/main/java/com/hbm/util/fauxpointtwelve/DirPos.java @@ -33,6 +33,41 @@ public class DirPos extends BlockPos { } } + public DirPos flip() { + return new DirPos(this.getX(), this.getY(), this.getZ(), this.getDir().getOpposite()); + } + + /** Useful for the opposing piece of a connector */ + public DirPos flipWithOffset() { + ForgeDirection dir = this.getDir(); + return new DirPos(this.getX() + dir.offsetX, this.getY() + dir.offsetY, this.getZ() + dir.offsetZ, dir.getOpposite()); + } + public ForgeDirection getDir() { return this.dir; } public BlockPos toPos() { return new BlockPos(x, y, z); } + + @Override + public int hashCode() { + return DimPos.getIdentity(this.getX(), this.getY(), this.getZ(), this.getDir().ordinal()); + } + + @Override + public boolean equals(Object toCompare) { + if(this == toCompare) { + return true; + } else if(!(toCompare instanceof BlockPos)) { + return false; + } else { + DirPos pos = (DirPos) toCompare; + if(this.getX() != pos.getX()) { + return false; + } else if(this.getY() != pos.getY()) { + return false; + } else if(this.getZ() != pos.getZ()) { + return false; + } else { + return this.getDir() == pos.getDir(); + } + } + } }