NPC - Dani-error/velar GitHub Wiki
Start by getting a builder from your configured platform:
val builder = platform.newNPCBuilder()Then chain the following methods:
-
entityId(id: Int)(optional)โ Manually set the entity ID. If omitted, Velar generates a random one.
-
position(position: Position)(required)โ Set the NPCโs world position. Use your platform-specific
Positionobject (Velar has Kotlin extensions to help). -
profile(profile: Profile.Resolved)(required)โ Provide a fully resolved profile (UUID + skin props).
-
profile(profile: Profile): CompletableFuture<Builder<W,P,I,E>>โ Pass an unresolved profile, e.g.
builder.profile(Profile.unresolved("NPC_NAME"))
Velar will resolve it for you.
-
profile(resolver: ProfileResolver?, profile: Profile): CompletableFuture<Builder<W,P,I,E>>โ Use a custom resolver if needed:
builder.profile(myResolver, Profile.unresolved("CustomNPC"))
-
eventHandler { โฆ }(optional)โ Configure NPCโs internal event handler. See all events here. Example:
builder.eventHandler { bind<AttackNPCEvent> { bukkitPlayer().sendMessage("[${bukkitNPC().profile.name}] Ouch, that hurt!") } } -
npcSettings { โฆ }(optional)โ Tweak spawn/tracking rules and per-viewer profile resolution.
builder.npcSettings { it .trackingRule(NPCTrackingRule.allPlayers()) .profileResolver(NPCProfileResolver.ofViewer()) }NPCSettings has:
-
trackingRule: choose from-
allPlayers(), -
onlyUnspecifiedPlayers(), -
onlyExplicitlyIncludedPlayers(), or create your own rule.
-
-
profileResolver: e.g.-
NPCProfileResolver.ofSpawnedNPC(), -
NPCProfileResolver.ofName("Bob"), -
NPCProfileResolver.ofUniqueId(uuid), -
NPCProfileResolver.ofProfile(profile), -
NPCProfileResolver.ofViewer(), or create your own resolver.
-
-
-
Flags (optional, see docs) โ Use
.flag(flag, value)or.flags(...).Flag Description Default LOOK_AT_PLAYERImitate playerโs head rotation falseHIT_WHEN_PLAYER_HITSSwing when player hits falseSNEAK_WHEN_PLAYER_SNEAKSCrouch when player crouches falseHIDE_NAME_TAGHide the nameplate above the NPC false
Style note: put your
.profile(Profile.unresolved(...))call last, then:.thenAccept { val npc = it.buildAndTrack() // or it.build() // now you've built the npc object and can manage it }
-
.build(): returns an untracked NPC (you must.trackPlayer(..)yourself). -
.buildAndTrack(): spawns, tracks and applies action-controller flags automatically
Once you have an NPC<W,P,I,E> instance, you can:
npc.shouldIncludePlayer(player) // will this NPC spawn to that player?
npc.includesPlayer(player) // is the player currently included?
npc.addIncludedPlayer(player) // add to spawn list
npc.removeIncludedPlayer(player) // remove from spawn list
npc.unlink() // despawn/unlink NPCnpc.tracksPlayer(player) // is NPC tracking that player?
npc.trackPlayer(player) // start tracking (spawn)
npc.forceTrackPlayer(player) // force track regardless of rules
npc.stopTrackingPlayer(player) // stop tracking for that playernpc.rotate(yaw, pitch) // packet: set yaw/pitch
npc.lookAt(position) // packet: look at a point
npc.playAnimation(EntityAnimation.SWING_MAIN_ARM) // packet: play animation
npc.changeItem(ItemSlot.MAIN_HAND, item) // packet: equip item
npc.changeMetadata(factory, value) // packet: update metadata-
EntityAnimation enums:
SWING_MAIN_ARM,TAKE_DAMAGE,LEAVE_BED,SWING_OFF_HAND,CRITICAL_EFFECT,MAGIC_CRITICAL_EFFECT, etc. -
ItemSlot enums:
MAIN_HAND,OFF_HAND,FEET,LEGS,CHEST,HEAD. -
Built-in metadata factories (via
EntityMetadataFactory):sneakingMetaFactory(),skinLayerMetaFactory(),entityStatusMetaFactory(),entityPoseMetaFactory(),shakingMetaFactory(),usingItemMetaFactory(),arrowCountMetaFactory().
Each NPCSpecificOutboundPacket can be sent with:
packet.scheduleForTracked() // all tracked players
packet.schedule(player) // single player
packet.schedule(players) // many players
packet.schedule { it.trackedPlayers } // custom extractorNeed practical usage? Check out the example code here.
It includes simple and advanced NPC setups, like:
- Skin resolution per viewer
- Custom tracking rules
- Builder usage with flags and events