Skip to content

Commit 04088f4

Browse files
committed
More work on machine graph
1 parent 4dd7f3f commit 04088f4

File tree

10 files changed

+348
-9
lines changed

10 files changed

+348
-9
lines changed

build.gradle

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,7 @@ publishing {
262262
}
263263

264264
test {
265-
useJUnitPlatform()
266-
filter {
267-
exclude "com/robotgryphon/compactmachines/tests/minecraft/**"
265+
useJUnitPlatform {
266+
excludeTags "minecraft"
268267
}
269268
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.robotgryphon.compactmachines.data.graph;
2+
3+
import net.minecraft.util.math.ChunkPos;
4+
5+
import java.util.Objects;
6+
7+
/**
8+
* Represents the inside of a Compact Machine.
9+
*/
10+
public class CompactMachineInsideNode implements IMachineGraphNode {
11+
12+
private final ChunkPos pos;
13+
14+
public CompactMachineInsideNode(ChunkPos pos) {
15+
this.pos = pos;
16+
}
17+
18+
@Override
19+
public String getId() {
20+
return getIdFor(this.pos);
21+
}
22+
23+
@Override
24+
public String label() {
25+
return String.format("Compact Machine {%s,%s}", pos.x, pos.z);
26+
}
27+
28+
public static String getIdFor(ChunkPos pos) {
29+
long v = pos.toLong();
30+
return "internal_" + (v < 0 ? "N" : "") + Math.abs(v);
31+
}
32+
33+
@Override
34+
public boolean equals(Object o) {
35+
if (this == o) return true;
36+
if (o == null || getClass() != o.getClass()) return false;
37+
CompactMachineInsideNode that = (CompactMachineInsideNode) o;
38+
return pos.equals(that.pos);
39+
}
40+
41+
@Override
42+
public int hashCode() {
43+
return Objects.hash(pos);
44+
}
45+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.robotgryphon.compactmachines.data.graph;
2+
3+
import com.google.common.graph.MutableGraph;
4+
import com.robotgryphon.compactmachines.teleportation.DimensionalPosition;
5+
6+
import java.util.Objects;
7+
8+
/**
9+
* Represents a machine's external point. This can be either inside a machine or in a dimension somewhere.
10+
*/
11+
public class CompactMachineNode implements IMachineGraphNode {
12+
public boolean isConnected;
13+
private int machineId;
14+
private IMachineGraphNode linkedTo;
15+
public MachineExternalLocation location;
16+
public DimensionalPosition position;
17+
private MutableGraph<IMachineGraphNode> graph;
18+
19+
public CompactMachineNode(MutableGraph<IMachineGraphNode> graph, int machine) {
20+
this.graph = graph;
21+
this.machineId = machine;
22+
this.isConnected = false;
23+
}
24+
25+
public void connectTo(IMachineGraphNode newInside) {
26+
if (this.linkedTo != null) {
27+
graph.removeEdge(this, linkedTo);
28+
this.isConnected = false;
29+
}
30+
31+
this.linkedTo = newInside;
32+
this.isConnected = true;
33+
graph.putEdge(this, linkedTo);
34+
}
35+
36+
@Override
37+
public String label() {
38+
return "Compact Machine #" + machineId;
39+
}
40+
41+
@Override
42+
public String getId() {
43+
return "machine" + machineId;
44+
}
45+
46+
@Override
47+
public boolean equals(Object o) {
48+
if (this == o) return true;
49+
if (o == null || getClass() != o.getClass()) return false;
50+
CompactMachineNode that = (CompactMachineNode) o;
51+
return machineId == that.machineId;
52+
}
53+
54+
@Override
55+
public int hashCode() {
56+
return Objects.hash(machineId);
57+
}
58+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.robotgryphon.compactmachines.data.graph;
2+
3+
public interface IMachineGraphNode {
4+
String label();
5+
String getId();
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.robotgryphon.compactmachines.data.graph;
2+
3+
public enum MachineExternalLocation {
4+
INSIDE_MACHINE,
5+
EXTERNAL_DIMENSION
6+
}

src/main/java/com/robotgryphon/compactmachines/data/player/theory.txt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ Machines A,B,C,D
55
machine locations (external)
66
======================================================================
77
A (01): 00, 00, 00 @ overworld
8-
A (05): 76, 40, 76 @ compact_world
9-
A (06): 51, 40, 51 @ compact_world
10-
B (02): 26, 40, 26 @ compact_world
11-
C (03): 51, 40, 51 @ compact_world
8+
B (02): 26, 40, 26 @ compact_world (inside A)
9+
C (03): 51, 40, 51 @ compact_world (inside B)
1210
D (04): 10, 10, 10 @ overworld
11+
A (05): 76, 40, 76 @ compact_world (inside D)
12+
A (06): 51, 40, 51 @ compact_world (inside C)
1313

1414
======================================================================
1515
Tree View of machine nesting
@@ -53,4 +53,8 @@ tail DimPos { 79, 40, 76 @ compact_world } (entered A from D)
5353
head DimPos { 10, 00, 10 @ overworld } (entered D)
5454

5555
Player P is represented as "inside" A, B, C, and D.
56-
B and C are included because A is inside C, and the tree was traversed upwards.
56+
B and C are included because A is inside C, and the tree was traversed upwards.
57+
58+
59+
60+

src/main/java/com/robotgryphon/compactmachines/datagen/RecipeGenerator.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ protected void buildShapelessRecipes(Consumer<IFinishedRecipe> consumer) {
4747

4848
private void addTunnelRecipes(Consumer<IFinishedRecipe> consumer) {
4949
// todo
50+
51+
ShapelessRecipeBuilder.shapeless()
52+
5053
}
5154

5255
private void addMachineRecipes(Consumer<IFinishedRecipe> consumer) {

src/main/java/com/robotgryphon/compactmachines/util/CompactMachineUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public static void teleportInto(ServerPlayerEntity serverPlayer, BlockPos machin
9494

9595
try {
9696
// Mark the player as inside the machine, set external spawn, and yeet
97-
CompactMachinePlayerUtil.addPlayerToMachine(serverPlayer, machinePos, tile.machineId);
97+
CompactMachinePlayerUtil.addPlayerToMachine(serverPlayer, machinePos);
9898
} catch (Exception ex) {
9999
CompactMachines.LOGGER.error(ex);
100100
}
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
package com.robotgryphon.compactmachines.tests;
2+
3+
import com.google.common.graph.*;
4+
import com.robotgryphon.compactmachines.CompactMachines;
5+
import com.robotgryphon.compactmachines.data.graph.CompactMachineInsideNode;
6+
import com.robotgryphon.compactmachines.data.graph.CompactMachineNode;
7+
import com.robotgryphon.compactmachines.data.graph.IMachineGraphNode;
8+
import com.robotgryphon.compactmachines.data.graph.MachineExternalLocation;
9+
import com.robotgryphon.compactmachines.util.MathUtil;
10+
import net.minecraft.util.math.ChunkPos;
11+
import net.minecraft.util.math.vector.Vector3i;
12+
import org.junit.jupiter.api.Assertions;
13+
import org.junit.jupiter.api.Test;
14+
15+
import java.io.FileNotFoundException;
16+
import java.io.PrintWriter;
17+
import java.util.*;
18+
import java.util.stream.Collectors;
19+
20+
@SuppressWarnings("UnstableApiUsage")
21+
public class GraphTests {
22+
23+
@Test
24+
void canCreateBasicGraph() {
25+
MutableGraph<IMachineGraphNode> g = GraphBuilder
26+
.directed()
27+
.nodeOrder(ElementOrder.sorted(Comparator.comparing(IMachineGraphNode::getId)))
28+
.build();
29+
30+
HashMap<String, IMachineGraphNode> lookup = new HashMap<>();
31+
32+
generateData(g, lookup);
33+
34+
String w = write(g);
35+
36+
try (PrintWriter pw = new PrintWriter("graph.dot")) {
37+
pw.println(w);
38+
} catch (FileNotFoundException e) {
39+
e.printStackTrace();
40+
}
41+
42+
Assertions.assertTrue(true);
43+
}
44+
45+
private void generateData(MutableGraph<IMachineGraphNode> g, HashMap<String, IMachineGraphNode> lookup) {
46+
Random r = new Random();
47+
MachineExternalLocation[] values = MachineExternalLocation.values();
48+
int numInsides = 0;
49+
int numOutsides = 0;
50+
51+
Set<IMachineGraphNode> disconnected = new HashSet<>();
52+
List<CompactMachineNode> externals = new ArrayList<>();
53+
List<CompactMachineInsideNode> internals = new ArrayList<>();
54+
55+
// Seed a couple of machines and insides so they're always there
56+
for(int i = 0; i < 10; i++) {
57+
ChunkPos machineChunk = getMachineChunkPos(numInsides + 1);
58+
CompactMachineNode extern = createMachineExternalNode(g, lookup, i);
59+
CompactMachineInsideNode intern = createMachineInternalNode(g, lookup, machineChunk);
60+
61+
externals.add(extern);
62+
internals.add(intern);
63+
64+
extern.connectTo(intern);
65+
numOutsides++;
66+
numInsides++;
67+
}
68+
69+
for(int i = 0; i < 50; i++) {
70+
71+
if(r.nextBoolean()) {
72+
// Creating the outside of a machine
73+
MachineExternalLocation loc = values[r.nextInt(values.length)];
74+
75+
CompactMachineNode machine = createMachineExternalNode(g, lookup, numOutsides + 1);
76+
externals.add(machine);
77+
78+
switch (loc) {
79+
case EXTERNAL_DIMENSION:
80+
int randomMachineInsideE = r.nextInt(internals.size());
81+
CompactMachineInsideNode miE = internals.get(randomMachineInsideE);
82+
machine.connectTo(miE);
83+
84+
// try to remove from disconnected if it exists there
85+
disconnected.remove(miE);
86+
break;
87+
88+
case INSIDE_MACHINE:
89+
int randomMachineInsideI = r.nextInt(internals.size());
90+
CompactMachineInsideNode miI = internals.get(randomMachineInsideI);
91+
92+
// Put the machine inside a randomly chosen existing machine
93+
g.putEdge(miI, machine);
94+
95+
boolean connectToAnother = r.nextBoolean();
96+
if(connectToAnother) {
97+
System.out.println("connect");
98+
int randomMachine = r.nextInt(internals.size());
99+
CompactMachineInsideNode in = internals.get(randomMachine);
100+
machine.connectTo(in);
101+
}
102+
break;
103+
}
104+
105+
numOutsides++;
106+
} else {
107+
// Creating the inside of a machine
108+
ChunkPos machineChunk= getMachineChunkPos(numInsides + 1);
109+
CompactMachineInsideNode mi = createMachineInternalNode(g, lookup, machineChunk);
110+
disconnected.add(mi);
111+
numInsides++;
112+
}
113+
}
114+
115+
if(!disconnected.isEmpty()) {
116+
for (IMachineGraphNode di : disconnected) {
117+
CompactMachineNode machine = createMachineExternalNode(g, lookup, numOutsides + 1);
118+
machine.connectTo(di);
119+
numOutsides++;
120+
}
121+
}
122+
123+
disconnected.clear();
124+
}
125+
126+
private ChunkPos getMachineChunkPos(int i) {
127+
Vector3i pos = MathUtil.getRegionPositionByIndex(i);
128+
ChunkPos machineChunk = new ChunkPos(pos.getX(), pos.getZ());
129+
return machineChunk;
130+
}
131+
132+
private CompactMachineInsideNode createMachineInternalNode(MutableGraph<IMachineGraphNode> g, HashMap<String, IMachineGraphNode> lookup, ChunkPos id) {
133+
CompactMachineInsideNode intern = new CompactMachineInsideNode(id);
134+
g.addNode(intern);
135+
lookup.put(intern.getId(), intern);
136+
return intern;
137+
}
138+
139+
private CompactMachineNode createMachineExternalNode(MutableGraph<IMachineGraphNode> g, HashMap<String, IMachineGraphNode> lookup, int id) {
140+
CompactMachineNode extern = new CompactMachineNode(g, id);
141+
g.addNode(extern);
142+
lookup.put(extern.getId(), extern);
143+
return extern;
144+
}
145+
146+
public static String write(final Graph<IMachineGraphNode> graph) {
147+
StringBuilder sb = new StringBuilder();
148+
sb
149+
.append("strict digraph G {")
150+
.append(System.lineSeparator())
151+
.append("\tlayout = fdp;").append(System.lineSeparator())
152+
.append("\tnode [shape=square,style=filled,color=lightgray];").append(System.lineSeparator());
153+
154+
Set<CompactMachineNode> topLevelMachines = graph.nodes().stream()
155+
.filter(n -> n instanceof CompactMachineNode)
156+
.map(n -> (CompactMachineNode) n)
157+
.filter(n -> graph.inDegree(n) == 0)
158+
.collect(Collectors.toSet());
159+
160+
for (CompactMachineNode n : topLevelMachines)
161+
outputExternalNode(sb, n);
162+
163+
graph.nodes().stream()
164+
.filter(n -> n instanceof CompactMachineInsideNode)
165+
.map(n -> (CompactMachineInsideNode) n)
166+
.forEach(n -> {
167+
outputMachineInside(graph, sb, n);
168+
});
169+
170+
sb.append("}");
171+
return sb.toString();
172+
}
173+
174+
private static void outputMachineInside(Graph<IMachineGraphNode> graph, StringBuilder sb, IMachineGraphNode inside) {
175+
if (inside instanceof CompactMachineInsideNode) {
176+
CompactMachineInsideNode min = (CompactMachineInsideNode) inside;
177+
178+
String insideClusterName = "cluster_" + min.getId();
179+
graph.predecessors(min).forEach(incoming -> {
180+
sb.append("\t")
181+
.append(incoming.getId())
182+
.append("->")
183+
.append(insideClusterName)
184+
.append(System.lineSeparator());
185+
});
186+
187+
sb.append("\t")
188+
.append("subgraph ").append(insideClusterName)
189+
.append(" {")
190+
.append(System.lineSeparator());
191+
192+
sb.append("\t\t")
193+
.append(String.format("graph [label=\"%s\",style=filled,color=cadetblue]", min.label()))
194+
.append(System.lineSeparator());
195+
196+
graph.successors(min).forEach(insideNode -> {
197+
if(insideNode instanceof CompactMachineNode) {
198+
CompactMachineNode men = (CompactMachineNode) insideNode;
199+
outputExternalNode(sb, men);
200+
}
201+
});
202+
203+
sb.append("\t")
204+
.append("}").append(System.lineSeparator())
205+
.append(System.lineSeparator());
206+
}
207+
}
208+
209+
private static void outputExternalNode(StringBuilder sb, CompactMachineNode men) {
210+
boolean connected = men.isConnected;
211+
sb.append("\t")
212+
.append(men.getId())
213+
.append(String.format(" [label=\"%s\",style=filled,color=%s]", men.label(), men.isConnected ? "lightgray" : "palevioletred1"))
214+
.append(System.lineSeparator());
215+
}
216+
}

0 commit comments

Comments
 (0)