diff --git a/build/client-renderer/build.gradle b/build/client-renderer/build.gradle deleted file mode 100644 index ab8d220..0000000 --- a/build/client-renderer/build.gradle +++ /dev/null @@ -1,48 +0,0 @@ -plugins { - id 'net.fabricmc.fabric-loom' version '1.18.0-alpha.15' - id 'java' -} - -group = 'dev.github.copilot' -version = '1.0.0' - -repositories { - maven { url = 'https://maven.fabricmc.net/' } - mavenCentral() -} - -def minecraftVersion = providers.environmentVariable('MINECRAFT_VERSION') - .orElse(providers.gradleProperty('minecraft_version')) - .get() - -dependencies { - minecraft "com.mojang:minecraft:${minecraftVersion}" - implementation "net.fabricmc:fabric-loader:0.19.3" - implementation 'com.google.code.gson:gson:2.11.0' -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(25) - } -} - -tasks.withType(JavaCompile).configureEach { - options.encoding = 'UTF-8' - options.release = 24 -} - -sourceSets { - main { - java.srcDir(file('src/client/java')) - resources.srcDir(file('../resourcepack')) - } -} - -loom { - runs { - client { - programArgs '--username', 'RenderBot' - } - } -} \ No newline at end of file diff --git a/build/client-renderer/settings.gradle b/build/client-renderer/settings.gradle deleted file mode 100644 index 7f2962e..0000000 --- a/build/client-renderer/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -pluginManagement { - repositories { - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - gradlePluginPortal() - } -} - -rootProject.name = 'renameable-item-renderer' \ No newline at end of file diff --git a/build/client-renderer/src/client/java/dev/github/copilot/renameable/RenderCatalogClient.java b/build/client-renderer/src/client/java/dev/github/copilot/renameable/RenderCatalogClient.java deleted file mode 100644 index 0209af2..0000000 --- a/build/client-renderer/src/client/java/dev/github/copilot/renameable/RenderCatalogClient.java +++ /dev/null @@ -1,300 +0,0 @@ -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.Minecraft; -import net.minecraft.client.Screenshot; -import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.core.component.DataComponents; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.Identifier; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; - -public final class RenderCatalogClient implements ClientModInitializer { - private static final Gson GSON = new Gson(); - private static final long SCREEN_ACTIVATION_TIMEOUT_MILLIS = 30_000L; - private static final long CAPTURE_TIMEOUT_MILLIS = 120_000L; - - private final List jobs = new ArrayList<>(); - private Path outputDir; - private int currentJobIndex; - private RenderScreen renderScreen; - - @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; - } - - System.out.println("[renderer] queued " + jobs.size() + " render jobs"); - Minecraft client = Minecraft.getInstance(); - renderScreen = new RenderScreen(); - - client.execute(() -> { - System.out.println("[renderer] opening render screen"); - client.setScreenAndShow(renderScreen); - client.execute(() -> { - System.out.println("[renderer] starting render loop after screen open"); - renderCurrentJob(client, renderScreen); - }); - }); - - Thread activationWatchdog = new Thread(() -> { - try { - Thread.sleep(SCREEN_ACTIVATION_TIMEOUT_MILLIS); - } catch (InterruptedException exception) { - Thread.currentThread().interrupt(); - return; - } - - if (!renderScreen.activated) { - System.err.println("[renderer] render screen never activated within " + SCREEN_ACTIVATION_TIMEOUT_MILLIS + "ms"); - Runtime.getRuntime().halt(1); - } - }, "renderer-activation-watchdog"); - activationWatchdog.setDaemon(true); - activationWatchdog.start(); - } - - 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; - - Item item = BuiltInRegistries.ITEM.getValue(Identifier.withDefaultNamespace(itemId)); - if (item == null) { - return; - } - - jobs.add(new RenderJob(renderPath, item, customName)); - } - - private Path readPathEnv(String key) { - String value = System.getenv(key); - if (value == null || value.isBlank()) { - return null; - } - - return Path.of(value); - } - - private void renderCurrentJob(Minecraft client, RenderScreen screen) { - if (currentJobIndex >= jobs.size()) { - client.stop(); - return; - } - - RenderJob job = jobs.get(currentJobIndex); - System.out.println("[renderer] rendering " + (currentJobIndex + 1) + "/" + jobs.size() + " -> " + job.outputPath()); - Path jobPath = outputDir.resolve(job.outputPath()).normalize(); - Path parent = jobPath.getParent(); - if (parent == null) { - client.stop(); - return; - } - - try { - Files.createDirectories(parent); - } catch (IOException exception) { - throw new RuntimeException("Failed to create render output directory", exception); - } - - String fileName = stripPngSuffix(jobPath.getFileName().toString()); - Screenshot.takeScreenshot(client.gameRenderer.mainRenderTarget(), screenshot -> { - try { - Path savedPath = saveScreenshot(screenshot, fileName, parent); - if (savedPath == null) { - throw new RuntimeException("Failed to save screenshot"); - } - System.out.println("[renderer] saved " + job.outputPath()); - } finally { - client.execute(this::advanceJob); - } - }); - screen.markCaptureQueued(); - } - - private Path saveScreenshot(com.mojang.blaze3d.platform.NativeImage screenshot, String fileName, Path destinationDir) { - try { - Files.createDirectories(destinationDir); - } catch (IOException exception) { - throw new RuntimeException("Failed to create render output directory", exception); - } - - Path screenshotFile = destinationDir.resolve(fileName + ".png"); - - try { - screenshot.writeToFile(screenshotFile); - } catch (IOException exception) { - throw new RuntimeException("Failed to write render output", exception); - } - - return screenshotFile; - } - - private void advanceJob() { - currentJobIndex++; - Minecraft client = Minecraft.getInstance(); - if (currentJobIndex >= jobs.size()) { - System.out.println("[renderer] completed all render jobs"); - client.stop(); - return; - } - - if (renderScreen != null) { - renderScreen.resetCaptureState(); - } - } - - private String stripPngSuffix(String fileName) { - if (fileName.endsWith(".png")) { - return fileName.substring(0, fileName.length() - 4); - } - - return fileName; - } - - private ItemStack createStack(RenderJob job) { - ItemStack stack = new ItemStack(job.item()); - if (stack.isEmpty()) { - return stack; - } - - if (job.customName() != null) { - stack.set(DataComponents.CUSTOM_NAME, Component.literal(job.customName())); - } - - return stack; - } - - private record RenderJob(String outputPath, Item item, String customName) { - } - - private final class RenderScreen extends Screen { - private boolean captureQueued; - private long captureQueuedAtMillis; - private volatile boolean activated; - - private RenderScreen() { - super(Component.literal("Rendering renameable items")); - } - - private void markCaptureQueued() { - captureQueued = true; - captureQueuedAtMillis = System.currentTimeMillis(); - } - - private void resetCaptureState() { - captureQueued = false; - captureQueuedAtMillis = 0L; - } - - @Override - public void extractRenderState(GuiGraphicsExtractor context, int mouseX, int mouseY, float delta) { - super.extractRenderState(context, mouseX, mouseY, delta); - context.fill(0, 0, width, height, 0x00000000); - - if (!activated) { - activated = true; - System.out.println("[renderer] render screen active"); - } - - if (currentJobIndex < jobs.size()) { - Minecraft client = Minecraft.getInstance(); - RenderJob job = jobs.get(currentJobIndex); - if (captureQueued && captureQueuedAtMillis > 0L && System.currentTimeMillis() - captureQueuedAtMillis > CAPTURE_TIMEOUT_MILLIS) { - throw new RuntimeException("Timed out waiting for screenshot capture for " + job.outputPath()); - } - - ItemStack stack = createStack(job); - if (stack.isEmpty()) { - client.execute(() -> advanceJob()); - return; - } - - context.item(stack, (width / 2) - 8, (height / 2) - 8); - - if (!captureQueued) { - captureQueued = true; - client.execute(() -> renderCurrentJob(client, this)); - } - } - } - - @Override - public boolean isPauseScreen() { - return false; - } - } -} diff --git a/build/client-renderer/src/main/resources/fabric.mod.json b/build/client-renderer/src/main/resources/fabric.mod.json deleted file mode 100644 index c14f97b..0000000 --- a/build/client-renderer/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "schemaVersion": 1, - "id": "renameable-item-renderer", - "version": "${version}", - "name": "Renameable Item Renderer", - "description": "Renders renameable item previews with the Minecraft client renderer.", - "environment": "client", - "entrypoints": { - "client": [ - "dev.github.copilot.renameable.RenderCatalogClient" - ] - }, - "depends": { - "minecraft": "*", - "fabricloader": ">=0.16.10" - } -} \ No newline at end of file