{"id":14969538,"url":"https://github.com/juliarn/npc-lib","last_synced_at":"2025-05-16T04:05:22.862Z","repository":{"id":38792322,"uuid":"239503863","full_name":"juliarn/npc-lib","owner":"juliarn","description":"Asynchronous, high-performance Minecraft NPC library for 1.8-1.21 servers.","archived":false,"fork":false,"pushed_at":"2025-05-05T21:37:40.000Z","size":22610,"stargazers_count":360,"open_issues_count":7,"forks_count":53,"subscribers_count":11,"default_branch":"v3","last_synced_at":"2025-05-05T22:35:01.390Z","etag":null,"topics":["minecraft","minecraft-npc-library","npc","npc-lib","protocollib","spigot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/juliarn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-02-10T12:14:19.000Z","updated_at":"2025-05-05T21:37:43.000Z","dependencies_parsed_at":"2022-07-09T13:30:39.125Z","dependency_job_id":"17e014b5-fc4f-49f2-9fbd-29255960af36","html_url":"https://github.com/juliarn/npc-lib","commit_stats":{"total_commits":110,"total_committers":7,"mean_commits":"15.714285714285714","dds":0.09090909090909094,"last_synced_commit":"c40c623f963fdfcc5932aaae775646c530253d1c"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliarn%2Fnpc-lib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliarn%2Fnpc-lib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliarn%2Fnpc-lib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliarn%2Fnpc-lib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/juliarn","download_url":"https://codeload.github.com/juliarn/npc-lib/tar.gz/refs/heads/v3","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254464895,"owners_count":22075570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["minecraft","minecraft-npc-library","npc","npc-lib","protocollib","spigot"],"created_at":"2024-09-24T13:42:00.627Z","updated_at":"2025-05-16T04:05:17.854Z","avatar_url":"https://github.com/juliarn.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n![GitHub License](https://img.shields.io/github/license/juliarn/npc-lib?logo=github)\n[![Maven Central Version](https://img.shields.io/maven-central/v/io.github.juliarn/npc-lib-api?logo=apachemaven)](https://central.sonatype.com/search?q=io.github.juliarn)\n\n![GitHub forks](https://img.shields.io/github/forks/juliarn/npc-lib)\n![GitHub Repo stars](https://img.shields.io/github/stars/juliarn/npc-lib)\n\n# Minecraft NPC-Lib\n\n#### Simple \u0026 Extendable NPC library for Minecraft Java Edition Servers\n\n\u003c/div\u003e\n\n## Features\n\n- **Bukkit \u0026 Forks** (including Folia) supported via **ProtocolLib** or **PacketEvents**\n- Full **Minestom** \u0026 **Fabric** support (latest version only)\n- **Skin** (Static and Dynamic loading)\n- **Attributes** (Status, Pose, Skin Layers)\n- **Equipment** (Main \u0026 Off-Hand, Armor)\n- **Interaction** (Interact \u0026 Attack)\n- **Action Controller** (Automatic Looking at Player, Player Imitation \u0026 Spawning etc.)\n- **LabyMod Extension** (Sending Emotes \u0026 Sprays)\n- ...\n\nThere are some **[images](#images)** down below showcasing the use and features of this library.\n\n## Installation\n\nAll modules are available in [maven central](https://central.sonatype.com/search?q=io.github.juliarn):\n\n| Module artifact name | Module description                                                                                                                                                                                    |\n|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| npc-lib-api          | General NPC-Lib API without platform specific class usage. This module should be used when the underlying implementation does not matter.                                                             |\n| npc-lib-common       | Abstract implementation of the api module. This module should be used when a new platform implementation is made.                                                                                     |\n| npc-lib-bukkit       | Platform specific implementation for Bukkit. This module implements the complete API (and common) to support Bukkit (and forks).                                                                      |\n| npc-lib-minestom     | Platform specific implementation for Minestom. This module implements the complete API (and common) to support Minestom (and forks).                                                                  |\n| npc-lib-fabric       | Platform specific implementation for Fabric. This module implements the complete API (and common) to support Fabric and [must be installed as a mod](https://modrinth.com/mod/npc-lib) on the server. |\n| npc-lib-labymod      | This module contains helper methods for accessing LabyMod NPC features (such as emotes and stickers). See the [LabyMod documentation](https://dev.labymod.net/) for more information.                 |\n\n### How to include a module\n\nMaven:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eio.github.juliarn\u003c/groupId\u003e\n  \u003cartifactId\u003e(module name from the list above)\u003c/artifactId\u003e\n  \u003cversion\u003e(latest version)\u003c/version\u003e\n  \u003cscope\u003ecompile\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\nGradle:\n\n```kts\nimplementation(\"io.github.juliarn\", \"(module name from the list above)\", \"(latest version)\")\n```\n\n### Repositories\n\nDepending on your setup you might need to add the following repositories as well to download all the transitive\ndependencies coming from the modules:\n\n- `https://repo.papermc.io/repository/maven-public/` (For [PaperLib](https://github.com/PaperMC/PaperLib))\n- `https://repository.derklaro.dev/releases/` (You can also use `https://jitpack.io` instead, used e.g.\n  for [ProtocolLib](https://github.com/dmulloy2/ProtocolLib)).\n- `https://repo.codemc.io/repository/maven-releases/` (For [PacketEvents](https://github.com/retrooper/packetevents))\n- `https://s01.oss.sonatype.org/content/repositories/snapshots/` (For all kinds of snapshot dependencies that don't have\n  a stable release published to maven central yet)\n\n### Shading\nThis library is specifically made in a way that it can be shaded into your plugin jar. Below is a list of packages that\nare used by this library and that you probably want to relocate to prevent dependency issues with other plugins\nincluding the same libraries. You can use the gradle or maven shade plugin to achieve this:\n\n- `net.kyori`\n- `io.papermc.lib`\n- `io.leangen.geantyref`\n- `io.github.retrooper`\n- `com.github.retrooper`\n- `com.github.juliarn.npclib`\n\n## Example Usage\n\nPlatform specific (server software specific) code is only needed to obtain a platform instance. The platform instance\ncan then be used to create NPCs, without knowing which underlying platform is actually used.\n\nUsually all classes you need provide a builder and shouldn't be instantiated directly.\nTo obtain a platform builder use the following:\n\n### On Bukkit\n\n```java\nBukkitPlatform.bukkitNpcPlatformBuilder()\n```\n\n### On Minestom\n\n```java\nMinestomPlatform.minestomNpcPlatformBuilder()\n```\n\n### On Fabric\n\n```java\nFabricPlatform.fabricNpcPlatformBuilder()\n```\n\n## Configuring the Platform\n\nIn all further examples bukkit will be used as a reference, but the api is the same on all other platforms:\n\n```java\nBukkitPlatform.bukkitNpcPlatformBuilder()\n  // enables debug logging in the platform. this mostly enables errors\n  // to be printed into the console directly instead of being held back\n  // to prevent spamming the console.\n  // Defaults to false (debug disabled).\n  .debug()\n  // sets the extension of the platform, which is usually the plugin that\n  // uses the plugin. on bukkit this is for example used to schedule sync\n  // tasks using the bukkit scheduler.\n  // This option has no default and must be set.\n  .extension()\n  // the logger to use for internal logging of the library. while this logger\n  // has the possibility to log info messages, the level won't be used unless\n  // information relevant to the user are being printed.\n  // Defaults to a platform-specific logger instance, on bukkit it uses an\n  // implementation which is backed by the plugin logger.\n  .logger()\n  // the event manager to use for the platform. all events, such as npc interacts\n  // or spawns are propagated using this event manager.\n  // Defaults to an internal default implementation.\n  .eventManager()\n  // the tracker for npcs that are created by this library. as explained below\n  // a spawned npc can either be tracked or kept untracked if not needed.\n  // the tracker is used to store all spawned npcs and automatically execute\n  // actions on them, for example automatic spawning when a player moves into\n  // their spawn distance. it's also used to fire npc events such as interact when\n  // an interact packet is received.\n  // Defaults to an internal default implementation.\n  .npcTracker()\n  // a scheduler for tasks that need to be executed either sync or async. the\n  // implementation depends on the platform, for bukkit it's backed by the bukkit\n  // scheduler, on minestom the minestom scheduler is used.\n  // Defaults to a platform-specific implementation.\n  .taskManager()\n  // the resolver to use for npc profiles. the resolver is given an unresolved\n  // version of a profile (for example only an uuid or name) and completes the\n  // profile data (name, uuid, textures).\n  // see BukkitProfileResolver for the available resolvers on bukkit (paper or spigot)\n  // Defaults to a platform-specific implementation.\n  .profileResolver()\n  // the resolver for worlds of npcs. each npc position contains a world identifier\n  // which is resolved using this resolver. the resolver can also provide the\n  // identifier of a world using the world instance.\n  // see BukkitWorldAccessor for the available resolvers on bukkit (name or key based)\n  // see MinestomWorldAccessor for the available resolver on minestom (uuid based)\n  // Defaults to a platform-specific implementation.\n  .worldAccessor()\n  // the provider for version information about the current platform. it's internally\n  // used to determine which features can be used. an example is the profile resolver:\n  // when on paper 1.12 or later the paper profile resolver is used, when on spigot\n  // 1.18.2 or later the spigot profile resolver is used, else a fallback mojang api\n  // based access is used.\n  // see BukkitVersionAccessor for the bukkit implementations (PaperLib based)\n  // see MinestomVersionAccessor for the minestom implementation\n  // Defaults to a platform-specific implementation.\n  .versionAccessor()\n  // the factory for packets that need to be sent in order to spawn and manage npcs.\n  // see BukkitProtocolAdapter for the available options on Bukkit (ProtocolLib or PacketEvents)\n  // see MinestomProtocolAdapter for the minestom implementation\n  // Defaults to a platform-specific implementation.\n  .packetFactory()\n  // configures the default action controller for the platform. if this method isn't called\n  // during the build process, the default action controller is disabled. the method provides\n  // a builder which can be used to modify the settings of the action controller. if the default\n  // values should be used, don't call any methods and just provide an empty lambda.\n  .actionController(builder -\u003e builder\n    .flag(NpcActionController.SPAWN_DISTANCE, 5))\n  // builds the final platform object which can then be used to spawn and manage npcs\n  .build();\n```\n\n### The action controller\n\nThe standard action controller controls stuff like automatic npc spawning, player imitation and more. The action\ncontroller implementations are controlled by flags which can be dynamically adjusted as needed. Custom flags can also\nbe added to control extra stuff that isn't directly available using the default action controller. The default action\ncontroller flags are the following (all located as constants in the `NpcActionController` class):\n\n| Flag Name                   | Default Value | Description                                                                                                                                                                                           |\n|-----------------------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| AUTO_SYNC_POSITION_ON_SPAWN | true          | Controls if the npc head rotation should automatically be set when the npc is spawned for a player. This only does something when the npc is set up to look at the player.                            |\n| SPAWN_DISTANCE              | 50            | The distance (in blocks) in which the npc will be shown to a player.                                                                                                                                  |\n| TAB_REMOVAL_TICKS           | 30            | The ticks before the player removal packet is sent when spawning an npc. This can be lowered on newer versions (1.19.3+) as the player isn't added to the tablist at all due to new protocol options. |\n| IMITATE_DISTANCE            | 20            | The distance (in blocks) in which the npc will start imitating the player actions.                                                                                                                    |\n\n## Spawning a NPC\n\nThe platform object constructed in the last step contains a method to construct a NPC builder: `newNpcBuilder`. This\nbuilder can be used to customize and spawn a npc:\n\n```java\nplatform.newNpcBuilder()\n  // the id to use for the entity. if not provided a random integer is generated and used instead.\n  .entityId()\n  // the position where the npc should be spawned and located.\n  // this option is required and must be set before spawning the npc.\n  .position()\n  // sets resolved or unresolved profile for the npc. if an unresolved profile is used the method\n  // returns a future completed with the current build when the profile was resolved. a specific\n  // profile resolver to use can be provided as well.\n  .profile()\n  // allows to add additional settings to the npc:\n  //  - a tracking rule to select the players which should be tracked automatically by the npc\n  //  - a profile resolver which can dynamically resolve the npc profile when it gets spawned\n  // if no builder callback is provided default npc settings are applied. this means that the npc will be\n  // spawned to all players in range and the skin (via the profile) provided to this builder will always be used.\n  .npcSettings()\n  // sets a value for a flag on the npc.\n  .flag();\n```\n\nThere are two ways to build a final npc instance: `build` and `buildAndTrack`. The first option only builds a raw NPC\ninstance, leaving the full control to the caller which actions should be executed on the NPC. The second one uses the\nnpc tracker of the base platform to track the npc, allowing the action controller and packet listeners to call actions\nfor the NPC.\n\n### NPC flags\n\nSome action controller related settings can also be done by using the npc flags (provided as constants in `NPC`).\nHowever, flags can also be used to add custom markers or settings to any flagged object, for example to store the base\nconfiguration from which a NPC was created.\n\n| Flag Name                | Default Value | Description                                                                                                                                                            |\n|--------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| LOOK_AT_PLAYER           | false         | Controls if tracked NPCs should automatically look at the player (only has an effect if the action controller is enabled on the platform)                              |\n| HIT_WHEN_PLAYER_HITS     | false         | Controls if tracked NPCs should swing their main hand in case the player swings his main hand (only has an effect if the action controller is enabled on the platform) |\n| SNEAK_WHEN_PLAYER_SNEAKS | false         | Controls if tracked NPCs should sneak when the player sneaks (only has an effect if the action controller is enabled on the platform)                                  |\n\n## Events\n\nThis library provides some events to catch when certain actions are executed. Note that all events shown below are not\nplatform specific. Event listeners must be registered into the event manager provided by the platform and not, for\nexample, into the bukkit event system. Note that event listeners can be called from any thread, there is no guarantee\nthat events happen on a specific thread (such as the main server thread). For example, if you need to access the Bukkit\napi, make sure that you manually execute the corresponding code on the main server thread.\n\n| Event Class Name  | Description                                                                                                                                       |\n|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------|\n| AttackNpcEvent    | Fired when a player hits (attacks) a NPC                                                                                                          |\n| InteractNpcEvent  | Fired when the player interacts with a NPC. Note that due to Minecraft weirdness this event is always called for both player hands at the moment. |\n| ShowNpcEvent.Pre  | Fired before a NPC is spawned for a player. This event can be cancelled to prevent this action.                                                   |\n| ShowNpcEvent.Post | Fired after a NPC was successfully spawned to a player.                                                                                           |\n| HideNpcEvent.Pre  | Fired before a NPC is despawned for a player. This event can be cancelled to prevent this action.                                                 |\n| HideNpcEvent.Post | Fired after a NPC was successfully despawned for a player.                                                                                        |\n\nUnfortunately events cannot be fired typesafe. Therefore, the player instance must be known to the event receiver and\nmust be put into a typed variable to give it a specific type rather than object:\n\n```java\npublic final class AttackEventConsumer implements NpcEventConsumer\u003cAttackNpcEvent\u003e {\n  @Override\n  public void handle(AttackNpcEvent event) {\n    var badPlayer = event.player(); // player type is object as the type couldn't be inferred\n    Player goodPlayer = event.player(); // player type is Player, but it must be known at compile time\n  }\n}\n```\n\n## Code Examples\n\n#### Minimal Example\nThe following code is a minimal example how a platform object is created and an NPC is spawned. In this example the\ndefault action controller is enabled which means that after spawning the npc using `buildAndTrack` the npc will\nautomatically be spawned and shown to players in a 50 block range:\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  private final Platform\u003cWorld, Player, ItemStack, Plugin\u003e platform = BukkitPlatform\n    .bukkitNpcPlatformBuilder()\n    .extension(this)\n    .actionController(builder -\u003e {}) // enable action controller without changing the default config\n    .build();\n\n  public void spawnNpc(Location location) {\n    this.platform.newNpcBuilder()\n      .position(BukkitPlatformUtil.positionFromBukkitLegacy(location))\n      .profile(Profile.unresolved(\"derklaro\"))\n      .thenAccept(builder -\u003e {\n        var npc = builder.buildAndTrack();\n        // continue using the npc...\n        npc.unlink(); // when the npc is no longer needed it can be completely removed using this method\n      });\n  }\n}\n```\n\n#### Configuring the action controller\nAs mentioned above the action controller can be changed using flags. In this example the action controller of the\nplatform is configured in a way that NPCs are shown to players being 100 blocks away and simulation already starts when\nthe player is 50 block away:\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  private final Platform\u003cWorld, Player, ItemStack, Plugin\u003e platform = BukkitPlatform\n    .bukkitNpcPlatformBuilder()\n    .extension(this)\n    .actionController(builder -\u003e builder\n      .flag(NpcActionController.SPAWN_DISTANCE, 100)\n      .flag(NpcActionController.IMITATE_DISTANCE, 50))\n    .build();\n}\n```\n\n#### Explicitly setting the protocol adapter and world resolver\nSometimes it's crucial that specific stuff is always setup the same, which isn't the case for some settings. In this\nexample the protocol adapter will be set to always use PacketEvents (rather than preferring ProtocolLib when available\non the server) and the world resolver will always use the world name (instead of using the world key in modern versions\non paper):\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  private final Platform\u003cWorld, Player, ItemStack, Plugin\u003e platform = BukkitPlatform\n    .bukkitNpcPlatformBuilder()\n    .extension(this)\n    .packetFactory(BukkitProtocolAdapter.packetEvents())\n    .worldAccessor(BukkitWorldAccessor.nameBasedAccessor())\n    .build();\n}\n```\n\n#### Using the NPC settings to use player skins and only track specific players\nIn this example the spawned NPC is configured to use the skin of the player it is being spawned to, as well as only\nbeing spawned to players that have reached an exp count of 50 or higher:\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  public void spawnNpc(Location location) {\n    this.platform.newNpcBuilder()\n      .position(BukkitPlatformUtil.positionFromBukkitLegacy(location))\n      .npcSettings(builder -\u003e builder\n        .profileResolver((player, npc) -\u003e {\n          // copy the profile properties into the profile of the npc to preserve the name\n          // and uuid of the npc and not use the player name / uuid instead.\n          var playerProfile = Profile.unresolved(player.getUniqueId());\n          return this.platform.profileResolver()\n            .resolveProfile(playerProfile)\n            .thenApply(profile -\u003e npc.profile().withProperties(profile.properties()));\n        })\n        .trackingRule((npc, player) -\u003e player.getExp() \u003e= 50))\n      .profile(Profile.unresolved(\"derklaro\"))\n      .thenAccept(builder -\u003e {\n        var npc = builder.buildAndTrack();\n        // continue using the npc...\n      });\n  }\n}\n```\n\n#### Adding a custom flag to a NPC\nCustom flags can be quite helpful when spawning a NPC, for example if the NPC was spawned based off a configuration: a\nflag can be used to keep the original configuration entry around, for example to easily allow modification or to resolve\nadditional settings on an NPC interact:\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  private static final NpcFlag\u003cNpcEntry\u003e CONFIG_ENTRY_FLAG = NpcFlag.flag(\"npc_config_entry\", null);\n\n  public void spawnNpc(NpcEntry configEntry) {\n    this.platform.newNpcBuilder()\n      .flag(CONFIG_ENTRY_FLAG, configEntry)\n      .position(BukkitPlatformUtil.positionFromBukkitLegacy(configEntry.location()))\n      .profile(Profile.unresolved(configEntry.profileName()))\n      .thenAccept(builder -\u003e {\n        var npc = builder.buildAndTrack();\n        var configEntry = npc.flagValue(CONFIG_ENTRY_FLAG).orElseThrow();\n        // continue using the npc...\n      });\n  }\n}\n```\n\n#### Customizing the imitation actions of the NPC\nBy default, a NPC will not imitate any actions the players and will not look at the player. In this example the flags\nwill be set to enable that behaviour: the NPC will look at the player and imitate if the player hits or sneaks:\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  public void spawnNpc(Location location) {\n    this.platform.newNpcBuilder()\n      .flag(Npc.LOOK_AT_PLAYER, true) // look at the player\n      .flag(Npc.HIT_WHEN_PLAYER_HITS, true) // swing main hand when the player does so\n      .flag(Npc.SNEAK_WHEN_PLAYER_SNEAKS, true) // sneak when the player does so\n      .position(BukkitPlatformUtil.positionFromBukkitLegacy(location))\n      .profile(Profile.unresolved(\"derklaro\"))\n      .thenAccept(builder -\u003e {\n        var npc = builder.buildAndTrack();\n        // continue using the npc...\n      });\n  }\n}\n```\n\n#### Handling interactions with a NPC\nWhen a NPC is tracked when being spawned the protocol will catch interacts with it and fire a corresponding lib event\ndepending on the action that was taken. When being attacked (usually triggered by a left click) a `AttackNpcEvent` event\nis fired, when being interacted with (usually triggered by a right click) a `InteractNpcEvent` event is set off:\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  private final Platform\u003cWorld, Player, ItemStack, Plugin\u003e platform = BukkitPlatform\n    .bukkitNpcPlatformBuilder()\n    .extension(this)\n    .actionController(builder -\u003e {}) // enable action controller without changing the default config\n    .build();\n\n  public void registerNpcListeners() {\n    var eventManager = this.platform.eventManager();\n    eventManager.registerEventHandler(AttackNpcEvent.class, attackEvent -\u003e {\n      var npc = attackEvent.npc();\n      Player player = attackEvent.player();\n      player.sendMessage(\"You attacked NPC \" + npc.profile().name() + \"! That's not nice!\");\n    });\n    eventManager.registerEventHandler(InteractNpcEvent.class, interactEvent -\u003e {\n      var npc = interactEvent.npc();\n      Player player = interactEvent.player();\n      player.sendMessage(\"[\" + npc.profile().name() + \"]: Move along citizen!\");\n    });\n  }\n}\n```\n\n#### Enabling skin layers \u0026 changing the entity status\nSome Minecraft functionalities are controlled by metadata. This includes for example sneaking, skin layers or the\nentity status. Note: in the example shown below the entity status will be reset when the npc meta of sneaking is\nupdated. Therefore, the auto sneaking action is basically exclusive with the entity status settings:\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  private final Platform\u003cWorld, Player, ItemStack, Plugin\u003e platform = BukkitPlatform\n    .bukkitNpcPlatformBuilder()\n    .extension(this)\n    .actionController(builder -\u003e {}) // enable action controller without changing the default config\n    .build();\n\n  public void registerNpcListeners() {\n    var eventManager = this.platform.eventManager();\n    eventManager.registerEventHandler(ShowNpcEvent.Post.class, showEvent -\u003e {\n      var npc = showEvent.npc();\n      Player player = showEvent.player();\n\n      // enable all skin players\n      npc.changeMetadata(EntityMetadataFactory.skinLayerMetaFactory(), true).schedule(player);\n\n      // set the npc on fire\n      // note: the glowing entity status must be sent in order for the entity to appear glowing. The logic of adding\n      // the npc into a team and setting the glowing color must be handled by your plugin.\n      var entityStatus = EnumSet.of(EntityStatus.ON_FIRE);\n      npc.changeMetadata(EntityMetadataFactory.entityStatusMetaFactory(), entityStatus).schedule(player);\n    });\n  }\n}\n```\n\n#### Adding items into the inventory of a npc\nYou can add items into the main hand, off hand \u0026 armor inventory item slots of a NPC:\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  private final Platform\u003cWorld, Player, ItemStack, Plugin\u003e platform = BukkitPlatform\n    .bukkitNpcPlatformBuilder()\n    .extension(this)\n    .actionController(builder -\u003e {}) // enable action controller without changing the default config\n    .build();\n\n  public void registerNpcListeners() {\n    var eventManager = this.platform.eventManager();\n    eventManager.registerEventHandler(ShowNpcEvent.Post.class, showEvent -\u003e {\n      var npc = showEvent.npc();\n      Player player = showEvent.player();\n\n      // puts a dragon egg into the main hand of the npc\n      var dragonEggItem = new ItemStack(Material.DRAGON_EGG);\n      npc.changeItem(ItemSlot.MAIN_HAND, dragonEggItem).schedule(player);\n    });\n  }\n}\n```\n\n#### Additional protocol-related methods in NPC\nThe NPC class contains a lot of utility methods to work with a NPC, some of them were shown already. This collection\nhere shows some additional useful methods that can be used when working with the NPC. Note that all constructed packets\nbelow are only sent to one specific player. If you want other players to see the change as well you can either provide\na list of players to send the change to or schedule it for all players that are tracked by the NPC (only works when the\naction controller is enabled in the platform):\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  private final Platform\u003cWorld, Player, ItemStack, Plugin\u003e platform = BukkitPlatform\n    .bukkitNpcPlatformBuilder()\n    .extension(this)\n    .actionController(builder -\u003e {}) // enable action controller without changing the default config\n    .build();\n\n  public void registerNpcListeners() {\n    var eventManager = this.platform.eventManager();\n    eventManager.registerEventHandler(ShowNpcEvent.Post.class, showEvent -\u003e {\n      var npc = showEvent.npc();\n      Player player = showEvent.player();\n\n      // let the NPC look into the direction of 0, 50, 0\n      var spawnLocation = Position.position(0, 50, 0, npc.position().worldId());\n      npc.lookAt(spawnLocation).schedule(player);\n\n      // lets the NPC swing his main arm\n      npc.playAnimation(EntityAnimation.SWING_MAIN_ARM).schedule(player);\n\n      // sets the player head rotation to yaw=0 \u0026 pitch=90 \n      npc.rotate(0, 90).schedule(player);\n    });\n  }\n}\n```\n\n#### Manually (de-) spawning a NPC\nSometimes you don't want to leave the job of automatically (de-) spawning a npc to the action controller. In these cases\nyou need to track and untrack the players manually from a NPC:\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  public void spawnNpcToPlayer(Npc\u003cWorld, Player, ItemStack, Plugin\u003e npc, Player player) {\n    // use this method if you want to spawn the npc to the player, but only if all preconditions\n    // (such as the player tracking rule) are met. You can manually check if a player would be\n    // tracked by a npc by calling: `npc.shouldIncludePlayer(player)`.\n    npc.trackPlayer(player);\n\n    // Use this method if you want to spawn the npc to the player even is preconditions aren't met.\n    // Note: this still calls the ShowNpc.Pre event which can still be cancelled by one of your event\n    // listeners causing the npc to not get spawned for the player.\n    npc.forceTrackPlayer(player);\n  }\n\n  public void removeNpcForPlayer(Npc\u003cWorld, Player, ItemStack, Plugin\u003e npc, Player player) {\n    // despawns the npc for the given player unless the npc is not spawned for the player. you can always\n    // check the players for which a NPC is spawned by calling `npc.trackedPlayers()` or check for a\n    // specific player by using `npc.tracksPlayer(player)`.\n    // Note: this method calls the HideNpcEvent.Pre event which means that an event listener can\n    // prevent the npc despawn process from being executed.\n    npc.stopTrackingPlayer(player);\n  }\n}\n```\n\n#### Letting the NPC do a LabyMod emote\nUsing the LabyMod extension module, packets can be constructed to make the players do LabyMod emotes and Sprays. Note\nthat NPCs must be spawned with their second uuid half being zeroed to use this feature. The factory only supports\nLabyMod version 4 (neo). A detailed explanation of the mentioned limitation and a list of available emotes can be found\nin the [LabyMod Developer Documentation](https://dev.labymod.net/pages/server/labymod/features/emotes):\n\n```java\npublic final class TestPlugin extends JavaPlugin {\n  public void playLabyModEmoteForPlayer(Npc\u003cWorld, Player, ItemStack, Plugin\u003e npc, Player player, int... emoteIds) {\n    LabyModExtension.createEmotePacket(npc.platform().packetFactory(), emoteIds).schedule(player, npc);\n  }\n}\n```\n\n## Compiling from source\n\nFollow these steps to build and publish the library to your local maven repository:\n\n```shell\ngit clone https://github.com/juliarn/npc-lib.git\ncd npc-lib\ngradlew publishToMavenLocal\n```\n\n## Images\n\n![S1](https://raw.githubusercontent.com/juliarn/npc-lib/v3/.img/trials_chamber.png)\n\n![S2](https://raw.githubusercontent.com/juliarn/npc-lib/v3/.img/cave_explorer.png)\n\n![S3](https://raw.githubusercontent.com/juliarn/npc-lib/v3/.img/portal_warden.png)\n\n![S4](https://raw.githubusercontent.com/juliarn/npc-lib/v3/.img/dragon_fight.png)\n\n![S5](https://raw.githubusercontent.com/juliarn/npc-lib/v3/.img/bastion.png)\n\nFeel free to open a pull request to add your image to this list.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliarn%2Fnpc-lib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjuliarn%2Fnpc-lib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliarn%2Fnpc-lib/lists"}