Skip to content

Commit 13aad52

Browse files
Merge pull request #31 from JasonTheKitten/generate-assets
Add screen blockstate/model generator
2 parents b768178 + 25261f9 commit 13aad52

54 files changed

Lines changed: 230 additions & 5057 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

projects/Fabric/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,9 @@ tasks.build {
3838

3939
afterEvaluate {
4040
extensions.getByType<RegExtension>().configureJarTask(tasks.shadowJar.get())
41+
}
42+
43+
// TODO: Figure out how to declare this in :Minecraft instead
44+
tasks.named("processResources") {
45+
dependsOn(project(":Minecraft").tasks.named("processResources"))
4146
}

projects/Minecraft/build.gradle.kts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,33 @@ neoForge {
66
neoFormVersion = libs.versions.neoForm.get()
77
}
88

9+
sourceSets {
10+
create("generator")
11+
}
12+
913
dependencies {
1014
shadeApi(project(":Core"))
15+
16+
"generatorImplementation"("com.google.code.gson:gson:2.13.2")
1117
}
1218

13-
tasks.register<Copy>("copyResources") {
14-
copy {
15-
from("${projectDir}/src/generated/resources/")
16-
into(file("build/resources/main/"))
17-
}
19+
val generateBlockstatesTask = tasks.register<JavaExec>("generateBlockstates") {
20+
group = "generation"
21+
description = "Generates Minecraft blockstate and model JSON files."
22+
23+
classpath = sourceSets.getByName("generator").runtimeClasspath
24+
25+
mainClass.set("li.cil.ocreloaded.generator.BlockstateJsonGenerator")
26+
27+
val outputDir = project.layout.buildDirectory.dir("generated/resources/assets/ocreloaded")
28+
args(outputDir.get().asFile.absolutePath)
29+
outputs.dir(project.layout.buildDirectory.dir("generated/resources"))
30+
}
31+
32+
tasks.named("processResources") {
33+
dependsOn(generateBlockstatesTask)
1834
}
35+
36+
sourceSets.main.get().resources {
37+
srcDir(generateBlockstatesTask)
38+
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
package li.cil.ocreloaded.generator;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
5+
import java.io.FileWriter;
6+
import java.io.IOException;
7+
import java.nio.file.Files;
8+
import java.nio.file.Path;
9+
import java.nio.file.Paths;
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
13+
public class BlockstateJsonGenerator {
14+
15+
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
16+
17+
public static void main(String[] args) {
18+
try {
19+
generateBlockStates(args[0]);
20+
} catch (IOException e) {
21+
e.printStackTrace();
22+
}
23+
}
24+
25+
private static void generateBlockStates(String outputDir) throws IOException {
26+
Files.createDirectories(Paths.get(outputDir, "blockstates"));
27+
Files.createDirectories(Paths.get(outputDir, "models/block/screen"));
28+
29+
Map<String, Object> variants = new HashMap<>();
30+
generateModelsAndVariants(outputDir, "north", variants);
31+
generateBlockstateFiles(outputDir, variants);
32+
}
33+
34+
private static void generateModelsAndVariants(String outputDir, String baseFacing, Map<String, Object> variants) throws IOException {
35+
for (String face : new String[]{ "wall", "floor", "ceiling" }) {
36+
for (boolean up : new boolean[]{ true, false }) {
37+
for (boolean down : new boolean[]{ true, false }) {
38+
for (boolean left : new boolean[]{ true, false }) {
39+
for (boolean right : new boolean[]{ true, false }) {
40+
String modelName = generateModelName(baseFacing, face, up, down, left, right);
41+
generateModelFile(outputDir, modelName, baseFacing, face, up, down, left, right);
42+
for (String facing : new String[]{ "north", "south", "east", "west" }) {
43+
String variantKey = generateVariantKey(facing, face, up, down, left, right);
44+
variants.put(variantKey, generateBlockstateVariant(modelName, facing, face));
45+
}
46+
}
47+
}
48+
}
49+
}
50+
}
51+
}
52+
53+
private static String generateVariantKey(String facing, String face, boolean up, boolean down, boolean left, boolean right) {
54+
return String.format("facing=%s,face=%s,up=%b,down=%b,left=%b,right=%b", facing, face, up, down, left, right);
55+
}
56+
57+
private static String generateModelName(String facing, String face, boolean up, boolean down, boolean left, boolean right) {
58+
StringBuilder nameBuilder = new StringBuilder("screen_");
59+
nameBuilder.append(face);
60+
61+
if (up) nameBuilder.append("_up");
62+
if (down) nameBuilder.append("_down");
63+
if (left) nameBuilder.append("_left");
64+
if (right) nameBuilder.append("_right");
65+
66+
return nameBuilder.toString();
67+
}
68+
69+
private static Map<String, Object> generateBlockstateVariant(String modelName, String facing, String face) {
70+
Map<String, Object> variant = new HashMap<>();
71+
variant.put("model", "ocreloaded:block/screen/" + modelName);
72+
73+
switch (facing) {
74+
case "north" -> variant.put("y", 0);
75+
case "south" -> variant.put("y", 180);
76+
case "east" -> variant.put("y", 90);
77+
case "west" -> variant.put("y", 270);
78+
}
79+
80+
return variant;
81+
}
82+
83+
private static void generateModelFile(String outputDir, String modelName, String baseFacing, String face, boolean up, boolean down, boolean left, boolean right) throws IOException {
84+
Map<String, Object> modelJson = new HashMap<>();
85+
modelJson.put("parent", "block/cube");
86+
87+
Map<String, String> textures = new HashMap<>();
88+
switch (face) {
89+
case "floor" -> {
90+
textures.put("down", "ocreloaded:" + determineTextureName(baseFacing, face, Side.BACK, up, down, left, right));
91+
textures.put("up", "ocreloaded:" + determineTextureName(baseFacing, face, Side.FRONT, up, down, left, right));
92+
textures.put("north", "ocreloaded:" + determineTextureName(baseFacing, face, Side.TOP, up, down, left, right));
93+
textures.put("south", "ocreloaded:" + determineTextureName(baseFacing, face, Side.BOTTOM, up, down, left, right));
94+
textures.put("east", "ocreloaded:" + determineTextureName(baseFacing, face, Side.RIGHT, up, down, left, right));
95+
textures.put("west", "ocreloaded:" + determineTextureName(baseFacing, face, Side.LEFT, up, down, left, right));
96+
}
97+
case "ceiling" -> {
98+
textures.put("down", "ocreloaded:" + determineTextureName(baseFacing, face, Side.FRONT, up, down, left, right));
99+
textures.put("up", "ocreloaded:" + determineTextureName(baseFacing, face, Side.BACK, up, down, left, right));
100+
textures.put("north", "ocreloaded:" + determineTextureName(baseFacing, face, Side.TOP, up, down, left, right));
101+
textures.put("south", "ocreloaded:" + determineTextureName(baseFacing, face, Side.BOTTOM, up, down, left, right));
102+
textures.put("east", "ocreloaded:" + determineTextureName(baseFacing, face, Side.RIGHT, up, down, left, right));
103+
textures.put("west", "ocreloaded:" + determineTextureName(baseFacing, face, Side.LEFT, up, down, left, right));
104+
}
105+
default -> {
106+
textures.put("north", "ocreloaded:" + determineTextureName(baseFacing, face, Side.FRONT, up, down, left, right));
107+
textures.put("south", "ocreloaded:" + determineTextureName(baseFacing, face, Side.BACK, up, down, left, right));
108+
textures.put("east", "ocreloaded:" + determineTextureName(baseFacing, face, Side.RIGHT, up, down, left, right));
109+
textures.put("west", "ocreloaded:" + determineTextureName(baseFacing, face, Side.LEFT, up, down, left, right));
110+
textures.put("up", "ocreloaded:" + determineTextureName(baseFacing, face, Side.TOP, up, down, left, right));
111+
textures.put("down", "ocreloaded:" + determineTextureName(baseFacing, face, Side.BOTTOM, up, down, left, right));
112+
}
113+
}
114+
modelJson.put("textures", textures);
115+
116+
Map<String, Object> faces = new HashMap<>();
117+
for (String faceName : new String[]{ "north", "south", "east", "west", "up", "down" }) {
118+
Map<String, Object> faceJson = new HashMap<>();
119+
faceJson.put("texture", "#" + faceName);
120+
faceJson.put("cullface", faceName);
121+
faceJson.put("tintindex", 0);
122+
faces.put(faceName, faceJson);
123+
}
124+
125+
Map<String, Object> elements = new HashMap<>();
126+
elements.put("from", new double[]{ 0, 0, 0 });
127+
elements.put("to", new double[]{ 16, 16, 16 });
128+
elements.put("faces", faces);
129+
130+
modelJson.put("elements", new Object[] { elements });
131+
132+
writeJsonToFile(Paths.get(outputDir, "models/block/screen", modelName + ".json"), modelJson);
133+
}
134+
135+
private static String determineTextureName(String facing, String face, Side side, boolean up, boolean down, boolean left, boolean right) {
136+
boolean isSideNonWall = !face.equals("wall") && (side != Side.FRONT && side != Side.BACK);
137+
138+
boolean invertY = (face.equals("floor") && side == Side.FRONT) || (face.equals("ceiling") && side == Side.BACK);
139+
boolean invertedUp = invertY ? down : up;
140+
boolean invertedDown = invertY ? up : down;
141+
String upDown = isSideNonWall ? "single" : switch (side) {
142+
case FRONT, BACK, LEFT, RIGHT -> selectPart(invertedUp, invertedDown, "single", "bottom", "top", "middle");
143+
case TOP, BOTTOM -> "single";
144+
};
145+
146+
String leftRight = !face.equals("wall") ?
147+
switch (side) {
148+
case BOTTOM -> selectPart(left, right, "single", "left", "right", "middle");
149+
case TOP -> selectPart(left, right, "single", "right", "left", "middle");
150+
case LEFT -> selectPart(up, down, "single", "left", "right", "middle");
151+
case RIGHT -> selectPart(up, down, "single", "right", "left", "middle");
152+
case FRONT, BACK -> selectPart(left, right, "single", "left", "right", "middle");
153+
} :
154+
switch (side) {
155+
case FRONT -> selectPart(left, right, "single", "right", "left", "middle");
156+
case BACK, TOP, BOTTOM -> selectPart(left, right, "single", "left", "right", "middle");
157+
case LEFT, RIGHT -> "single";
158+
};
159+
160+
StringBuilder textureName = new StringBuilder("block/screen/");
161+
textureName.append(side == Side.FRONT ? "front" : "back");
162+
textureName.append("_").append(upDown).append("_").append(leftRight);
163+
164+
if (
165+
((face.equals("floor") || face.equals("ceiling")) && isSideNonWall)
166+
|| (face.equals("wall") && !(side == Side.TOP || side == Side.BOTTOM) && !down)
167+
) {
168+
textureName.append("_side");
169+
}
170+
171+
return textureName.toString();
172+
}
173+
174+
private static String selectPart(boolean a, boolean b, String nn, String an, String nb, String ab) {
175+
if (a && b) return ab;
176+
else if (a) return an;
177+
else if (b) return nb;
178+
else return nn;
179+
}
180+
181+
private static void writeJsonToFile(Path path, Map<String, Object> json) throws IOException {
182+
try (FileWriter writer = new FileWriter(path.toFile())) {
183+
GSON.toJson(json, writer);
184+
}
185+
}
186+
187+
private static void generateBlockstateFiles(String outputDir, Map<String, Object> variants) throws IOException {
188+
Map<String, Object> blockstateJson = new HashMap<>();
189+
blockstateJson.put("variants", variants);
190+
191+
for (String fileName : new String[]{ "screen1.json", "screen2.json", "screen3.json" }) {
192+
writeJsonToFile(Paths.get(outputDir, "blockstates", fileName), blockstateJson);
193+
}
194+
}
195+
196+
private enum Side {
197+
FRONT, BACK, LEFT, RIGHT, TOP, BOTTOM;
198+
}
199+
200+
}

0 commit comments

Comments
 (0)