render all block entities from the dumped vanilla models with decompiled renderer poses, drop the cem block-entity path
This commit is contained in:
1 parent
c66ebaa942
commit
022b080fce
14 files changed
+659
-567
No files matched your search
@@ -33,14 +33,20 @@ public class BlockEntityTestRender {
|
||||
static BlockEntityBaker beBaker;
|
||||
static DecorationBaker decoBaker;
|
||||
|
||||
static BlockEntityState be(Kind kind, int bx, int by, int bz, float yaw) {
|
||||
return new BlockEntityState(kind, bx, by, bz, yaw, ChestKind.SINGLE, 0, null, "oak",
|
||||
null, null, null, List.of(), List.of(), null, null, null);
|
||||
/** A block-entity state at (bx, 0, bz); unused fields default. */
|
||||
static BlockEntityState st(Kind kind, int bx, int bz, float yaw, String direction, boolean active, String color,
|
||||
int baseColor, String head, List<BannerPattern> pats, List<String> sherds) {
|
||||
return new BlockEntityState(kind, bx, 0, bz, yaw, direction, active, ChestKind.SINGLE, baseColor, color,
|
||||
head, null, pats, sherds, null, null);
|
||||
}
|
||||
|
||||
static BlockEntityState be(Kind kind, float yaw) {
|
||||
return st(kind, 0, 0, yaw, null, false, null, 0, null, List.of(), List.of());
|
||||
}
|
||||
|
||||
static BlockEntityState sign(Kind kind, float yaw, SignText front, SignText back) {
|
||||
return new BlockEntityState(kind, 0, 0, 0, yaw, null, 0, null, "oak",
|
||||
null, null, null, List.of(), List.of(), null, front, back);
|
||||
return new BlockEntityState(kind, 0, 0, 0, yaw, null, false, null, 0, null, null, null,
|
||||
List.of(), List.of(), front, back);
|
||||
}
|
||||
|
||||
static SignText txt(org.bukkit.DyeColor dye, boolean glow, String... lines) {
|
||||
@@ -57,7 +63,7 @@ public class BlockEntityTestRender {
|
||||
BlockModelRegistry registry = new BlockModelRegistry(reader, textures);
|
||||
BiomeTintProvider tint = new BiomeTintProvider(textures);
|
||||
CemModelLoader geo = new CemModelLoader();
|
||||
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/cem_template_models.json"), log); // entity fallback only
|
||||
geo.load(new java.io.FileInputStream("src/main/resources/cem/vanilla_entity_models.json"), log);
|
||||
SkinCache skins = new SkinCache();
|
||||
eu.mhsl.minecraft.pixelpics.assets.font.BitmapFont font =
|
||||
@@ -113,49 +119,86 @@ public class BlockEntityTestRender {
|
||||
chest(Kind.COPPER_CHEST, 0, 0, 0, ChestKind.LEFT, "oxidized"),
|
||||
chest(Kind.COPPER_CHEST, -1, 0, 0, ChestKind.RIGHT, "oxidized")));
|
||||
frontCam.put("copper_oxidized_double", 0f);
|
||||
scenes.put("sign", List.of(be(Kind.SIGN, 0, 0, 0, 0)));
|
||||
scenes.put("wall_sign", List.of(be(Kind.WALL_SIGN, 0, 0, 0, 0)));
|
||||
scenes.put("hanging_sign", List.of(be(Kind.HANGING_SIGN, 0, 0, 0, 0)));
|
||||
// --- sign text (calibration) --- facingDeg=180 → front (model −Z) faces the camera (north).
|
||||
// --- sign text (boards are block models, not drawn here) --- facingDeg 180 → front faces north.
|
||||
org.bukkit.DyeColor B = org.bukkit.DyeColor.BLACK;
|
||||
scenes.put("sign_text", List.of(sign(Kind.SIGN, 180,
|
||||
txt(B, false, "Hello World", "zweite Zeile", "Gruesse: AÖÜ", "ßäöü 12345"), null)));
|
||||
scenes.put("wall_sign_text", List.of(sign(Kind.WALL_SIGN, 180,
|
||||
txt(B, false, "Wall Sign", "Line 2", "Line 3", "Line 4"), null)));
|
||||
scenes.put("hanging_sign_text", List.of(sign(Kind.HANGING_SIGN, 180,
|
||||
txt(B, false, "Hanging", "sign text", "row 3", "row 4"), null)));
|
||||
scenes.put("sign_text_red", List.of(sign(Kind.SIGN, 180,
|
||||
txt(org.bukkit.DyeColor.RED, false, "RED INK", "colored", "sign text", ""), null)));
|
||||
scenes.put("sign_text_glow", List.of(sign(Kind.SIGN, 180,
|
||||
txt(org.bukkit.DyeColor.LIME, true, "GLOWING", "lime glow", "outline!", ""), null)));
|
||||
scenes.put("sign_text_front", List.of(sign(Kind.SIGN, 180,
|
||||
txt(B, false, "FRONT", "side", "", ""), txt(org.bukkit.DyeColor.BLUE, false, "BACK", "side", "", ""))));
|
||||
// View the BACK side head-on (facingDeg=0 turns the back face toward the camera).
|
||||
scenes.put("sign_view_back", List.of(sign(Kind.SIGN, 0,
|
||||
txt(B, false, "FRONTXY", "f2", "", ""), txt(org.bukkit.DyeColor.BLUE, false, "BACKXY", "b2", "", ""))));
|
||||
String[] D = {"S", "W", "N", "E"};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float yaw = i * 90;
|
||||
scenes.put("sign_text_" + D[i], List.of(sign(Kind.SIGN, yaw, txt(B, false, "Hello World", "zweite Zeile", "Gruesse: AÖÜ", "ßäöü 12345"), null)));
|
||||
frontCam.put("sign_text_" + D[i], yaw);
|
||||
}
|
||||
scenes.put("sign_text_diag", List.of(sign(Kind.SIGN, 22.5f * 3, txt(B, false, "rot 3", "67.5 deg", "", ""), null)));
|
||||
frontCam.put("sign_text_diag", 22.5f * 3);
|
||||
scenes.put("wall_sign_text", List.of(sign(Kind.WALL_SIGN, 180, txt(B, false, "Wall Sign", "Line 2", "Line 3", "Line 4"), null)));
|
||||
frontCam.put("wall_sign_text", 180f);
|
||||
scenes.put("wall_sign_text_E", List.of(sign(Kind.WALL_SIGN, 270, txt(B, false, "Wall East", "Line 2", "", ""), null)));
|
||||
frontCam.put("wall_sign_text_E", 270f);
|
||||
scenes.put("hanging_sign_text", List.of(sign(Kind.HANGING_SIGN, 180, txt(B, false, "Hanging", "sign text", "row 3", "row 4"), null)));
|
||||
frontCam.put("hanging_sign_text", 180f);
|
||||
scenes.put("sign_text_red", List.of(sign(Kind.SIGN, 180, txt(org.bukkit.DyeColor.RED, false, "RED INK", "colored", "sign text", ""), null)));
|
||||
frontCam.put("sign_text_red", 180f);
|
||||
scenes.put("sign_text_glow", List.of(sign(Kind.SIGN, 180, txt(org.bukkit.DyeColor.LIME, true, "GLOWING", "lime glow", "outline!", ""), null)));
|
||||
frontCam.put("sign_text_glow", 180f);
|
||||
// Back side viewed head-on: the camera looks at the side opposite the front.
|
||||
scenes.put("sign_view_back", List.of(sign(Kind.SIGN, 180, txt(B, false, "FRONTXY", "f2", "", ""), txt(org.bukkit.DyeColor.BLUE, false, "BACKXY", "b2", "", ""))));
|
||||
frontCam.put("sign_view_back", 0f);
|
||||
scenes.put("sign_1line", List.of(sign(Kind.SIGN, 180, txt(B, false, "", "SHOP", "", ""), null)));
|
||||
scenes.put("sign_2line", List.of(sign(Kind.SIGN, 180, txt(B, false, "", "Welcome", "home!", ""), null)));
|
||||
frontCam.put("sign_1line", 180f);
|
||||
scenes.put("sign_long", List.of(sign(Kind.SIGN, 180, txt(B, false, "a very long line here", "", "", ""), null)));
|
||||
scenes.put("banner", List.of(new BlockEntityState(Kind.BANNER, 0, 0, 0, 0, null, 0xFFCC2020, null, null, null, null, null, List.of(), List.of(), null, null, null)));
|
||||
scenes.put("banner_patterned", List.of(new BlockEntityState(Kind.BANNER, 0, 0, 0, 0, null, 0xFFFFFFFF, null, null, null, null, null,
|
||||
List.of(new BannerPattern("stripe_bottom", 0xFFCC2020), new BannerPattern("cross", 0xFF2040CC), new BannerPattern("border", 0xFF20A020)), List.of(), null, null, null)));
|
||||
scenes.put("wall_banner", List.of(new BlockEntityState(Kind.WALL_BANNER, 0, 0, 0, 0, null, 0xFF2040CC, null, null, null, null, null, List.of(), List.of(), null, null, null)));
|
||||
scenes.put("bed", List.of(
|
||||
new BlockEntityState(Kind.BED, 0, 0, 0, 0, null, 0, "red", null, BedPart.FOOT, null, null, List.of(), List.of(), null, null, null),
|
||||
new BlockEntityState(Kind.BED, 0, 0, 1, 0, null, 0, "red", null, BedPart.HEAD, null, null, List.of(), List.of(), null, null, null)));
|
||||
scenes.put("shulker_box", List.of(new BlockEntityState(Kind.SHULKER_BOX, 0, 0, 0, 0, null, 0, null, null, null, null, null, List.of(), List.of(), null, null, null)));
|
||||
scenes.put("conduit", List.of(be(Kind.CONDUIT, 0, 0, 0, 0)));
|
||||
scenes.put("decorated_pot", List.of(be(Kind.DECORATED_POT, 0, 0, 0, 0)));
|
||||
scenes.put("decorated_pot_sherds", List.of(new BlockEntityState(Kind.DECORATED_POT, 0, 0, 0, 0, null, 0, null, null, null, null, null,
|
||||
List.of(), List.of("angler_pottery_sherd", "heart_pottery_sherd", "skull_pottery_sherd", "brick"), null, null, null)));
|
||||
scenes.put("bell", List.of(be(Kind.BELL, 0, 0, 0, 0)));
|
||||
scenes.put("head_skeleton", List.of(head("skeleton")));
|
||||
scenes.put("head_zombie", List.of(head("zombie")));
|
||||
scenes.put("head_creeper", List.of(head("creeper")));
|
||||
scenes.put("head_dragon", List.of(head("dragon")));
|
||||
scenes.put("head_piglin", List.of(head("piglin")));
|
||||
scenes.put("wither_skull", List.of(headKind(Kind.HEAD, "wither_skeleton")));
|
||||
scenes.put("wall_head", List.of(headKind(Kind.WALL_HEAD, "skeleton")));
|
||||
frontCam.put("sign_long", 180f);
|
||||
// --- banners: standing (rotation 0/4/6), wall (4 facings), patterned ---
|
||||
List<BannerPattern> pats = List.of(new BannerPattern("stripe_bottom", 0xFFCC2020), new BannerPattern("cross", 0xFF2040CC), new BannerPattern("border", 0xFF20A020));
|
||||
for (float yaw : new float[] {0, 90, 135}) {
|
||||
String k = "banner_" + (int) yaw;
|
||||
scenes.put(k, List.of(st(Kind.BANNER, 0, 0, yaw, null, false, null, 0xFFCC2020, null, List.of(), List.of())));
|
||||
frontCam.put(k, yaw);
|
||||
}
|
||||
scenes.put("banner_patterned", List.of(st(Kind.BANNER, 0, 0, 0, null, false, null, 0xFFFFFFFF, null, pats, List.of())));
|
||||
frontCam.put("banner_patterned", 0f);
|
||||
scenes.put("banner_side", scenes.get("banner_patterned"));
|
||||
frontCam.put("banner_side", 90f);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
scenes.put("wall_banner_" + D[i], List.of(st(Kind.WALL_BANNER, 0, 0, i * 90, null, false, null, 0xFF2040CC, null, pats, List.of())));
|
||||
frontCam.put("wall_banner_" + D[i], i * 90f);
|
||||
}
|
||||
// --- shulker boxes: 6 facings ---
|
||||
for (String d : new String[] {"up", "down", "north", "south", "east", "west"}) {
|
||||
scenes.put("shulker_" + d, List.of(st(Kind.SHULKER_BOX, 0, 0, 0, d, false, d.equals("up") ? null : "red", 0, null, List.of(), List.of())));
|
||||
frontCam.put("shulker_" + d, 0f);
|
||||
}
|
||||
scenes.put("conduit", List.of(be(Kind.CONDUIT, 0)));
|
||||
scenes.put("conduit_active", List.of(st(Kind.CONDUIT, 0, 0, 0, null, true, null, 0, null, List.of(), List.of())));
|
||||
List<String> sherds = List.of("heart_pottery_sherd", "skull_pottery_sherd", "angler_pottery_sherd", "brick");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
scenes.put("pot_" + D[i], List.of(st(Kind.DECORATED_POT, 0, 0, i * 90, null, false, null, 0, null, List.of(), sherds)));
|
||||
frontCam.put("pot_" + D[i], i * 90f);
|
||||
}
|
||||
scenes.put("pot_plain", List.of(be(Kind.DECORATED_POT, 0)));
|
||||
frontCam.put("pot_plain", 0f);
|
||||
scenes.put("bell", List.of(be(Kind.BELL, 0)));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
scenes.put("lectern_book_" + D[i], List.of(st(Kind.LECTERN, 0, 0, i * 90, null, true, null, 0, null, List.of(), List.of())));
|
||||
frontCam.put("lectern_book_" + D[i], i * 90f);
|
||||
}
|
||||
// --- heads: every type facing the camera (rotation 0), plus rotations and wall mounts ---
|
||||
for (String t : new String[] {"skeleton", "wither_skeleton", "zombie", "creeper", "player", "piglin", "dragon"}) {
|
||||
scenes.put("head_" + t, List.of(head(Kind.HEAD, t, 0)));
|
||||
frontCam.put("head_" + t, 0f);
|
||||
}
|
||||
scenes.put("head_dragon_side", List.of(head(Kind.HEAD, "dragon", 0)));
|
||||
frontCam.put("head_dragon_side", 90f);
|
||||
for (float yaw : new float[] {90, 157.5f, 270}) {
|
||||
scenes.put("head_creeper_" + yaw, List.of(head(Kind.HEAD, "creeper", yaw)));
|
||||
frontCam.put("head_creeper_" + yaw, yaw);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
scenes.put("wall_head_" + D[i], List.of(head(Kind.WALL_HEAD, "skeleton", i * 90)));
|
||||
frontCam.put("wall_head_" + D[i], i * 90f);
|
||||
}
|
||||
scenes.put("wall_dragon_N", List.of(head(Kind.WALL_HEAD, "dragon", 180)));
|
||||
frontCam.put("wall_dragon_N", 180f);
|
||||
scenes.put("wall_piglin_E", List.of(head(Kind.WALL_HEAD, "piglin", 270)));
|
||||
frontCam.put("wall_piglin_E", 270f);
|
||||
|
||||
// Decoration scenes (paintings + item frames), rendered via the same scene path.
|
||||
LinkedHashMap<String, List<DecorationState>> decoScenes = new LinkedHashMap<>();
|
||||
@@ -206,13 +249,12 @@ public class BlockEntityTestRender {
|
||||
static final Map<String, Float> frontCam = new HashMap<>();
|
||||
|
||||
static BlockEntityState chest(Kind kind, int bx, int bz, float yaw, ChestKind ck, String variant) {
|
||||
return new BlockEntityState(kind, bx, 0, bz, yaw, ck, 0, variant, null, null, null, null,
|
||||
List.of(), List.of(), null, null, null);
|
||||
return new BlockEntityState(kind, bx, 0, bz, yaw, null, false, ck, 0, variant, null, null,
|
||||
List.of(), List.of(), null, null);
|
||||
}
|
||||
|
||||
static BlockEntityState head(String type) { return headKind(Kind.HEAD, type); }
|
||||
static BlockEntityState headKind(Kind kind, String type) {
|
||||
return new BlockEntityState(kind, 0, 0, 0, 0, null, 0, null, null, null, type, null, List.of(), List.of(), null, null, null);
|
||||
static BlockEntityState head(Kind kind, String type, float yaw) {
|
||||
return st(kind, 0, 0, yaw, null, false, null, 0, type, List.of(), List.of());
|
||||
}
|
||||
|
||||
static BufferedImage renderScene(DefaultScreenRenderer renderer, WorldSnapshot world, SkyContext sky,
|
||||
|
||||
@@ -156,6 +156,29 @@ public class VanillaModelDump {
|
||||
failed.add(name + " (layer: " + t + ")");
|
||||
}
|
||||
}
|
||||
// Block-entity models posed by their own setupAnim with the static state the vanilla
|
||||
// BlockEntityRenderer uses ("posed/<layer>"): skulls at animation 0 (dragon jaw, piglin ears), banner
|
||||
// flags at wave phase 0 (item/static pose), the lectern's open book (LecternRenderer.BOOK_STATE).
|
||||
// Rest-pose-only models (chest, bell, shulker box, pot, conduit) use "layer/<layer>" directly.
|
||||
posedBlockEntity(out, failed, set, net.minecraft.client.model.geom.ModelLayers.DRAGON_SKULL,
|
||||
m -> new net.minecraft.client.model.object.skull.DragonHeadModel(m),
|
||||
new net.minecraft.client.model.object.skull.SkullModelBase.State());
|
||||
posedBlockEntity(out, failed, set, net.minecraft.client.model.geom.ModelLayers.PIGLIN_HEAD,
|
||||
m -> new net.minecraft.client.model.object.skull.PiglinHeadModel(m),
|
||||
new net.minecraft.client.model.object.skull.SkullModelBase.State());
|
||||
posedBlockEntity(out, failed, set, net.minecraft.client.model.geom.ModelLayers.STANDING_BANNER_FLAG,
|
||||
m -> new net.minecraft.client.model.object.banner.BannerFlagModel(m), 0.0F);
|
||||
posedBlockEntity(out, failed, set, net.minecraft.client.model.geom.ModelLayers.WALL_BANNER_FLAG,
|
||||
m -> new net.minecraft.client.model.object.banner.BannerFlagModel(m), 0.0F);
|
||||
try {
|
||||
Field bookState = Class.forName("net.minecraft.client.renderer.blockentity.LecternRenderer")
|
||||
.getDeclaredField("BOOK_STATE");
|
||||
bookState.setAccessible(true);
|
||||
posedBlockEntity(out, failed, set, net.minecraft.client.model.geom.ModelLayers.BOOK,
|
||||
m -> new net.minecraft.client.model.object.book.BookModel(m), bookState.get(null));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
failed.add("posed/book (" + e + ")");
|
||||
}
|
||||
JsonObject root = new JsonObject();
|
||||
root.addProperty("version", SharedConstants.getCurrentVersion().name());
|
||||
JsonObject models = new JsonObject();
|
||||
@@ -171,6 +194,26 @@ public class VanillaModelDump {
|
||||
for (String f : failed) System.out.println("FAILED " + f);
|
||||
}
|
||||
|
||||
/** One block-entity model posed with {@code state} (see main), stored as {@code posed/<model>#<layer>}. */
|
||||
static void posedBlockEntity(
|
||||
Map<String, JsonObject> out,
|
||||
List<String> failed,
|
||||
EntityModelSet set,
|
||||
ModelLayerLocation loc,
|
||||
java.util.function.Function<ModelPart, Model<?>> factory,
|
||||
Object state) {
|
||||
String name = "posed/" + loc.model().getPath() + "#" + loc.layer();
|
||||
try {
|
||||
JsonObject jem = dump(factory.apply(set.bakeLayer(loc)), state, name, failed);
|
||||
if (jem == null) return;
|
||||
JsonObject entry = new JsonObject();
|
||||
entry.addProperty("model", new Gson().toJson(jem));
|
||||
out.put(name, entry);
|
||||
} catch (Throwable t) {
|
||||
failed.add(name + " (" + t + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Small, name-based tweaks so the default render state shows the typical idle look: illagers stand
|
||||
* with crossed arms (their peaceful pose) instead of the empty-handed "neutral" pose.
|
||||
|
||||
@@ -91,6 +91,31 @@ public class PPTest extends JavaPlugin {
|
||||
scenes.put("layers_top", new Scene("layers_top", this::layers, 5.5, 6, 2.0, 5.5, 0, 2.5));
|
||||
scenes.put("layers_wither", new Scene("layers_wither", this::withers, 3.5, 4, -9, 3.5, 2.2, 1));
|
||||
scenes.put("layers_wither_close", new Scene("layers_wither_close", this::withers, 6, 3.4, -3.5, 6, 2.6, 1));
|
||||
// Block entities (vanilla BlockEntityRenderer poses): signs, banners, heads in all 16 rotations + wall
|
||||
// mounts, and bells/pots/shulker boxes/lecterns/conduits, each layout seen from two sides.
|
||||
scenes.put("be_signs_s", new Scene("be_signs_s", this::beSigns, 7, 3, 8, 7, 0.5, 1));
|
||||
scenes.put("be_signs_n", new Scene("be_signs_n", this::beSigns, 7, 1.3, -8, 7, 0.6, 1));
|
||||
scenes.put("be_signs_close", new Scene("be_signs_close", this::beSigns, 3, 1.8, 4.2, 3, 0.8, 2));
|
||||
scenes.put("be_signs_wall", new Scene("be_signs_wall", this::beSigns, 4.6, 2.2, 10.2, 3.5, 0.9, 7));
|
||||
scenes.put("be_signs_wall_n", new Scene("be_signs_wall_n", this::beSigns, 1.4, 2.2, 3.8, 3.5, 0.9, 7));
|
||||
scenes.put("be_signs_wall2", new Scene("be_signs_wall2", this::beSigns, 12.5, 2.4, 10.2, 10, 1.2, 7));
|
||||
scenes.put("be_signs_hang", new Scene("be_signs_hang", this::beSigns, 4, 1.3, 0.2, 4, 1.4, -3));
|
||||
scenes.put("be_banners_s", new Scene("be_banners_s", this::beBanners, 7, 3, 10, 7, 1, 1.5));
|
||||
scenes.put("be_banners_n", new Scene("be_banners_n", this::beBanners, 7, 3, -6, 7, 1, 1.5));
|
||||
scenes.put("be_banners_wall", new Scene("be_banners_wall", this::beBanners, 13, 3.5, 9, 16, 1.5, 5));
|
||||
scenes.put("be_banners_wall_n", new Scene("be_banners_wall_n", this::beBanners, 13, 3.5, 1, 16, 1.5, 5));
|
||||
scenes.put("be_heads_s", new Scene("be_heads_s", this::beHeads, 5, 5, 11, 5, 0, 3));
|
||||
scenes.put("be_heads_n", new Scene("be_heads_n", this::beHeads, 5, 5, -6, 5, 0, 3));
|
||||
scenes.put("be_heads_close", new Scene("be_heads_close", this::beHeads, 4, 2.2, 9.5, 4, 0.3, 5));
|
||||
scenes.put("be_heads_wall_w", new Scene("be_heads_wall_w", this::beHeads, 7, 3, 2.5, 12, 1, 2.5));
|
||||
scenes.put("be_heads_wall_e", new Scene("be_heads_wall_e", this::beHeads, 17, 3, 2.5, 12, 1, 2.5));
|
||||
scenes.put("be_misc_s", new Scene("be_misc_s", this::beMisc, 6, 5, 11, 6, 0.5, 3));
|
||||
scenes.put("be_misc_n", new Scene("be_misc_n", this::beMisc, 6, 5, -6, 6, 0.5, 3));
|
||||
scenes.put("be_misc_close", new Scene("be_misc_close", this::beMisc, 3, 2.5, 3, 3, 0.5, 0));
|
||||
scenes.put("be_misc_lectern", new Scene("be_misc_lectern", this::beMisc, 3, 2.2, 9.5, 3, 0.6, 6));
|
||||
scenes.put("be_misc_shulker", new Scene("be_misc_shulker", this::beMisc, 11, 2.8, 9.5, 11, 0.3, 4));
|
||||
scenes.put("be_items", new Scene("be_items", this::beItems, 4.5, 2.6, 11, 4.5, 0.8, 3));
|
||||
scenes.put("be_items_back", new Scene("be_items_back", this::beItems, 4.5, 2.6, -5, 4.5, 0.8, 3));
|
||||
scenes.put("proj_stuck_sw", new Scene("proj_stuck_sw", this::projStuck, -3, 6, 10, 8, 1.5, 2));
|
||||
}
|
||||
|
||||
@@ -741,4 +766,122 @@ public class PPTest extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- block-entity scenes ------------------------------------------------------------------------
|
||||
|
||||
private void put(Location o, int x, int y, int z, String data) {
|
||||
o.clone().add(x, y, z).getBlock().setBlockData(Bukkit.createBlockData("minecraft:" + data), false);
|
||||
}
|
||||
|
||||
private void signText(Location o, int x, int y, int z, String front, String back) {
|
||||
if (!(o.clone().add(x, y, z).getBlock().getState() instanceof org.bukkit.block.Sign sg)) return;
|
||||
sg.getSide(org.bukkit.block.sign.Side.FRONT).setLine(1, front);
|
||||
sg.getSide(org.bukkit.block.sign.Side.BACK).setLine(1, back);
|
||||
sg.getSide(org.bukkit.block.sign.Side.BACK).setColor(DyeColor.BLUE);
|
||||
sg.update(true, false);
|
||||
}
|
||||
|
||||
private static final String[] DIRS = {"north", "east", "south", "west"};
|
||||
private static final int[][] STEP = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
|
||||
|
||||
/** A stone pillar with one wall-mounted block on each of its four sides ({@code %s} = facing). */
|
||||
private void pillar(Location o, int x, int z, int y, String fmt) {
|
||||
put(o, x, y, z, "stone");
|
||||
for (int i = 0; i < 4; i++) put(o, x + STEP[i][0], y, z + STEP[i][1], String.format(fmt, DIRS[i]));
|
||||
}
|
||||
|
||||
/** Standing signs rot 0..15 (two rows), ceiling hanging signs rot 0..15, wall + wall-hanging signs. */
|
||||
private void beSigns(Location o) {
|
||||
for (int r = 0; r < 16; r++) {
|
||||
int x = (r % 8) * 2, z = r < 8 ? 0 : 2;
|
||||
put(o, x, 0, z, "oak_sign[rotation=" + r + "]");
|
||||
signText(o, x, 0, z, "F" + r, "B" + r);
|
||||
put(o, r, 2, -3, "stone");
|
||||
put(o, r, 1, -3, "spruce_hanging_sign[rotation=" + r + ",attached=true]");
|
||||
signText(o, r, 1, -3, "F" + r, "B" + r);
|
||||
}
|
||||
pillar(o, 3, 7, 0, "birch_wall_sign[facing=%s]");
|
||||
pillar(o, 3, 7, 1, "cherry_wall_hanging_sign[facing=%s]");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
signText(o, 3 + STEP[i][0], 0, 7 + STEP[i][1], DIRS[i], "back");
|
||||
signText(o, 3 + STEP[i][0], 1, 7 + STEP[i][1], DIRS[i], "back");
|
||||
}
|
||||
pillar(o, 10, 7, 1, "dark_oak_wall_sign[facing=%s]");
|
||||
for (int i = 0; i < 4; i++) signText(o, 10 + STEP[i][0], 1, 7 + STEP[i][1], DIRS[i].toUpperCase(), "");
|
||||
}
|
||||
|
||||
/** Standing banners rot 0..15 with patterns, wall banners on a pillar. */
|
||||
private void beBanners(Location o) {
|
||||
DyeColor[] cols = DyeColor.values();
|
||||
for (int r = 0; r < 16; r++) {
|
||||
int x = (r % 8) * 2, z = r < 8 ? 0 : 3;
|
||||
put(o, x, 0, z, cols[r].name().toLowerCase() + "_banner[rotation=" + r + "]");
|
||||
if (o.clone().add(x, 0, z).getBlock().getState() instanceof org.bukkit.block.Banner b) {
|
||||
b.addPattern(new org.bukkit.block.banner.Pattern(DyeColor.BLACK, org.bukkit.block.banner.PatternType.STRIPE_TOP));
|
||||
b.addPattern(new org.bukkit.block.banner.Pattern(DyeColor.WHITE, org.bukkit.block.banner.PatternType.CREEPER));
|
||||
b.update(true, false);
|
||||
}
|
||||
}
|
||||
pillar(o, 16, 5, 2, "red_wall_banner[facing=%s]");
|
||||
put(o, 16, 1, 5, "stone");
|
||||
put(o, 16, 0, 5, "stone");
|
||||
}
|
||||
|
||||
/** Every head type in five rotations (0, 2, 4, 8, 12) per row, wall heads on pillars. */
|
||||
private void beHeads(Location o) {
|
||||
String[] t = {"skeleton_skull", "wither_skeleton_skull", "zombie_head", "creeper_head", "player_head", "piglin_head", "dragon_head"};
|
||||
int[] rots = {0, 2, 4, 8, 12};
|
||||
for (int i = 0; i < t.length; i++)
|
||||
for (int j = 0; j < rots.length; j++) put(o, j * 2, 0, i, t[i] + "[rotation=" + rots[j] + "]");
|
||||
String[] wall = {"skeleton_wall_skull", "dragon_wall_head", "piglin_wall_head", "player_wall_head"};
|
||||
for (int i = 0; i < wall.length; i++) pillar(o, 12, i * 3 - 2, 1, wall[i] + "[facing=%s]");
|
||||
for (int i = 0; i < wall.length; i++) put(o, 12, 0, i * 3 - 2, "stone");
|
||||
}
|
||||
|
||||
/** Bells (all attachments/facings), decorated pots with sherds, shulker boxes (6 facings), lecterns, conduit. */
|
||||
private void beMisc(Location o) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
put(o, i * 2, 0, 0, "bell[attachment=floor,facing=" + DIRS[i] + "]");
|
||||
put(o, i * 2, 2, 2, "stone");
|
||||
put(o, i * 2, 1, 2, "bell[attachment=ceiling,facing=" + DIRS[i] + "]");
|
||||
put(o, i * 2, 0, 4, "decorated_pot[facing=" + DIRS[i] + "]");
|
||||
if (o.clone().add(i * 2, 0, 4).getBlock().getState() instanceof org.bukkit.block.DecoratedPot pot) {
|
||||
pot.setSherd(org.bukkit.block.DecoratedPot.Side.FRONT, Material.HEART_POTTERY_SHERD);
|
||||
pot.setSherd(org.bukkit.block.DecoratedPot.Side.LEFT, Material.SKULL_POTTERY_SHERD);
|
||||
pot.setSherd(org.bukkit.block.DecoratedPot.Side.RIGHT, Material.ANGLER_POTTERY_SHERD);
|
||||
pot.update(true, false);
|
||||
}
|
||||
put(o, i * 2, 0, 6, "lectern[facing=" + DIRS[i] + ",has_book=true]");
|
||||
}
|
||||
put(o, 9, 1, 0, "stone");
|
||||
put(o, 10, 1, 0, "bell[attachment=single_wall,facing=east]");
|
||||
put(o, 12, 1, 0, "stone");
|
||||
put(o, 11, 1, 0, "bell[attachment=double_wall,facing=east]");
|
||||
String[] f6 = {"up", "down", "north", "south", "east", "west"};
|
||||
String[] c6 = {"", "red_", "blue_", "lime_", "black_", "white_"};
|
||||
for (int i = 0; i < 6; i++) put(o, 9 + (i % 3) * 2, 0, 3 + (i / 3) * 2, c6[i] + "shulker_box[facing=" + f6[i] + "]");
|
||||
put(o, 9, 0, 7, "conduit");
|
||||
put(o, 8, 0, 6, "lectern[facing=south,has_book=false]");
|
||||
}
|
||||
|
||||
/** Block-entity items: held by armor stands, worn on heads, as item displays and as block displays. */
|
||||
private void beItems(Location o) {
|
||||
Material[] m = {Material.CHEST, Material.RED_BANNER, Material.SHULKER_BOX, Material.DECORATED_POT,
|
||||
Material.CONDUIT, Material.DRAGON_HEAD, Material.PIGLIN_HEAD, Material.CREEPER_HEAD, Material.PLAYER_HEAD};
|
||||
for (int i = 0; i < m.length; i++) {
|
||||
ArmorStand as = spawn(o, i + 0.5, 0, 6.5, 0, ArmorStand.class);
|
||||
as.setArms(true);
|
||||
as.getEquipment().setItemInMainHand(it(m[i]));
|
||||
if (m[i].name().endsWith("_HEAD")) as.getEquipment().setHelmet(it(m[i]));
|
||||
ItemDisplay d = spawn(o, i + 0.5, 0.6, 3, 0, ItemDisplay.class);
|
||||
d.setItemStack(it(m[i]));
|
||||
d.setTransformation(new Transformation(new Vector3f(), new Quaternionf(), new Vector3f(0.6f), new Quaternionf()));
|
||||
}
|
||||
String[] blocks = {"chest[facing=south]", "red_banner[rotation=0]", "shulker_box[facing=up]", "decorated_pot[facing=south]",
|
||||
"skeleton_skull[rotation=8]", "lectern[facing=south,has_book=true]"};
|
||||
for (int i = 0; i < blocks.length; i++) {
|
||||
BlockDisplay b = spawn(o, i * 1.5, 0, 0, 0, BlockDisplay.class);
|
||||
b.setBlock(Bukkit.createBlockData("minecraft:" + blocks[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
# Source: the CEM Template Loader data (Ewan Howell / wynem) — vanilla Java entity models as JSON,
|
||||
# already correctly posed. These ultimately mirror Mojang's hardcoded Java EntityModel classes.
|
||||
#
|
||||
# NOTE: this set is now only the FALLBACK (rest-pose geometry) + the block-entity models (chests, signs,
|
||||
# heads, banners, armor_layer_*). Mob models come from the vanilla client dump — regenerate that with
|
||||
# tools/update-vanilla-models.sh <version> on every Minecraft update.
|
||||
# NOTE: this set is now only the FALLBACK (rest-pose geometry) for entity types missing from the vanilla
|
||||
# client dump (+ the elytra fallback). Mob AND block-entity models come from that dump — regenerate it
|
||||
# with tools/update-vanilla-models.sh <version> on every Minecraft update.
|
||||
#
|
||||
# Usage: tools/update-cem-models.sh # update if newer
|
||||
# tools/update-cem-models.sh --force # always overwrite
|
||||
|
||||
Reference in new issue
Block a user