Apoli (1.83.0)
Curse Maven Snippet
What's new
1.83.0
Added
own_keyonapoli:power_storage. A stored power is really granted, so it also answers the keybind its author gave it. For a satchel of spells that is the point; for stealing an ability it is not, because the stolen power arrives on whatever key its author picked — usually a key the thief already uses — so one press fires both, and theapoli:run_stored_poweryou wired up becomes a redundant second route to the same ability. Withown_key: falsethe stored power stays fully granted — resources, cooldowns, HUD bars,apoli:multiplesub-powers, all of it — but its own key does nothing andapoli:run_stored_poweris the only way to fire it. Defaults totrue, so nothing changes for a pack that does not set it.It follows a stored
apoli:multipledown into its sub-powers, so a stolen bundle goes quiet as a unit, and it silences only what came out of that storage: a power the holder also has from their origin keeps its key, and so does their own power on the same key. That is the difference fromapoli:prevent_key_press, which blocks a key for everything the holder has.
Fixed
- A power storage granted by command deleted itself.
/apoli:power grant <targets> <power>with no explicit source uses the power's own id as its source, which put anapoli:power_storageinto its own source list — and the storage then revoked itself the next time it reconciled. Granting a storage straight to a player, which is the obvious way to try the feature out, produced a power that vanished and a storage that appeared to do nothing. A storage declared inside anapoli:multipleis sourced by the bundle and was never affected.
1.82.0
Added
Dev mode explains power storage. Every way
apoli:store_powercan quietly do nothing now prints a line under/apoli:dev_mode, naming the storage and the power: stored, or refused because the target holds no storage at all, because no storage has the id you named, becausefrom_heldfound nothing matching on the actor, because the power carries none of the storage's tags, because it is already stored, or because every slot is full.from_heldalso names the entity it read the powers from, since storing into the wrong side of a bi-entity action is the usual reason nothing happens.apoli:run_stored_powerdoes the same for a cast that does nothing: whether the storage was empty, whetherpower/tags/indexmatched nothing, or whether something matched and refused to fire — the last one being the case worth naming, since a stored power only answers that action if it is key-driven, and its own condition, cooldown andapoli:prevent_key_pressall still apply.
Fixed
apoli:stored_powercounted powers that no longer exist. An entry whose power had been deleted, renamed, or had its data pack disabled still counted toward the condition, soapoli:stored_powerandapoli:resourceread against the same storage could disagree by exactly the number of dead entries — and a storage that looked non-empty to the condition could not be emptied by anything. Both now skip them.
1.81.1
Fixed
- Bedrock models were flat on Fabric 1.20.1.
BedrockModelParser.vector()on that tree read only the first component of apivot,origin,sizeor cuberotationarray, so every one of them collapsed to(x, 0, 0)andapoli:custom_model_renderingeometrymode baked zero-height slivers stacked on the floor. It read all three on both 1.21.1 trees; the file is now identical across all three. Animation parsing was never affected.
1.81.0
Changed
grantonapoli:power_storagenow defaults totrue. It shipped opt-in in 1.80.2, and that was the wrong default: without it a stored power is only as capable as a single key press can express, so anything built out of several pieces — the usual shape of an ability, one key power plus the resources, timers and cooldown behind it — fired into a void. Every branch reading a resource took the wrong path and the ability appeared to do nothing.grant: falseis still there for a storage that is a list rather than a loadout, such as a spell book cast entirely throughapoli:run_stored_power.
1.80.3
Fixed
- A storage could store itself, and then hold nothing useful.
tagsis read twice from the same JSON key: once as the power's own tags, and once byapoli:power_storageas its accept-filter. So"tags": "contractable"on a storage also tagged that storagecontractable, which made it a candidate for its own filter —apoli:store_powerwithfrom_heldsaw it in the holder's power list, and withslots: 1andreplace_oldestit could evict the real ability and store the storage instead. The result was a power that applied and did nothing, and which ability won varied run to run. Aapoli:power_storagecan no longer be stored in a storage.
1.80.2
Added
grantonapoli:power_storage. A stored power is inert by design — it does not tick, holds no resources and draws no HUD, which is right for a spell book and wrong for anything assembled from more than one piece. Anapoli:multipleis usually one key ability plus the resources, timers and cooldown behind it, so stored inertly the ability fired and everything underneath it was missing. Withgrant: truea power is really granted while it sits in the storage, with the storage power as its source: resources exist,action_over_timesub-powers tick, HUD bars draw, and a stored multiple grants all of its sub-powers. Evicting it, clearing the storage or losing the storage power revokes everything it brought.
1.80.1
Fixed
tagson anapoli:multiplewas silently discarded.tagsis a top-level power field, but it was missing from the bundle's reserved-field list, so the loader treated it as a would-be sub-power, found it wasn't an object, and dropped it — leaving the bundle with no tags at all. Anything that selects powers by tag therefore skipped everyapoli:multiple: most visiblyapoli:store_powerwithfrom_heldand atagsfilter, which would happily store a tagged plain power and never a tagged bundle.- A field on an
apoli:multiplethat is neither reserved nor an object is now logged by name at load instead of being ignored without a word. That is what made the bug above invisible. - A stored power whose JSON no longer exists could never be cleared. It kept occupying a slot, kept counting toward the storage's resource value, and there was no command that could remove it. Such an entry is now ignored when reading the storage, never fired, and dropped the next time something is stored.
Added
apoli:power_storageis now a writable resource, so/apoli:resource set <targets> <storage> 0empties a storage. A smaller number keeps that many of the most recently stored powers.
1.80.0
Added
- Grief-log attribution for Ledger and Indexor. When a power edits the world, the log entry is
labelled with the power — and, with Origins installed, the origin it came from — instead of
@explosionor@player. A Ledger entry reads@blaze/fireball (Steve), and the label is a real Ledger source, so/ledger search source:blaze/fireballand/ledger rollback source:blaze/fireballboth work on it. Indexor entries that could only be blamed onEnvironmentget the acting player and the power filled in instead. Attribution followsapoli:delayandapoli:loopchains, and nested powers attribute to the innermost one running. Neither integration touches the block-entity NBT either mod replays during a rollback. No supported logger installed means no cost at all — the mechanism compiles out. apoli:sound_playing(entity condition; aliasesplaying_sound,hearing_sound) — true when a matching sound started near the entity withindurationticks. Fields:sound,category,duration,range(defaults to the sound's own audible radius). Only sounds a loaded power actually names are tracked, so a pack that never uses it pays nothing.gui_scale_lockonapoli:overlay— draw an overlay at a fixed GUI scale instead of the viewer's, so a reticle or frame is the same physical size on every client.0(the default) follows the viewer's setting.actionsarray onapoli:action_over_time— several actions on their own intervals inside one power, all driven by a single evaluation of the power's condition. Each step takesinterval,entity_action, and optionalonset_delayandcondition. Three effects on three beats now cost one condition check per interval instead of three.
Changed
strength,red,greenandblueonapoli:overlayaccept expressions, so a tint can follow a resource. A plain number is folded at load and costs nothing to draw.
1.79.0
Added
load_condition— a top-level power field checked while the data pack loads, before the power is parsed at all. This is what makes one pack work across two game versions: a branch whose fields this version's codec would reject is dropped before it can fail. A runtimeconditioncannot do this, because the power has to parse first.apoli:mod_loaded(mod,mods,version,comparison; aliasmod_installed) andapoli:minecraft_version(version,data_version,comparison; aliasesgame_version,mc_version), registered on all condition registries — entity, bi-entity, item, block, fluid, biome, damage, and the new load-time one.- A static condition registry for
load_condition, holdingall_of,any_of,constant,nothingand the two new types. Anything else in a gate is a clean parse error naming the power, rather than a condition that silently answers wrong.
Notes
- Version comparison uses one shared comparator on every loader and version, so the same JSON answers
identically everywhere. Snapshots do not order sensibly — use
data_versionfor those. - Requires Origins 1.35.0 or newer if you use both.
1.78.1
Fixed
- Server crash when two powers shared a key-sequence prefix and one of them ended on a held step — pressing two keys on the same tick could run the matcher past the end of the sequence.
1.78.0
Added
- Key-sequence steps. Entries in
key_sequencecan now be objects instead of bare key names, withkey,taps(1–16),hold(ticks) andmax_gap(ticks). "Tap it three times and hold the last one" is a single entry. A bare string behaves exactly as it always has. graceonapoli:key_pressed(0–40 ticks) — keeps the condition passing for a moment after the key is released, for keyboards that drop a keystroke under rollover.
Fixed
- A one-tick keyboard dropout no longer reads as a release. The transport stays raw and the smoothing is
applied per consumer, so
action_on_key_sequencestill sees real press and release edges and double-taps keep working. key_sequencekeys are now watched even when they are not also listed inkeys— a combo built only out of sequence keys could never fire.- The documented nested form of a
keysentry ({"key": {"key": "key.x"}}) parses again.
1.77.0
Fixed
action_on_landnever fired for anyone withtake_fall_damage: false. The immunity was clearing fall distance every tick, and fall distance is the only signal that a landing happened. The immunity is now applied after the landing hook instead.
Changed
/apoli:dev_modetraces held-key changes (held keys +key.x -key.y), so you can tell "the server saw a release" from "the power logic is wrong".
1.76.0
Fixed
bientity_conditiononapoli:modify_tick_ratedid nothing onceaffect_chunkswas on. A rejected entity simply got no tick state and fell back to the chunk's rate. Rejected entities are now written an explicitly-normal rate. Settingbientity_conditionon a target it cannot filter now logs the power at load instead of sitting silently inert.- A stored
apoli:multiplenever ran. Neither key dispatch nor the stored-power tick had a branch for a bundle, so a stored multiple forwarded to none of its children. apoli:power_storagedid not always clear when the power was removed. Deleting, renaming or disabling the storage power's JSON and then revoking it left the stored list behind, so the next grant of that id inherited the old contents.drop_on_deathonapoli:power_storagewas declared and read by nothing; it now clears the storage.- Black custom particles. Not a render bug —
particle.fshis straight-alpha, and a soft-edged PNG whose feathered pixels lost their colour legitimately paints black. Every vanilla particle texture is binary-alpha, so nothing in the game exercised that path.
Added
alpha_bleedonapoli:customparticles — dilates the opaque colour outward into the semi-transparent fringe at load, which fixes the black ring above without touching the source file. Opt-in, because full dilation would also flatten a deliberately coloured ramp.
1.75.0
Added
apoli:six_armsbuilt-in player model, in the same idiom asapoli:four_arms— three pairs fanning outward, every vanilla arm state (swing, item, bow, sleeping, elytra) reaching all six arms.apoli:four_armsis unchanged.
Fixed
- NeoForge: speech-to-action crashed on startup with
Could not initialize class com.sun.jna.Native. Minecraft ships its own JNA and was winning the resource lookup, so Apoli's JNA loaded the wrong native library. The isolated loader is now child-first for resources as well as classes.
1.74.0
Fixed
- No fall damage for anyone, anywhere.
apoli:modify_bouncinesswas cancelling vanilla's fall-damage call for every entity and every block, whether or not any power matched. Shipped in the same commit that added the power type. - Performance, same area: the bounciness hook ran a block lookup and allocated a context for every living entity in every loaded chunk, every tick they were on the ground — not just on landing.
Added
apoli:power_storage— holds power ids without granting them, in the holder's own data. Deliberately ungranted, so a storedaction_over_timedoes not quietly run. Readable as a resource, so HUD bars and$(key)macros work on it for free.apoli:run_stored_power(entity action) — fires a stored power with a key of your choosing. The power does not need to be held or granted.apoli:store_power(entity and bi-entity) —operation: add | remove | clear, andfrom_heldto take the ids straight off the actor's held powers.apoli:stored_power(entity condition) — a count condition, so "has X", "is full" and "is empty" are all one type.apoli:same_equipped_item(bi-entity condition) —compare_id,compare_countandcompare_tagare independent switches, slots accept one or a list, and multi-slot means any-against-any.
All Relations
- All Relations
- Embedded Library
- Optional Dependency
- Required Dependency
- Tool
- Incompatible
- Include

