diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/Main.java b/src/main/java/eu/mhsl/minecraft/pixelpics/Main.java index ccbbbde..cf1fe9a 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/Main.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/Main.java @@ -4,17 +4,29 @@ import eu.mhsl.minecraft.pixelpics.assets.AssetReader; import eu.mhsl.minecraft.pixelpics.assets.BlockModelRegistry; import eu.mhsl.minecraft.pixelpics.assets.ResourcePack; import eu.mhsl.minecraft.pixelpics.assets.ResourcePackLoader; +import eu.mhsl.minecraft.pixelpics.assets.SkinCache; import eu.mhsl.minecraft.pixelpics.assets.TextureCache; +import eu.mhsl.minecraft.pixelpics.assets.font.BitmapFont; +import eu.mhsl.minecraft.pixelpics.assets.font.FontLoader; import eu.mhsl.minecraft.pixelpics.commands.PixelPicsCommand; import eu.mhsl.minecraft.pixelpics.listeners.OnMapInitialize; import eu.mhsl.minecraft.pixelpics.render.RenderManager; +import eu.mhsl.minecraft.pixelpics.render.entity.cem.BlockEntityBaker; +import eu.mhsl.minecraft.pixelpics.render.entity.cem.CemBaker; +import eu.mhsl.minecraft.pixelpics.render.entity.cem.CemModelLoader; import eu.mhsl.minecraft.pixelpics.render.render.DefaultScreenRenderer; import eu.mhsl.minecraft.pixelpics.render.tint.BiomeTintProvider; +import eu.mhsl.minecraft.pixelpics.survival.CameraListener; +import eu.mhsl.minecraft.pixelpics.survival.CraftingListener; +import eu.mhsl.minecraft.pixelpics.survival.JoinListener; +import eu.mhsl.minecraft.pixelpics.survival.SurvivalRecipes; +import eu.mhsl.minecraft.pixelpics.utils.MapColorPalette; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.plugin.java.JavaPlugin; import java.io.File; +import java.io.InputStream; import java.util.Objects; import java.util.Optional; @@ -45,10 +57,10 @@ public final class Main extends JavaPlugin { Bukkit.getPluginManager().registerEvents(new OnMapInitialize(), this); Objects.requireNonNull(Bukkit.getPluginCommand("pixelPic")).setExecutor(new PixelPicsCommand()); - Bukkit.getPluginManager().registerEvents(new eu.mhsl.minecraft.pixelpics.survival.CameraListener(), this); - Bukkit.getPluginManager().registerEvents(new eu.mhsl.minecraft.pixelpics.survival.CraftingListener(), this); - Bukkit.getPluginManager().registerEvents(new eu.mhsl.minecraft.pixelpics.survival.JoinListener(), this); - eu.mhsl.minecraft.pixelpics.survival.SurvivalRecipes.register(); + Bukkit.getPluginManager().registerEvents(new CameraListener(), this); + Bukkit.getPluginManager().registerEvents(new CraftingListener(), this); + Bukkit.getPluginManager().registerEvents(new JoinListener(), this); + SurvivalRecipes.register(); initRenderer(); } @@ -87,33 +99,33 @@ public final class Main extends JavaPlugin { BlockModelRegistry registry = new BlockModelRegistry(reader, textures); BiomeTintProvider tintProvider = new BiomeTintProvider(textures); - eu.mhsl.minecraft.pixelpics.render.entity.cem.CemModelLoader cemLoader = - new eu.mhsl.minecraft.pixelpics.render.entity.cem.CemModelLoader(); - try (java.io.InputStream in = getResource("cem/cem_template_models.json")) { + CemModelLoader cemLoader = + new CemModelLoader(); + try (InputStream in = getResource("cem/cem_template_models.json")) { int n = in == null ? 0 : cemLoader.load(in, getLogger()); getLogger().info("Loaded " + n + " CEM entity models."); } catch (Exception e) { getLogger().severe("Failed to load CEM entity models: " + e.getMessage()); } - eu.mhsl.minecraft.pixelpics.assets.SkinCache skinCache = new eu.mhsl.minecraft.pixelpics.assets.SkinCache(); - eu.mhsl.minecraft.pixelpics.assets.font.BitmapFont font = - eu.mhsl.minecraft.pixelpics.assets.font.FontLoader.load(resourcePack, textures, getLogger()); + SkinCache skinCache = new SkinCache(); + BitmapFont font = + FontLoader.load(resourcePack, textures, getLogger()); getLogger().info("Loaded sign font (" + (font.isEmpty() ? "no glyphs — text disabled" : "ok") + ")."); - eu.mhsl.minecraft.pixelpics.render.entity.cem.CemBaker entityBaker = - new eu.mhsl.minecraft.pixelpics.render.entity.cem.CemBaker(cemLoader, textures, skinCache); - eu.mhsl.minecraft.pixelpics.render.entity.cem.BlockEntityBaker blockEntityBaker = - new eu.mhsl.minecraft.pixelpics.render.entity.cem.BlockEntityBaker(cemLoader, textures, skinCache, font); + CemBaker entityBaker = + new CemBaker(cemLoader, textures, skinCache); + BlockEntityBaker blockEntityBaker = + new BlockEntityBaker(cemLoader, textures, skinCache, font); this.screenRenderer = new DefaultScreenRenderer(registry, tintProvider, textures, entityBaker, blockEntityBaker, getLogger(), renderManager.tracePool()); // Warm the map palette on the main thread so off-thread dithering never triggers its first init. - eu.mhsl.minecraft.pixelpics.utils.MapColorPalette.size(); + MapColorPalette.size(); getLogger().info("PixelPics renderer initialized with resource pack assets."); } @Override public void onDisable() { - eu.mhsl.minecraft.pixelpics.survival.SurvivalRecipes.unregister(); + SurvivalRecipes.unregister(); if (renderManager != null) { renderManager.shutdown(); renderManager = null; diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/assets/BlockModelRegistry.java b/src/main/java/eu/mhsl/minecraft/pixelpics/assets/BlockModelRegistry.java index 67f09fd..1f0c3fb 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/assets/BlockModelRegistry.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/assets/BlockModelRegistry.java @@ -8,6 +8,7 @@ import eu.mhsl.minecraft.pixelpics.assets.model.ResolvedModel; import org.bukkit.Material; import org.bukkit.block.data.BlockData; +import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -51,7 +52,7 @@ public final class BlockModelRegistry { List variants = blockStateResolver.resolve(data); - List elements = new java.util.ArrayList<>(); + List elements = new ArrayList<>(); AverageColor.Accumulator avgColor = new AverageColor.Accumulator(); FlatModel lastFlat = null; diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/assets/ModelResolver.java b/src/main/java/eu/mhsl/minecraft/pixelpics/assets/ModelResolver.java index f111f52..b691d01 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/assets/ModelResolver.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/assets/ModelResolver.java @@ -3,6 +3,7 @@ package eu.mhsl.minecraft.pixelpics.assets; import eu.mhsl.minecraft.pixelpics.assets.dto.ModelFileDto; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -36,7 +37,7 @@ public final class ModelResolver { } Map textures = new HashMap<>(); - java.util.List elements = dto.elements; + List elements = dto.elements; if (dto.parent != null && depth < MAX_DEPTH && !dto.parent.startsWith("builtin/")) { FlatModel parent = resolve(ResourceLocation.parse(dto.parent), depth + 1); diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/render/entity/cem/BlockEntityBaker.java b/src/main/java/eu/mhsl/minecraft/pixelpics/render/entity/cem/BlockEntityBaker.java index bd18939..c18a643 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/render/entity/cem/BlockEntityBaker.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/render/entity/cem/BlockEntityBaker.java @@ -15,6 +15,7 @@ import eu.mhsl.minecraft.pixelpics.render.entity.RenderedEntity; import eu.mhsl.minecraft.pixelpics.render.entity.TextureOps; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -186,7 +187,7 @@ public final class BlockEntityBaker implements EntityBaker { /** Hidden set that leaves only {@code keep} visible out of {@code all}. */ private static Set onlyPart(String keep, Set all) { - Set hidden = new java.util.HashSet<>(all); + Set hidden = new HashSet<>(all); hidden.remove(keep); return hidden; } @@ -200,7 +201,7 @@ public final class BlockEntityBaker implements EntityBaker { if (base == null) return List.of(); List layers = new ArrayList<>(); // Structure (rim/neck/foot) comes from the combined base texture; the four sides are NOT in it. - layers.add(new Layer(base, new java.util.HashSet<>(java.util.List.of("front", "back", "left", "right")))); + layers.add(new Layer(base, new HashSet<>(List.of("front", "back", "left", "right")))); // Each side: its sherd pattern if set, else the plain brick side. The model's per-face UV maps the // centre of the 16x16 texture onto the face (centred, edges intact). for (int i = 0; i < POT_FACES.length; i++) { diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/render/entity/cem/CemBaker.java b/src/main/java/eu/mhsl/minecraft/pixelpics/render/entity/cem/CemBaker.java index e89f3f4..875cbeb 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/render/entity/cem/CemBaker.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/render/entity/cem/CemBaker.java @@ -15,7 +15,10 @@ import eu.mhsl.minecraft.pixelpics.render.entity.RenderedEntity; import eu.mhsl.minecraft.pixelpics.render.entity.TextureOps; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; /** * Bakes an {@link EntityState} into world-space cubes using a vanilla Java {@link CemModelLoader.CemModel} @@ -27,9 +30,9 @@ import java.util.List; public final class CemBaker implements EntityBaker { // Parts representing an alternate state (rolled-up, sleeping, …) that must not render in the idle pose. - private static final java.util.Map> HIDDEN_PARTS = java.util.Map.of( - "armadillo", java.util.Set.of("cube"), // the rolled-up ball - "illager", java.util.Set.of("left_arm", "right_arm") + private static final Map> HIDDEN_PARTS = Map.of( + "armadillo", Set.of("cube"), // the rolled-up ball + "illager", Set.of("left_arm", "right_arm") ); private final CemModelLoader models; @@ -67,7 +70,7 @@ public final class CemBaker implements EntityBaker { // rotations and handedness; only px->block scaling is applied. Affine pre = Affine.scale(sc / 16.0); - java.util.Set hidden = new java.util.HashSet<>(HIDDEN_PARTS.getOrDefault(cem, java.util.Set.of())); + Set hidden = new HashSet<>(HIDDEN_PARTS.getOrDefault(cem, Set.of())); // Donkeys/llamas carry the chest boxes inside the base model; hide them unless a chest is equipped. if (!s.chest()) { if (cem.equals("donkey")) { hidden.add("left_chest"); hidden.add("right_chest"); } @@ -76,7 +79,7 @@ public final class CemBaker implements EntityBaker { // The body model is baked even when invisible — not drawn, but used as the ground-snap reference // so equipment stays at body height (e.g. a lone helmet sits at the head, not on the floor). List body = (model != null && tex != null) - ? CemGeometry.bakeModel(model, tex, pre, hidden) : java.util.List.of(); + ? CemGeometry.bakeModel(model, tex, pre, hidden) : List.of(); List baked = new ArrayList<>(); if (!invisible) { @@ -200,7 +203,7 @@ public final class CemBaker implements EntityBaker { int[][] saddleTex = textures.get(ResourceLocation.parse("entity/equipment/" + s.typeKey() + "_saddle/saddle")).orElse(null); if (saddleTex == null) return; // Show only the saddle-specific parts: hide every part the base body model also defines. - java.util.Set hideBase = new java.util.HashSet<>(); + Set hideBase = new HashSet<>(); for (CemModelLoader.CemPart p : base.parts()) hideBase.add(p.name()); baked.addAll(CemGeometry.bakeModel(sm, saddleTex, pre, hideBase)); } @@ -211,10 +214,10 @@ public final class CemBaker implements EntityBaker { // shoes=boots; // armor_layer_2 (texture entity/equipment/humanoid_leggings/): waist+legs=leggings. // Each slot may use a different material, so each is baked separately, showing only its parts. - private static final java.util.Set ARMOR1_HEAD = java.util.Set.of("head"); - private static final java.util.Set ARMOR1_CHEST = java.util.Set.of("body", "left_arm", "right_arm"); - private static final java.util.Set ARMOR1_FEET = java.util.Set.of("left_shoe", "right_shoe"); - private static final java.util.Set ARMOR2_LEGS = java.util.Set.of("waist", "left_leg", "right_leg"); + private static final Set ARMOR1_HEAD = Set.of("head"); + private static final Set ARMOR1_CHEST = Set.of("body", "left_arm", "right_arm"); + private static final Set ARMOR1_FEET = Set.of("left_shoe", "right_shoe"); + private static final Set ARMOR2_LEGS = Set.of("waist", "left_leg", "right_leg"); private static final int GLINT_COLOR = 0xFF8040CC; // approximated enchantment-glint purple private void addArmorLayers(EntityState s, Affine pre, List baked) { @@ -231,14 +234,14 @@ public final class CemBaker implements EntityBaker { } /** Bake one armor slot: its layer model with only {@code show} parts, textured for the material. */ - private void bakeArmorPiece(EntityState.EquipPiece piece, String modelName, java.util.Set show, + private void bakeArmorPiece(EntityState.EquipPiece piece, String modelName, Set show, String layerFolder, Affine pre, List baked) { if (piece == null) return; CemModelLoader.CemModel model = models.get(modelName); if (model == null) return; int[][] tex = buildArmorTexture(piece, layerFolder); if (tex == null) return; - java.util.Set hidden = new java.util.HashSet<>(); + Set hidden = new HashSet<>(); for (CemModelLoader.CemPart p : model.parts()) if (!show.contains(p.name())) hidden.add(p.name()); baked.addAll(CemGeometry.bakeModel(model, tex, pre, hidden)); } @@ -299,7 +302,7 @@ public final class CemBaker implements EntityBaker { if (tex == null) return; int[][] out = TextureOps.deepCopy(tex); if (piece.glint()) applyGlint(out); - baked.addAll(CemGeometry.bakeModel(model, out, pre, java.util.Set.of())); + baked.addAll(CemGeometry.bakeModel(model, out, pre, Set.of())); } private RenderedEntity fallbackBox(EntityState s, int[][] tex) { diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/render/raytrace/SnapshotRaytracer.java b/src/main/java/eu/mhsl/minecraft/pixelpics/render/raytrace/SnapshotRaytracer.java index 3d3ec4e..31976d8 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/render/raytrace/SnapshotRaytracer.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/render/raytrace/SnapshotRaytracer.java @@ -16,6 +16,9 @@ import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; import org.bukkit.util.Vector; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + /** * Traces a single ray against a {@link WorldSnapshot}, sampling block models via the * {@link ElementIntersector} and applying biome tint, directional face shading, transparency and @@ -39,7 +42,7 @@ public final class SnapshotRaytracer { private final double maxDistance; private final int reflectionDepth; private final int maxSteps; - private final java.util.Map tintCache = new java.util.concurrent.ConcurrentHashMap<>(); + private final Map tintCache = new ConcurrentHashMap<>(); public SnapshotRaytracer(BlockModelRegistry registry, BiomeTintProvider tintProvider, SkyRenderer skyRenderer, double maxDistance, int reflectionDepth) { diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/BlockEntitySnapshotBuilder.java b/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/BlockEntitySnapshotBuilder.java index 74a5df3..82819d3 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/BlockEntitySnapshotBuilder.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/BlockEntitySnapshotBuilder.java @@ -15,16 +15,24 @@ import org.bukkit.block.Banner; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.DecoratedPot; +import org.bukkit.block.Sign; import org.bukkit.block.Skull; import org.bukkit.block.banner.Pattern; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; import org.bukkit.block.data.Rotatable; +import org.bukkit.block.data.type.Bed; +import org.bukkit.block.data.type.Bell; +import org.bukkit.block.data.type.Chest; +import org.bukkit.block.sign.Side; +import org.bukkit.block.sign.SignSide; +import org.bukkit.profile.PlayerProfile; import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; +import java.util.Locale; import java.util.Map; /** @@ -77,7 +85,7 @@ public final class BlockEntitySnapshotBuilder { Kind kind = mat == Material.TRAPPED_CHEST ? Kind.TRAPPED_CHEST : mat == Material.ENDER_CHEST ? Kind.ENDER_CHEST : Kind.CHEST; ChestKind ck = ChestKind.SINGLE; - if (data instanceof org.bukkit.block.data.type.Chest cd) { + if (data instanceof Chest cd) { ck = switch (cd.getType()) { case LEFT -> ChestKind.LEFT; case RIGHT -> ChestKind.RIGHT; @@ -88,8 +96,8 @@ public final class BlockEntitySnapshotBuilder { } // --- beds --- - if (data instanceof org.bukkit.block.data.type.Bed bed) { - BedPart part = bed.getPart() == org.bukkit.block.data.type.Bed.Part.HEAD ? BedPart.HEAD : BedPart.FOOT; + if (data instanceof Bed bed) { + BedPart part = bed.getPart() == Bed.Part.HEAD ? BedPart.HEAD : BedPart.FOOT; return base(Kind.BED, bx, by, bz, faceToYaw(bed.getFacing())) .bedPart(part).colorName(stripColor(n, "_BED")).build(); } @@ -131,9 +139,9 @@ public final class BlockEntitySnapshotBuilder { kind = Kind.SIGN; yaw = rotationYaw(data); } Builder b = base(kind, bx, by, bz, yaw).wood(wood); - if (ts instanceof org.bukkit.block.Sign sign) { - b.frontText(signText(sign.getSide(org.bukkit.block.sign.Side.FRONT))); - b.backText(signText(sign.getSide(org.bukkit.block.sign.Side.BACK))); + if (ts instanceof Sign sign) { + b.frontText(signText(sign.getSide(Side.FRONT))); + b.backText(signText(sign.getSide(Side.BACK))); } return b.build(); } @@ -165,7 +173,7 @@ public final class BlockEntitySnapshotBuilder { // --- bell --- if (mat == Material.BELL) { BellAttach attach = BellAttach.FLOOR; - if (data instanceof org.bukkit.block.data.type.Bell bd) { + if (data instanceof Bell bd) { attach = switch (bd.getAttachment()) { case FLOOR -> BellAttach.FLOOR; case CEILING -> BellAttach.CEILING; @@ -226,11 +234,11 @@ public final class BlockEntitySnapshotBuilder { // --- data extraction helpers --- private static String stripColor(String name, String suffix) { - return name.substring(0, name.length() - suffix.length()).toLowerCase(java.util.Locale.ROOT); + return name.substring(0, name.length() - suffix.length()).toLowerCase(Locale.ROOT); } /** One sign side → {@link BlockEntityState.SignText}, or null when all four lines are blank. */ - private static BlockEntityState.SignText signText(org.bukkit.block.sign.SignSide side) { + private static BlockEntityState.SignText signText(SignSide side) { String[] raw = side.getLines(); List lines = new ArrayList<>(raw.length); boolean any = false; @@ -251,7 +259,7 @@ public final class BlockEntitySnapshotBuilder { for (String suf : new String[]{"_WALL_HANGING_SIGN", "_HANGING_SIGN", "_WALL_SIGN", "_SIGN"}) { if (s.endsWith(suf)) { s = s.substring(0, s.length() - suf.length()); break; } } - return s.toLowerCase(java.util.Locale.ROOT); + return s.toLowerCase(Locale.ROOT); } private static String headType(String name) { @@ -274,14 +282,14 @@ public final class BlockEntitySnapshotBuilder { for (DecoratedPot.Side side : new DecoratedPot.Side[]{ DecoratedPot.Side.FRONT, DecoratedPot.Side.LEFT, DecoratedPot.Side.RIGHT, DecoratedPot.Side.BACK}) { Material m = pot.getSherd(side); - out.add(m.name().toLowerCase(java.util.Locale.ROOT)); + out.add(m.name().toLowerCase(Locale.ROOT)); } return out; } private static String skinUrl(Skull skull) { try { - org.bukkit.profile.PlayerProfile profile = skull.getOwnerProfile(); + PlayerProfile profile = skull.getOwnerProfile(); if (profile != null && profile.getTextures().getSkin() != null) { return profile.getTextures().getSkin().toString(); } diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/DecorationSnapshotBuilder.java b/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/DecorationSnapshotBuilder.java index 44043be..749127b 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/DecorationSnapshotBuilder.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/DecorationSnapshotBuilder.java @@ -4,6 +4,7 @@ import eu.mhsl.minecraft.pixelpics.render.entity.DecorationState; import org.bukkit.Location; import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; +import org.bukkit.entity.GlowItemFrame; import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Painting; import org.bukkit.inventory.ItemStack; @@ -47,7 +48,7 @@ public final class DecorationSnapshotBuilder { } if (e instanceof ItemFrame frame) { BoundingBox bb = e.getBoundingBox(); - boolean glow = e instanceof org.bukkit.entity.GlowItemFrame + boolean glow = e instanceof GlowItemFrame || e.getType().getKey().getKey().equals("glow_item_frame"); String itemId = itemId(frame.getItem()); int rot = frame.getRotation().ordinal() * 45; diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/EntitySnapshotBuilder.java b/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/EntitySnapshotBuilder.java index 7a1ebd6..980dc6c 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/EntitySnapshotBuilder.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/render/snapshot/EntitySnapshotBuilder.java @@ -1,18 +1,61 @@ package eu.mhsl.minecraft.pixelpics.render.snapshot; +import com.destroystokyo.paper.profile.ProfileProperty; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import eu.mhsl.minecraft.pixelpics.render.entity.EntityState; import eu.mhsl.minecraft.pixelpics.render.util.ColorUtil; +import io.papermc.paper.datacomponent.DataComponentTypes; +import org.bukkit.Keyed; import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.AbstractHorse; +import org.bukkit.entity.AbstractNautilus; import org.bukkit.entity.Ageable; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Axolotl; +import org.bukkit.entity.Cat; +import org.bukkit.entity.ChestedHorse; +import org.bukkit.entity.Chicken; +import org.bukkit.entity.Cow; import org.bukkit.entity.Entity; +import org.bukkit.entity.Fox; +import org.bukkit.entity.Frog; +import org.bukkit.entity.Horse; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Llama; +import org.bukkit.entity.MushroomCow; +import org.bukkit.entity.Panda; +import org.bukkit.entity.Parrot; +import org.bukkit.entity.Pig; import org.bukkit.entity.Player; +import org.bukkit.entity.Rabbit; +import org.bukkit.entity.Sheep; +import org.bukkit.entity.Shulker; +import org.bukkit.entity.Slime; +import org.bukkit.entity.TraderLlama; +import org.bukkit.entity.Villager; +import org.bukkit.entity.Wolf; +import org.bukkit.entity.Zombie; +import org.bukkit.entity.ZombieVillager; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.potion.PotionEffectType; import org.bukkit.util.Vector; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; import java.util.List; +import java.util.Locale; +import java.util.Set; import java.util.UUID; +import java.util.function.DoubleSupplier; /** * Captures entities near the view frustum into immutable {@link EntityState}s. MUST run on the main @@ -24,7 +67,7 @@ public final class EntitySnapshotBuilder { // Technical / non-mob entity types that have no meaningful geometry; rendering them would only // produce stray fallback boxes. Markers, displays, item frames, paintings, projectiles, drops, etc. - private static final java.util.Set NON_RENDERABLE = java.util.Set.of( + private static final Set NON_RENDERABLE = Set.of( "area_effect_cloud", "marker", "interaction", "item_frame", "glow_item_frame", "painting", "block_display", "item_display", "text_display", @@ -35,7 +78,7 @@ public final class EntitySnapshotBuilder { // Entities whose vanilla renderer draws the humanoid armor layers (HumanoidArmorLayer) and held // items. Their CEM bodies share standard humanoid proportions, so the armor_layer_1/2 models align. - private static final java.util.Set HUMANOID_ARMOR_WEARERS = java.util.Set.of( + private static final Set HUMANOID_ARMOR_WEARERS = Set.of( "player", "mannequin", "armor_stand", "giant", "zombie", "husk", "drowned", "zombie_villager", "zombified_piglin", "skeleton", "stray", "wither_skeleton", "bogged", @@ -67,13 +110,13 @@ public final class EntitySnapshotBuilder { } boolean baby = (e instanceof Ageable a && !a.isAdult()) - || (e instanceof org.bukkit.entity.Zombie z && z.isAdult()); + || (e instanceof Zombie z && z.isAdult()); // Invisible entities render only their equipment (like vanilla): the generic invisible flag, an // invisibility potion effect, or an explicitly-hidden armor stand. boolean invisible = e.isInvisible() - || (e instanceof org.bukkit.entity.ArmorStand as && !as.isVisible()) - || (e instanceof LivingEntity inv && inv.hasPotionEffect(org.bukkit.potion.PotionEffectType.INVISIBILITY)); + || (e instanceof ArmorStand as && !as.isVisible()) + || (e instanceof LivingEntity inv && inv.hasPotionEffect(PotionEffectType.INVISIBILITY)); double width = safeDim(e::getWidth, () -> e.getBoundingBox().getWidthX()); double height = safeDim(e::getHeight, () -> e.getBoundingBox().getHeight()); @@ -98,65 +141,65 @@ public final class EntitySnapshotBuilder { String bodyEquip = null; try { // Slime & magma cube (MagmaCube extends Slime) scale their model by size (1/2/4). - if (e instanceof org.bukkit.entity.Slime sl) sizeScale = sl.getSize(); + if (e instanceof Slime sl) sizeScale = sl.getSize(); // MushroomCow extends Cow, ZombieVillager does not extend Villager — order matters. - if (e instanceof org.bukkit.entity.Sheep sh) { + if (e instanceof Sheep sh) { tint = ColorUtil.dyeArgb(sh.getColor(), 0); - } else if (e instanceof org.bukkit.entity.Cat c) { + } else if (e instanceof Cat c) { variant = keyOf(c.getCatType()); - } else if (e instanceof org.bukkit.entity.Wolf w) { + } else if (e instanceof Wolf w) { variant = keyOf(w.getVariant()); - } else if (e instanceof org.bukkit.entity.Axolotl a) { + } else if (e instanceof Axolotl a) { variant = keyOf(a.getVariant()); - } else if (e instanceof org.bukkit.entity.Parrot p) { + } else if (e instanceof Parrot p) { variant = keyOf(p.getVariant()); - } else if (e instanceof org.bukkit.entity.Rabbit r) { + } else if (e instanceof Rabbit r) { variant = keyOf(r.getRabbitType()); - } else if (e instanceof org.bukkit.entity.Horse h) { + } else if (e instanceof Horse h) { variant = keyOf(h.getColor()); markings = markingsKey(h.getStyle()); saddle = isSaddled(h); bodyEquip = horseArmorKey(h); - } else if (e instanceof org.bukkit.entity.Llama l) { + } else if (e instanceof Llama l) { variant = keyOf(l.getColor()); chest = l.isCarryingChest(); // Trader llamas wear a fixed decor; normal llamas carry a dyed carpet in the decor slot. - bodyEquip = (e instanceof org.bukkit.entity.TraderLlama) ? "trader_llama" : carpetKey(l); - } else if (e instanceof org.bukkit.entity.ChestedHorse ch) { + bodyEquip = (e instanceof TraderLlama) ? "trader_llama" : carpetKey(l); + } else if (e instanceof ChestedHorse ch) { // Donkey & mule (llama already handled above). chest = ch.isCarryingChest(); saddle = isSaddled(ch); - } else if (e instanceof org.bukkit.entity.AbstractHorse ah) { + } else if (e instanceof AbstractHorse ah) { // Skeleton/zombie horse: only saddle (no colour/markings/armor variants). saddle = isSaddled(ah); - } else if (e instanceof org.bukkit.entity.AbstractNautilus nl) { + } else if (e instanceof AbstractNautilus nl) { // Nautilus body armor + saddle are same-UV overlays (like horse armor). - org.bukkit.inventory.EntityEquipment eq = nl.getEquipment(); - bodyEquip = equipAsset(eq.getItem(org.bukkit.inventory.EquipmentSlot.BODY)); - org.bukkit.inventory.ItemStack sd = eq.getItem(org.bukkit.inventory.EquipmentSlot.SADDLE); + EntityEquipment eq = nl.getEquipment(); + bodyEquip = equipAsset(eq.getItem(EquipmentSlot.BODY)); + ItemStack sd = eq.getItem(EquipmentSlot.SADDLE); saddle = !sd.getType().isAir(); - } else if (e instanceof org.bukkit.entity.Fox f) { + } else if (e instanceof Fox f) { variant = keyOf(f.getFoxType()); - } else if (e instanceof org.bukkit.entity.MushroomCow mc) { + } else if (e instanceof MushroomCow mc) { variant = keyOf(mc.getVariant()); - } else if (e instanceof org.bukkit.entity.Panda pa) { + } else if (e instanceof Panda pa) { variant = keyOf(pa.getMainGene()); - } else if (e instanceof org.bukkit.entity.Frog fr) { + } else if (e instanceof Frog fr) { variant = keyOf(fr.getVariant()); - } else if (e instanceof org.bukkit.entity.Shulker s) { + } else if (e instanceof Shulker s) { variant = s.getColor() == null ? null : keyOf(s.getColor()); - } else if (e instanceof org.bukkit.entity.ZombieVillager zv) { + } else if (e instanceof ZombieVillager zv) { variant = keyOf(zv.getVillagerType()); // ZombieVillager exposes no level via Bukkit -> no profession-level badge (matches vanilla). - } else if (e instanceof org.bukkit.entity.Villager vi) { + } else if (e instanceof Villager vi) { variant = keyOf(vi.getVillagerType()); profession = keyOf(vi.getProfession()); villagerLevel = vi.getVillagerLevel(); - } else if (e instanceof org.bukkit.entity.Cow co) { + } else if (e instanceof Cow co) { variant = keyOf(co.getVariant()); - } else if (e instanceof org.bukkit.entity.Pig pg) { + } else if (e instanceof Pig pg) { variant = keyOf(pg.getVariant()); - } else if (e instanceof org.bukkit.entity.Chicken ch) { + } else if (e instanceof Chicken ch) { variant = keyOf(ch.getVariant()); } } catch (Throwable ignored) { @@ -177,7 +220,7 @@ public final class EntitySnapshotBuilder { /** Worn armor (4 slots) from a humanoid wearer; null when nothing is equipped. */ private static EntityState.Equipment captureEquipment(LivingEntity le) { try { - org.bukkit.inventory.EntityEquipment eq = le.getEquipment(); + EntityEquipment eq = le.getEquipment(); if (eq == null) return null; EntityState.Equipment equip = new EntityState.Equipment( armorPiece(eq.getHelmet()), armorPiece(eq.getChestplate()), @@ -189,7 +232,7 @@ public final class EntitySnapshotBuilder { } /** One armor slot -> EquipPiece (asset, leather dye, trim, glint); null for empty / non-armor items. */ - private static EntityState.EquipPiece armorPiece(org.bukkit.inventory.ItemStack it) { + private static EntityState.EquipPiece armorPiece(ItemStack it) { if (it == null || it.getType().isAir()) return null; String asset = armorAsset(it.getType()); if (asset == null) return null; // not a humanoid-armor item (e.g. a mob head / pumpkin) @@ -197,10 +240,10 @@ public final class EntitySnapshotBuilder { String trimMat = null, trimPat = null; boolean glint = false; if (it.hasItemMeta()) { - org.bukkit.inventory.meta.ItemMeta meta = it.getItemMeta(); + ItemMeta meta = it.getItemMeta(); glint = meta.hasEnchants(); - if (meta instanceof org.bukkit.inventory.meta.LeatherArmorMeta lam) dye = lam.getColor().asARGB(); - if (meta instanceof org.bukkit.inventory.meta.ArmorMeta am && am.getTrim() != null) { + if (meta instanceof LeatherArmorMeta lam) dye = lam.getColor().asARGB(); + if (meta instanceof ArmorMeta am && am.getTrim() != null) { trimMat = keyOf(am.getTrim().getMaterial()); trimPat = keyOf(am.getTrim().getPattern()); } @@ -209,7 +252,7 @@ public final class EntitySnapshotBuilder { } /** Item Material -> equipment asset id (= texture name): strips the slot suffix; null if not armor. */ - private static String armorAsset(org.bukkit.Material m) { + private static String armorAsset(Material m) { String key = m.getKey().getKey(); if (key.equals("elytra")) return "elytra"; if (key.equals("turtle_helmet")) return "turtle_scute"; @@ -222,32 +265,32 @@ public final class EntitySnapshotBuilder { } /** Horse coat markings overlay key (vanilla texture suffix); null for the plain NONE style. */ - private static String markingsKey(org.bukkit.entity.Horse.Style style) { - if (style == null || style == org.bukkit.entity.Horse.Style.NONE) return null; - return style.name().toLowerCase(java.util.Locale.ROOT).replace("_", ""); // WHITE_DOTS -> whitedots + private static String markingsKey(Horse.Style style) { + if (style == null || style == Horse.Style.NONE) return null; + return style.name().toLowerCase(Locale.ROOT).replace("_", ""); // WHITE_DOTS -> whitedots } /** Horse armor material -> equipment/horse_body texture key (golden uses the "gold" file); null if none. */ - private static String horseArmorKey(org.bukkit.entity.Horse h) { - org.bukkit.inventory.ItemStack a = h.getInventory().getArmor(); + private static String horseArmorKey(Horse h) { + ItemStack a = h.getInventory().getArmor(); if (a == null || a.getType().isAir()) return null; String k = a.getType().getKey().getKey().replace("_horse_armor", ""); return k.equals("golden") ? "gold" : k; } /** Llama carpet decor -> equipment/llama_body colour key; null if none. */ - private static String carpetKey(org.bukkit.entity.Llama l) { - org.bukkit.inventory.ItemStack d = l.getInventory().getDecor(); + private static String carpetKey(Llama l) { + ItemStack d = l.getInventory().getDecor(); if (d == null || d.getType().isAir()) return null; String k = d.getType().getKey().getKey(); return k.endsWith("_carpet") ? k.substring(0, k.length() - "_carpet".length()) : null; } /** Equipment asset id (= equipment/ texture name) from an item's EQUIPPABLE component; null if none. */ - private static String equipAsset(org.bukkit.inventory.ItemStack it) { + private static String equipAsset(ItemStack it) { if (it == null || it.getType().isAir()) return null; try { - var comp = it.getData(io.papermc.paper.datacomponent.DataComponentTypes.EQUIPPABLE); + var comp = it.getData(DataComponentTypes.EQUIPPABLE); if (comp != null && comp.assetId() != null) return comp.assetId().value(); } catch (Throwable ignored) { } @@ -255,8 +298,8 @@ public final class EntitySnapshotBuilder { } /** Whether a horse-like mount carries a saddle in its dedicated saddle slot. */ - private static boolean isSaddled(org.bukkit.entity.AbstractHorse h) { - org.bukkit.inventory.ItemStack st = h.getInventory().getSaddle(); + private static boolean isSaddled(AbstractHorse h) { + ItemStack st = h.getInventory().getSaddle(); return st != null && !st.getType().isAir(); } @@ -264,21 +307,21 @@ public final class EntitySnapshotBuilder { private static String keyOf(Object o) { return switch(o) { case null -> null; - case org.bukkit.Keyed k -> k.getKey().getKey(); - case Enum en -> en.name().toLowerCase(java.util.Locale.ROOT); - default -> o.toString().toLowerCase(java.util.Locale.ROOT); + case Keyed k -> k.getKey().getKey(); + case Enum en -> en.name().toLowerCase(Locale.ROOT); + default -> o.toString().toLowerCase(Locale.ROOT); }; } /** Returns {skinUrl, model} from the player's profile texture property, or {null, null}. */ private static String[] resolveSkin(Player player) { try { - for (com.destroystokyo.paper.profile.ProfileProperty prop : player.getPlayerProfile().getProperties()) { + for (ProfileProperty prop : player.getPlayerProfile().getProperties()) { if (!prop.getName().equals("textures")) continue; - String json = new String(java.util.Base64.getDecoder().decode(prop.getValue()), - java.nio.charset.StandardCharsets.UTF_8); - com.google.gson.JsonObject root = com.google.gson.JsonParser.parseString(json).getAsJsonObject(); - com.google.gson.JsonObject skin = root.getAsJsonObject("textures").getAsJsonObject("SKIN"); + String json = new String(Base64.getDecoder().decode(prop.getValue()), + StandardCharsets.UTF_8); + JsonObject root = JsonParser.parseString(json).getAsJsonObject(); + JsonObject skin = root.getAsJsonObject("textures").getAsJsonObject("SKIN"); String url = skin.get("url").getAsString(); String model = null; if (skin.has("metadata") && skin.getAsJsonObject("metadata").has("model")) { @@ -292,7 +335,7 @@ public final class EntitySnapshotBuilder { } /** Reads a dimension via {@code primary}, falling back to {@code fallback} on any version mismatch. */ - private static double safeDim(java.util.function.DoubleSupplier primary, java.util.function.DoubleSupplier fallback) { + private static double safeDim(DoubleSupplier primary, DoubleSupplier fallback) { try { return primary.getAsDouble(); } catch (Throwable t) { diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/render/util/ColorUtil.java b/src/main/java/eu/mhsl/minecraft/pixelpics/render/util/ColorUtil.java index 8bb9a32..a027c2d 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/render/util/ColorUtil.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/render/util/ColorUtil.java @@ -1,5 +1,8 @@ package eu.mhsl.minecraft.pixelpics.render.util; +import org.bukkit.Color; +import org.bukkit.DyeColor; + /** * Helpers for packed ARGB integer colors. */ @@ -17,9 +20,9 @@ public final class ColorUtil { } /** Opaque ARGB for a Bukkit dye colour, or {@code fallback} when {@code dye} is null. */ - public static int dyeArgb(org.bukkit.DyeColor dye, int fallback) { + public static int dyeArgb(DyeColor dye, int fallback) { if (dye == null) return fallback; - org.bukkit.Color c = dye.getColor(); + Color c = dye.getColor(); return argb(0xFF, c.getRed(), c.getGreen(), c.getBlue()); } @@ -27,8 +30,8 @@ public final class ColorUtil { * The vanilla sign-text colour for a dye (opaque ARGB), from Mojang's {@code DyeColor.getTextColor()} * table (the firework/text colours, NOT the cloth colours). Null = black (the default sign ink). */ - public static int signTextColor(org.bukkit.DyeColor dye) { - int rgb = switch (dye == null ? org.bukkit.DyeColor.BLACK : dye) { + public static int signTextColor(DyeColor dye) { + int rgb = switch (dye == null ? DyeColor.BLACK : dye) { case WHITE -> 0xF9FFFE; case ORANGE -> 0xF9801D; case MAGENTA -> 0xC74EBD; @@ -53,7 +56,7 @@ public final class ColorUtil { * The fill colour for sign text: glowing text uses the full dye colour; non-glowing text is the dye * colour darkened to 40% (matching vanilla {@code SignRenderer}, which is why normal ink looks dim). */ - public static int signFillArgb(org.bukkit.DyeColor dye, boolean glowing) { + public static int signFillArgb(DyeColor dye, boolean glowing) { int base = signTextColor(dye); return glowing ? base : (0xFF000000 | (shade(base, 0.4) & 0xFFFFFF)); } @@ -63,8 +66,8 @@ public final class ColorUtil { * the dye colour darkened to 40%, except glowing BLACK ink which gets a light cream outline so it * stays readable. */ - public static int signOutlineArgb(org.bukkit.DyeColor dye) { - if ((dye == null ? org.bukkit.DyeColor.BLACK : dye) == org.bukkit.DyeColor.BLACK) return 0xFFF0EBCC; + public static int signOutlineArgb(DyeColor dye) { + if ((dye == null ? DyeColor.BLACK : dye) == DyeColor.BLACK) return 0xFFF0EBCC; return 0xFF000000 | (shade(signTextColor(dye), 0.4) & 0xFFFFFF); } diff --git a/src/main/java/eu/mhsl/minecraft/pixelpics/survival/CameraItems.java b/src/main/java/eu/mhsl/minecraft/pixelpics/survival/CameraItems.java index b14fd45..17e0228 100644 --- a/src/main/java/eu/mhsl/minecraft/pixelpics/survival/CameraItems.java +++ b/src/main/java/eu/mhsl/minecraft/pixelpics/survival/CameraItems.java @@ -8,6 +8,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -112,7 +113,7 @@ public final class CameraItems { // --- internals --- - private static boolean hasMarker(ItemStack item, org.bukkit.NamespacedKey key) { + private static boolean hasMarker(ItemStack item, NamespacedKey key) { if (item == null || item.getType() != Material.PLAYER_HEAD || !item.hasItemMeta()) return false; PersistentDataContainer pdc = item.getItemMeta().getPersistentDataContainer(); return pdc.has(key, PersistentDataType.BYTE);