NPC-Lib Documentation

repository·v3·Indexed 18 days ago

https://github.com/juliarn/npc-lib

A simple and extendable library for managing NPCs in Minecraft Java Edition servers. It provides a platform-agnostic API compatible with Bukkit (including Folia), Minestom, and Fabric. The library includes modular implementations (npc-lib-bukkit, npc-lib-minestom, npc-lib-fabric), an action controller for automatic behaviors like spawning and player imitation, and a platform-agnostic event system for handling NPC interactions such as AttackNpcEvent and InteractNpcEvent.

Tokens
6.2K
Snippets
21
Records
23
Agent score
14%

What's inside NPC-Lib

  1. Initialize the NPC Platform

    v3

    To use NPC-Lib, you must first obtain a platform instance using a platform-specific builder. Once you have the platform instance, you can create and manage NPCs without needing to know the underlying implementation details.

    Platform Builders

    • Bukkit: BukkitPlatform.bukkitNpcPlatformBuilder()
    • Minestom: MinestomPlatform.minestomNpcPlatformBuilder()
    • Fabric: FabricPlatform.fabricNpcPlatformBuilder()
    // Example: Initializing a Bukkit platform
    var platform = BukkitPlatform.bukkitNpcPlatformBuilder()
      .extension(myPluginInstance) // Required: set the plugin/extension instance
      .build();
  2. Handle NPC events

    v3

    The library provides platform-agnostic events to react to NPC interactions.

    Important Implementation Details:

    • Registration: You must register listeners with the event manager provided by the platform, not the underlying server's event system (e.g., Bukkit).
    • Threading: Event listeners can be called from any thread. There is no guarantee of being on the main server thread. If you need to access platform-specific APIs (like Bukkit), you must manually schedule that code to run on the main server thread.
    • Type Safety: Because events are not type-safe regarding the player, you must explicitly cast the player object to your desired type (e.g., Player) within your handler.
    public final class AttackEventConsumer implements NpcEventConsumer<AttackNpcEvent> {
      @Override
      public void handle(AttackNpcEvent event) {
        // event.player() returns Object; cast it to your specific Player type
        Player goodPlayer = (Player) event.player(); 
      }
    }
  3. Configure required repositories for NPC-Lib

    v3

    To resolve transitive dependencies (like ProtocolLib or PacketEvents), you may need to add the following repositories to your build configuration:

    • https://repository.derklaro.dev/releases/ (or https://jitpack.io for ProtocolLib)
    • https://repo.codemc.io/repository/maven-releases/ (for PacketEvents)
  4. Spawn an NPC using the NPC Builder

    v3

    To spawn an NPC, use the newNpcBuilder() method provided by your platform instance. The builder allows you to configure the entity's identity, position, and profile.

    Required Configuration:

    • .position(): The location where the NPC should be spawned. This must be set before spawning.

    Optional Configuration:

    • .entityId(): The unique ID for the entity. If omitted, a random integer is generated.
    • .profile(): Sets the NPC's skin/profile. If an unresolved profile is used, the method returns a future that completes when the profile is resolved.
    • .npcSettings(): Configures tracking rules (which players see the NPC) and profile resolvers.
    • .flag(): Sets specific flags on the NPC (see NPC Flags).

    Building the NPC: There are two ways to finalize the build:

    1. build(): Returns a raw NPC instance. You are responsible for all subsequent actions and tracking.
    2. buildAndTrack(): Builds the NPC and registers it with the platform's NPC tracker. This enables the action controller and packet listeners to function for this NPC.
    platform.newNpcBuilder()
      .entityId(12345)
      .position(location)
      .profile(profile)
      .buildAndTrack();
  5. Install NPC-Lib modules

    v3

    NPC-Lib is modular. You should primarily use npc-lib-api to keep your code platform-agnostic. Choose a platform-specific implementation module based on your server software (Bukkit, Minestom, or Fabric).

    Available Modules

    ModuleDescription
    npc-lib-apiGeneral API without platform-specific usage. Recommended for most use cases.
    npc-lib-commonAbstract implementation used for creating new platforms.
    npc-lib-bukkitImplementation for Bukkit and its forks (including Folia).
    npc-lib-minestomImplementation for Minestom and its forks.
    npc-lib-fabricImplementation for Fabric. Must be installed as a mod on the server.
    npc-lib-labymodHelpers for LabyMod features like emotes and stickers.

    Maven Configuration

    <dependency>
      <groupId>io.github.juliarn</groupId>
      <artifactId>(module name from the list above)</artifactId>
      <version>(latest version)</version>
      <scope>compile</scope>
    </dependency>

    Gradle Configuration

    implementation("io.github.juliarn", "(module name from the list above)", "(latest version)")
    <!-- Example Maven dependency for the API -->
    <dependency>
      <groupId>io.github.juliarn</groupId>
      <artifactId>npc-lib-api</artifactId>
      <version>3.0.0-beta9</version>
      <scope>compile</scope>
    </dependency>
  6. Shade and relocate NPC-Lib packages

    v3

    If you are shading NPC-Lib into your plugin JAR, it is highly recommended to relocate the following packages to prevent dependency conflicts with other plugins:

    • net.kyori
    • io.leangen.geantyref
    • io.github.retrooper
    • com.github.retrooper
    • com.github.juliarn.npclib
  7. Compile npc-lib from source

    v3

    To build the library and publish it to your local Maven repository, clone the repository and use the Gradle wrapper to run the publishToMavenLocal task.

    git clone https://github.com/juliarn/npc-lib.git
    cd npc-lib
    gradlew publishToMavenLocal
  8. Configure the NpcActionController

    v3

    The actionController manages when NPCs are spawned and simulated for players based on distance. You can configure these distances using flags during platform construction.

    Available flags:

    • NpcActionController.SPAWN_DISTANCE: The distance at which the NPC is spawned for a player.
    • NpcActionController.IMITATE_DISTANCE: The distance at which the NPC starts imitating player actions.
    private final Platform<World, Player, ItemStack, Plugin> platform = BukkitPlatform
      .bukkitNpcPlatformBuilder()
      .extension(this)
      .actionController(builder -> builder
        .flag(NpcActionController.SPAWN_DISTANCE, 100)
        .flag(NpcActionController.IMITATE_DISTANCE, 50))
      .build();
  9. Spawn an NPC using the Platform API

    v3

    To spawn an NPC, use the Platform instance to create a new NPC builder. You must specify a position and a profile. Using buildAndTrack() will spawn the NPC and automatically handle visibility for players within the configured range (default is 50 blocks if the action controller is enabled). Use npc.unlink() to completely remove the NPC when it is no longer needed.

    public final class TestPlugin extends JavaPlugin {
      private final Platform<World, Player, ItemStack, Plugin> platform = BukkitPlatform
        .bukkitNpcPlatformBuilder()
        .extension(this)
        .actionController(builder -> {}) // enable action controller
        .build();
    
      public void spawnNpc(Location location) {
        this.platform.newNpcBuilder()
          .position(BukkitPlatformUtil.positionFromBukkitLegacy(location))
          .profile(Profile.unresolved("derklaro"))
          .thenAccept(builder -> {
            var npc = builder.buildAndTrack();
            // continue using the npc...
            npc.unlink(); // remove the npc
          });
      }
    }
  10. Configure the NPC Platform builder

    v3

    The platform builder allows you to customize how the library interacts with your server software. While many options have defaults, some are critical.

    Key Configuration Methods

    MethodDescription
    .debug()Enables debug logging (prints errors directly to console). Defaults to false.
    .extension(T extension)Required. Sets the extension (e.g., your Bukkit plugin) used for scheduling tasks.
    .logger()Sets the logger for internal library logging. Defaults to a platform-specific logger.
    .eventManager()Sets the manager for propagating NPC events (interact, spawn, etc.).
    .npcTracker()Sets the tracker for managing spawned NPCs and automatic actions.
    .taskManager()Sets the scheduler for sync/async tasks.
    .profileResolver()Sets the resolver for NPC profiles (UUID/Name to textures/data).
    .worldAccessor()Sets the resolver for NPC world identifiers.
    .versionAccessor()Sets the provider for platform version information.
    .packetFactory()Sets the factory for sending spawn/management packets.
    .actionController(Consumer<Builder> builder)Configures the default NpcActionController. If not called, the default controller is disabled.
    .build()Finalizes the configuration and returns the platform instance.
    BukkitPlatform.bukkitNpcPlatformBuilder()
      .debug()
      .extension(myPlugin)
      .logger(myLogger)
      .actionController(builder -> builder
        .flag(NpcActionController.SPAWN_DISTANCE, 5))
      .build();
  11. Change NPC items and inventory slots

    v3

    Use changeItem to add or modify items in an NPC's inventory. Supported slots include ItemSlot.MAIN_HAND, ItemSlot.OFF_HAND, and various armor slots.

    eventManager.registerEventHandler(ShowNpcEvent.Post.class, showEvent -> {
      var npc = showEvent.npc();
      var player = showEvent.player();
    
      var dragonEggItem = new ItemStack(Material.DRAGON_EGG);
      npc.changeItem(ItemSlot.MAIN_HAND, dragonEggItem).schedule(player);
    });
  12. Explicitly set Protocol Adapter and World Resolver

    v3

    You can override default platform behaviors by explicitly setting the packet factory and world accessor during platform construction. This is useful for ensuring consistent behavior (e.g., always using PacketEvents instead of ProtocolLib, or using name-based world resolution).

    private final Platform<World, Player, ItemStack, Plugin> platform = BukkitPlatform
      .bukkitNpcPlatformBuilder()
      .extension(this)
      .packetFactory(BukkitProtocolAdapter.packetEvents())
      .worldAccessor(BukkitWorldAccessor.nameBasedAccessor())
      .build();