Files
PixelPics/tools/ObjectTestRender.java
T
MineTec 32afe08f03 render entities from vanilla client models, add items, displays and leashes
- dump entity models straight from the unobfuscated client jar
  (tools/VanillaModelDump.java, tools/update-vanilla-models.sh): models posed
  by vanilla setupAnim, baby/variant/layer models, renderer transforms,
  default textures, pose variants (sitting, holding items, illager arms)
  and all layer definitions; the old CEM template is only a fallback now
- fix adult zombies captured as babies, zero-thickness planes (wings,
  fins) and back faces in the entity intersector
- held items, head items (pumpkins, skulls), shields, elytra, saddles and
  body equipment for every mount, armor following the pose
- block/item/text display entities, dropped items, falling blocks, primed
  TNT, minecart contents, block entities inside displays, leash ropes
- item models resolved from the 26.x item definitions with display
  transforms; generated items extruded like vanilla
- bundle the vanilla font definitions as fallback so sign/text rendering
  works with packs that lack font/*.json
- one failing entity no longer aborts the whole photo
- edge-case test plugin (tools/edgecase-plugin) and offline harnesses
2026-11-04 13:11:39 +01:00

107 lines
6.0 KiB
Java

import eu.mhsl.minecraft.pixelpics.assets.*;
import eu.mhsl.minecraft.pixelpics.render.entity.*;
import eu.mhsl.minecraft.pixelpics.render.render.*;
import eu.mhsl.minecraft.pixelpics.render.sky.SkyContext;
import eu.mhsl.minecraft.pixelpics.render.snapshot.WorldSnapshot;
import eu.mhsl.minecraft.pixelpics.render.tint.BiomeTintProvider;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.util.Vector;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.List;
import java.util.logging.Logger;
/**
* Standalone (no server) render of {@link ObjectState}s — block/item/text displays, dropped items,
* falling blocks — in one scene, to check the ObjectBaker geometry, UV orientation and transforms.
* Output: ~/Dokumente/PixelPics-Entity-Renders/objects.png
*/
public class ObjectTestRender {
static final String ROOT = "/home/elias/Dokumente/mcTestServer/plugins/PixelPics";
/** Server-free BlockData stand-in: material + blockstate string are all the model registry needs. */
static BlockData block(Material m, String state) {
String s = "minecraft:" + m.getKey().getKey() + (state == null ? "" : "[" + state + "]");
return (BlockData) Proxy.newProxyInstance(ObjectTestRender.class.getClassLoader(),
new Class<?>[]{BlockData.class}, (p, meth, a) -> switch (meth.getName()) {
case "getMaterial" -> m;
case "getAsString" -> s;
case "equals" -> p == a[0];
case "hashCode" -> System.identityHashCode(p);
case "toString" -> s;
default -> {
Class<?> rt = meth.getReturnType();
yield rt == boolean.class ? false : (rt.isPrimitive() ? 0 : null);
}
});
}
static ObjectState obj(ObjectState.Kind k, Affine a, BlockData b, String item, List<String> lines, int bg) {
return switch (k) {
case BLOCK -> ObjectState.block(a, b, null);
case ITEM -> ObjectState.item(a, new ItemSpec(item, b, null, false), "none", false);
case TEXT -> ObjectState.text(a, lines, 200, 0xFFFFFFFF, bg, true);
case LEASH -> ObjectState.leash(new double[6]);
};
}
public static void main(String[] args) throws Exception {
Logger log = Logger.getLogger("test");
ResourcePack pack = ResourcePackLoader.load(new File(ROOT, "resourcepack"), log).orElseThrow();
AssetReader reader = new AssetReader(pack);
TextureCache textures = new TextureCache(pack);
BlockModelRegistry registry = new BlockModelRegistry(reader, textures);
BiomeTintProvider tint = new BiomeTintProvider(textures);
var geo = new eu.mhsl.minecraft.pixelpics.render.entity.cem.CemModelLoader();
var font = eu.mhsl.minecraft.pixelpics.assets.font.FontLoader.load(pack, textures, log);
SkinCache skins = new SkinCache();
var baker = new eu.mhsl.minecraft.pixelpics.render.entity.cem.CemBaker(geo, textures, skins);
var beBaker = new eu.mhsl.minecraft.pixelpics.render.entity.cem.BlockEntityBaker(geo, textures, skins, font);
geo.load(new java.io.FileInputStream("src/main/resources/cem/cem_template_models.json"), log);
geo.load(new java.io.FileInputStream("src/main/resources/cem/vanilla_entity_models.json"), log);
DefaultScreenRenderer renderer = new DefaultScreenRenderer(registry, tint, textures, baker, beBaker, log);
List<ObjectState> objs = new ArrayList<>();
// Block displays: plain grass block (tinted), rotated + scaled stairs.
objs.add(obj(ObjectState.Kind.BLOCK, Affine.translation(0, 0, 0), block(Material.GRASS_BLOCK, "snowy=false"), null, List.of(), 0));
objs.add(obj(ObjectState.Kind.BLOCK,
Affine.translation(2, 0, 0).mul(Affine.rotY(Math.toRadians(30))).mul(Affine.scale(0.75)),
block(Material.OAK_STAIRS, "facing=north,half=bottom,shape=straight,waterlogged=false"), null, List.of(), 0));
// Item displays: a flat item and a block item (centred).
objs.add(obj(ObjectState.Kind.ITEM, Affine.translation(0.5, 2.0, 0.5), null, "diamond_sword", List.of(), 0));
objs.add(obj(ObjectState.Kind.ITEM, Affine.translation(2.5, 2.0, 0.5).mul(Affine.scale(0.6)),
block(Material.OAK_LOG, "axis=y"), "oak_log", List.of(), 0));
// Text display (facing the camera side), opaque background.
objs.add(obj(ObjectState.Kind.TEXT,
Affine.translation(1.5, 3.0, 0).mul(Affine.rotY(Math.PI)).mul(Affine.scale(0.025)), null, null,
List.of("Hallo PixelPics!", "Zeile zwei äöü"), 0xFF203040));
// Text seen from the BACK (front faces +Z, camera is on -Z) and a shield item.
objs.add(obj(ObjectState.Kind.TEXT, Affine.translation(-0.5, 3.0, 0).mul(Affine.scale(0.025)), null, null,
List.of("Rueckseite"), 0));
objs.add(obj(ObjectState.Kind.ITEM, Affine.translation(4, 1.0, 0.5), null, "shield", List.of(), 0));
// Dropped item (flat) on the ground.
objs.add(obj(ObjectState.Kind.ITEM, Affine.translation(-1, 0.3, 0.5).mul(Affine.scale(0.5)), null, "apple", List.of(), 0));
BlockData air = block(Material.AIR, null);
WorldSnapshot empty = new WorldSnapshot(Map.of(), 0, 1, air);
SkyContext sky = new SkyContext(6000, 0, 6000);
int W = 480, H = 360;
Vector cam = new Vector(1.5, 3.2, -6.5);
Location loc = new Location(null, cam.getX(), cam.getY(), cam.getZ());
loc.setDirection(new Vector(1.2, 1.3, 0.5).subtract(cam));
List<Vector> rayMap = EntityTestRender.buildRayMap(loc, W * 3, H * 3);
RenderJob job = new RenderJob(empty, rayMap, cam, W, H, sky, List.of(), List.of(), List.of(), objs);
BufferedImage img = renderer.execute(job);
File out = new File("/home/elias/Dokumente/PixelPics-Entity-Renders/objects.png");
ImageIO.write(img, "png", out);
System.out.println("WROTE " + out);
}
}