├── .idea
├── .name
├── vcs.xml
├── .gitignore
├── encodings.xml
├── modules.xml
├── hotswap_agent.xml
├── misc.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── compiler.xml
├── jarRepositories.xml
└── uiDesigner.xml
├── src
├── META-INF
│ └── MANIFEST.MF
└── main
│ ├── resources
│ ├── example.png
│ ├── configexample.png
│ ├── net
│ │ └── ryanland
│ │ │ └── dfschematics
│ │ │ ├── logo.png
│ │ │ └── fxml
│ │ │ ├── update.fxml
│ │ │ ├── main.fxml
│ │ │ └── configuration.fxml
│ └── project.properties
│ └── java
│ ├── net
│ └── ryanland
│ │ └── dfschematics
│ │ ├── Main.java
│ │ ├── schematic
│ │ ├── special
│ │ │ ├── Head.java
│ │ │ ├── TrackedBlocks.java
│ │ │ ├── TrackedBlock.java
│ │ │ └── Sign.java
│ │ ├── StructureContainer.java
│ │ ├── StructurePart.java
│ │ ├── TemplateFactory.java
│ │ ├── DFSchematic.java
│ │ └── LitematicConverter.java
│ │ ├── df
│ │ ├── code
│ │ │ ├── SetVariable.java
│ │ │ ├── CodeBlock.java
│ │ │ ├── Tag.java
│ │ │ ├── Function.java
│ │ │ ├── SetVariableCreateList.java
│ │ │ ├── SetVariableAppendValue.java
│ │ │ ├── ChestCodeBlock.java
│ │ │ └── CodeLine.java
│ │ ├── value
│ │ │ ├── Scope.java
│ │ │ ├── Value.java
│ │ │ ├── Item.java
│ │ │ ├── Str.java
│ │ │ ├── Num.java
│ │ │ ├── Vector.java
│ │ │ ├── Variable.java
│ │ │ └── Location.java
│ │ └── api
│ │ │ ├── WSClient.java
│ │ │ ├── API.java
│ │ │ ├── RecodeItemAPI.java
│ │ │ └── CodeClientAPI.java
│ │ ├── DFSchematics.java
│ │ ├── fxml
│ │ ├── UpdateCheckController.java
│ │ ├── ConfigController.java
│ │ └── MainController.java
│ │ └── UpdateChecker.java
│ └── module-info.java
├── .gitignore
├── README.md
└── pom.xml
/.idea/.name:
--------------------------------------------------------------------------------
1 | DFSchematics
--------------------------------------------------------------------------------
/src/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Main-Class: net.ryanland.dfschematics.DFSchematics
3 |
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | out
3 | DFSchematics.exe
4 | DFSchematics.iml
5 | dependency-reduced-pom.xml
6 | launch4j.log
--------------------------------------------------------------------------------
/src/main/resources/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RyanLandDev/DFSchematics/HEAD/src/main/resources/example.png
--------------------------------------------------------------------------------
/src/main/resources/configexample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RyanLandDev/DFSchematics/HEAD/src/main/resources/configexample.png
--------------------------------------------------------------------------------
/src/main/resources/net/ryanland/dfschematics/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RyanLandDev/DFSchematics/HEAD/src/main/resources/net/ryanland/dfschematics/logo.png
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/Main.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics;
2 |
3 | public class Main {
4 |
5 | public static void main(String[] args) {
6 | DFSchematics.main(args);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/schematic/special/Head.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.schematic.special;
2 |
3 | import net.sandrohc.schematic4j.schematic.types.SchematicBlockPos;
4 |
5 | public record Head(SchematicBlockPos pos, String texture) {
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/code/SetVariable.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.code;
2 |
3 | public abstract class SetVariable implements ChestCodeBlock {
4 |
5 | @Override
6 | public String getBlock() {
7 | return "set_var";
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 | # Other
10 | discord.xml
11 | dbnavigator.xml
12 | runConfigurations.xml
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/hotswap_agent.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/value/Scope.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.value;
2 |
3 | public enum Scope {
4 |
5 | LOCAL("local"),
6 | GAME("unsaved"),
7 | SAVED("saved"),
8 | LINE("line")
9 | ;
10 |
11 | private String id;
12 |
13 | Scope(String id) {
14 | this.id = id;
15 | }
16 |
17 | public String getId() {
18 | return id;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/code/CodeBlock.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.code;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public interface CodeBlock {
6 |
7 | String getBlock();
8 |
9 | String getAction();
10 |
11 | int getWeight();
12 |
13 | default JsonObject toJson() {
14 | JsonObject json = new JsonObject();
15 | json.addProperty("id", "block");
16 | json.addProperty("block", getBlock());
17 | json.addProperty("action", getAction());
18 | return json;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/value/Value.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.value;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public interface Value {
6 |
7 | String getType();
8 |
9 | JsonObject getData();
10 |
11 | default JsonObject toJson(int slot) {
12 | JsonObject data = new JsonObject();
13 | data.addProperty("id", getType());
14 | data.add("data", getData());
15 |
16 | JsonObject json = new JsonObject();
17 | json.add("item", data);
18 | json.addProperty("slot", slot);
19 | return json;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/value/Item.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.value;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public interface Item extends Value {
6 |
7 | @Override
8 | default String getType() {
9 | return "item";
10 | }
11 |
12 | @Override
13 | default JsonObject getData() {
14 | JsonObject json = new JsonObject();
15 | json.addProperty("item", getItemNBT());
16 | return json;
17 | }
18 |
19 | /**
20 | * Returns a JSON String representing the item's NBT data.
21 | */
22 | String getItemNBT();
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/value/Str.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.value;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public class Str implements Value {
6 |
7 | private final String value;
8 |
9 | public Str(String value) {
10 | this.value = value;
11 | }
12 |
13 | public String getValue() {
14 | return value;
15 | }
16 |
17 | @Override
18 | public String getType() {
19 | return "txt";
20 | }
21 |
22 | @Override
23 | public JsonObject getData() {
24 | JsonObject json = new JsonObject();
25 | json.addProperty("name", value);
26 | return json;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/api/WSClient.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.api;
2 |
3 | import org.java_websocket.client.WebSocketClient;
4 | import org.java_websocket.handshake.ServerHandshake;
5 |
6 | import java.net.URI;
7 |
8 | //Todo better close/error handling?
9 | public class WSClient extends WebSocketClient {
10 |
11 | public WSClient(URI serverUri) {
12 | super(serverUri);
13 | }
14 |
15 | @Override
16 | public void onMessage(String s) {}
17 |
18 | @Override
19 | public void onOpen(ServerHandshake serverHandshake) {}
20 |
21 | @Override
22 | public void onClose(int i, String s, boolean b) {}
23 |
24 | @Override
25 | public void onError(Exception e) {}
26 | }
--------------------------------------------------------------------------------
/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 | module net.ryanland.dfschematics {
2 | requires javafx.controls;
3 | requires javafx.fxml;
4 | requires com.google.gson;
5 | requires org.slf4j;
6 | requires org.java_websocket;
7 | requires schematic4j;
8 | requires net.kyori.adventure;
9 | requires net.kyori.adventure.text.serializer.gson;
10 | requires net.kyori.adventure.text.serializer.legacy;
11 | requires org.jetbrains.annotations;
12 | requires java.logging;
13 | requires jo.nbt;
14 | requires static lombok;
15 |
16 | opens net.ryanland.dfschematics to javafx.fxml;
17 | exports net.ryanland.dfschematics;
18 | exports net.ryanland.dfschematics.fxml;
19 | opens net.ryanland.dfschematics.fxml to javafx.fxml;
20 | }
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/value/Num.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.value;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public class Num implements Value {
6 |
7 | private final String value;
8 |
9 | public Num(String value) {
10 | this.value = value;
11 | }
12 |
13 | public Num(float value) {
14 | this.value = String.valueOf(value).replaceAll("\\.0+$", "");// optionally remove .00 at the end
15 | }
16 |
17 | public String getValue() {
18 | return value;
19 | }
20 |
21 | @Override
22 | public String getType() {
23 | return "num";
24 | }
25 |
26 | @Override
27 | public JsonObject getData() {
28 | JsonObject json = new JsonObject();
29 | json.addProperty("name", value);
30 | return json;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/code/Tag.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.code;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public record Tag(String name, String option) {
6 |
7 | public JsonObject toJson(String block, String action, int slot) {
8 | if (block.equals("func")) action = "dynamic";
9 |
10 | JsonObject data = new JsonObject();
11 | data.addProperty("option", option);
12 | data.addProperty("tag", name);
13 | data.addProperty("action", action);
14 | data.addProperty("block", block);
15 |
16 | JsonObject item = new JsonObject();
17 | item.addProperty("id", "bl_tag");
18 | item.add("data", data);
19 |
20 | JsonObject json = new JsonObject();
21 | json.add("item", item);
22 | json.addProperty("slot", slot);
23 | return json;
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/schematic/special/TrackedBlocks.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.schematic.special;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class TrackedBlocks {
7 |
8 | private final List blocks = new ArrayList<>();
9 | private double[] offset = new double[3];
10 |
11 | public List getBlocks() {
12 | return blocks;
13 | }
14 |
15 | public void add(TrackedBlock block) {
16 | blocks.add(block);
17 | }
18 |
19 | public void remove(TrackedBlock block) {
20 | blocks.remove(block);
21 | }
22 |
23 | public void reset() {
24 | for (TrackedBlock block : blocks) block.getLocations().clear();
25 | }
26 |
27 | public double[] getOffset() {
28 | return offset;
29 | }
30 |
31 | public void setOffset(int index, double offset) {
32 | this.offset[index] = offset;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/value/Vector.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.value;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public class Vector implements Value {
6 |
7 | private final float x;
8 | private final float y;
9 | private final float z;
10 |
11 | public Vector(float x, float y, float z) {
12 | this.x = x;
13 | this.y = y;
14 | this.z = z;
15 | }
16 |
17 | public float getX() {
18 | return x;
19 | }
20 |
21 | public float getY() {
22 | return y;
23 | }
24 |
25 | public float getZ() {
26 | return z;
27 | }
28 |
29 | @Override
30 | public String getType() {
31 | return "vec";
32 | }
33 |
34 | @Override
35 | public JsonObject getData() {
36 | JsonObject json = new JsonObject();
37 | json.addProperty("x", x);
38 | json.addProperty("y", y);
39 | json.addProperty("z", z);
40 | return json;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/code/Function.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.code;
2 |
3 | import com.google.gson.JsonObject;
4 | import net.ryanland.dfschematics.df.value.Value;
5 |
6 | import java.util.List;
7 |
8 | public class Function implements ChestCodeBlock {
9 |
10 | private final String name;
11 |
12 | public Function(String name) {
13 | this.name = name;
14 | }
15 |
16 | public String getName() {
17 | return name;
18 | }
19 |
20 | @Override
21 | public List getParameters() {
22 | return null;
23 | }
24 |
25 | @Override
26 | public List getTags() {
27 | return List.of(new Tag("Is Hidden", "False"));
28 | }
29 |
30 | @Override
31 | public String getBlock() {
32 | return "func";
33 | }
34 |
35 | @Override
36 | public String getAction() {
37 | return null;
38 | }
39 |
40 | @Override
41 | public int getWeight() {
42 | return 0;
43 | }
44 |
45 | @Override
46 | public JsonObject toJson() {
47 | JsonObject json = ChestCodeBlock.super.toJson();
48 | json.remove("action");
49 | json.addProperty("data", getName());
50 | return json;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/code/SetVariableCreateList.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.code;
2 |
3 | import net.ryanland.dfschematics.df.value.Value;
4 | import net.ryanland.dfschematics.df.value.Variable;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class SetVariableCreateList extends SetVariable {
10 |
11 | private final Variable variable;
12 | private final List values;
13 |
14 | public SetVariableCreateList(Variable variable, List extends Value> values) {
15 | this.variable = variable;
16 | this.values = (List) values;
17 | }
18 |
19 | @Override
20 | public List getParameters() {
21 | List parameters = new ArrayList<>();
22 | parameters.add(variable);
23 | parameters.addAll(values);
24 | return parameters;
25 | }
26 |
27 | @Override
28 | public List getTags() {
29 | return null;
30 | }
31 |
32 | @Override
33 | public String getAction() {
34 | return "CreateList";
35 | }
36 |
37 | @Override
38 | public int getWeight() {
39 | if (getParameters().get(1).getType().equals("item")) return 1;// block entities
40 | return getParameters().size();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/code/SetVariableAppendValue.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.code;
2 |
3 | import net.ryanland.dfschematics.df.value.Value;
4 | import net.ryanland.dfschematics.df.value.Variable;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class SetVariableAppendValue extends SetVariable {
10 |
11 | private final Variable variable;
12 | private final List values;
13 |
14 | public SetVariableAppendValue(Variable variable, List extends Value> values) {
15 | this.variable = variable;
16 | this.values = (List) values;
17 | }
18 |
19 | @Override
20 | public List getParameters() {
21 | List parameters = new ArrayList<>();
22 | parameters.add(variable);
23 | parameters.addAll(values);
24 | return parameters;
25 | }
26 |
27 | @Override
28 | public List getTags() {
29 | return null;
30 | }
31 |
32 | @Override
33 | public String getAction() {
34 | return "AppendValue";
35 | }
36 |
37 | @Override
38 | public int getWeight() {
39 | if (getParameters().get(1).getType().equals("item")) return 1;// block entities
40 | return getParameters().size();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/code/ChestCodeBlock.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.code;
2 |
3 | import com.google.gson.JsonArray;
4 | import com.google.gson.JsonObject;
5 | import net.ryanland.dfschematics.df.value.Value;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Represents a code block with a chest (can have parameters + tags)
11 | */
12 | public interface ChestCodeBlock extends CodeBlock {
13 |
14 | List getParameters();
15 |
16 | List getTags();
17 |
18 | @Override
19 | default JsonObject toJson() {
20 | JsonObject json = CodeBlock.super.toJson();
21 | JsonObject args = new JsonObject();
22 | JsonArray items = new JsonArray();
23 |
24 | if (getParameters() != null) {
25 | int i = 0;
26 | for (Value parameter : getParameters()) {
27 | items.add(parameter.toJson(i));
28 | i++;
29 | }
30 | }
31 | if (getTags() != null) {
32 | int i = 26;
33 | for (Tag tag : getTags()) {
34 | items.add(tag.toJson(getBlock(), getAction(), i));
35 | i--;
36 | }
37 | }
38 |
39 | args.add("items", items);
40 | json.add("args", args);
41 | return json;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/value/Variable.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.value;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public class Variable/**/ implements Value {
6 |
7 | private final String name;
8 | private final Scope scope;
9 |
10 | /**
11 | * Creates a variable with {@link Scope#LOCAL}
12 | * @param name The variable name
13 | */
14 | public Variable(String name) {
15 | this(name, Scope.LOCAL);
16 | }
17 |
18 | /**
19 | * Creates a variable
20 | * @param name The variable name
21 | * @param scope The variable scope
22 | */
23 | public Variable(String name, Scope scope) {
24 | this.name = name;
25 | this.scope = scope;
26 | }
27 |
28 | public String getName() {
29 | return name;
30 | }
31 |
32 | public Scope getScope() {
33 | return scope;
34 | }
35 |
36 | @Override
37 | public String getType() {
38 | return "var";
39 | }
40 |
41 | @Override
42 | public JsonObject getData() {
43 | JsonObject json = new JsonObject();
44 | json.addProperty("name", name);
45 | json.addProperty("scope", scope.getId());
46 | return json;
47 | }
48 |
49 | @Override
50 | public boolean equals(Object obj) {
51 | return getName().equals(((Variable) obj).getName()) &&
52 | getScope().equals(((Variable) obj).getScope());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/resources/net/ryanland/dfschematics/fxml/update.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
20 |
28 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/schematic/special/TrackedBlock.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.schematic.special;
2 |
3 | import javafx.scene.image.ImageView;
4 | import net.ryanland.dfschematics.df.value.Location;
5 | import net.ryanland.dfschematics.df.value.Variable;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public final class TrackedBlock {
11 |
12 | private final Variable variable;
13 | private final String material;
14 | private final boolean remove;
15 | private final ImageView icon;
16 | private final List locations = new ArrayList<>();
17 |
18 | public TrackedBlock(Variable variable, String material, boolean remove) {
19 | this.variable = variable;
20 | this.material = material;
21 | this.remove = remove;
22 | this.icon = null;//new ImageView("https://mcapi.marveldc.me/item/"+material+"?width=20&height=20");
23 | }
24 |
25 | public Variable getVariable() {
26 | return variable;
27 | }
28 |
29 | public String getMaterial() {
30 | return material;
31 | }
32 |
33 | public boolean isRemoved() {
34 | return remove;
35 | }
36 |
37 | public ImageView getIcon() {
38 | return icon;
39 | }
40 |
41 | public List getLocations() {
42 | return locations;
43 | }
44 |
45 | public void addLocation(Location location) {
46 | locations.add(location);
47 | }
48 |
49 | public int getOccurrences() {
50 | return locations.size();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/schematic/StructureContainer.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.schematic;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class StructureContainer {
7 |
8 | private final List palette = new ArrayList<>();
9 | private final List parts = new ArrayList<>();
10 |
11 | public List getPalette() {
12 | return palette;
13 | }
14 |
15 | public void addToPalette(String material) {
16 | material = material.replace("minecraft:", "");
17 | if (!material.equals("air") && !palette.contains(material)) palette.add(material);
18 | }
19 |
20 | public int indexOf(String material) {
21 | if (material.equals("air")) return -1;
22 | return palette.indexOf(material);
23 | }
24 |
25 | public List getParts() {
26 | return parts;
27 | }
28 |
29 | private StructurePart partInProgress = null;
30 |
31 | public void addBlock(String material) {
32 | material = material.replace("minecraft:", "");
33 |
34 | if (partInProgress != null && partInProgress.getBlockIndex() != indexOf(material)) {
35 | finalizePart();
36 | }
37 | if (partInProgress == null) {
38 | partInProgress = new StructurePart(indexOf(material), 0);
39 | }
40 |
41 | partInProgress.increaseAmount();
42 | }
43 |
44 | public void finalizePart() {
45 | addPart(partInProgress);
46 | partInProgress = null;
47 | }
48 |
49 | public void addPart(StructurePart part) {
50 | parts.add(part);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/schematic/StructurePart.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.schematic;
2 |
3 | public final class StructurePart {
4 |
5 | private final int blockIndex;//-1 equals air
6 | private int amount;
7 |
8 | public StructurePart(int blockIndex, int amount) {
9 | this.blockIndex = blockIndex;
10 | this.amount = amount;
11 | }
12 |
13 | public int getBlockIndex() {
14 | return blockIndex;
15 | }
16 |
17 | public int getAmount() {
18 | return amount;
19 | }
20 |
21 | public void setAmount(int amount) {
22 | this.amount = amount;
23 | }
24 |
25 | public void increaseAmount() {
26 | amount++;
27 | }
28 |
29 | @Override
30 | public String toString() {
31 | return "StructurePart[" +
32 | "blockIndex=" + blockIndex + ", " +
33 | "amount=" + amount + ']';
34 | }
35 |
36 | private static final String[] compressChars;
37 | static {
38 | compressChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#|%&+/<>?@()-=*,:;[]^_`{}~".split("");
39 | }
40 |
41 | public String getText() {
42 | if (blockIndex == -1) return String.valueOf(amount);//air
43 |
44 | int length = compressChars.length; // 80, index 0-79
45 |
46 | int char1Index = (int) Math.floor(blockIndex / length) - 1;
47 | String char1;
48 | if (char1Index == -1) char1 = "";
49 | else char1 = compressChars[char1Index];
50 |
51 | String char2 = compressChars[blockIndex % length];
52 |
53 | return char1 + char2 + (amount == 1 ? "" : amount);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/value/Location.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.value;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public class Location implements Value {
6 |
7 | private final float x;
8 | private final float y;
9 | private final float z;
10 | private final float pitch;
11 | private final float yaw;
12 |
13 | public Location(float x, float y, float z) {
14 | this(x, y, z, 0, 0);
15 | }
16 |
17 | public Location(float x, float y, float z, float pitch, float yaw) {
18 | this.x = x;
19 | this.y = y;
20 | this.z = z;
21 | this.pitch = pitch;
22 | this.yaw = yaw;
23 | }
24 |
25 | public float getX() {
26 | return x;
27 | }
28 |
29 | public float getY() {
30 | return y;
31 | }
32 |
33 | public float getZ() {
34 | return z;
35 | }
36 |
37 | public float getPitch() {
38 | return pitch;
39 | }
40 |
41 | public float getYaw() {
42 | return yaw;
43 | }
44 |
45 | public Location add(Location location) {
46 | return new Location(x+location.x, y+location.y, z+location.z, pitch+location.pitch, yaw+location.yaw);
47 | }
48 |
49 | @Override
50 | public String getType() {
51 | return "loc";
52 | }
53 |
54 | @Override
55 | public JsonObject getData() {
56 | JsonObject loc = new JsonObject();
57 | loc.addProperty("x", x);
58 | loc.addProperty("y", y);
59 | loc.addProperty("z", z);
60 | loc.addProperty("pitch", pitch);
61 | loc.addProperty("yaw", yaw);
62 |
63 | JsonObject json = new JsonObject();
64 | json.addProperty("isBlock", false);//what is this for???
65 | json.add("loc", loc);
66 | return json;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/DFSchematics.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics;
2 |
3 | import javafx.application.Application;
4 | import javafx.application.HostServices;
5 | import javafx.fxml.FXMLLoader;
6 | import javafx.scene.Scene;
7 | import javafx.scene.image.Image;
8 | import javafx.stage.Stage;
9 | import net.ryanland.dfschematics.df.api.API;
10 |
11 | import java.io.IOException;
12 | import java.util.Properties;
13 |
14 | public class DFSchematics extends Application {
15 |
16 | public static Stage stage;
17 | public static HostServices hostServices;
18 | public static String version;
19 | public static String builderTemplate;
20 |
21 | @Override
22 | public void start(Stage stage) throws IOException {
23 | fetchProperties();
24 |
25 | FXMLLoader fxmlLoader = new FXMLLoader(DFSchematics.class.getResource("fxml/main.fxml"));
26 | Scene scene = new Scene(fxmlLoader.load(), 600, 400);
27 | //setUserAgentStylesheet(new PrimerDark().getUserAgentStylesheet());
28 | stage.setTitle("DFSchematics");
29 | stage.setScene(scene);
30 | stage.getIcons().add(new Image(String.valueOf(DFSchematics.class.getResource("logo.png"))));
31 | stage.setResizable(false);
32 | stage.show();
33 |
34 | DFSchematics.stage = stage;
35 | DFSchematics.hostServices = getHostServices();
36 | API.attemptConnections();
37 | }
38 |
39 | private void fetchProperties() throws IOException {
40 | Properties properties = new Properties();
41 | properties.load(this.getClass().getClassLoader().getResourceAsStream("project.properties"));
42 | version = properties.getProperty("version");
43 | builderTemplate = properties.getProperty("template");
44 | }
45 |
46 | public static void main(String[] args) {
47 | launch();
48 | }
49 | }
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/api/API.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.api;
2 |
3 | import net.ryanland.dfschematics.df.code.CodeLine;
4 | import net.ryanland.dfschematics.fxml.MainController;
5 |
6 | import java.util.List;
7 |
8 | public class API {
9 |
10 | public static void attemptConnections() {
11 | RecodeItemAPI.attemptConnection();
12 | CodeClientAPI.attemptConnection();
13 | if (RecodeItemAPI.connected && CodeClientAPI.connected) {
14 | MainController.instance.retryButton.setDisable(true);
15 | }
16 | if (RecodeItemAPI.connected || CodeClientAPI.connected) {
17 | if (MainController.selectedFile != null) MainController.instance.sendTemplates.setDisable(false);
18 | MainController.instance.sendBuilder.setDisable(false);
19 | }
20 | if (CodeClientAPI.connected && MainController.selectedFile != null) {
21 | MainController.instance.placeTemplates.setDisable(false);
22 | }
23 | }
24 |
25 | public static void sendTemplates(List codeLines, String name) {
26 | if (RecodeItemAPI.connected) {
27 | RecodeItemAPI.sendTemplates(codeLines, name);
28 | } else if (CodeClientAPI.connected) {
29 | CodeClientAPI.sendTemplates(codeLines, name);
30 | } else {
31 | throw new IllegalStateException("No connections available");
32 | }
33 | }
34 |
35 | public static void sendRawTemplates(List codeLines, String name) {
36 | if (RecodeItemAPI.connected) {
37 | RecodeItemAPI.sendRawTemplates(codeLines, name);
38 | } else if (CodeClientAPI.connected) {
39 | CodeClientAPI.sendRawTemplates(codeLines, name);
40 | } else {
41 | throw new IllegalStateException("No connections available");
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/api/RecodeItemAPI.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.api;
2 |
3 | import com.google.gson.JsonObject;
4 | import lombok.SneakyThrows;
5 | import net.ryanland.dfschematics.df.code.CodeLine;
6 | import net.ryanland.dfschematics.fxml.MainController;
7 |
8 | import java.net.URI;
9 | import java.util.List;
10 |
11 | public class RecodeItemAPI {
12 |
13 | private static WSClient socket;
14 | public static boolean connected = false;
15 |
16 | @SneakyThrows
17 | public static void attemptConnection() {
18 | if (connected) return;
19 |
20 | socket = new WSClient(new URI("ws://localhost:31371")); // recode API endpoint
21 | if (!socket.connectBlocking()) {
22 | // Failed connecting
23 | MainController.instance.setRecodeStatus("Failed connecting to recode", false);
24 | return;
25 | }
26 | // connected
27 | MainController.instance.setRecodeStatus("Connected to recode", true);
28 | connected = true;
29 | }
30 |
31 | @SneakyThrows
32 | public static void sendTemplates(List codeLines, String name) {
33 | sendRawTemplates(codeLines.stream().map(CodeLine::toCompressedJson).toList(), name);
34 | }
35 |
36 | @SneakyThrows
37 | public static void sendRawTemplates(List codeLines, String name) {
38 | int i = 0;
39 | for (String codeLine : codeLines) {
40 | if (i != 0) Thread.sleep(400);//delay necessary to send multiple items
41 | i++;
42 | JsonObject json = new JsonObject();
43 | json.addProperty("type", "template");
44 | JsonObject data = new JsonObject();
45 | data.addProperty("data", codeLine);
46 | data.addProperty("name", name + (codeLines.size() > 1 ? " "+i+"/"+codeLines.size() : ""));
47 | json.addProperty("data", data.toString());
48 | json.addProperty("source", "DFSchematics");
49 |
50 | socket.send(json + "\n");
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/fxml/UpdateCheckController.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.fxml;
2 |
3 | import javafx.application.Platform;
4 | import javafx.fxml.FXML;
5 | import javafx.fxml.FXMLLoader;
6 | import javafx.fxml.Initializable;
7 | import javafx.scene.Parent;
8 | import javafx.scene.Scene;
9 | import javafx.scene.control.Label;
10 | import javafx.scene.image.Image;
11 | import javafx.stage.Modality;
12 | import javafx.stage.Stage;
13 | import lombok.SneakyThrows;
14 | import net.ryanland.dfschematics.DFSchematics;
15 | import net.ryanland.dfschematics.UpdateChecker;
16 |
17 | import java.net.URL;
18 | import java.util.ResourceBundle;
19 |
20 | public class UpdateCheckController implements Initializable {
21 |
22 | public static UpdateChecker checker = new UpdateChecker("RyanLandDev", "DFSchematics", DFSchematics.version);
23 |
24 | @FXML private Label desc;
25 |
26 | @Override
27 | public void initialize(URL location, ResourceBundle resources) {
28 | desc.setText("There is a new version available (v%s).\nYou are currently using v%s."
29 | .formatted(checker.getLatestVersion(), checker.getCurrentVersion()));
30 | }
31 |
32 | @FXML
33 | void viewRelease() {
34 | DFSchematics.hostServices.showDocument("https://github.com/RyanLandDev/DFSchematics/releases");
35 | }
36 |
37 | public static void checkForUpdates() {
38 | Platform.runLater(() -> {
39 | checker.check();
40 | if (checker.isUpdateAvailable()) {
41 | showUpdateAvailable();
42 | }
43 | });
44 | }
45 |
46 | @SneakyThrows
47 | private static void showUpdateAvailable() {
48 | FXMLLoader loader = new FXMLLoader(UpdateCheckController.class.getResource("update.fxml"));
49 | Parent root = loader.load();
50 |
51 | Stage stage = new Stage();
52 | stage.setTitle("Update Available");
53 | Scene scene = new Scene(root);
54 | stage.setScene(scene);
55 | stage.getIcons().add(new Image(String.valueOf(DFSchematics.class.getResource("logo.png"))));
56 | stage.setResizable(false);
57 | stage.initModality(Modality.WINDOW_MODAL);
58 | stage.initOwner(DFSchematics.stage.getScene().getWindow());
59 | stage.setOnCloseRequest(evt -> MainController.instance.disableRoot(false));
60 | MainController.instance.disableRoot(true);
61 | stage.showAndWait();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/schematic/special/Sign.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.schematic.special;
2 |
3 | import com.google.gson.JsonArray;
4 | import com.google.gson.JsonObject;
5 | import net.kyori.adventure.text.Component;
6 | import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
7 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
8 | import net.ryanland.dfschematics.df.value.Item;
9 | import net.sandrohc.schematic4j.schematic.types.SchematicBlockPos;
10 |
11 | import java.util.List;
12 |
13 | public record Sign(SchematicBlockPos pos, Side front, Side back) implements Item {
14 |
15 | // example sign
16 | // {Count:1b,DF_NBT:3578,id:\"minecraft:oak_sign\",tag:{display:{Lore:['{\"extra\":[{\"text\":\"1front\"}]}','{\"extra\":[{\"text\":\"2front\"}]}','{\"extra\":[{\"text\":\"3front\"}]}','{\"extra\":[{\"text\":\"4front\"}]}','{\"extra\":[{\"text\":\"1back\"}]}','{\"extra\":[{\"text\":\"2back\"}]}','{\"extra\":[{\"text\":\"3back\"}]}','{\"extra\":[{\"text\":\"4back\"}]}']}}}
17 |
18 | @Override
19 | public String getItemNBT() {
20 | JsonObject item = new JsonObject();
21 | item.addProperty("id", "minecraft:oak_sign");
22 | item.addProperty("count", 1);
23 |
24 | JsonArray lore = new JsonArray(8);
25 | for (String frontLine : front.lines) lore.add(frontLine);
26 | lore.add(front.getDFColor());
27 | lore.add(front.getDFGlowing());
28 | for (String backLine : back.lines) lore.add(backLine);
29 | lore.add(back.getDFColor());
30 | lore.add(back.getDFGlowing());
31 |
32 | JsonObject components = new JsonObject();
33 | components.add("lore", lore);
34 | components.addProperty("custom_name", extra("%s,%s,%s".formatted(pos.x, pos.y, pos.z)));
35 | item.add("components", components);
36 |
37 | return item.toString();
38 | // Results in an oak sign with
39 | // Item name as xyz coordinates
40 | // 1-4 lore lines as sign's front lines & 5-6 lore lines as sign's front color and glow
41 | // 7-10 lore lines as sign's back lines & 11-12 lore lines as sign's back color and glow
42 | }
43 |
44 | private static String extra(String input) {
45 | return "{\"extra\":[{\"text\":\"%s\"}],\"text\":\"\"}".formatted(input);
46 | }
47 |
48 | public boolean isEmpty() {
49 | return front.lines.stream().allMatch(this::isComponentEmpty) &&
50 | back.lines.stream().allMatch(this::isComponentEmpty);
51 | }
52 |
53 | private boolean isComponentEmpty(String json) {
54 | if (json.isEmpty()) return true;
55 | Component component = GsonComponentSerializer.gson().deserialize(json);
56 | return LegacyComponentSerializer.legacySection().serialize(component).isEmpty();
57 | }
58 |
59 | public record Side(List lines, boolean glowing, String color) {
60 |
61 | private String getDFGlowing() {
62 | return extra(glowing ? "Enable" : "Disable");
63 | }
64 |
65 | private String getDFColor() {
66 | return extra(color.substring(0, 1).toUpperCase() + color.substring(1).replaceAll("_", " "));
67 | }
68 |
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NEW VERSION > https://ryanland.dev/schematic-importer
2 |
3 | # DFSchematics v1.5.2
4 | Tool to import schematic files into DiamondFire.
5 |
6 | 
7 |
8 | You can use this application to convert schematic files to
9 | DiamondFire data templates, which can then be imported into
10 | a plot using a builder function.
11 | This is useful for e.g. importing maps from the internet, saving plot space, and for games with rotating
12 | (destructible) maps. This is the successor to Schem2DF.
13 |
14 | _I do not take responsibility for the ownership/copyright of any builds imported through this program._
15 |
16 | ## Install
17 |
18 | To install the application, go to the [releases page](https://github.com/RyanLandDev/DFSchematics/releases) and download the executable file from the latest version.
19 |
20 | ## How to use
21 |
22 | 1. Launch Minecraft with either [recode](https://github.com/homchom/recode) or [CodeClient](https://github.com/DFOnline/CodeClient) installed.
23 | 2. Navigate to a plot in dev mode.
24 | 3. Open the program, click _'Pick file...'_ and choose a schematic file (`.schem` `.litematic` `.schematic`)*.
25 | 4. (Optional) [Configure the schematic.](#schematic-configuration)
26 | 5. Send the generated schematic data template(s) to Minecraft and place them in order.
27 | 6. Send the builder template to Minecraft and place it.
28 | 7. Call the builder function and configure the chest parameters.
29 |
30 | _*At the moment, only Sponge, Litematica and Schematica schematics are compatible, although additional formats may be supported in the future.
31 | If you have a different format, please convert it to a valid format beforehand._
32 |
33 | ## Schematic configuration
34 |
35 | You can customize the output template using the Schematic Configuration tab,
36 | accessed by clicking _'Configure schematic...'_.
37 |
38 | 
39 |
40 | The schematic name is used for the function name.
41 | Both the schematic name and author will be placed inside the `Metadata` list.
42 |
43 | ### Tracked blocks
44 |
45 | A tracked block is a type of block that will be looked for in the schematic.
46 | All instances of the block's locations will be put into a list variable.
47 | - This is useful for automatically generating a list of e.g. team spawnpoints, loot boxes, power-ups, etc.
48 | - The generated tracked block lists will be completely ignored by the schematic builder, it is up to you to use the lists.
49 | - The _Remove from structure_ option will replace all block instances with air when enabled.
50 | For example, if you have gold blocks representing spawn points, this feature will remove those unwanted blocks automatically.
51 | - The configured _Tracked Block Offset XYZ_ coordinates will be added to every found location.
52 |
53 | **NOTE:** All generated locations ignore the schematic origin location.
54 | To circumvent this, either add the origin location when using locations or use the _Tracked Block Offset XYZ_ feature.
55 |
56 | ## Support
57 |
58 | If you need help using the program, you can contact me on Discord at `ryandev.`.
59 |
60 | ## Suggestions/Bugs
61 |
62 | Do you have a suggestion or have you found a bug? Please [open an issue](https://github.com/RyanLandDev/DFSchematics/issues/new)
63 | or contact me on Discord at `ryandev.`.
64 |
65 | ## Dependencies
66 |
67 | The program reads schematic files using [schematic4j](https://github.com/SandroHc/schematic4j).
68 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/code/CodeLine.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.code;
2 |
3 | import com.google.gson.JsonArray;
4 | import com.google.gson.JsonObject;
5 | import lombok.SneakyThrows;
6 |
7 | import java.io.ByteArrayOutputStream;
8 | import java.nio.charset.StandardCharsets;
9 | import java.util.ArrayList;
10 | import java.util.Base64;
11 | import java.util.Collection;
12 | import java.util.List;
13 | import java.util.zip.GZIPOutputStream;
14 |
15 | /**
16 | * Represents a DiamondFire code line.
17 | */
18 | public class CodeLine {
19 |
20 | private final List codeBlocks = new ArrayList<>();
21 |
22 | public List getCodeBlocks() {
23 | return codeBlocks;
24 | }
25 |
26 | public boolean isEmpty() {
27 | return getCodeBlocks().isEmpty();
28 | }
29 |
30 | /**
31 | * Adds a {@link CodeBlock} to this line at the end.
32 | * @param codeBlock The code block to add
33 | */
34 | public void add(CodeBlock codeBlock) {
35 | codeBlocks.add(codeBlock);
36 | }
37 |
38 | /**
39 | * Adds {@link CodeBlock CodeBlocks} to this line at the end.
40 | * @param codeBlocks The code blocks to add
41 | */
42 | public void add(CodeBlock... codeBlocks) {
43 | this.codeBlocks.addAll(List.of(codeBlocks));
44 | }
45 |
46 | /**
47 | * Adds {@link CodeBlock CodeBlocks} to this line at the end.
48 | * @param codeBlocks The code blocks to add
49 | */
50 | public , B extends CodeBlock> void addAll(C codeBlocks) {
51 | this.codeBlocks.addAll(codeBlocks);
52 | }
53 |
54 | /**
55 | * Adds a {@link CodeBlock} to this line at the end minus a provided index.
56 | * @param codeBlock The code block to add
57 | * @param insertBefore Offset index for the end, e.g. 1 would add this code block to the second-last position.
58 | */
59 | public void add(CodeBlock codeBlock, int insertBefore) {
60 | codeBlocks.add(codeBlocks.size() - 1 - insertBefore, codeBlock);
61 | }
62 |
63 | /**
64 | * Inserts a {@link CodeBlock} in this line at the specified index.
65 | * @param index The index to add the code block at
66 | * @param codeBlock The code block to insert
67 | */
68 | public void insert(int index, CodeBlock codeBlock) {
69 | codeBlocks.add(index, codeBlock);
70 | }
71 |
72 | public JsonObject toJson() {
73 | JsonArray blocks = new JsonArray();
74 | codeBlocks.forEach(block -> blocks.add(block.toJson()));
75 |
76 | JsonObject json = new JsonObject();
77 | json.add("blocks", blocks);
78 | return json;
79 | }
80 |
81 | public String toCompressedJson() {
82 | return compressGzipBase64(toJson().toString());
83 | }
84 |
85 | @SneakyThrows
86 | private static String compressGzipBase64(String uncompressed) {
87 | ByteArrayOutputStream bos = new ByteArrayOutputStream(uncompressed.length());
88 | GZIPOutputStream gzip = new GZIPOutputStream(bos);
89 |
90 | // Convert to gzip
91 | gzip.write(uncompressed.getBytes());
92 | gzip.close();
93 | byte[] compressed = bos.toByteArray();
94 | bos.close();
95 |
96 | // Convert to base64 and returns it
97 | //return new String(compressed, StandardCharsets.UTF_8);
98 | return new String(Base64.getEncoder().encode(compressed), StandardCharsets.UTF_8);
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/df/api/CodeClientAPI.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.df.api;
2 |
3 | import lombok.SneakyThrows;
4 | import net.ryanland.dfschematics.df.code.CodeBlock;
5 | import net.ryanland.dfschematics.df.code.CodeLine;
6 | import net.ryanland.dfschematics.fxml.MainController;
7 |
8 | import java.net.URI;
9 | import java.util.List;
10 |
11 | public class CodeClientAPI {
12 |
13 | private static WSClient socket;
14 | public static boolean connected = false;
15 |
16 | @SneakyThrows
17 | public static void attemptConnection() {
18 | if (connected) return;
19 |
20 | socket = new WSClient(new URI("ws://localhost:31375")){
21 | @Override
22 | public void onMessage(String s) {
23 | handleMessage(s);
24 | }
25 | }; // codeclient api endpoint
26 | if (!socket.connectBlocking()) {
27 | // Failed connecting
28 | MainController.instance.setCodeClientStatus("Failed connecting to CodeClient", false);
29 | return;
30 | }
31 | // connected
32 | MainController.instance.setCodeClientStatus("Connected to CodeClient", true);
33 | connected = true;
34 | }
35 |
36 | public static void sendTemplates(List codeLines, String name) {
37 | sendRawTemplates(codeLines.stream().map(CodeLine::toCompressedJson).toList(), name);
38 | }
39 |
40 | public static void sendRawTemplates(List codeLines, String name) {
41 | int i = 0;
42 | for (String codeLine : codeLines) {
43 | i++;
44 | String counter = codeLines.size() > 1 ? " "+i+"/"+codeLines.size() : "";
45 | String nbt = "{components:{\"minecraft:custom_data\":{PublicBukkitValues:{\"hypercube:codetemplatedata\":'{\"author\":\"RyanLand\",\"name\":\"" + name + counter + "\",\"version\":1,\"code\":\""+ codeLine + "\"}'}},\"minecraft:custom_name\":'{\"text\":\""+ name + counter +"\", \"color\":\"aqua\"}'},count:1,id:\"minecraft:ender_chest\"}";
46 | socket.send("give " + nbt);
47 | }
48 | }
49 |
50 | private static void handleMessage(String msg) {
51 | if (msg.equals("default")) {
52 | // Attempting to place templates but unauthorized
53 | socket.send("scopes write_code read_plot");//sends user an auth request
54 | MainController.instance.error("Please authorize DFSchematics to place templates in-game...");
55 | }
56 | if (msg.equals("auth") || msg.equals("write_code read_plot default")) {
57 | // User authorized DFSchematics or has already authorized, get plot size
58 | socket.send("size");
59 | }
60 | if (msg.equals("BASIC") || msg.equals("LARGE") || msg.equals("MASSIVE") || msg.equals("MEGA")) {
61 | // Got plot size, check and place templates
62 | List codeBlocks = MainController.schematic.getTemplateFactory().generateCodeBlocks();
63 | // codeclient currently returns wrong plot size
64 | //if (codeBlocks.size() * 2 > getPlotSize(msg)) {
65 | // MainController.instance.error("Plot size too small for templates");
66 | // return;
67 | //}
68 | placeTemplates(MainController.schematic.getTemplateFactory().splitCodeBlocks(codeBlocks));
69 | }
70 | }
71 |
72 | private static int getPlotSize(String type) {
73 | return switch (type) {
74 | case "BASIC" -> 51;
75 | case "LARGE" -> 101;
76 | case "MASSIVE", "MEGA" ->//Mega codespace limit is 301, not 1001
77 | 301;
78 | default -> 0;
79 | };
80 | }
81 |
82 | public static void auth() {
83 | socket.send("scopes");//Ask codeclient what scopes we have
84 | }
85 |
86 | public static void placeTemplates(List codeLines) {
87 | socket.send("place compact");
88 | for (CodeLine codeLine : codeLines) {
89 | socket.send("place " + codeLine.toCompressedJson());
90 | }
91 | socket.send("place go");
92 | MainController.instance.success("Templates placed");
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/resources/net/ryanland/dfschematics/fxml/main.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
28 |
33 |
38 |
43 |
44 |
45 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
63 |
64 |
65 |
66 |
67 |
68 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
86 |
87 |
88 |
93 |
98 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | net.ryanland
8 | DFSchematics
9 | 1.5.2
10 | DFSchematics
11 |
12 |
13 | UTF-8
14 |
15 |
16 |
17 |
18 | org.openjfx
19 | javafx-controls
20 | 17-ea+11
21 |
22 |
23 | org.openjfx
24 | javafx-fxml
25 | 17-ea+11
26 |
27 |
28 |
29 | com.google.code.gson
30 | gson
31 | 2.10.1
32 |
33 |
34 | org.apache.logging.log4j
35 | log4j-api
36 | 2.22.0
37 |
38 |
39 | org.apache.logging.log4j
40 | log4j-core
41 | 2.22.0
42 |
43 |
44 | org.java-websocket
45 | Java-WebSocket
46 | 1.5.4
47 |
48 |
49 |
50 | net.sandrohc
51 | schematic4j
52 | 1.1.0
53 |
54 |
55 |
56 | net.kyori
57 | adventure-api
58 | 4.14.0
59 |
60 |
61 | net.kyori
62 | adventure-text-serializer-gson
63 | 4.14.0
64 |
65 |
66 | net.kyori
67 | adventure-text-serializer-legacy
68 | 4.14.0
69 |
70 |
71 | se.llbit
72 | jo-nbt
73 | 1.3.0
74 |
75 |
76 | org.projectlombok
77 | lombok
78 | 1.18.34
79 | provided
80 |
81 |
82 |
83 |
84 |
85 |
86 | org.apache.maven.plugins
87 | maven-compiler-plugin
88 | 3.8.1
89 |
90 | 17
91 | 17
92 |
93 |
94 | org.projectlombok
95 | lombok
96 | 1.18.34
97 |
98 |
99 |
100 |
101 |
102 | org.openjfx
103 | javafx-maven-plugin
104 | 0.0.6
105 |
106 |
107 |
108 | default-cli
109 |
110 | net.ryanland.dfschematics/net.ryanland.dfschematics.Main
111 |
112 |
113 |
114 |
115 |
116 | org.apache.maven.plugins
117 | maven-shade-plugin
118 |
119 |
120 |
121 | shade
122 |
123 |
124 | true
125 |
126 |
128 | net.ryanland.dfschematics.Main
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 | src/main/resources
139 | true
140 |
141 |
142 |
143 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/fxml/ConfigController.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.fxml;
2 |
3 | import javafx.collections.FXCollections;
4 | import javafx.event.ActionEvent;
5 | import javafx.fxml.FXML;
6 | import javafx.fxml.Initializable;
7 | import javafx.scene.Node;
8 | import javafx.scene.control.*;
9 | import javafx.stage.Stage;
10 | import javafx.util.StringConverter;
11 | import net.ryanland.dfschematics.df.value.Scope;
12 | import net.ryanland.dfschematics.df.value.Variable;
13 | import net.ryanland.dfschematics.schematic.special.TrackedBlock;
14 |
15 | import java.net.URL;
16 | import java.util.ArrayList;
17 | import java.util.List;
18 | import java.util.ResourceBundle;
19 |
20 | import static net.ryanland.dfschematics.fxml.MainController.schematic;
21 |
22 | // "Configure schematic..." controller
23 | public class ConfigController implements Initializable {
24 |
25 | static Label configLabel;
26 |
27 | @FXML private Label label;
28 | @FXML private TextField schemNameField;
29 | @FXML private TextField authorField;
30 |
31 | @FXML private CheckBox removeCheckBox;
32 | @FXML private ChoiceBox varScopePicker;
33 | @FXML private ListView trackedBlocks;
34 | @FXML private TextField varNameField;
35 | @FXML private TextField blockField;
36 | @FXML private Button addTrackedBlockButton;
37 |
38 | @FXML private Spinner offsetX;
39 | @FXML private Spinner offsetY;
40 | @FXML private Spinner offsetZ;
41 |
42 | @Override
43 | public void initialize(URL location, ResourceBundle resources) {
44 | configLabel = label;
45 | label.setText(MainController.selectedFile.getName());
46 |
47 | schemNameField.setText(schematic.getName());
48 | schemNameField.textProperty().addListener((l, oldName, newName) -> schematic.setName(newName));
49 | authorField.setText(schematic.getAuthor());
50 | authorField.textProperty().addListener((l, oldAuthor, newAuthor) -> schematic.setAuthor(newAuthor));
51 |
52 | trackedBlocks.setCellFactory(view -> new ListCell<>() {
53 | @Override
54 | protected void updateItem(TrackedBlock item, boolean empty) {
55 | super.updateItem(item, empty);
56 |
57 | if (empty || item == null) {
58 | setText(null);
59 | setGraphic(null);
60 | } else {
61 | setText("%s [%s] (%s) - %s found%s".formatted(
62 | item.getVariable().getName(), item.getVariable().getScope().name(),
63 | item.getMaterial(), item.getOccurrences(),
64 | item.isRemoved() ? " & removed" : ""));
65 | setGraphic(item.getIcon());
66 | }
67 | setOnContextMenuRequested(event -> {
68 | view.getItems().remove(item);
69 | usedVariables.remove(item.getVariable());
70 | schematic.getTrackedBlocks().remove(item);
71 | schematic.read();
72 | });
73 | }
74 | });
75 | trackedBlocks.setItems(FXCollections.observableArrayList(schematic.getTrackedBlocks().getBlocks()));
76 | usedVariables = new ArrayList<>();
77 |
78 | varNameField.textProperty().addListener((l, oldName, newName) -> addTrackedBlockButton.setDisable(newName.isBlank() || blockField.getText().isBlank()));
79 | blockField.textProperty().addListener((l, oldBlock, newBlock) -> addTrackedBlockButton.setDisable(newBlock.isBlank() || varNameField.getText().isBlank()));
80 | varScopePicker.setItems(FXCollections.observableArrayList(Scope.LINE, Scope.LOCAL, Scope.GAME, Scope.SAVED));
81 | varScopePicker.setValue(Scope.LOCAL);
82 |
83 | offsetX.setValueFactory(getFactory(0));
84 | offsetY.setValueFactory(getFactory(1));
85 | offsetZ.setValueFactory(getFactory(2));
86 | }
87 |
88 | private SpinnerValueFactory.DoubleSpinnerValueFactory getFactory(int index) {
89 | SpinnerValueFactory.DoubleSpinnerValueFactory factory = new SpinnerValueFactory.DoubleSpinnerValueFactory(0.0, 301.0, 0.0, 0.1);
90 | factory.setConverter(new OffsetConverter(index));
91 | factory.valueProperty().setValue(schematic.getTrackedBlocks().getOffset()[index]);
92 | return factory;
93 | }
94 |
95 | @FXML
96 | void close(ActionEvent event) {
97 | ((Stage) ((Node) event.getSource()).getScene().getWindow()).close();
98 | MainController.instance.disableRoot(false);
99 | }
100 |
101 | private List usedVariables = new ArrayList<>();
102 |
103 | @FXML
104 | void addTrackedBlock() {
105 | Variable var = new Variable(varNameField.getText(), varScopePicker.getValue());
106 | if (usedVariables.contains(var)) return;
107 | usedVariables.add(var);
108 |
109 | TrackedBlock block = new TrackedBlock(var, blockField.getText(), removeCheckBox.isSelected());
110 | schematic.getTrackedBlocks().add(block);
111 | schematic.read();
112 | trackedBlocks.getItems().add(block);
113 | }
114 |
115 | static class OffsetConverter extends StringConverter {
116 |
117 | private Double value = 0.0;
118 | private int index;
119 |
120 | public OffsetConverter(int index) {
121 | this.index = index;
122 | }
123 |
124 | @Override
125 | public String toString(Double object) {
126 | String str = String.format("%.1f", object).replaceAll(",", ".");
127 | value = Double.valueOf(str);
128 | schematic.getTrackedBlocks().setOffset(index, value);
129 | return str;
130 | }
131 |
132 | @Override
133 | public Double fromString(String string) {
134 | try {
135 | return Double.parseDouble(string);
136 | } catch (NumberFormatException e) {
137 | return value;
138 | }
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/UpdateChecker.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics;
2 |
3 | import org.jetbrains.annotations.Contract;
4 | import org.jetbrains.annotations.NotNull;
5 |
6 | import java.io.IOException;
7 | import java.net.HttpURLConnection;
8 | import java.net.MalformedURLException;
9 | import java.net.URL;
10 | import java.util.Optional;
11 | import java.util.concurrent.CompletableFuture;
12 | import java.util.concurrent.CompletionException;
13 | import java.util.logging.Logger;
14 |
15 | /**
16 | * Checks for updates on a GitHub repository
17 | */
18 | public class UpdateChecker {
19 |
20 | private final String currentVersion;
21 | private final URL url;
22 | private final boolean disabled;
23 |
24 | private transient CompletableFuture latestVersionFuture = null;
25 |
26 | /**
27 | * Start the program with -Dtechnicjelle.updatechecker.disabled to disable the update checker
28 | *
29 | * @param author GitHub Username
30 | * @param repoName GitHub Repository Name
31 | * @param currentVersion Current version of the program. This must be in the same format as the version tags on GitHub
32 | */
33 | public UpdateChecker(@NotNull String author, @NotNull String repoName, @NotNull String currentVersion) {
34 | this.currentVersion = removePrefix(currentVersion);
35 | this.disabled = System.getProperty("technicjelle.updatechecker.disabled") != null;
36 | try {
37 | this.url = new URL("https://github.com/" + author + "/" + repoName + "/releases/latest");
38 | } catch (MalformedURLException e) {
39 | throw new RuntimeException(e);
40 | }
41 | }
42 |
43 | /**
44 | * Checks for updates from a GitHub repository's releases
45 | * This method blocks the thread it is called from
46 | *
47 | * @see #checkAsync()
48 | */
49 | public void check() {
50 | checkAsync();
51 | latestVersionFuture.join();
52 | }
53 |
54 | /**
55 | * Checks for updates from a GitHub repository's releases
56 | * This method does not block the thread it is called from
57 | *
58 | * @see #check()
59 | */
60 | public void checkAsync() {
61 | latestVersionFuture = CompletableFuture.supplyAsync(this::fetchLatestVersion);
62 | }
63 |
64 | /**
65 | * Checks if necessary and returns the latest available version
66 | *
67 | * @return the latest available version
68 | */
69 | public synchronized String getLatestVersion() {
70 | if (latestVersionFuture == null) checkAsync();
71 | return latestVersionFuture.join();
72 | }
73 |
74 | private String fetchLatestVersion() {
75 | if (disabled) return currentVersion;
76 | try {
77 | // Connect to GitHub website
78 | HttpURLConnection con;
79 | con = (HttpURLConnection) url.openConnection();
80 | con.setInstanceFollowRedirects(false);
81 |
82 | // Check if the response is a redirect
83 | String newUrl = con.getHeaderField("Location");
84 |
85 | if (newUrl == null) {
86 | throw new IOException("Did not get a redirect");
87 | }
88 |
89 | // Get the latest version tag from the redirect url
90 | String[] split = newUrl.split("/");
91 | return removePrefix(split[split.length - 1]);
92 | } catch (IOException ex) {
93 | throw new CompletionException("Exception trying to fetch the latest version", ex);
94 | }
95 | }
96 |
97 | /**
98 | * Checks if necessary and returns whether an update is available or not
99 | *
100 | * @return true if there is an update available or false otherwise.
101 | */
102 | public boolean isUpdateAvailable() {
103 | return !getLatestVersion().equals(currentVersion);
104 | }
105 |
106 | /**
107 | * Checks if necessary and returns a message if an update is available.
108 | * The message will contain the latest version and a link to the GitHub releases page.
109 | * Useful if you don't use Java's own {@link java.util.logging.Logger} and you want to use your own.
110 | * Example:
111 | * New version available: v2.5 (current: v2.4)
112 | * Download it at https://github.com/TechnicJelle/UpdateCheckerJava/releases/latest
113 | *
114 | * @return An optional containing the update message or an empty optional if there is no update available
115 | */
116 | public Optional getUpdateMessage() {
117 | if (isUpdateAvailable()) {
118 | return Optional.of("New version available: v" + getLatestVersion() + " (current: v" + currentVersion + ")\nDownload it at " + url);
119 | }
120 | return Optional.empty();
121 | }
122 |
123 | /**
124 | * Gets the current version of the program.
125 | * Useful in case you want to log a custom message.
126 | *
127 | * Does not actually check for updates
128 | *
129 | * @return The current version of the program
130 | */
131 | public String getCurrentVersion() {
132 | return currentVersion;
133 | }
134 |
135 | /**
136 | * Gets the URL to the GitHub releases page,
137 | * where the latest version can be downloaded.
138 | * Useful in case you want to log a custom message.
139 | *
140 | * Does not actually check for updates
141 | *
142 | * @return The URL to the GitHub releases page
143 | */
144 | public String getUpdateUrl() {
145 | return url.toString();
146 | }
147 |
148 | /**
149 | * This method logs a message to the console if an update is available
150 | *
151 | * @param logger Logger to log a potential update notification to
152 | */
153 | public void logUpdateMessage(@NotNull Logger logger) {
154 | getUpdateMessage().ifPresent(logger::warning);
155 | }
156 |
157 | /**
158 | * This method logs a message to the console if an update is available, asynchronously
159 | *
160 | * @param logger Logger to log a potential update notification to
161 | */
162 | public synchronized void logUpdateMessageAsync(@NotNull Logger logger) {
163 | if (latestVersionFuture == null) checkAsync();
164 | latestVersionFuture.thenRun(() -> logUpdateMessage(logger));
165 | }
166 |
167 | /**
168 | * Removes a potential v prefix from a version
169 | *
170 | * @param version Version to remove the prefix from
171 | * @return The version without the prefix
172 | */
173 | @Contract(pure = true)
174 | private static @NotNull String removePrefix(@NotNull String version) {
175 | return version.replaceFirst("^v", "");
176 | }
177 | }
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/schematic/TemplateFactory.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.schematic;
2 |
3 | import net.ryanland.dfschematics.df.code.*;
4 | import net.ryanland.dfschematics.df.value.*;
5 | import net.ryanland.dfschematics.schematic.special.Head;
6 | import net.ryanland.dfschematics.schematic.special.TrackedBlock;
7 | import net.sandrohc.schematic4j.schematic.Schematic;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class TemplateFactory {
13 |
14 | private final DFSchematic schematic;
15 | private final Schematic file;
16 |
17 | public TemplateFactory(DFSchematic schematic) {
18 | this.schematic = schematic;
19 | this.file = schematic.getSchematic();
20 | }
21 |
22 | public List generate() {
23 | return splitCodeBlocks(generateCodeBlocks());
24 | }
25 |
26 | public List generateCodeBlocks() {
27 | // put codeblocks together
28 | List codeBlocks = new ArrayList<>();
29 | codeBlocks.add(new Function(schematic.getName()));
30 | codeBlocks.add(getMetadata());
31 | codeBlocks.addAll(getPalette());
32 | if (!schematic.getHeads().isEmpty() || !schematic.getSigns().isEmpty()) {
33 | codeBlocks.addAll(getBlockEntities());
34 | }
35 | codeBlocks.addAll(getBlocks());
36 | if (!schematic.getTrackedBlocks().getBlocks().isEmpty()) {
37 | codeBlocks.addAll(getTrackedBlocks());
38 | }
39 | return codeBlocks;
40 | }
41 |
42 | public List splitCodeBlocks(List codeBlocks) {
43 | // splitter
44 | List lines = new ArrayList<>();
45 | int weight = 0;
46 | CodeLine line = new CodeLine();
47 | for (CodeBlock block : codeBlocks) {
48 | weight += block.getWeight();
49 | line.add(block);
50 | if (weight >= 52) {
51 | lines.add(line);
52 | line = new CodeLine();
53 | weight = 0;
54 | }
55 | }
56 | if (!line.isEmpty()) lines.add(line);
57 |
58 | return lines;
59 | }
60 |
61 | private SetVariableCreateList getMetadata() {
62 | List values = new ArrayList<>();
63 |
64 | values.add(new Str(schematic.getName()));
65 | values.add(new Str(schematic.getAuthor()));
66 | values.add(new Vector(file.width(), file.height(), file.length()));
67 |
68 | return new SetVariableCreateList(new Variable("Metadata"), values);
69 | }
70 |
71 | private List getPalette() {
72 | // convert palette to texts
73 | List palette = schematic.getStructure().getPalette();
74 | List texts = new ArrayList<>();
75 | String text = "";
76 | for (String material : palette) {
77 | text += material + ".";
78 | if (text.length() > 2600) {//create the next string, don't go over data limit
79 | texts.add(text.substring(0, text.length()-1));//-1 removes final comma
80 | text = "";
81 | }
82 | }
83 | texts.add(text.substring(0, text.length()-1));
84 |
85 | return textsListToCodeBlocks(texts, "Palette");
86 | }
87 |
88 | private List getBlocks() {
89 | // convert structure to texts
90 | StructureContainer structure = schematic.getStructure();
91 | List texts = new ArrayList<>();
92 | String text = "";
93 | for (StructurePart part : structure.getParts()) {
94 | text += part.getText() + ".";
95 | if (text.length() > 2600) {//create the next string, don't go over data limit
96 | texts.add(text.substring(0, text.length()-1));//-1 removes final comma
97 | text = "";
98 | }
99 | }
100 | texts.add(text.substring(0, text.length()-1));
101 |
102 | return textsListToCodeBlocks(texts, "Blocks");
103 | }
104 |
105 | private List getBlockEntities() {
106 | List values = new ArrayList<>();
107 |
108 | // heads format: H6,1,8,RyanLand;3,4,5,oiaejroaiejroaapPEOFIJapeoifja
109 | List heads = schematic.getHeads();
110 | if (heads.size() > 0) {
111 | String str = "H";
112 | for (Head head : heads) {
113 | str += head.pos().x + "," + head.pos().y + "," + head.pos().z + "," + head.texture() + ";";
114 | if (str.length() > 2600) {
115 | values.add(new Str(str.substring(0, str.length() - 1)));
116 | str = "H";
117 | }
118 | }
119 | values.add(new Str(str.substring(0, str.length() - 1)));
120 | }
121 |
122 | // signs use a sign item with lores
123 | values.addAll(schematic.getSigns());
124 |
125 | return listToCodeBlocks(values, "BlockEntities");
126 | }
127 |
128 | private List getTrackedBlocks() {
129 | List blocks = new ArrayList<>();
130 | Location offset = new Location((float) schematic.getTrackedBlocks().getOffset()[0], (float) schematic.getTrackedBlocks().getOffset()[1], (float) schematic.getTrackedBlocks().getOffset()[2]);
131 | for (TrackedBlock block : schematic.getTrackedBlocks().getBlocks()) {
132 | blocks.addAll(listToCodeBlocks(block.getLocations().stream().map(loc -> loc.add(offset)).toList(), block.getVariable()));
133 | }
134 | return blocks;
135 | }
136 |
137 | private static List textsListToCodeBlocks(List texts, String listName) {
138 | return listToCodeBlocks(texts.stream().map(Str::new).toList(), listName);
139 | }
140 |
141 | private static List listToCodeBlocks(List list, String listName) {
142 | return listToCodeBlocks(list, new Variable(listName));
143 | }
144 |
145 | private static List listToCodeBlocks(List list, Variable var) {
146 | List> valuesLists = partition(list, 26);// split values into batches of 26, to fit in codeblock
147 |
148 | List line = new ArrayList<>();
149 | int i = 0;
150 | for (List l : valuesLists) {
151 | if (i == 0) line.add(new SetVariableCreateList(var, l));
152 | else line.add(new SetVariableAppendValue(var, l));
153 | i++;
154 | }
155 | return line;
156 | }
157 |
158 | private static List> partition(List collection, int batchSize) {
159 | int i = 0;
160 | List> batches = new ArrayList<>();
161 | while (i < collection.size()) {
162 | int nextInc = Math.min(collection.size()-i, batchSize);
163 | List batch = collection.subList(i, i+nextInc);
164 | batches.add(batch);
165 | i = i + nextInc;
166 | }
167 |
168 | return batches;
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/fxml/MainController.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.fxml;
2 |
3 | import javafx.application.Platform;
4 | import javafx.event.ActionEvent;
5 | import javafx.fxml.FXML;
6 | import javafx.fxml.FXMLLoader;
7 | import javafx.fxml.Initializable;
8 | import javafx.scene.Node;
9 | import javafx.scene.Parent;
10 | import javafx.scene.Scene;
11 | import javafx.scene.control.Button;
12 | import javafx.scene.control.Label;
13 | import javafx.scene.image.Image;
14 | import javafx.scene.layout.BorderPane;
15 | import javafx.scene.paint.Color;
16 | import javafx.stage.FileChooser;
17 | import javafx.stage.Modality;
18 | import javafx.stage.Stage;
19 | import lombok.SneakyThrows;
20 | import net.ryanland.dfschematics.DFSchematics;
21 | import net.ryanland.dfschematics.df.api.API;
22 | import net.ryanland.dfschematics.df.api.CodeClientAPI;
23 | import net.ryanland.dfschematics.df.code.CodeLine;
24 | import net.ryanland.dfschematics.schematic.DFSchematic;
25 | import net.sandrohc.schematic4j.SchematicLoader;
26 |
27 | import java.io.File;
28 | import java.net.URL;
29 | import java.util.List;
30 | import java.util.ResourceBundle;
31 | import java.util.concurrent.Executors;
32 | import java.util.concurrent.TimeUnit;
33 |
34 | public class MainController implements Initializable {
35 |
36 | public static MainController instance;
37 |
38 | @FXML BorderPane root;
39 |
40 | @Override
41 | public void initialize(URL location, ResourceBundle resources) {
42 | instance = this;
43 | versionLabel.setText("v" + DFSchematics.version);
44 | Executors.newScheduledThreadPool(0).schedule(UpdateCheckController::checkForUpdates, 500, TimeUnit.MILLISECONDS);
45 | }
46 |
47 | public void disableRoot(boolean disable) {
48 | root.setDisable(disable);
49 | }
50 |
51 | // CONNECTIONS ----------------
52 |
53 | @FXML Label recodeStatus;
54 | @FXML Label codeClientStatus;
55 | @FXML public Button retryButton;
56 |
57 | @FXML
58 | void retryConnections() {
59 | API.attemptConnections();
60 | }
61 |
62 | public void setRecodeStatus(String text, boolean success) {
63 | recodeStatus.setTextFill(success ? Color.GREEN : Color.RED);
64 | recodeStatus.setText(text);
65 | }
66 |
67 | public void setCodeClientStatus(String text, boolean success) {
68 | codeClientStatus.setTextFill(success ? Color.GREEN : Color.RED);
69 | codeClientStatus.setText(text);
70 | }
71 |
72 | // PICK SCHEMATIC ----------------
73 |
74 | @FXML private Button filePicker;
75 | @FXML private Label fileStatus;
76 |
77 | public static File selectedFile;
78 | public static DFSchematic schematic;
79 |
80 | @FXML
81 | void pickFile() {
82 | // create file chooser
83 | FileChooser fileChooser = new FileChooser();
84 | fileChooser.setTitle("Select Schematic...");
85 | fileChooser.setInitialDirectory(new File(System.getProperty("user.home") + "/Downloads"));
86 |
87 | // extension filter
88 | FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("Schematic files (*.schem *.litematic *.schematic)", "*.schem", "*.litematic", "*.schematic");
89 | fileChooser.getExtensionFilters().add(extFilter);
90 |
91 | // choose file
92 | File file = fileChooser.showOpenDialog(DFSchematics.stage);
93 | if (file == null) {
94 | System.out.println("No file selected");
95 | return;
96 | }
97 |
98 | fileStatus.setVisible(true);
99 | fileStatus.setTextFill(Color.LIGHTBLUE);
100 | fileStatus.setText("Reading...");
101 |
102 | // file selected
103 | System.out.println("Selected file: " + file.getAbsolutePath());
104 | filePicker.setText(file.getName());
105 | selectedFile = file;
106 | String format = file.getName().replaceAll("^.+\\.", "");
107 |
108 | // read schematic
109 | Platform.runLater(() -> {
110 | try {
111 | schematic = new DFSchematic(SchematicLoader.load(file));
112 | } catch (Exception e) {
113 | error("Error: " + e.getMessage());
114 | e.printStackTrace();
115 | return;
116 | }
117 |
118 | API.attemptConnections();
119 | configureButton.setDisable(false);
120 |
121 | System.out.println(schematic.getSchematic().format());
122 | success("Successfully loaded (Size: %sx%sx%s)"
123 | .formatted(schematic.getSchematic().width(), schematic.getSchematic().height(), schematic.getSchematic().length()));
124 | System.out.println("Loaded Schematic: " + file.getName());
125 | });
126 | }
127 |
128 | public void error(String msg) {
129 | Platform.runLater(() -> {
130 | fileStatus.setVisible(true);
131 | fileStatus.setTextFill(Color.RED);
132 | fileStatus.setText(msg);
133 | });
134 | }
135 |
136 | public void success(String msg) {
137 | Platform.runLater(() -> {
138 | fileStatus.setVisible(true);
139 | fileStatus.setTextFill(Color.GREEN);
140 | fileStatus.setText(msg);
141 | });
142 | }
143 |
144 | // CONFIGURE SCHEMATIC --------------
145 |
146 | @FXML private Button configureButton;
147 |
148 | @FXML @SneakyThrows
149 | void configure(ActionEvent event) {
150 | FXMLLoader loader = new FXMLLoader(getClass().getResource("configuration.fxml"));
151 | Parent root = loader.load();
152 |
153 | Stage stage = new Stage();
154 | stage.setTitle("Schematic Configuration");
155 | Scene scene = new Scene(root);
156 | stage.setScene(scene);
157 | stage.getIcons().add(new Image(String.valueOf(DFSchematics.class.getResource("logo.png"))));
158 | stage.setResizable(false);
159 | stage.initModality(Modality.WINDOW_MODAL);
160 | stage.initOwner(((Node) event.getSource()).getScene().getWindow());
161 | stage.setOnCloseRequest(evt -> this.root.setDisable(false));
162 | this.root.setDisable(true);
163 | stage.showAndWait();
164 | }
165 |
166 | // SEND ------------------
167 |
168 | @FXML public Button sendTemplates;
169 | @FXML public Button placeTemplates;
170 | @FXML public Button sendBuilder;
171 |
172 | @FXML
173 | void sendTemplates() {
174 | List codeLines = schematic.getTemplateFactory().generate();
175 | API.sendTemplates(codeLines, selectedFile.getName());
176 | success(codeLines.size() + " template" + (codeLines.size() == 1 ? "" : "s") + " sent");
177 | }
178 |
179 | @FXML
180 | void sendBuilderTemplate() {
181 | API.sendRawTemplates(List.of(DFSchematics.builderTemplate), "DFSchematics Builder");
182 | success("Template sent");
183 | }
184 |
185 | @FXML
186 | void placeTemplates() {// CodeClient only
187 | CodeClientAPI.auth();
188 | }
189 |
190 | @FXML
191 | void viewInstructions() {
192 | DFSchematics.hostServices.showDocument("http://github.com/RyanLandDev/DFSchematics#how-to-use");
193 | }
194 |
195 | // VERSION -------------------
196 |
197 | @FXML private Label versionLabel;
198 |
199 | @FXML
200 | void onVersionClick() {
201 | DFSchematics.hostServices.showDocument("http://github.com/RyanLandDev/DFSchematics");
202 | }
203 |
204 | @FXML
205 | void onVersionEnter() {
206 | versionLabel.setUnderline(true);
207 | }
208 |
209 | @FXML
210 | void onVersionExit() {
211 | versionLabel.setUnderline(false);
212 | }
213 | }
--------------------------------------------------------------------------------
/src/main/resources/net/ryanland/dfschematics/fxml/configuration.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
112 |
113 |
114 |
115 |
116 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/src/main/java/net/ryanland/dfschematics/schematic/DFSchematic.java:
--------------------------------------------------------------------------------
1 | package net.ryanland.dfschematics.schematic;
2 |
3 | import net.ryanland.dfschematics.fxml.MainController;
4 | import net.ryanland.dfschematics.df.value.Location;
5 | import net.ryanland.dfschematics.schematic.special.Head;
6 | import net.ryanland.dfschematics.schematic.special.Sign;
7 | import net.ryanland.dfschematics.schematic.special.TrackedBlock;
8 | import net.ryanland.dfschematics.schematic.special.TrackedBlocks;
9 | import net.sandrohc.schematic4j.schematic.Schematic;
10 | import net.sandrohc.schematic4j.schematic.types.SchematicBlock;
11 | import net.sandrohc.schematic4j.schematic.types.SchematicBlockEntity;
12 | import net.sandrohc.schematic4j.schematic.types.SchematicBlockPos;
13 |
14 | import java.util.*;
15 |
16 | public class DFSchematic {
17 |
18 | private final Schematic schematic;
19 | private final TemplateFactory templateFactory;
20 |
21 | private StructureContainer structure;
22 | private List heads;
23 | private List signs;
24 | private final TrackedBlocks trackedBlocks = new TrackedBlocks();
25 |
26 | private String name;
27 | private String author;
28 |
29 | public DFSchematic(Schematic schematic) {
30 | this.schematic = schematic;
31 | read();
32 |
33 | name = Objects.requireNonNullElse(schematic.name(), MainController.selectedFile.getName().replaceAll("\\.schem$|\\.litematic$|\\.schematic$|", ""));
34 | author = Objects.requireNonNullElse(schematic.author(), "Unknown");
35 |
36 | templateFactory = new TemplateFactory(this);
37 | }
38 |
39 | public Schematic getSchematic() {
40 | return schematic;
41 | }
42 |
43 | public StructureContainer getStructure() {
44 | return structure;
45 | }
46 |
47 | public TemplateFactory getTemplateFactory() {
48 | return templateFactory;
49 | }
50 |
51 | public List getHeads() {
52 | return heads;
53 | }
54 |
55 | public List getSigns() {
56 | return signs;
57 | }
58 |
59 | public TrackedBlocks getTrackedBlocks() {
60 | return trackedBlocks;
61 | }
62 |
63 | public String getName() {
64 | return name;
65 | }
66 |
67 | public void setName(String name) {
68 | this.name = name;
69 | }
70 |
71 | public String getAuthor() {
72 | return author;
73 | }
74 |
75 | public void setAuthor(String author) {
76 | this.author = author;
77 | }
78 |
79 | private static final Map DEFAULT_BLOCK_STATES = Map.of(
80 | "snowy", "false",
81 | "axis", "y",
82 | "powered", "false",
83 | "open", "false"
84 | );
85 |
86 | public void read() {
87 | //reset in case of a re-read
88 | structure = new StructureContainer();
89 | heads = new ArrayList<>();
90 | signs = new ArrayList<>();
91 | trackedBlocks.reset();
92 |
93 | // iterates through all x, then z, then y - same as RepeatOnGrid
94 | SchematicBlockPos offset = schematic.offset();
95 | System.out.println("offset: " + offset);
96 | for (int y = 0; y < schematic.height(); y++) {
97 | for (int z = 0; z < schematic.length(); z++) {
98 | for (int x = 0; x < schematic.width(); x++) {
99 | //System.out.println("xyz: " + x + " " + y + " " + z);
100 | SchematicBlock offsetBlock = schematic.block(x + offset.x, y + offset.y, z + offset.z);
101 | SchematicBlock block = schematic.block(x, y, z);
102 | String material = block.block;
103 | //System.out.println("offset: " + offsetBlock.block + " regular: " + block.block);
104 |
105 | // Tracked Blocks
106 | boolean remove = false;
107 | for (TrackedBlock trackedBlock : trackedBlocks.getBlocks()) {
108 | if (material.equals("minecraft:"+trackedBlock.getMaterial())) {
109 | trackedBlock.addLocation(new Location(x, y, z));
110 | remove = trackedBlock.isRemoved();
111 | break;
112 | }
113 | }
114 | if (remove) {
115 | material = "air";
116 | block = new SchematicBlock("air");
117 | }
118 |
119 | Map states = new HashMap<>(block.states);
120 | DEFAULT_BLOCK_STATES.forEach(states::remove);
121 | String result = material + (states.isEmpty() ? "" : "[" + String.join(",",
122 | states.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).toList()) + "]");
123 |
124 | structure.addToPalette(result); // includes block states such as facing=up
125 | structure.addBlock(result);
126 | }
127 | }
128 | }
129 | structure.finalizePart();
130 |
131 | for (SchematicBlockEntity block : schematic.blockEntities().toList()) {
132 | if (block.data.containsKey("front_text")) {
133 | // Signs after MC 1.20 ----------
134 | Map frontCompound = ((Map) block.data.get("front_text"));
135 | Map backCompound = ((Map) block.data.get("back_text"));
136 |
137 | Sign.Side front = new Sign.Side(
138 | ((List) frontCompound.get("messages")),
139 | ((byte) frontCompound.get("has_glowing_text")) == 1,
140 | (String) frontCompound.get("color")
141 | );
142 |
143 | Sign.Side back = new Sign.Side(
144 | ((List) backCompound.get("messages")),
145 | ((byte) backCompound.get("has_glowing_text")) == 1,
146 | (String) backCompound.get("color")
147 | );
148 |
149 | Sign sign = new Sign(block.pos, front, back);
150 | if (!sign.isEmpty()) signs.add(sign);
151 |
152 | } else if (block.data.containsKey("Text1")) {
153 | // Signs before MC 1.20 ---------
154 | Sign sign = new Sign(block.pos, new Sign.Side(List.of(
155 | ((String) block.data.get("Text1")),
156 | ((String) block.data.get("Text2")),
157 | ((String) block.data.get("Text3")),
158 | ((String) block.data.get("Text4"))), false, "black"),
159 | new Sign.Side(List.of("", "", "", ""), false, "black"));
160 | if (!sign.isEmpty()) signs.add(sign);
161 | } else if (block.data.containsKey("profile")) {
162 | // Heads after MC 1.20.5 -------
163 | Map data = (TreeMap) block.data.get("profile");
164 | if (data.containsKey("properties")) {
165 | String owner = (String) data.get("name");
166 | String value = (String) ((Map) ((List