Split renderer into client source set
This commit is contained in:
+216
@@ -0,0 +1,216 @@
|
||||
package dev.github.copilot.renameable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.util.ScreenshotRecorder;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public final class RenderCatalogClient implements ClientModInitializer {
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
private final List<RenderJob> jobs = new ArrayList<>();
|
||||
private Path outputDir;
|
||||
private int currentJobIndex;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
Path manifestPath = readPathEnv("RENDER_MANIFEST");
|
||||
outputDir = readPathEnv("RENDER_OUTPUT_DIR");
|
||||
|
||||
if (manifestPath == null || outputDir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
loadJobs(manifestPath);
|
||||
} catch (IOException exception) {
|
||||
throw new RuntimeException("Failed to load render manifest", exception);
|
||||
}
|
||||
|
||||
jobs.sort(Comparator.comparing(RenderJob::outputPath));
|
||||
if (jobs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
client.execute(() -> client.setScreen(new RenderScreen()));
|
||||
}
|
||||
|
||||
private void loadJobs(Path manifestPath) throws IOException {
|
||||
try (Reader reader = Files.newBufferedReader(manifestPath, StandardCharsets.UTF_8)) {
|
||||
JsonElement root = JsonParser.parseReader(reader);
|
||||
if (!root.isJsonArray()) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonArray records = root.getAsJsonArray();
|
||||
for (JsonElement recordElement : records) {
|
||||
if (!recordElement.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject record = recordElement.getAsJsonObject();
|
||||
collectJob(record.get("item"), record.get("render_path"), null);
|
||||
|
||||
JsonElement casesElement = record.get("cases");
|
||||
if (!casesElement.isJsonArray()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (JsonElement caseElement : casesElement.getAsJsonArray()) {
|
||||
if (!caseElement.isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonObject caseRecord = caseElement.getAsJsonObject();
|
||||
collectJob(record.get("item"), caseRecord.get("render_path"), caseRecord.get("when"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void collectJob(JsonElement itemElement, JsonElement renderPathElement, JsonElement customNameElement) {
|
||||
if (itemElement == null || !itemElement.isJsonPrimitive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (renderPathElement == null || renderPathElement.isJsonNull() || !renderPathElement.isJsonPrimitive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String itemId = itemElement.getAsString();
|
||||
String renderPath = renderPathElement.getAsString();
|
||||
String customName = customNameElement != null && customNameElement.isJsonPrimitive() ? customNameElement.getAsString() : null;
|
||||
|
||||
ItemStack stack = new ItemStack(Registries.ITEM.get(Identifier.of("minecraft", itemId)));
|
||||
if (stack.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (customName != null) {
|
||||
stack.setCustomName(Text.literal(customName));
|
||||
}
|
||||
|
||||
jobs.add(new RenderJob(renderPath, stack));
|
||||
}
|
||||
|
||||
private Path readPathEnv(String key) {
|
||||
String value = System.getenv(key);
|
||||
if (value == null || value.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Path.of(value);
|
||||
}
|
||||
|
||||
private void renderCurrentJob(MinecraftClient client, RenderScreen screen) {
|
||||
if (currentJobIndex >= jobs.size()) {
|
||||
client.scheduleStop();
|
||||
return;
|
||||
}
|
||||
|
||||
RenderJob job = jobs.get(currentJobIndex);
|
||||
Path jobPath = outputDir.resolve(job.outputPath()).normalize();
|
||||
Path parent = jobPath.getParent();
|
||||
if (parent == null) {
|
||||
client.scheduleStop();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Files.createDirectories(parent);
|
||||
} catch (IOException exception) {
|
||||
throw new RuntimeException("Failed to create render output directory", exception);
|
||||
}
|
||||
|
||||
String fileName = stripPngSuffix(jobPath.getFileName().toString());
|
||||
ScreenshotRecorder.saveScreenshot(parent.toFile(), fileName, client.getFramebuffer(), client.getWindow().getFramebufferWidth(), status -> client.execute(this::advanceJob));
|
||||
screen.markCaptureQueued();
|
||||
}
|
||||
|
||||
private void advanceJob() {
|
||||
currentJobIndex++;
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
if (currentJobIndex >= jobs.size()) {
|
||||
client.scheduleStop();
|
||||
return;
|
||||
}
|
||||
|
||||
Screen currentScreen = client.currentScreen;
|
||||
if (currentScreen instanceof RenderScreen renderScreen) {
|
||||
renderScreen.resetCaptureState();
|
||||
}
|
||||
}
|
||||
|
||||
private String stripPngSuffix(String fileName) {
|
||||
if (fileName.endsWith(".png")) {
|
||||
return fileName.substring(0, fileName.length() - 4);
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private record RenderJob(String outputPath, ItemStack stack) {
|
||||
}
|
||||
|
||||
private final class RenderScreen extends Screen {
|
||||
private boolean captureQueued;
|
||||
|
||||
private RenderScreen() {
|
||||
super(Text.literal("Rendering renameable items"));
|
||||
}
|
||||
|
||||
private void markCaptureQueued() {
|
||||
captureQueued = true;
|
||||
}
|
||||
|
||||
private void resetCaptureState() {
|
||||
captureQueued = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
context.fill(0, 0, width, height, 0x00000000);
|
||||
|
||||
if (currentJobIndex < jobs.size()) {
|
||||
RenderJob job = jobs.get(currentJobIndex);
|
||||
context.getMatrices().push();
|
||||
context.getMatrices().translate(width / 2.0, height / 2.0, 0.0);
|
||||
context.getMatrices().scale(8.0f, 8.0f, 1.0f);
|
||||
context.drawItem((LivingEntity) null, job.stack(), -1, -1, 0);
|
||||
context.getMatrices().pop();
|
||||
|
||||
if (!captureQueued) {
|
||||
captureQueued = true;
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
client.execute(() -> renderCurrentJob(client, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldPause() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user