
Overgrown's Apoli
A data-driven power system that's build for custom abilities, mechanics, and entire origin systems from JSON alone.
Оцените первым
826
4
Список изменений
Added
Scoreboard teams
apoli:in_team: Entity Condition (aliasapoli:team). Takesteam/teams, each either a team name or an object of properties to match. With neither, it just asks "is this entity on a team?".apoli:same_team: Bi-Entity Condition (aliasapoli:allied), withallow_teamless.apoli:team: Entity Action with anoperationofjoin,leave,create,modify,emptyordelete; the/teamcommand as a data-pack action.apoli:join_team,apoli:leave_teamandapoli:modify_teamare aliases that preset the operation.- New Team Data Type, used by all three. Eggolib's camelCase field spellings (
friendlyFire,nametagVisibility, …) are accepted, soeggolib:in_teamJSON loads unchanged. One difference: a multi-field object here requires all of those properties to match, where Eggolib passed if any single one did (useteamsfor the old behaviour).
Speech to action has been reworked end to end:
- Transcription is now fully in-house and offline, using a bundled Vosk recogniser. The local web server and browser tab are gone.
- With Simple Voice Chat installed, Apoli reads the audio it has already captured on your machine, before it is encoded. No second microphone, no device conflict, and your own push-to-talk is the gate. Without it, Apoli opens the microphone itself behind a new Speech to Action keybind.
- Recognised text never leaves the client. Matching happens locally; only "power X matched" is sent, and the server re-checks that you hold it before running the action.
- New client options in
apoli-client.json:speechSource,speechInstant,speechPushToTalk,speechInputDevice,speechEcho.
Key sequences
timeout (default 20 ticks) forgets a partial combo after inactivity.
Power sources
- New concept: a power source is anything that owns a list of powers: an origin, an origin layer, a skill tree, or an
apoli:multiplepower. Apoli can now resolve a source id to its powers, which is what makes "grant everything this origin has" possible. apoli:grant_all_powersgainedfrom(a single id or a list). It grants only the powers those sources provide.sourceis now optional and defaults per entry to thefromid, soapoli:revoke_all_powerswith the same id undoes the grant exactly.apoli:revoke_all_powerssourceaccepts a list, and now also resolves real power sources removing those powers completely, sub-powers included, whichever source granted them.
Commands
/apoli:power removeandremoveall, aliases ofrevokeandrevokeall./apoli:clone:summon,removeandlistfor player clones, the same entityapoli:summon_clonecreates. Options are one NBT compound:count,lifetime,can_attack,can_sit,follow_owner,slim,inherit_equipment,powers,summon_id,wide_texture,slim_texture. No short alias since/cloneis vanilla. Permission nodeapoli.command.clone./apoli:skill_tree points remove <targets> <tree> <value>, next topoints add.
Entity selector options
@e[power=<id>]: Entities holding a power. Works on any entity, not just players.@e[suppressed_power=<id>]: Entities holding a power that is currently suppressed.@a[skill=<id>]: players who purchased a skill.@a[origin=<id>]and@a[origin_layer=<id>](needs Origins installed; without it they produce a clear error rather than silently matching nothing).- All five accept
!for negation and offer tab-completion.
Raycast
apoli:raycastis now registered as a bi-entity action as well (type aliasapoli:raycast_between). In that form the ray is cast from the actor's eyes straight at the target and clamped to the distance between them — the "is there a wall between us" trace, or a particle line drawn between two entities.aim_at_target(defaulttrue) andstop_at_target(defaulttrue) control that. An explicitdirectionstill wins.
Fixed
apoli:action_on_key_sequencecombos no longer trigger each other. Two problems: a power only saw key presses from its ownkeyslist, so an unrelated key could not break a partial match; and powers matched independently, so finishingA B Calso firedA Bon the way through. All of a player's sequences are now matched in one pass and only the longest match fires — a shorter combo waits while a longer one is still reachable, and is cancelled if that longer one completes./apoli:resourcereported resources you no longer had. A resource's value is kept after the power is revoked so re-granting restores it, but every sub-command read that raw value without checking you still hold the power. Tab-completion now suggests only what the targets actually have.- Powers from a previous origin could leave their effects behind. When a power's definition is missing at removal time its
onRemovedcannot run, so attribute modifiers stayed applied. Those are now stripped explicitly. Relatedly, the client no longer replaces the shared power table in single-player, where a client-side parse failure could delete a definition the server still needed, and client parse errors are logged instead of being swallowed. - Disguises are animated. The stand-in model is now ticked, so walking, attacking, hurt, death and pose all follow the disguised entity; Iron Golem and Warden attack animations play, and fire shows through. The disguise stays silent.
apoli:model_colorapplies to disguises. The colour was looked up on the stand-in model, which holds no powers, so it silently did nothing.apoli:modify_cursor_speedhooks the single place the camera turn is applied instead of rewriting the mouse handler's internals, so other input mods can no longer bypass it.- A crash in the server tick loop:
apoli:resourceboundary actions dereferenced a living-entity owner that is null for non-living power holders. The same pattern was fixed in seven other power types. - Skill trees that keep their skills as files loaded zero skills. Every file in
data/<namespace>/skill_trees/was parsed as a tree, so a pack using the classic layout — one file per skill, carryingparent,power,costand conditions — ended up with a folder full of empty auto-granted trees and nothing to buy. Points went into keys nothing read,buyreported "unknown skill", and the whole feature looked dead. A file inskill_trees/is now a skill when it has aparentand a tree when it does not. That one field is the whole rule. Both layouts work and end up in the same tree; skills declared in a power'sskillblock still win on an id collision. A skill file'spoweris accepted as well aspowers. - Empty or malformed files in
skill_trees/are now skipped with a message naming the file instead of failing with an opaque codec error. - Revoking a power left its sub-powers behind.
removePowerCompletelydeleted the container entry without running the power type's removal hook, so revoking anapoli:multiplepower orphaned every sub-power it had granted. It now runs the hook for each source and sweeps anything still held under that power as a source. This affects theapoli:remove_poweraction and therevokecommand. tick_bientity_actionnow keeps firing on dedicated servers. Fired projectiles were tracked by hard object reference. Whenever the projectile object was momentarily unresolvable — the tick after it is spawned but before it is visible to the level's entity index, or after a chunk unload / reload swaps it for a fresh instance from NBT — the tracking entry was dropped permanently and that projectile never ticked again. Projectiles are now tracked by UUID and re resolved against the server's levels, with a short grace window, so unload / reload and spawn-tick races no longer end tracking. Single player rarely hit this because the shooter's chunks stay loaded and projectiles die on impact within a second.- One failing tick action no longer stops every other projectile. The tracking list was rebuilt in place while iterating, so an exception from any single
tick_bientity_actiondiscarded every entry that had not been visited yet — killing per-tick actions for all players at once. Failures are now contained to the projectile that caused them and logged once. - The actor passed to
tick_bientity_actionsurvives respawn and dimension changes. The shooter was captured as an object reference; once the server replaced that player instance the action received anullactor for the rest of the projectile's life. The owner is now re-resolved by UUID, so actions that read the shooter keep working. This mostly showed up in multiplayer, where respawns and portals are constant. - Powers that fail to re-encode for client sync are now reported. A power whose config could not be written back to JSON was dropped from the sync silently, so it worked on the server but was invisible to every client — with no clue in the log. The failure is now logged with the power id and the codec error.
Changed
/apoli:powerrewritten. The tree is nowgrant,revoke,grantall,revokeall,has,suppressandunsuppress. Thepoweralias is unchanged.revoke <targets> <power>removes the power completely — every source that granted it, plus its sub-powers. Addfrom <source>to drop only one grant.- Sub-powers are named
<parent>_<key>, so typingexample:fire_tab-completes the ones you can target individually. grantall/revokealltake a power source (origin, layer, skill tree orapoli:multiplepower) instead of meaning "everything".has <targets>with no power id lists every power the target holds, with the sources that granted each and a marker on suppressed ones. With an id it prints true/false per target and returns the match count.suppress/unsuppresstake apower <id>or akey <keybind>mode — the key mode switches off every held power bound to that key at once, which is useful for packs that stack a dozen abilities on one button.unsuppress <targets> allclears the lot.- Removed:
remove(it wasrevokewith extra steps),clear,list,sourcesanddump. apoli:raycast'spierceis now a shorthand for two separate flags,pierce_blocksandpierce_entities. Settingpiercestill sets both, so existing packs are unaffected; setting either explicitly overrides it. Lasers can now go through walls or through crowds without having to do both.- Commands validate the ids they are given and report what is loaded when one is wrong, so a typo can no longer look like a broken command.
Файлы
apoli-1.12.0.jar(28.08 MiB)
ОсновнойМетаданные
Канал релиза
Beta
Номер версии
1.12.0
Загрузчики
NeoForge
Версии игры
1.21.1
Загрузок
16
Дата публикации
31.07.2026
