NPC - Dani-error/velar GitHub Wiki

๐Ÿ› ๏ธ Create NPC

Start by getting a builder from your configured platform:

val builder = platform.newNPCBuilder()

Then chain the following methods:

  1. entityId(id: Int) (optional)

    โ€“ Manually set the entity ID. If omitted, Velar generates a random one.

  2. position(position: Position) (required)

    โ€“ Set the NPCโ€™s world position. Use your platform-specific Position object (Velar has Kotlin extensions to help).

  3. profile(profile: Profile.Resolved) (required)

    โ€“ Provide a fully resolved profile (UUID + skin props).

  4. 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.

  5. profile(resolver: ProfileResolver?, profile: Profile): CompletableFuture<Builder<W,P,I,E>>

    โ€“ Use a custom resolver if needed:

    builder.profile(myResolver, Profile.unresolved("CustomNPC"))
  6. 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!")
      }
    }
  7. 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.
  8. Flags (optional, see docs) โ€“ Use .flag(flag, value) or .flags(...).

    Flag Description Default
    LOOK_AT_PLAYER Imitate playerโ€™s head rotation false
    HIT_WHEN_PLAYER_HITS Swing when player hits false
    SNEAK_WHEN_PLAYER_SNEAKS Crouch when player crouches false
    HIDE_NAME_TAG Hide 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

๐Ÿ”ง Manage NPC

Once you have an NPC<W,P,I,E> instance, you can:

Inclusion / Visibility

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 NPC

Tracking

npc.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 player

Packets & Actions

npc.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().

Scheduling Outbound Packets

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 extractor

๐Ÿ”— Examples

Need 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
โš ๏ธ **GitHub.com Fallback** โš ๏ธ