render item frame contents with the item geometry like vanilla ItemFrameRenderer (fixed context, 8 rotations, all facings), frame block models, map contents incl. pixelpics photos, invisible frames, head skins/banner patterns from item meta
This commit is contained in:
1 parent
a743dc32c7
commit
2d56a1910c
13 files changed
+408
-96
No files matched your search
@@ -13,6 +13,7 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Bed;
|
||||
import org.bukkit.command.Command;
|
||||
@@ -128,6 +129,13 @@ public class PPTest extends JavaPlugin {
|
||||
// Needs a datapack cat variant "pptest:ocelotcat" (asset_id entity/cat/ocelot) in the world's datapacks.
|
||||
scenes.put("rf_dpcat", new Scene("rf_dpcat", this::rfDatapackCat, 1.2, 1.4, -2.2, 1.2, 0.2, 0.5));
|
||||
scenes.put("rf_armor", new Scene("rf_armor", this::rfArmor, 7, 3.2, -6.5, 7, 1.0, 1.5));
|
||||
// Item frames (vanilla ItemFrameRenderer): north wall with rotations 0-7, block/flat/tool/block-entity
|
||||
// items, photo + synthetic + vanilla-data maps, invisible and glow frames; frames on all 6 block sides.
|
||||
scenes.put("frames", new Scene("frames", this::frames, 4.5, 2.8, -3.5, 4.5, 2.6, 4));
|
||||
scenes.put("frames_close", new Scene("frames_close", this::frames, 2.6, 2.4, 0.8, 2.6, 2.3, 4));
|
||||
scenes.put("frames_side", new Scene("frames_side", this::frames, -1.5, 3.2, -1.0, 4.5, 2.6, 3.6));
|
||||
scenes.put("frames_dirs_ne", new Scene("frames_dirs_ne", this::framesDirs, 16, 7.5, -4, 8, 4, 3.5));
|
||||
scenes.put("frames_dirs_sw", new Scene("frames_dirs_sw", this::framesDirs, 0, 1.2, 10, 8, 4, 3.5));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,7 +173,7 @@ public class PPTest extends JavaPlugin {
|
||||
Location eye = o.clone().add(sc.camX, sc.camY, sc.camZ);
|
||||
Vector look = o.clone().add(sc.lookX, sc.lookY, sc.lookZ).toVector().subtract(eye.toVector());
|
||||
eye.setDirection(look);
|
||||
RenderJob job = r.prepare(eye, sc.name.startsWith("proj_") || sc.name.startsWith("rf_") ? new Resolution(960, 640) : new Resolution(480, 320), null);
|
||||
RenderJob job = r.prepare(eye, sc.name.startsWith("proj_") || sc.name.startsWith("rf_") || sc.name.startsWith("frames") ? new Resolution(960, 640) : new Resolution(480, 320), null);
|
||||
if (sc.name.equals("dbg")) {
|
||||
try {
|
||||
java.lang.reflect.Field f = DefaultScreenRenderer.class.getDeclaredField("objectBaker");
|
||||
@@ -1098,4 +1106,133 @@ public class PPTest extends JavaPlugin {
|
||||
b.setBlock(Bukkit.createBlockData("minecraft:" + blocks[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// --- item frames -------------------------------------------------------------------------------
|
||||
|
||||
private void frames(Location o) {
|
||||
for (int x = -2; x <= 11; x++)
|
||||
for (int y = 0; y <= 5; y++) w.getBlockAt(o.getBlockX() + x, o.getBlockY() + y, o.getBlockZ() + 4).setType(Material.STONE, false);
|
||||
BlockFace f = BlockFace.NORTH;
|
||||
for (int r = 0; r < 8; r++) frame(o, r, 4, 3, f, false, it(Material.DIAMOND_SWORD), r, true);
|
||||
ItemStack banner = it(Material.RED_BANNER);
|
||||
org.bukkit.inventory.meta.BannerMeta bm = (org.bukkit.inventory.meta.BannerMeta) banner.getItemMeta();
|
||||
bm.addPattern(new org.bukkit.block.banner.Pattern(DyeColor.YELLOW, org.bukkit.block.banner.PatternType.STRIPE_TOP));
|
||||
banner.setItemMeta(bm);
|
||||
ItemStack[] row3 = {it(Material.STONE), it(Material.OAK_STAIRS), it(Material.GRASS_BLOCK), it(Material.APPLE),
|
||||
it(Material.TORCH), it(Material.CHEST), banner, eu.mhsl.minecraft.pixelpics.survival.CameraItems.createCamera(3),
|
||||
it(Material.CREEPER_HEAD), it(Material.SHIELD)};
|
||||
for (int i = 0; i < row3.length; i++) frame(o, i - 1, 3, 3, f, false, row3[i], 0, true);
|
||||
ItemStack photo = photoMap(), synth = synthMap(), vmap = vanillaMap();
|
||||
int[] photoRot = {0, 1, 2, 3, 5};
|
||||
for (int i = 0; i < photoRot.length; i++) frame(o, i - 1, 2, 3, f, false, photo, photoRot[i], true);
|
||||
frame(o, 4, 2, 3, f, false, synth, 0, true);
|
||||
frame(o, 5, 2, 3, f, false, synth, 1, true);
|
||||
frame(o, 6, 2, 3, f, false, vmap, 0, true);
|
||||
frame(o, 7, 2, 3, f, false, it(Material.MAP), 0, true);
|
||||
frame(o, 8, 2, 3, f, false, it(Material.FILLED_MAP), 0, true);
|
||||
ItemStack[] inv = {it(Material.DIAMOND_SWORD), it(Material.STONE), synth, it(Material.CHEST)};
|
||||
for (int i = 0; i < inv.length; i++) frame(o, i - 1, 1, 3, f, false, inv[i], i == 0 ? 1 : 0, false);
|
||||
ItemStack[] glow = {it(Material.APPLE), it(Material.STONE), synth, null};
|
||||
for (int i = 0; i < glow.length; i++) frame(o, i + 3, 1, 3, f, true, glow[i], 0, true);
|
||||
frame(o, 7, 1, 3, f, false, null, 0, true);
|
||||
frame(o, 8, 1, 3, f, true, null, 0, true);
|
||||
}
|
||||
|
||||
/** Three stone blocks with a frame on every side: block item, tool, synthetic map (all at rotation 1). */
|
||||
private void framesDirs(Location o) {
|
||||
ItemStack[] items = {it(Material.OAK_STAIRS), it(Material.DIAMOND_SWORD), synthMap()};
|
||||
BlockFace[] faces = {BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST, BlockFace.UP, BlockFace.DOWN};
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
int bx = 3 + i * 5, by = 4, bz = 3;
|
||||
w.getBlockAt(o.getBlockX() + bx, o.getBlockY() + by, o.getBlockZ() + bz).setType(Material.STONE, false);
|
||||
for (BlockFace face : faces)
|
||||
frame(o, bx + face.getModX(), by + face.getModY(), bz + face.getModZ(), face, i == 2, items[i], 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
private ItemFrame frame(Location o, int x, int y, int z, BlockFace face, boolean glow, ItemStack item, int rot, boolean visible) {
|
||||
Location l = o.clone().add(x + 0.5, y + 0.5, z + 0.5);
|
||||
Class<? extends ItemFrame> c = glow ? GlowItemFrame.class : ItemFrame.class;
|
||||
ItemFrame fr = w.spawn(l, c, e -> {
|
||||
e.setFacingDirection(face, true);
|
||||
e.setPersistent(false);
|
||||
});
|
||||
if (item != null) fr.setItem(item, false);
|
||||
fr.setRotation(Rotation.values()[rot]);
|
||||
fr.setVisible(visible);
|
||||
fr.setFixed(true);
|
||||
return fr;
|
||||
}
|
||||
|
||||
private static ItemStack mapItem(org.bukkit.map.MapView view) {
|
||||
ItemStack s = it(Material.FILLED_MAP);
|
||||
org.bukkit.inventory.meta.MapMeta mm = (org.bukkit.inventory.meta.MapMeta) s.getItemMeta();
|
||||
mm.setMapView(view);
|
||||
s.setItemMeta(mm);
|
||||
return s;
|
||||
}
|
||||
|
||||
/** A real stored PixelPics photo (lowest managed map id on disk), or the synthetic map if none exists. */
|
||||
private ItemStack photoMap() {
|
||||
File dir = new File(Main.getInstance().getDataFolder(), "images");
|
||||
int best = Integer.MAX_VALUE;
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null)
|
||||
for (File f : files) {
|
||||
java.util.regex.Matcher m = java.util.regex.Pattern.compile("mapId_(\\d+)\\.mcmap").matcher(f.getName());
|
||||
if (m.matches()) best = Math.min(best, Integer.parseInt(m.group(1)));
|
||||
}
|
||||
int id = best == Integer.MAX_VALUE ? -1 : best;
|
||||
@SuppressWarnings("deprecation") org.bukkit.map.MapView v = id < 0 ? null : Bukkit.getMap(id);
|
||||
if (v == null) return synthMap();
|
||||
if (v.getRenderers().stream().noneMatch(r -> r instanceof eu.mhsl.minecraft.pixelpics.utils.ImageMapRenderer)) {
|
||||
byte[] idx = eu.mhsl.minecraft.pixelpics.utils.MapManager.readIndices(id);
|
||||
if (idx != null) eu.mhsl.minecraft.pixelpics.utils.MapManager.attachView(v, new eu.mhsl.minecraft.pixelpics.utils.ImageMapRenderer(idx));
|
||||
}
|
||||
getLogger().info("frames: photo map id " + id);
|
||||
return mapItem(v);
|
||||
}
|
||||
|
||||
private ItemStack synthMap;
|
||||
|
||||
/** Asymmetric test picture as a PixelPics map: red top-left, blue top-right, green bottom-left, black "F". */
|
||||
private ItemStack synthMap() {
|
||||
if (synthMap != null) return synthMap;
|
||||
BufferedImage img = new BufferedImage(128, 128, BufferedImage.TYPE_INT_RGB);
|
||||
java.awt.Graphics2D g = img.createGraphics();
|
||||
g.setColor(java.awt.Color.WHITE);
|
||||
g.fillRect(0, 0, 128, 128);
|
||||
g.setColor(java.awt.Color.RED);
|
||||
g.fillRect(0, 0, 32, 32);
|
||||
g.setColor(java.awt.Color.BLUE);
|
||||
g.fillRect(96, 0, 32, 32);
|
||||
g.setColor(new java.awt.Color(0, 160, 0));
|
||||
g.fillRect(0, 96, 32, 32);
|
||||
g.setColor(java.awt.Color.BLACK);
|
||||
g.fillRect(48, 24, 14, 80);
|
||||
g.fillRect(48, 24, 44, 14);
|
||||
g.fillRect(48, 56, 32, 12);
|
||||
g.dispose();
|
||||
org.bukkit.map.MapView v = Bukkit.createMap(w);
|
||||
eu.mhsl.minecraft.pixelpics.utils.MapManager.attachView(v, new eu.mhsl.minecraft.pixelpics.utils.ImageMapRenderer(img));
|
||||
return synthMap = mapItem(v);
|
||||
}
|
||||
|
||||
/** A plain vanilla map whose server-side colours are written directly (diagonal colour bands + transparent corner). */
|
||||
private ItemStack vanillaMap() {
|
||||
org.bukkit.map.MapView v = Bukkit.createMap(w);
|
||||
try {
|
||||
java.lang.reflect.Field wm = v.getClass().getDeclaredField("worldMap");
|
||||
wm.setAccessible(true);
|
||||
Object data = wm.get(v);
|
||||
byte[] colors = (byte[]) data.getClass().getField("colors").get(data);
|
||||
byte[] palette = {(byte) (18 * 4 + 2), (byte) (7 * 4 + 2), (byte) (12 * 4 + 1), (byte) (29 * 4 + 2)};
|
||||
for (int y = 0; y < 128; y++)
|
||||
for (int x = 0; x < 128; x++)
|
||||
colors[y * 128 + x] = x < 24 && y < 24 ? 0 : palette[((x + y) / 32) % palette.length];
|
||||
} catch (ReflectiveOperationException e) {
|
||||
getLogger().warning("vanillaMap: " + e);
|
||||
}
|
||||
return mapItem(v);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user