# Developer API 3DEH exposes its manager and model directly through the plugin instance. There is no separate API artifact and no `ServicesManager` registration — depend on the plugin jar and cast. The public surface is `dev.fauza.tdeh.ThreeDehPlugin`, the `model` package, and `dev.fauza.tdeh.manager.HologramManager`. Everything else is internal and may change between releases. ## Depending on 3DEH ```kotlin repositories { maven("https://repo.papermc.io/repository/maven-public/") } dependencies { compileOnly("io.papermc.paper:paper-api:1.20.6-R0.1-SNAPSHOT") compileOnly(files("libs/3DEH-Lite-1.0.0.jar")) } ``` Declare the dependency in your `plugin.yml` so load order is correct: ```yaml depend: [3DEH-Lite] # or softdepend, if your plugin works without it ``` ## Getting the manager ```java ThreeDehPlugin threeDeh = (ThreeDehPlugin) getServer().getPluginManager().getPlugin("3DEH-Lite"); HologramManager manager = threeDeh.manager(); ``` ## Creating a hologram ```java TextPart title = new TextPart("Arena"); title.billboard(BillboardMode.CENTER); title.scale(Vec3.of(1.5)); ItemPart icon = new ItemPart("diamond_sword"); icon.offset(new Vec3(0, 0.8, 0)); icon.transform(ItemTransform.HEAD); Hologram hologram = new Hologram( "arena", new HologramLocation("world", 120.5, 65.0, -43.5), List.of(title, icon)); manager.create(hologram); manager.requestSave(); ``` `create` registers the hologram, indexes it by chunk, and spawns it if that chunk is loaded. It does not save on its own — call `requestSave()` when you are done with a batch of changes. ## Editing Two entry points, and picking the right one matters: ```java // Attribute change: pushed to the live entity, no respawn, no flicker. manager.editPart(hologram, 0, part -> part.scale(Vec3.of(2))); // Structural change: the anchor, or the part list. Despawns and respawns. manager.restructure(hologram, () -> hologram.addPart(new ItemPart("emerald"))); manager.requestSave(); ``` Part indices back the live entity list positionally, so anything that shifts them — adding a part, removing one, changing an offset, moving the anchor — has to go through `restructure`. ## Reading ```java Optional found = manager.find("arena"); // case-insensitive Collection all = manager.all(); boolean live = manager.isSpawned("arena"); ``` ## Threading 3DEH is written for Folia, and any plugin touching its model has to respect the same rules. **Model objects are mutable and shared.** `HologramManager` synchronises on the `Hologram` instance while mutating or encoding it, so the autosave never sees a half-applied edit. If you mutate a part outside `editPart`/`restructure`, synchronise on the hologram yourself: ```java synchronized (hologram) { hologram.part(0).viewRange(2.0f); } manager.markDirty(); ``` **Never touch a display entity directly.** Use `editPart`; it dispatches through the entity's own scheduler, which is the only form that stays correct when an entity crosses a region boundary. **Do not use `BukkitScheduler`.** It has no meaning on Folia. `dev.fauza.tdeh.manager.Scheduling` wraps the regional API if you need the same primitives. ## Validation Model setters enforce their own bounds and throw `IllegalArgumentException`, so invalid state cannot reach the renderer: ```java part.teleportDuration(120); // rejected: vanilla allows 0-59 new Brightness(16, 0); // rejected: light levels are 0-15 new TextPart("hi").lineWidth(0); // rejected: must be positive ``` Catch it and report to your user; 3DEH's own commands do exactly that. ## Text formatting `dev.fauza.tdeh.text.TextFormat` is a pure utility and safe to call from anywhere: ```java Component rendered = TextFormat.render("&6&lHUB"); // detects the dialect String preview = TextFormat.plain("HUB"); // "HUB" TextFormat.Dialect dialect = TextFormat.dialectOf(input); ``` Store the raw string an operator typed, not a serialised component, and let `TextFormat` render it. That is what 3DEH does, so the text survives a round-trip through `data.yml` unchanged. ## Serialisation `dev.fauza.tdeh.codec.HologramCodec` converts between a `Hologram` and a plain `Map` — useful for exporting to your own storage. It has no Bukkit dependency: ```java Map encoded = HologramCodec.encode(hologram); Hologram decoded = HologramCodec.decode("arena", encoded); // throws CodecException on bad input ```