Skip to content

Repository files navigation

AddonBridge

Run Minecraft Bedrock addons (.mcaddon / .mcpack) on a PowerNukkitX server. Drop the files in, restart, and everything is live: items, blocks, entities, recipes, loot tables, spawn rules, AI, creative menu groups, the resource pack served to players, and the @minecraft/server scripts, actually executed by an embedded JavaScript engine.

No conversion, no manual BP/RP splitting, no code to write.

Usage

plugins/AddonBridge/addons/
|- Rustic Furniture.mcaddon
|- Free Fire Gun 1.9.mcaddon
`- The Lost Age.mcaddon
  1. Put the jar into plugins/.
  2. Start once (this creates plugins/AddonBridge/addons/ and config.yml).
  3. Drop your .mcaddon files in there.
  4. Restart.

AddonBridge accepts .mcaddon, .mcpack, .zip and already extracted folders, including nested ones: a .mcaddon containing two .mcpack files is handled on its own. Archives are extracted into plugins/AddonBridge/cache/ and only re-extracted when their content changes, so later restarts are immediate.

On startup:

[AddonBridge]: Addons detected: 14 packs (7 BP, 7 RP).
[AddonBridge]: Load finished in 3 s: 10232 items, 420 blocks, 29 entities,
               10126 recipes, 11 loot tables, 16 spawn rules,
               40 creative groups, 7 resource packs.
[AddonBridge]: Scripts active: 5 modules, 10 custom components.

Command

/addons (alias /addonbridge), permission addonbridge.command (op):

Command Effect
/addons list List the loaded addons and their packs (BP / RP)
/addons status Counters from the last load
/addons scripts JS engine state plus any missing @minecraft/server API reached
/addons info <name> Details for one addon: version, uuid, scripts
/addons check Cross checks the behavior packs against the resource packs: item icons, geometries, armor attachables, texture files, client entity definitions. Add all to also list the block textures that come from vanilla rather than from an addon pack

/addons check exists because nothing in this pipeline fails loudly when a resource pack is incomplete: a missing icon key just renders as the purple and black checkerboard, an armor with no attachables/ entry equips but shows nothing on the player, and an entity with no entity/**.json client definition spawns invisible. The command names every one of them.

What gets loaded

Behavior pack content Status
items/**.json Full items: icon, name, durability, damage, armor, enchantability, digger, food, fuel, block placer, shooter/throwable, cooldown, tags, repairable, render offsets, mining speed
items with minecraft:wearable Real armor: the slot is inferred from the enchant slot when it is missing, minecraft:armor merges into the protection value, and /addons check tells you whether the matching attachable exists
items with minecraft:digger destroy_speeds evaluated like the client, Molang conditions included ("1", q.any_tag(...), &&, `
blocks/**.json Full blocks: geometry, material instances, collision and selection boxes (a list of boxes becomes their union instead of a full cube), integer and string states, permutations, tags, hardness, light, friction, map color
blocks with the minecraft:placement_direction trait The block faces the player who places it
entities/**.json Entities: health, collision box, speed, attack, families, physics, spawn egg, /summon, plus rideable seats, saddle, ride controls, horse jump strength, tameable, ageable, breedable, healable, home, inventory, equippable, boostable, item controllable
entities component_groups and events Applied at runtime: add / remove, sequence, weighted randomize, trigger chains, run_command, and the common filters. The active groups are saved with the entity
entities with minecraft:rideable Interacting mounts the player on the declared seat, whether the component sits in the base components or in a group an event turns on later
entities with minecraft:interact Right clicking with the declared item fires the event, plays the sound and consumes the item
entities with minecraft:timer, spawn_entity, despawn, damage_sensor, experience_reward Ticked at runtime: countdowns fire their event, spawners produce their entity, damage immunity is honoured
entities with minecraft:behavior.* AI translated into PowerNukkitX behaviors, with the route finder and controllers chosen from minecraft:navigation.* / minecraft:movement.*, so a flying or swimming mob no longer walks a ground path. Covers roaming, melee and ranged attack, targeting by family, retaliation, fleeing, panic, tempt, breeding, following, looking, hovering
loot_tables/**.json Block and entity drops: pools, rolls, weights, set_count, set_damage, set_data, enchant_randomly, looting_enchant, specific_enchants, and the killed_by_player, random_chance, match_tool conditions
spawn_rules/**.json Natural spawning: surface, underground, underwater, brightness, height, biome, density, herd size, weight
recipes/**.json recipe_shaped, recipe_shapeless, recipe_furnace
item_catalog/**.json Custom creative menu groups
scripts/**.js Executed, see the next section
Resource pack Zipped and served to players, flagged as an addon pack

Components PowerNukkitX does not model yet are forwarded as is to the client (passthrough-unknown-components), so rendering stays correct even for recent components.

The @minecraft/server scripts

PowerNukkitX has no JavaScript engine, so AddonBridge embeds one: GraalJS, full ES2023 including ES modules, classes, async/await, optional chaining and private fields. Scripts run on the main thread, like on Bedrock, and are loaded once the worlds are ready.

The implemented API covers the core of @minecraft/server:

Area Implemented
world getDimension, getAllPlayers, getEntity, sendMessage, getAbsoluteTime, getTimeOfDay/setTimeOfDay, getDay, dynamic properties, beforeEvents/afterEvents, scoreboard (read)
system run, runTimeout, runInterval, runJob (generators, sliced per tick), clearRun, currentTick, waitTicks, beforeEvents.startup
Dimension getBlock, getTopmostBlock, setBlockType, setBlockPermutation, spawnEntity, spawnItem, getEntities/getPlayers with the full filter set (type, families, tags, their exclude* counterparts, minDistance/maxDistance, closest/farthest), runCommand(Async), createExplosion, playSound
Entity / Player Position, rotation, velocity, teleport, getComponent, getComponents, triggerEvent, effects, tags, applyDamage, kill, runCommand, dynamic properties, nameTag, onScreenDisplay, game mode, XP, getBlockFromViewDirection, playSound, playMusic
Block typeId, permutation, setType, setPermutation, above/below/north/offset, getComponent("inventory"), tags
BlockPermutation resolve, getState, withState, getAllStates, matches, clone, getItemStack
ItemStack Constructor, typeId, amount, nameTag, getLore/setLore, clone, getComponent
Components health, inventory with Container and ContainerSlot, equippable, movement, durability, rideable (getRiders, addRider, ejectRider(s), seats), type_family, variant, mark_variant, scale, tameable, is_baby, onfire, leashable
Events playerSpawn, playerJoin, playerLeave, playerBreakBlock, playerPlaceBlock, playerInteractWithBlock, playerInteractWithEntity, itemUse, entityHurt, entityHitEntity, entityDie, entitySpawn, projectileHitBlock, projectileHitEntity, scriptEventReceive, chatSend. The beforeEvents variants are cancellable
Custom components blockComponentRegistry and itemComponentRegistry: onPlayerInteract, onPlace, onPlayerDestroy / onBreak, onStepOn, onStepOff, onEntityFallOn, onTick, onRandomTick, onUse, onUseOn, onMineBlock, onHitEntity
Sounds playSound on world, Dimension and Player sends the name straight to the client, so a sound declared in the addon sound_definitions.json plays like any vanilla one
@minecraft/server-ui ActionFormData, MessageFormData, ModalFormData mapped onto PowerNukkitX forms

The API is not exhaustive. When a script reaches an unimplemented method, AddonBridge names it in the console on startup and through /addons scripts, instead of failing silently. That is how you find out exactly what is left to add for a given addon.

What is not loaded

  • trading/, dialogue/, server side animation_controllers.
  • Molang beyond what the digger conditions and entity filters need: no full expression engine, so a permutations condition still reaches the client as written rather than being evaluated server side.
  • minecraft:transformation, minecraft:environment_sensor and minecraft:boss are read but not acted on.
  • Vanilla entity overrides (minecraft:zombie and friends) are ignored.
  • An obfuscated addon loads and runs, but resolves API names dynamically, which is where /addons scripts helps most.

An item whose identifier already belongs to a block of the same addon is skipped: that is the block item, already created when the block was registered.

Configuration

plugins/AddonBridge/config.yml:

Key Default Effect
enabled true Turn the plugin off entirely
addons-folder addons Scanned folder, relative to the plugin folder
serve-resource-packs true Send addon resource packs to players
creative-menu true Add content to the creative menu, see below
register-items / -blocks / -entities / -recipes / -creative-groups true Enable each content type
register-loot-tables true Drops driven by the addon loot tables
register-entity-ai true Translate minecraft:behavior.* into PowerNukkitX AI
run-scripts true Execute the @minecraft/server scripts
passthrough-unknown-components true Forward unmodelled components to the client
apply-placement-traits true Face blocks towards the player placing them
force-reextract false Re-extract archives on every startup
disabled [] File or folder names to ignore, without extension
log-level normal quiet, normal or verbose

Creative menu grouping

creative-group-per-addon (on by default) gives each addon its own creative groups. A pack with thousands of tools declares the vanilla group names (itemGroup.name.pickaxe and friends), so its 1021 pickaxes land inside the vanilla pickaxe group and your iron pickaxe disappears among them. With the option on, that pack gets a Blocks Armor Tools Pickaxe group of its own and the vanilla groups stay clean. A pack shipping its own item_catalog already declares real groups and is left alone.

Creative menu ordering

Addon items and blocks are registered sorted by creative category and group. PowerNukkitX appends every custom entry to the end of the creative list while tagging it with its own group index, and a Bedrock client only draws a group as a group when its entries are next to each other. Registering pack by pack therefore produced one axe, then one helmet, then one pickaxe, and so on: a large addon turned the creative menu into an unsorted wall. Sorting first keeps each group in one block.

creative-menu and very large addons

PowerNukkitX rescans the entire creative menu on every item added, which makes filling it quadratic. Measured on this server with the same addons:

Content creative-menu: true creative-menu: false
6 addons, 442 items and blocks 1 s 1 s
Plus one addon with 10232 items 279 s 3 s

The true default is right in almost every case. Switching to false removes nothing: content stays placeable, craftable and obtainable with /give, it just no longer shows up in the creative tab, and custom creative groups are skipped since they would be empty. AddonBridge prints the hint on its own past 3000 entries.

How it works

During onLoad, before PowerNukkitX freezes its registries, the plugin:

  1. Extracts archives into cache/extracted/ with a SHA-256 fingerprint, zip slip protection and the same GBK encoding fallback PowerNukkitX uses.
  2. Finds every manifest.json and classifies the pack as BP or RP.
  3. Translates each JSON into a CustomItemDefinition, CustomBlockDefinition or CustomEntityDefinition.
  4. Generates one Java class per identifier at runtime with ASM and MethodHandles.Lookup.defineClass, because the PowerNukkitX registries register by class and not by instance. That includes real Java enums for string block states.
  5. Re-zips each resource pack into cache/resourcepacks/ and adds it to the ResourcePackManager through a dedicated loader.

Then, once the worlds are loaded (POSTWORLD), it starts the GraalJS context, publishes @minecraft/server as a virtual ES module backed by a Java bridge, evaluates each pack script entry, emits system.beforeEvents.startup and hooks its scheduler onto the server tick.

ASM comes from the server jar. GraalJS is bundled into the plugin jar, around 35 MB, which makes it self contained on a standard JDK 21.

Build

./build.sh
./build.sh --deploy

The PowerNukkitX jar is a compileOnly dependency: the local dev server one by default, otherwise LINESIA_PNX_JAR=/path/to/powernukkitx.jar.

About

Run Minecraft Bedrock addons on PowerNukkitX: blocks, items, entities, loot tables, spawn rules, AI and @minecraft/server scripts

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages