Skip to content

Feat/modelengine support - #315

Open
mattwithabat wants to merge 2 commits into
FancyInnovations:mainfrom
mattwithabat:feat/modelengine-support
Open

Feat/modelengine support#315
mattwithabat wants to merge 2 commits into
FancyInnovations:mainfrom
mattwithabat:feat/modelengine-support

Conversation

@mattwithabat

@mattwithabat mattwithabat commented Aug 7, 2026

Copy link
Copy Markdown

📋 Description

This PR adds ModelEngine support to the fancynpcs-model addon, alongside the existing
BetterModel support. Until now the addon was hard-wired to BetterModel and listed it as a
required dependency, so servers running ModelEngine (the most widely used custom-model plugin
in the ecosystem) could not use custom models on FancyNpcs NPCs at all.

Rather than bolting a second integration onto the existing code, the BetterModel-specific logic
is extracted behind a small ModelProvider abstraction. Both plugins are now optional
dependencies and either (or both) can be installed. All existing behaviour, commands and config
are preserved — an existing setup keeps working unchanged after updating.

The ModelEngine integration needs a different strategy than BetterModel: FancyNpcs NPCs are
packet-based and don't exist in the world, so ModelEngine cannot track them like a normal entity.
Instead, a ModelEngine Dummy base entity carrying the model is created at the NPC's location,
the NPC entity itself is made invisible, and the dummy is kept in sync with the NPC's location
via a ModelEngine tick task.

No related issue is open that I'm aware of — happy to link one if there is.

✅ Checklist

  • My code follows the project's coding style and guidelines
  • I have tested my changes locally and they work as expected — see notes under How to Test
  • I have added necessary documentation (if applicable)
  • I have linked related issues using Fixes #issue_number or Closes #issue_number — no related issue found
  • I have rebased/merged with the latest main branch — branched off 2da46d9

🔍 Changes

  • Added ModelProvider interface (Javadoc'd) abstracting model listing, attach/detach,
    animations and interaction handling from a concrete model plugin
  • Added ModelProviderRegistry, which detects installed model plugins at enable time and
    resolves model names to a provider
  • Refactored the existing BetterModel logic out of CustomModelAttribute into
    BetterModelProvider — behaviour unchanged
  • Added ModelEngineProvider + ModelEngineInteractListener implementing the ModelEngine
    integration (dummy base entity, invisible NPC, location sync, scale, hitbox clicks)
  • Added NpcEntityAccess utility holding the shared NPC → Bukkit entity reflection lookup
  • Changed model name resolution: unprefixed names resolve against BetterModel first, then
    ModelEngine; names may be prefixed to force a provider (bm:/bettermodel:,
    me:/meg:/modelengine:)
  • Changed /npc custom_model, /npc play_animation and the play_animation_once /
    play_animation_loop actions to dispatch through the active provider
  • Changed paper-plugin.yml: BetterModel is now optional, ModelEngine added as optional;
    the plugin disables itself with a clear message if neither is installed
  • Changed the custom_model.applied message to also name the provider that was used
  • Added com.ticxo.modelengine:ModelEngine:R4.1.1 as a non-transitive compileOnly
    dependency plus the mvn.lumine.io repository
  • Fixed the NPC staying visible next to its ModelEngine model until the next metadata
    refresh, by setting the invisible flag before the attribute cycle sends entity metadata
  • Added a module README.md, a CHANGELOG.md entry, and bumped VERSION to 1.2.0

🧪 How to Test

Setup: Paper or Folia 26.2 with FancyNpcs 2.11.0 and this addon build. Test once with
ModelEngine R4.1.1 installed, and once with BetterModel 3.2.0, to confirm neither path regressed.

  1. Install only ModelEngine with at least one imported model. Create a player NPC
    (/npc create test) and apply a model: /npc custom_model test <model>. The model should
    appear and the player NPC should become invisible immediately — no visible Steve alongside
    the model, and none for players who join afterwards.
  2. Left- and right-click the model's hitbox and confirm the NPC's actions trigger for both.
  3. Add an animation action (play_animation_loop) and run
    /npc play_animation test <animation> --loop — tab-completion should list the model's
    animations, and the animation should play/loop.
  4. Run /npc moveHere test and /npc teleport — the model should follow the NPC's new location.
  5. Set /npc scale test 2 and re-apply the model; the model and its hitbox should scale.
  6. Remove the model with /npc custom_model test @none — the model disappears and the normal
    player NPC becomes visible again. Then /npc remove test with a model applied and confirm no
    orphan model is left in the world. Reload/restart the server and confirm models are restored
    from the saved attribute without duplicates.
  7. Install only BetterModel and repeat steps 1–6 to confirm the existing behaviour is
    unchanged.
  8. With both installed, confirm bm:<model> and me:<model> each force the intended
    provider, and that switching an NPC from one provider to the other leaves nothing behind.
  9. Uninstall both model plugins and confirm the addon disables itself with the explanatory
    log message instead of throwing.

claude added 2 commits August 6, 2026 20:41
- introduce ModelProvider abstraction with BetterModel and ModelEngine implementations
- resolve unprefixed model names via BetterModel first, then ModelEngine; support bm:/me: prefixes
- ModelEngine models are attached to a Dummy base entity that follows the (invisible) NPC
- route ModelEngine hitbox clicks to FancyNpcs interactions, keep native clicks as fallback
- make BetterModel optional and add ModelEngine as optional dependency

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e model

The invisible flag was only set in the deferred model-creation task, one tick
after FancyNpcs had already sent the entity metadata - so the player NPC
stayed visible next to the model until the next metadata refresh. Set the
flag before the attribute application cycle sends metadata, and restore
visibility if model creation fails.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants