Changelog¶
Every AkumaLib release for Minecraft 1.20.1, newest first, as published on CurseForge.
2.5.0¶
Released 2026-09-24 · Download
Two large groups of additions since 2.4.0: professions (workstations, catchable creatures, traps, gathering) — the systems behind Cruise Cruise no Mi — and worldgen and dimensions (a cell grid, the overworld read from another dimension, travel between dimensions, the worldgen and fluid registers) — the ones behind Mine Mine no Mi: Sky Island. Both are written for every addon.
No signature was removed or changed: an addon built against 2.4.0 keeps compiling and keeps working. That is why this is a minor bump.
Requires Minecraft 1.20.1, Forge 47+ and Mine Mine no Mi 0.11.5. JEI and EMI are optional.
⚠️ The network protocol moves from 2 to 3: a client and a server must both run 2.5.0, or the connection is refused. Update both sides together.
New
Professions
- Framework: a profession registry (
AkumaProfessionRegistry), per-player XP and levels (AkumaProfessions, theProfessionDatacapability), level curves in data (data/<ns>/professions/*.json:base_xp × L^exponent), synced to the client. Events:ProfessionXpEvent,ProfessionLevelUpEvent,ProfessionChangeEvent. - Modes (
akumalib-server.toml,professionMode): Solo (every profession), Crew (one chosen profession per player; changing it resets everything), Auto (Solo in singleplayer and LAN, Crew on a dedicated server)./professioncommand (choose, mode, reset, get, set, addxp). - Professions screen (K, and a plank on Mine Mine no Mi's character screen): levels and XP; in Crew mode only the chosen profession, or the list with Choose buttons before any choice.
- Profession pages: the screen wears Mine Mine no Mi's parchment and planks; clicking a profession opens its page in the base mod's book: level, perks (
Profession.withPerk) and unlocks by level (ProfessionUnlocks: workstation recipes, profession-only seeds and blocks by their minimum level, and addon providers; synced from the server). - Mine Mine no Mi's character creator: in Crew mode, a fourth tab "Profession" (a client mixin): the arrows cycle the professions and Random, Finish applies the choice.
- Icons: an item (
withIcon) or a dedicated texture of any size (withIconTexture), shown in the screen and in the creator tab. - XP boosts:
ProfessionXpBoostEffect, and exclusive effect groups (AkumaEffectGroups: one effect of a group at a time).
Workstations
WorkstationBlock+ProfessionRecipe(JSON, shapeless, a level and an XP each) + one shared menu and screen: recipes shown as silhouettes until the level is reached and until first made.ProfessionCraftEventcan change the result.- Recipes are not a crafting grid: up to 36 ingredients (
ProfessionRecipe.MAX_INGREDIENTS), read as a bill of materials (getPortions(): each ingredient with its count). The workstation screen shows each line as have / need. - JEI and EMI: every workstation of every addon gets a category (the ingredients as a list with their counts, the result, the level, the XP), with no addon code.
- Notes in JEI and EMI (
RecipeViewers.note(items, text...)): an information page for an item no recipe explains (a part made at one station and fitted at another). - Profession drops in JEI and EMI (
ProfessionDrops): what a gathering profession gets and from what (the rocks a miner breaks, the creatures a hunter catches), with each output's chance, count, level and XP; built on the server and synced before the recipes.LootSummaryreads a loot table into outputs with their chances.CreatureHabitatssays where a catchable creature lives (its biomes in the wild and in traps), shown under a "Where?" label;BiomeNamesis the biome list it uses, for any other "where" line.
Catchable creatures
CatchableCreature/CatchableFlyingCreature: small creatures caught rather than killed, with variants (a rare one as a texture swap), a minimum render range, a capture that rollscapture/<entity>and firesCreatureCaptureEvent, and release from an item (a released creature is calm and kept).- Reactions to a player who does not sneak:
FLEE,TAKE_OFF(runs 2–3 s, flies off and vanishes),ATTACK(a few hits, then the take-off). - Perches (
CreaturePerch): on top of a block (a hornet on a flower, a lizard on a rock) or on a side face (a beetle on a trunk, drawn nose up byCatchableCreatureRenderer); still until disturbed or hurt; tall plants are sat on, not in; one creature to a block; breaking a perch (or the block above or below it) startles the creature, which flees. - Flying creatures stay airborne when spawned in the air; one that
canLand()rests on solid ground now and then (never on water); they flee up into the air. - Surface spawner (
data/<ns>/creature_spawns/*.json: entity, biomes, chance, group, max around the player, sky, altitude): tries every 5 s around each player, on the surface, through the entity's own spawn rules. Vanilla's natural spawning put most attempts underground. - Creature spawns take an optional
time(dayornight: a firefly),underground(a spot in the caves under the surface: a floor, room above, no sky),min_yandmax_y(with the biomes under the base mod's sky islands, the islands alone). - Creature spawns keep to their dimension: the Overworld, unless
"dimensions"names others ([]for every one). An entry with no biomes no longer spawns in the Nether. - Lures:
CreatureSpawns.lure(level, player, rounds)runs a player's spawn entries a few rounds early and says how many landed. It cannot bring anything the place would not give on its own.
Traps
TrapBlock(+ one shared block entity type): set on the ground, it closes on a creature after a random delay, picked fromdata/<ns>/trapping/*.json(entity, weight, biomes, sky, which traps); a right-click collects it through the capture. Single use or reusable; optionally kept to one profession.- Trap catches keep to their dimension too: the Overworld unless
"dimensions"says otherwise. - A trap remembers what it was made of: the stack it was placed from (
getGear(), NBT included) is saved with it, handed to the capture, and given back when it is broken. Two hooks read it:delayFor(gear, random)andisSpentBy(player, gear).
Gathering
HangingFruitBlock: a fruit hanging under leaves that ripens (random ticks, bone meal) and grows back once picked; kept softly to a profession (others bruise half the fruit, practitioners sometimes pick two and earn XP). Hangs in generated trees through vanilla'sattached_to_leavesdecorator.ProfessionBlockItem: a block item only a profession's practitioners can place (a farmer's sapling) — or one of several (or(profession, minLevel): "Only a Farmer or a Lumberjack can plant this.").ProfessionCropBlockandProfessionSeedsItem(both item classes take a minimum level): a crop with the fruit's rules (others spoil half the ripe harvests, practitioners sometimes reap one more and earn XP), and seeds only the profession sows.
Worldgen and dimensions
- Worldgen registers on
AkumaRegistry:DENSITY_FUNCTION_TYPES,BIOME_SOURCES,CHUNK_GENERATORS,STRUCTURE_TYPES,STRUCTURE_PLACEMENT_TYPES,STRUCTURE_PIECE_TYPES,FEATURESandPLACEMENT_MODIFIER_TYPES. They register codecs and types; the instances come from datapack registries. ⚠️ A structure whose piece type is not registered generates once and is lost on reload. - Fluids:
FLUIDSandFLUID_TYPESonAkumaRegistry. AFluidthat is not aFlowingFluidnever flows — a body of liquid that stays where it was placed (a sea with no container); the javadoc says why and whatLiquidBlockwould do instead. AkumaCells: a deterministic grid of jittered cells, each of which may hold a round feature — "an island here, and nothing for a few thousand blocks".mask,cellAt,featureAt, and a filter every reader shares. The outline can be warped off a circle (off by default);blendmixes a per-cell value across overlapping features (weighted, no seam where two meet); aRadiusRule(withRadiusRule) lets a cell's radius depend on the cell. The nine-cell condition is stated in the javadoc as an inequality to check with your own numbers.OverworldLookup: the overworld's biome and seed from anywhere, including another dimension's worldgen thread:is(x, z, tag),coverage(x, z, tag)(0 to 1, smoothed over a window wide enough to be a fade),seed().AkumaDimensionTravel: send a body to another dimension with what it rides and who rides it, arriving with a chosen velocity (send); push an entity so the push sticks on the client, rider case included (launch); generate the arrival early (preload). The arrival chunk is held loaded across the transfer, for a boat or a mob as for a player.AkumaJigsaw: add a placed feature or a structure template to another mod's jigsaw pool (a village's decorations) at server start, without replacing its files.
Currency
AkumaCurrency: read, give and take Belly and Extol through Mine Mine no Mi.
Doriki
AkumaStats: read and grant Mine Mine no Mi's Doriki, synced to the client.DorikiGainEffect: an effect that multiplies the Doriki earned in fights (NPC and player kills) while it lasts.AkumaDevilFruits: which fruit an entity ate, whether it is a Zoan, whether it is transformed; end its abilities' cooldowns.AkumaStats.runsOnCola/getCola/addCola: refill a cyborg's Cola as the base mod's Cola does, synced.SatietyEffect: an effect that slows hunger drain while it lasts.
Advancements
- Triggers
akumalib:profession_level,akumalib:profession_craft(item predicate on the result, NBT included),akumalib:creature_capture(creature, variant, tool, released).
Registry
AkumaRegistry: menu, block entity, recipe type and recipe serializer registers (and the worldgen and fluid registers above).
Fixes (within this cycle, never released)
- A data-load crash (
TrapCatchesbuilt before its Gson) that made every world fail to load. - The profession sync no longer throws for a player with no open connection (a player being disconnected, a game test's player).
- A blank profession no longer reads as a finished one ("level 1, Max", a gold XP bar).
- From the code review: a reusable trap waited no delay after a collection;
requires_skyfailed under leaves (now: nothing solid above); the spawner goes through Forge's spawn hooks; workstation ingredients are matched rather than first-fit; an interrupted take-off no longer leaves a creature floating.
2.4.0¶
Released 2026-09-18 · Download
Nine groups of additions and two fixes since 2.3.0. No signature was removed or changed: an addon built against 2.3.0 keeps compiling and keeps working. That is why this is a minor bump.
Requires Minecraft 1.20.1, Forge 47+ and Mine Mine no Mi 0.11.5.
⚠️ One fix changes how existing abilities behave: a charge force-stopped from outside (water, Seastone, handcuffs) now releases what its start put in the world. See Fixes below.
New
Targeting: three more AkumaTargeting helpers
AkumaTargeting already had firstInLine, firstInSight and inCone. It gains the three checks aimed abilities kept re-deriving by hand:
| Method | Answers |
|---|---|
aimPoint(caster, range) |
where the caster is aiming: the hit location, or range blocks along the look on a miss |
isEnemy(user, target) |
the one enemy check, through the base mod's own faction predicate, caster excluded |
sizedRange(caster, base) |
a reach grown by the caster's own bulk, so a fixed range stays usable in a large morph |
Pulls: AkumaMotion and PullProfile
Moving a body toward a point - a target dragged to a centre, a user lunging at a target, loot drawn to hand - as one call. A PullProfile states the speed curve (base, perBlock, max, boost), the vertical rule, whether the pull replaces or adds to the motion, and a minimum distance. The velocity always goes through AbilityHelper.setDeltaMovement, so a player's client cannot drop it.
Deferred work: AkumaTickQueue
One queue for work that has to wait for a later tick - typically a blow that must land at the end of the tick so the triggering hit's invulnerability frames do not swallow it.
Effect owners: EffectOwners
Who applied an effect to whom, for effects whose point is that relationship. Keyed on the target's UUID, so it survives the entity object being replaced while the effect lives on - a dimension change, a respawn, a chunk reload.
Charges: ChargeGuard, IChargeInterruptible, AkumaCharges.interrupt
ChargeGuardtells a completed charge from one stopped early, and gives the partial cooldown an early stop should cost. It reads the charge's own progress rather than counting ticks, so it agrees with the component under a changedTIME_PROGRESSION.IChargeInterruptible: a charge whose start puts something in the world (a lock, a pose, a sphere) implements it to take that back when the charge is cut from outside.AkumaCharges.interrupt(entity, ability): the one right way to cut a charge yourself - neither firing the ability nor leaking its start state.DomainAbility.interruptCharge: a zone's charge can be cancelled from outside, taking down its sphere or putting back the blocks it had placed.
Zone sounds: ZoneSoundSet.intervalClip
A zone's charge sound was replayed every 18 ticks - the pace of the base mod's short Room sound - so any longer clip layered two or three copies of itself over the whole charge. A set can now declare its clip's length, and setZoneSounds replays it only once a play has finished. The cadence is taken at the slot's base pitch, since a lower pitch plays a clip for longer. A set without it keeps the old cadence.
Protected areas: AkumaProtection
The protected-area checks the base mod only runs on the caster and on block placement, for everything else an ability touches (a pulled target, a landing point, a container). Matches the base mod exactly: the server's global whitelist, ABILITY_GRIEFING and the mobGriefing gamerule.
Lines: AkumaLines
A line between two anchors - a rope, a thread, a tether - drawn on the client as real geometry. One packet instead of a particle per step, and an end anchored to an entity follows it every frame.
Failed presses: AkumaAbilityHelper.FAILED_PRESS_COOLDOWN
The cooldown an aimed ability charges when it finds nothing or is refused: never zero (a held key would sweep a room for free), never the full cooldown. GrabAbility.DEFAULT_WHIFF_COOLDOWN now points to it, at the same value.
Fixes
- A force-stopped charge now cleans up after itself.
AbilityHelper.emergencyStopAbility- reached by water, Seastone, handcuffs, nets and anything callingdisableAbilities- skipped the charge's end event, which is where a charge takes back what its start put in the world. A zone left its sphere behind, a spreading zone's charge blocks became permanent, and a charging user stayed rooted. A mixin now runsAkumaCharges.interruptfirst.StompAbility,OceanAbilityand everyDomainAbilityimplement the cleanup. OceanAbilityscans one surface per column and covers grass, instead of leaving holes in a meadow.
Documentation
- New pages and sections for every addition above
ChargeGuarddocumented as preventive for most abilities, with the exact list of stops that reach a charge's end event- The awakened-Zoan smoke head anchor does not work on every partial morph, and why
2.3.0¶
Released 2026-09-14 · Download
One addition, three fixes and one deprecation since 2.2.0. No signature was removed: a renamed constant keeps its old name as a deprecated alias, so an addon built against 2.2.0 keeps compiling and keeps working. That is why this is a minor bump.
Requires Minecraft 1.20.1, Forge 47+ and Mine Mine no Mi 0.11.5.
⚠️ Two fixes change how existing abilities play: every InstantDashAbility now hits over the
width it declares, and a RunningSmashAbility hits a target twice a second instead of every tick.
See Fixes below.
New
Spreading zones are restored when their holder leaves
A SpreadingBlockAbility puts back the ground it converted from its own ticks, and those ticks stop
the moment its holder is gone: a logout, a dimension change, a server shutdown. The ability reloaded
afterwards is a fresh instance that knows none of the positions, so the converted blocks stayed in the
world for good.
The static zone registry that allows a restore from outside existed, but the only thing draining it lived in Awaken Awaken no Mi. Any other addon extending the class left its blocks behind.
The library now ships SpreadingBlockCleanupHandler itself:
| Event | Restores |
|---|---|
PlayerLoggedOutEvent |
the zones of the player leaving |
EntityLeaveLevelEvent |
the zones of an entity changing dimension or being unloaded |
ServerStoppingEvent |
every zone still active |
- You wire nothing. Extending
SpreadingBlockAbilityis enough. - Running alongside an addon's own copy is harmless. A zone leaves the registry when it restores, and each restore walks a snapshot of the registry, so whichever handler runs second finds nothing left to do. An addon can drop its copy on its next library bump rather than in lockstep.
Fixes
InstantDashAbility hits over GetWidth()
GetWidth() (default 2.5) was declared overridable and never read: the dash path was swept with the
user's entity reach instead. An override changed nothing, and the width grew in creative mode and with
any reach bonus.
⚠️ Every dash changes width:
| Dash | Before | After |
|---|---|---|
| Ferret Dart (InoFruits) | about 3, more in creative | 1.5, the width it already declared |
| Totsushin (InoFruits) | about 3 | 2.5 |
| Hyozan: Kyousou (Awaken Awaken no Mi) | about 3 | 2.5 |
The width no longer depends on the game mode or on reach bonuses.
RunningSmashAbility no longer hits every tick
Its hit tracker was cleared every tick while its hits clear the target's invulnerability frames, so
nothing limited the rate: a target the knockback did not throw clear took the damage 20 times a
second. The tracker now resets every 10 ticks, the window MoveAbility already uses, so a
target in contact is hit about twice a second.
⚠️ A subclass that turns knockback off was the one hitting every tick, and loses the most. Awaken Awaken no Mi's Reverse Slow Smash, at its default damage, drops from 16 to 1.6 real HP per second against a target in contact.
The 10-tick window is shared by all targets: a target first hit on the last tick of a window can be hit once more on the next tick.
CraftingAbility shows a real message when materials are missing
Its default message was a developer placeholder, "A message is missing here please contact the dev
to fix it.", shown to every player lacking the materials unless the subclass set its own. The
default is now "You do not have the materials to use this ability." It stays overridable through
the message field.
Deprecated
AkumaI18n.MESSAGE_MISSING: useMESSAGE_MISSING_MATERIALS. The old name is an alias of the new one, and its lang keyakumalib.ability.missing_messagestays mapped to the new text, so an addon built against 2.2.0 shows the right line rather than a raw key. Both go at the next major version.
Notes for addon developers
- Bump your
akumalib_versionto2.3.0if you rely on the zone restore: below it, yourmods.tomlrange would accept a library that restores nothing. - If you carried your own copy of
SpreadingBlockCleanupHandler, delete it once you require 2.3.0. Keeping it is harmless, just redundant. - Check your dashes and running smashes in game. A dash declaring a narrow
GetWidth()now needs a more precise aim; a running smash without knockback deals a tenth of what it did. - The distributable jar still comes from
gradlew releaseJar, inbuild/release— never frombuild/libs. - Run the control build (
gradlew build -PakumalibFromMavenin the consumer, aftergradlew publishToMavenLocalhere) before releasing anything that depends on this version.
Consumers
- Awaken Awaken no Mi, in its next release, requires AkumaLib 2.3.0 and drops its own copy of the zone restore handler.
2.2.0¶
Released 2026-09-13 · Download
Six additions and one behaviour change since 2.1.0. No existing signature moved, so an addon built against 2.1.0 keeps compiling. That is why this is a minor bump.
Requires Minecraft 1.20.1, Forge 47+ and Mine Mine no Mi 0.11.5.
⚠️ One default changed: a TornadoEntity is no longer put out by rain. See Changes below.
New
AkumaLootInjection — addon fruits inside the base mod's own box pool
An addon fruit could never come out of the base mod's 5% tier cascade — the roll where a wooden box upgrades into an iron one — because that nested roll resolves through a code path that skips loot modifiers by design. Every addon fruit was therefore rarer than a base mod fruit of the same tier, and no number in a loot file could fix it.
The fruit is now added as an entry inside the pool mineminenomi:fruits, while the table is
still being loaded:
- Parity is weight 100, the figure every base mod fruit already carries. No share to compute and nothing to re-tune when a fruit is added.
- The cascade works, because the upgraded roll draws from a pool that now holds the addon fruit.
- The base mod's own guard applies: the entry carries
FruitAlreadyExistsFunction, as theirs do.
registerFruitItem injects by default, into the box matching the fruit's tier, with an
inLootBoxes overload to opt out. That removes a whole class of bug: a fruit registered with no loot
entry exists, drops from commands and grants its abilities, and cannot be found in survival — with
nothing logged. Two consumers had shipped exactly that.
AkumaLootInjection.addFruit(...) is public for anything registered another way. Each injected table
logs one line at server start.
BlockHighlightManager — outline block positions through terrain, for one player
Draws a box around scattered block positions visible through walls, sent to a single player. The
three obvious routes each fail: particles are depth-tested against terrain, glowing marker entities
cost hundreds of real entities per player, and BlockOverlayManager shades a contiguous zone rather
than single blocks.
BlockHighlightManager.show(player, groupId, positions, colour, ticks);
BlockHighlightManager.clear(player, groupId);
- Positions travel in groups, one colour each, keyed by a UUID the caller owns.
- A group counts itself down on the client: an ability showing something for twelve seconds sends one packet and never has to take it away.
- ⚠️ Capped at 512 positions per group, enforced when writing and when reading.
- Cleared on level unload, so highlights never survive into the next world.
GrabAbility.beginGrab(user, target) — a grab that is not a melee swing
GrabAbility only knew one way to catch somebody: open a reach window, then turn the next hit into
the grab. A ranged grab — a tongue, a rope, a harpoon — decides its target when a projectile
arrives, with no swing to intercept. beginGrab is that entry; the pull, the hold and the release
run exactly as they do for a melee catch.
- It applies the one-tick
ANTI_KNOCKBACKthe melee path applies. Without it, the impact that caught the target knocks them straight back out of the grab. - Server side only, and it refuses to start a second grab while one is running.
AkumaTargeting.inCone(caster, target, halfAngleDegrees)
The cone test two consumers were carrying as character-for-character copies. Written as a plain dot
product against a cosine rather than delegated to TargetPredicate.testAdvancedInView(float), whose
float is documented nowhere. A target standing exactly on the caster counts as inside the cone.
IAwakenZoanSmokeLayerHeadAnchor — the awakened-zoan smoke follows the model's head
A form implementing this marker has its smoke moved to the pivot of the morph model's head, read at render time, before its Y/Z offsets apply. On most morph models that pivot is where the neck leaves the body, so the offsets shrink to small corrections — and the scarf follows the model when it moves its head.
- Only Y and Z follow the pivot, never X: some models shift the head group sideways and compensate in the cubes.
- Opt-in: a form without the marker renders exactly as before.
AkumaRollTableModifier — an insertion mode
"mode": "append" (the default, and what every existing file already means) or "mode": "compete".
compete inserts the rolled loot at the front of the list, for a container that keeps only its
first match. An unrecognised value is a hard codec error rather than a silent fall back to append.
For Devil Fruit boxes you no longer need this at all — AkumaLootInjection handles them. It stays
for chests and any container whose pool cannot be reached.
Changes
A tornado is no longer put out by rain
TornadoEntity was a copy of the base mod's Suna Suna no Mi sandstorm, and it inherited the
sandstorm's rule: water and rain discard it. A generic funnel switching itself off when the weather
turns is nonsense, so the rule is now two hooks:
| Hook | Default | |
|---|---|---|
isQuenchedByWater() |
true |
kept — water is the universal Devil Fruit weakness |
isQuenchedByRain() |
false |
changed — override and return true for a sand funnel |
⚠️ This changes existing consumers. A tornado subclass that overrides neither hook now survives rain where it did not before — AwakenAwakenNoMi's diamond funnel among them.
Fixes
competecould replace a higher-tier fruit with a lower one. The cascade pool is rolled before the same-tier pool, so its fruit heads the list, and acompeteinsert went in front of it: the player lost the upgrade, and nothing said so.
Notes for addon developers
- Bump your
akumalib_versionto2.2.0so yourmods.tomlrange refuses an older library rather than loading against one and crashing during registration. - ⚠️ If you shipped loot modifier files for Devil Fruit boxes, delete them. With injection on by default, keeping them makes a fruit appear in the pool and get inserted by the modifier.
- The distributable jar still comes from
gradlew releaseJar, inbuild/release— never frombuild/libs. - Run the control build (
gradlew build -PakumalibFromMavenin the consumer, aftergradlew publishToMavenLocalhere) before releasing anything that depends on this version.
Consumers released alongside
- Awaken Awaken no Mi 1.1.0 requires AkumaLib 2.2.0: its twelve new awakened forms place their smoke with the head anchor.
2.1.0¶
Released 2026-09-10 · Download
Six additions since 2.0.0. Everything here is additive — no existing signature moved, so an addon built against 2.0.0 keeps compiling. That is why this is a minor bump.
Requires Minecraft 1.20.1, Forge 47+ and Mine Mine no Mi 0.11.5.
New
MorphGates — a factory for requiresMorph conditions
Every ability locked to a form was writing the same use-condition by hand, and a form gate that is subtly wrong fails in the worst possible way: the ability is simply usable out of shape, which nothing logs and nobody notices until somebody tries it. One addon had eleven such copies. They are now one constant each.
MorphStats — a builder for a morph ability's attribute block
A Zoan form is mostly a wall of attribute modifiers — speed, armour, knockback resistance, step height, jump height, reach — and the base mod's own morphs write them out longhand. This builds the block instead, which makes two forms of the same fruit readable side by side and stops the modifier UUIDs being copy-pasted between them.
onlyWhile(...) adds a conditional block: a set of modifiers that applies only while some
predicate holds, so a form that is faster in water or heavier on land is one declaration rather than
a tick handler.
AkumaTargeting — the target-picking helpers
Consolidates the entity selection every ability was reimplementing, and — more usefully — documents which of them exclude the caster and which do not. That distinction had already produced two shipped bugs in a consumer, where a technique with a radius damaged the person who used it.
AmplifiedPresentation and the amplification bus
The pattern where a form amplifies its own fruit's kit — the base mod does it with Venom Demon and Shinokuni — has three axes: the numbers, the shape of the technique, and its name and icon. The third is pushed once by the form rather than polled by each technique, and that is the part a sixth ability in a kit forgets.
AmplificationBus.push(entity, amplified, ...abilities) is the whole of the wiring;
IAmplifiableAbility and AmplifiedPresentation are what a technique implements to answer.
MarkerEffect — a base for effects that are read, not felt
An effect that exists only so something else can ask about it has no per-tick work, and saying so
matters: returning true from isDurationEffectTick asks the game to tick it every single tick for
nothing. It also settles the client-visibility override that, left at its default, makes an effect
exist only on the server — so the overlay is never painted and the failure looks like the colour
being wrong rather than like the effect being invisible.
OverlayEffect — a marker that also tints the body it is on
Adds the body tint on top of MarkerEffect. ⚠️ The alpha has to be spelled out: new Color(rgb)
fills it in at 255, which paints the body a flat silhouette with no skin left underneath. Two
calibrated values are documented on the class — around 100 for something the user wears and has to
stay readable through, around 150 for a mark whose whole job is to be impossible to miss.
⚠️ The amplifier on such an effect is not always a potency. An instance carries a duration and an
amplifier and nothing else, so it is the only place a per-application value can travel — one consumer
puts a DyeColor id there, which is what makes sixteen colours one registered effect instead of
sixteen.
Documentation
Three corrections, each of which had already cost somebody a wrong answer:
ModAttributes.STEP_HEIGHTis an alias, not an inert attribute. It resolves to Forge's own, so writing to it works and reading the Forge one back reflects it.- What does and does not exclude the caster, spelled out per helper rather than left to be discovered by damaging yourself.
- Only one of
MarkerEffect's four overrides was ever load-bearing — the other three restate defaults, and the class says which is which so a subclass knows what it is actually inheriting.
Notes for addon developers
- Bump your
akumalib_versionto2.1.0so yourmods.tomlrange refuses an older library rather than loading against one and crashing during registration. gradlew buildleaves a mapped jar inbuild/libs; the distributable comes fromgradlew releaseJar, inbuild/release. The two are indistinguishable by eye, and shipping the mapped one produces a mod that loads and then fails on its first Minecraft call.- Consumers resolving AkumaLib from Maven need
gradlew publishToMavenLocalin this checkout first. - ⚠️ Run the control build before releasing anything that depends on this. The composite build
(
includeBuild('../AkumaLib')) puts this project's classes on the classpath directly, which hides a resource missing from the packaged jar completely — a lang file, a texture,mods.tomlitself.gradlew build -PakumalibFromMavenin the consumer is the only build that would catch it.
2.0.0¶
Released 2026-09-07 · Download
Ten changes since 1.0.0. Everything here is additive — no existing signature moved, so an addon built against 1.0.0 keeps compiling.
Requires Minecraft 1.20.1, Forge 47+ and Mine Mine no Mi 0.11.5.
New
GrabAbility — a base class for grabs
Mine Mine no Mi has exactly one worked grab, SpinningBrawlAbility, and roughly two thirds of it is
plumbing rather than technique. This class owns that part: the four-way state machine behind the key,
the reach window that turns the first entity struck into the grabbed target, the hold, and a cooldown
that runs once however the grab ends — at full price only if the grab actually connected.
A subclass provides three things: what happens on the catch, on each tick of the hold, and on release. The throw is deliberately left out, so a technique can end by hurling its target or by dropping it.
BarrelRollAnimation — the missing roll axis
ForwardRollAnimation somersaults; the base mod's YAW_SPIN pirouettes. Neither is a body spinning
about the axis it faces along. Typed on EntityModel rather than HumanoidModel, so it is not
restricted to player-shaped models.
ProduceItemAbility — for fruits that make their own substance
The counterpart of CraftingAbility. Crafting is materials in, result out — a recipe, a cost, a
failure message. A fruit producing salt, ink, honey or bone has none of those, because the user is
the material. On CraftingAbility such an ability spends three abstract methods saying nothing and
carries a charge component it never starts.
A subclass provides the stack, and optionally a sound. A full inventory and a holder with no inventory at all are both handled here.
BoomerangProjectile — an out-and-back projectile
The base mod's ChakramEntity has reusable return maths but an unusable base class: it extends
AbstractArrow and hurts with a vanilla trident source, which carries no AbilityCore and therefore
skips the ability damage pipeline entirely. This extends NuProjectileEntity like every other ability
projectile and borrows only the steering.
registerFruitItem — group a fruit's abilities
registerItem was the wrong entry point for a Devil Fruit and nothing said so. The difference is one
call, AbilityGroups.addFruitGroup, and it is what ties a fruit's moves together in the ability menu.
Registered as a plain item, a fruit loads, drops, is edible and grants its abilities — ungrouped.
Nothing logs it; it shows up only when a player opens the menu.
akumalib:roll_table — a loot modifier consumers drive from data
Addons need to add items to loot tables they do not own. Minecraft loot tables do not merge, so the only supported route is a Forge global loot modifier, which needs a codec registered in Java — and the codec is identical for every addon. Consumers now ship JSON only.
Fixed
The loot modifier never rolled its table
It had never worked. Every invocation logged Detected infinite loop in loot tables and contributed
nothing. Found after about fifty wooden Devil Fruit boxes in a dev client produced no drop against a
0.208 chance — roughly 1 in 116,000 of being luck.
Opening a box could crash the server thread
StackOverflowError, from the modifier re-entering itself: every public getRandomItems* overload
funnels into one private method that calls ForgeHooks.modifyLoot, so rolling a table from inside a
modifier re-enters the modifier pipeline with the same context. The nested table is now rolled raw.
Notes for addon developers
gradlew buildleaves a mapped jar inbuild/libs; the distributable comes fromgradlew releaseJar, inbuild/release. The two are indistinguishable by eye, and shipping the mapped one produces a mod that loads and then fails on its first Minecraft call.- Consumers resolving AkumaLib from Maven need
gradlew publishToMavenLocalin this checkout first. - Bump your
akumalib_versionto2.0.0so yourmods.tomlrange refuses an older library rather than loading against one and crashing during registration.
1.0.0¶
Released 2026-09-03 · Download
AkumaLib is a shared ability framework for Mine Mine no Mi addons.
⚠️ This is a library, not a content mod. On its own it adds no fruits, no abilities and no items — nothing will change in your game. Install it only because another mod requires it.
For players
Install it alongside Mine Mine no Mi and the addon that asked for it. That's all there is to do.
Requires
- Minecraft 1.20.1
- Forge 47.4.18 or newer
- Mine Mine no Mi
Known consumers
- Awaken Awaken no Mi 1.0.0 — the addon AkumaLib was extracted from
For addon developers
Mine Mine no Mi gives you Ability and a set of components. Everything above that — a zone that charges and expands, a wave that converts terrain, a passive that grants attribute bonuses under a condition — you would otherwise write yourself, slightly differently each time. AkumaLib is that layer, extracted once and shared: 65 classes, 17 ability base classes, 12 utilities.
Ability base classes
| Class | For |
|---|---|
ZoneAbility |
a charged spherical zone applying effects continuously |
SpreadingBlockAbility |
a zone that replaces ground blocks and restores them at the end |
DomainAbility |
the shared parent of both, carrying the four-slot ZoneSoundSet |
BlockWaveAbility |
a radial wave converting blocks outward — sphere, surface or terrain-following |
ConditionalStatPassiveAbility |
a passive granting attribute bonuses while a condition holds |
AuraAbility |
a passive aura ticking every nearby enemy |
StompAbility · MoveAbility · InstantDashAbility |
charged stomp, continuous dash, teleport dash |
BlockUseAbility · CraftingAbility · TransmutationAbility · GroundAbility |
smaller bases |
Utilities
PropagationHelper (BFS propagation with easing), BlockPlacingHelper, AttributeBonusHelper (idempotent attribute modifiers), tooltip helpers, plus morph, animation and networking scaffolding.
Why the base classes carry so many warnings
Most exist because something shipped broken first. Extending the class gets you the fix for free:
SpreadingBlockAbilityrestores blocks throughBlock.updateFromNeighbourShapes— putting a remembered state back raw leaves a grass block flaggedsnowyunder open sky.- Its zones are tracked statically and restored on
PlayerLoggedOutEvent, because the tick that drains the restore queue stops the moment the holder leaves — and the blocks stayed permanently. ConditionalStatPassiveAbilityapplies and removes idempotently rather than on transitions:addPermanentModifierpersists in NBT, and a reconnect turned a conditional bonus into a permanent one.- It also hooks
DisableComponent.addStartEvent, because a Devil Fruit passive is disabled the moment its holder gets wet, andPassiveAbility.tick()stops dispatching before it can clean up.
Adding it to your project
# gradle.properties
akumalib_version=1.0.0
// build.gradle
implementation fg.deobf("com.inovactio:akumalib:${akumalib_version}")
# mods.toml
[[dependencies.yourmod]]
modId = "akumalib"
mandatory = true
versionRange = "[${akumalib_version},)"
ordering = "AFTER"
side = "BOTH"
⚠️ API stability
Publishing freezes the API. From 1.0.0 onward, a breaking change to the shared surface is a major version bump and forces a synchronised release of the library and every consumer. Your versionRange should exclude the next major.
All Rights Reserved.