Remove client renderer module
This commit is contained in:
@@ -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'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
pluginManagement {
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
name = 'Fabric'
|
|
||||||
url = 'https://maven.fabricmc.net/'
|
|
||||||
}
|
|
||||||
gradlePluginPortal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rootProject.name = 'renameable-item-renderer'
|
|
||||||
-300
@@ -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<RenderJob> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user