================================================================================
MODELEDNPCS — UPDATE v8.0
Date: 2026-03-30
================================================================================
This update introduces major new systems, a reworked interaction pipeline, per-NPC extended configuration, and a full public API expansion.
Every feature listed below is configurable and works with /mnpc reload.
1. NPC HOVER SYSTEM (NPCHoverManager)
A brand-new system that detects when a player aims their crosshair at a nearby NPC and reacts visually and interactively in real time.
How it works
- Every few ticks (configurable), the plugin checks every online player’s aim.
- Uses entity ray tracing first, then a cone-angle scan as fallback (covers ModelEngine marker bones that have no normal hitbox).
On hover enter
- Scales the ModelEngine model up (shared across all hovering players — only applies once when the first player starts hovering).
- Scales the player’s personal hologram up (per-player).
- Plays a configurable sound for the hovering player.
- Shows an action-bar hint message (for example: [Right-Click] Interact).
- Plays a custom hover animation on the ModelEngine model (per-NPC, configured in npc-extras.yml — see Section 4).
- Fires a cancellable NPCHoverEvent (ENTER) for API/addon use.
On hover exit
- Restores model scale when the last hovering player leaves.
- Restores idle animation.
- Restores the player’s hologram scale.
- Clears the action bar.
- Fires NPCHoverEvent (LEAVE).
Right-click while hovering
If a player right-clicks air or a block while hovering an NPC, the interaction triggers automatically — no need to physically click the entity hitbox.
Global config (config.yml → npc.hover)
Code (YAML):
npc:
hover:
enabled
: true
# Detection range in blocks
range
: 10.0
# Cone half-angle in degrees — how precisely the player must aim
angle_deg
: 15.0
# ModelEngine scale multiplier while hovered (1.0 = normal)
scale
: 1.2
# Sound played when hover starts
sound
: UI_BUTTON_CLICK
sound_volume
: 0.6
sound_pitch
: 1.4
# Scale the player's personal hologram when hovering
scale_hologram
: true
hologram_scale
: 1.3
# Tick interval for the aim check (lower = more responsive)
check_interval_ticks
: 2
# Action-bar text shown while hovering. Leave blank to disable.
hint_text
:
"&e[Right-Click] &fInteract"
Per-NPC overrides (npc-extras.yml)
- hover_enabled: true/false — enable or disable hover for this NPC
- hover_hint: "&e[Right-Click] &fShop" — override the action-bar text
- hover_animation: "wave" — ModelEngine animation to loop while hovered
Note: All hover config keys are live-reloadable via /mnpc reload.
2. RIGHT-CLICK FALLBACK (NPCListener)
Previously, right-click interaction only triggered when the player physically clicked on the entity’s hitbox (PlayerInteractEntityEvent). With ModelEngine models, hitboxes are often smaller or offset, causing missed clicks.
The new right_fallback catches RIGHT_CLICK_AIR and RIGHT_CLICK_BLOCK events, then performs the same ray-trace + cone-scan detection used by the hover system to find which NPC the player was aiming at.
How it works
- Fires on RIGHT_CLICK_AIR or RIGHT_CLICK_BLOCK (main hand only).
- Ignores the admin tool.
- Runs a ray trace along the crosshair up to range blocks.
- Falls back to cone scan if no entity is hit by the ray.
- If an NPC is found:
- cancels the interact event,
- plays the interact animation,
- triggers the full NPC interaction pipeline.
- Has its own dedup guard so it never double-fires with a direct hitbox click.
Config (config.yml)
Code (YAML):
npc:
interaction:
right_fallback:
enabled
: true
range
: 5.5
# blocks — how far a missed right-click can reach
angle_deg
: 30.0
# cone half-angle in degrees
left_fallback uses the same structure and was already present.
Note: Both fallbacks are reloaded by /mnpc reload.
3. CONFIG BUG FIX — Duplicate npc: key
The config.yml had two separate top-level npc: keys. In YAML, the second key overwrites the first, which meant the entire npc.hover section was silently discarded at runtime.
Any value set in:
- npc.hover.range
- npc.hover.scale
- npc.hover.angle_deg
- etc.
had no effect — the code always used its hardcoded defaults.
Fix
The duplicate npc: key
(which only held schedule_inactive_message) was merged into the first npc: block.
All hover and interaction config values now load correctly on both:
4. NPC-EXTRAS SYSTEM (npc-extras.yml + NPCExtrasConfig)
npc-extras.yml is a per-NPC extended config file. Each top-level key is an NPC id
(integer). All fields are optional — defaults are applied if missing.
Changes take effect after /mnpc reload.
Full list of supported keys per NPC
LuxDialogues Integration
- lux_dialogue: "my_dialogue_id"
Assigns a LuxDialogues conversation to this NPC. When the player interacts, the specified dialogue is triggered via LuxDialogues.
- lux_first_page: "1"
The first page/node of the LuxDialogues conversation to open. Default: "1".
Particle Effects
- particle: "HEART"
Bukkit Particle enum name. Played continuously around the NPC. Leave empty to disable.
- particle_count: 5
Number of particles spawned per cycle.
- particle_radius: 0.6
Radius (blocks) of the particle orbit around the NPC.
- particle_height: 1.0
Height offset (blocks) above the NPC base for the particle orbit.
Greeting System
- greet_message: "&aHello, traveler!"
Chat/action-bar message sent to the player when they enter greet range. Supports & color codes.
- greet_animation: "wave"
ModelEngine animation played on the NPC when greeting a player.
- greet_range: 8.0
Distance in blocks at which the greeting triggers. Default: 8.0.
Proximity Message
- proximity_message: "&7A merchant is nearby..."
Message shown to the player when they are within proximity_range of this NPC. Different from greet — can be shown repeatedly, not just on first approach.
- proximity_range: 5.0
Distance in blocks that triggers the proximity message. Default: 5.0.
Schedule System
- schedule_start: 6
In-game hour (0–23) at which this NPC becomes active. Default: -1 (always active).
- schedule_end: 20
In-game hour (0–23) at which this NPC becomes inactive. Default: -1 (always active).
- schedule_weather: "ANY"
Weather condition required for the NPC to be active.
Values: ANY, CLEAR, RAIN. Default: ANY.
When an NPC is outside its active schedule, interaction is blocked and the message from config.yml (npc.schedule_inactive_message) is shown.
Hover System Overrides
- hover_enabled: true
Set to false to completely disable hover detection for this specific NPC.
- hover_hint: "&e[Right-Click] &fShop"
Overrides the global hint_text from config.yml for this NPC only. Leave empty to use the global value.
- hover_animation: "wave"
ModelEngine animation to loop while this NPC is being hovered. When hover ends, the NPC returns to its normal idle animation. Leave empty to keep the idle animation during hover.
Hologram Text Animation
- hologram_frames:
A list of text frames cycled through on the NPC’s hologram, creating a color/text animation effect.
Example:
Code (YAML):
hologram_frames
:
[LIST
]
[*
]
"&aWelcome!"
[*
]
"&eWelcome!"
[*
]
"&6Welcome!"
[*]hologram_frame_interval: 20
Ticks between each frame transition. 20 ticks = 1 second. Default: 20.
[/LIST]
NPC State System
- active_state: "default"
The currently active state for this NPC. Persists across restarts. Changing the state swaps the animation and hologram suffix.
Can be changed via API:
Code (Java):
ModeledNPCsAPI.
get
(
).
setNPCState
(id,
"stateName"
)
;
Fires a cancellable NPCStateChangeEvent.
Example:
Code (YAML):
active_state
:
"default"
states:
default:
animation
:
"idle"
hologram_suffix
:
""
busy:
animation
:
"talk"
hologram_suffix
:
" &7(Busy)"
combat:
animation
:
"attack"
hologram_suffix
:
" &c(In Combat)"
Any number of custom states can be defined.
5. PUBLIC API EXPANSION (ModeledNPCsAPI)
The public API (com.github.el211:ModeledNPCS-API:v8.0) has been expanded with the following new abstract methods.
All methods are accessible via:
Code (Java):
ModeledNPCsAPI.
get
(
).
*
Hover System
Code (Java):
int getHoveredNPCId
(Player player
)
boolean isPlayerHoveringNPC
(Player player,
int npcId
)
void setNPCHoverEnabled
(
int npcId,
boolean enabled
)
boolean isNPCHoverEnabled
(
int npcId
)
void setNPCHoverHint
(
int npcId,
String hint
)
String getNPCHoverHint
(
int npcId
)
void setNPCHoverAnimation
(
int npcId,
String animation
)
String getNPCHoverAnimation
(
int npcId
)
NPC States
Code (Java):
void setNPCState
(
int npcId,
String state
)
String getNPCState
(
int npcId
)
Schedule
Code (Java):
boolean isNPCActive
(
int npcId
)
void setNPCSchedule
(
int npcId,
int startHour,
int endHour
)
int getNPCScheduleStart
(
int npcId
)
int getNPCScheduleEnd
(
int npcId
)
Hologram Animation
Code (Java):
void setNPCHologramFrames
(
int npcId, List
<String
> frames
)
List
<String
> getNPCHologramFrames
(
int npcId
)
void setNPCHologramFrameInterval
(
int npcId,
int ticks
)
int getNPCHologramFrameInterval
(
int npcId
)
LuxDialogues Integration
Code (Java):
boolean isLuxDialoguesAvailable
(
)
boolean triggerLuxDialogue
(Player player,
int npcId
)
boolean isPlayerInLuxDialogue
(Player player
)
void setNPCLuxDialogue
(
int npcId,
String dialogueId
)
String getNPCLuxDialogue
(
int npcId
)
void setNPCLuxFirstPage
(
int npcId,
String page
)
String getNPCLuxFirstPage
(
int npcId
)
New API Events
NPCHoverEvent — fired on hover ENTER and LEAVE. Cancellable.
- getPlayer() — the hovering player
- getNPCData() — the NPC being hovered
- getHoverAction() — HoverAction.ENTER or HoverAction.LEAVE
NPCStateChangeEvent — fired when an NPC state changes. Cancellable.
- getNPCData() — the NPC whose state is changing
- getPreviousState() — the old state name
- getNewState() — the new state name
6. /mnpc reload IMPROVEMENTS
/mnpc reload now also reloads:
- all npc.hover.* config values (range, angle, scale, sound, etc.)
- restarts the hover tick task with the new check_interval_ticks
- npc.interaction.right_fallback.* values
- npc.interaction.left_fallback.* values
Previously, hover config changes required a full server restart to take effect.
7. EXAMPLE npc-extras.yml ENTRY
Example: NPC id 5 — a merchant with full extras configured.
Code (YAML):
5:
lux_dialogue
:
"merchant_talk"
lux_first_page
:
"1"
particle
:
"HEART"
particle_count
: 5
particle_radius
: 0.6
particle_height
: 1.0
greet_message
:
"&eWelcome to my shop!"
greet_animation
:
"wave"
greet_range
: 8.0
proximity_message
:
"&7A merchant is nearby..."
proximity_range
: 5.0
schedule_start
: 6
schedule_end
: 20
schedule_weather
:
"CLEAR"
hover_enabled
: true
hover_hint
:
"&e[Right-Click] &fOpen Shop"
hover_animation
:
"wave"
hologram_frames
:
-
"&aShop &fOpen"
-
"&6Shop &fOpen"
-
"&eShop &fOpen"
hologram_frame_interval
: 20
active_state
:
"default"
states:
default:
animation
:
"idle"
hologram_suffix
:
""
busy:
animation
:
"talk"
hologram_suffix
:
" &7(Busy)"