Apoli is a mod for building custom powers, unique abilities, and entirely new game mechanics. All through data packs that are themed around modular design. It's the engine behind Overgrown's Origins.
To get started, create a power file under data/<namespace>/powers/ in your data pack.
The mod features:
- A power system with 100+ built-in ability types, grantable to any entity. Think of it as a toolkit for superpowers (No Java Required).
- A typed action system spanning entity, bi-entity, block, item, and meta actions.
- A comprehensive condition system across 7 context types.
- Data-driven skill trees for progression paths and unlockable abilities.
- A physics-based rope and grapple system (swing, leap, and reel).
- An entity disguise system for transforming mobs and players.
- Custom entities: projectiles, minions, and player clones.
- Data-driven keybindings, defined entirely through data packs.
- Custom recipes and loot functions that grant powers.
- A built-in expression engine for math-driven power values.
- Optional integration with Trinkets, Curios, Accessories, Figura, Icarus, and Hardcore Revival.
- Built for real servers: indexed power lookups, chunked network sync for large packs, and a versioned protocol that fails safely instead of desyncing.
Available for Fabric and NeoForge, on 1.20.1 and 1.21.1.
How to Install Overgrown's Apoli (Mod)
Overgrown's Apoli by Overgrown is verified for Fabric, Neoforge across Minecraft versions 1.20.1, 1.21.1 (latest release: 1.124.0, file size: 4.0 MB). Follow the steps below to install it safely from ModCraft.tv:
- Click the Download button above and select your Minecraft version (1.20.1, 1.21.1) and platform (Fabric, Neoforge).
- Make sure you have the compatible loader or environment installed for Fabric, Neoforge.
- Move the downloaded Overgrown's Apoli file into your Minecraft
.minecraft/modsfolder and launch the game.
All Versions
+ Add Version### Before you update
apoli:sneakyandapoli:share_effectsare gone, and a power that uses either one no longer loads. Both can be built from other powers.
### Removed:
apoli:sneaky and apoli:share_effectsapoli:sneaky and apoli:share_effects were both compositions of powers Apoli already has. For Sneaky, apoli:scale on apoli:visibility makes mobs notice the player from 80% of the usual distance. apoli:modify_label_render fades the nameplate and hides it past 32 blocks with an apoli:distance condition. apoli:replace_sound_emission mutes step sounds while apoli:on_block holds, and apoli:prevent_game_event stops the minecraft:step vibration. Foxes and the "Time Sneaked" statistic read vanilla's sneak flag directly, so those are the two things the composition doesn't cover.For Share Effects, an
apoli:action_over_time that runs an apoli:area_of_effect with apoli:transfer_effects does the same job. This one gives the holder's tamed pets within 8 blocks a copy of every effect the holder has, twice a second:``
json
{
"type": "apoli:action_over_time",
"interval": 10,
"entity_action": {
"type": "apoli:area_of_effect",
"radius": {
"x": 8,
"y": 2,
"z": 8
},
"bientity_condition": {
"type": "apoli:all_of",
"conditions": [
{
"type": "apoli:owner"
},
{
"type": "apoli:target_condition",
"condition": {
"type": "apoli:tamed"
}
}
]
},
"bientity_action": {
"type": "apoli:transfer_effects",
"mode": "give",
"copy": true
}
}
}
`
### Performance: apoli:attribute
Attribute powers now use less memory and CPU. They check their modifiers every tick. That is how the modifiers come back after a login or a reload, and how they follow a condition. The check used to build a lookup key, a string and a modifier id for every modifier on every holder, every tick, and on 1.20.1 it also hashed the id with MD5. Apoli now works out the ids once per power and reads the value it applies straight from the entity's own attribute. A power with four modifiers went from 1.1 KB of garbage and 1.1 µs per tick to none and 0.13 µs on 1.21.1, and from 2.8 KB and 1.7 µs to 64 bytes and 0.09 µs on 1.20.1. Apoli tests the condition once per power instead of once per modifier, and it no longer scans every attribute modifier in the world when an entity is removed.
## 1.123.0
### Before you update
- The voice chat and speech powers left Apoli for a new addon, Birdsong:
action_on_speak, action_on_reply, action_on_speech, modify_speaking_range, the five voice_* conditions and the voice_* expression variables. Install Birdsong to keep them working. Without it, packs that use the apoli: ids still load, but those powers do nothing, the conditions read false and the variables read 0.loading_priority` now decides between packs for global power sets and ori...### Before you update
apoli:sneakyandapoli:share_effectsare gone, and a power that uses either one no longer loads. Both can be built from other powers.
### Removed:
apoli:sneaky and apoli:share_effectsapoli:sneaky and apoli:share_effects were both compositions of powers Apoli already has. For Sneaky, apoli:scale on apoli:visibility makes mobs notice the player from 80% of the usual distance. apoli:modify_label_render fades the nameplate and hides it past 32 blocks with an apoli:distance condition. apoli:replace_sound_emission mutes step sounds while apoli:on_block holds, and apoli:prevent_game_event stops the minecraft:step vibration. Foxes and the "Time Sneaked" statistic read vanilla's sneak flag directly, so those are the two things the composition doesn't cover.For Share Effects, an
apoli:action_over_time that runs an apoli:area_of_effect with apoli:transfer_effects does the same job. This one gives the holder's tamed pets within 8 blocks a copy of every effect the holder has, twice a second:``
json
{
"type": "apoli:action_over_time",
"interval": 10,
"entity_action": {
"type": "apoli:area_of_effect",
"radius": {
"x": 8,
"y": 2,
"z": 8
},
"bientity_condition": {
"type": "apoli:all_of",
"conditions": [
{
"type": "apoli:owner"
},
{
"type": "apoli:target_condition",
"condition": {
"type": "apoli:tamed"
}
}
]
},
"bientity_action": {
"type": "apoli:transfer_effects",
"mode": "give",
"copy": true
}
}
}
`
### Performance: apoli:attribute
Attribute powers now use less memory and CPU. They check their modifiers every tick. That is how the modifiers come back after a login or a reload, and how they follow a condition. The check used to build a lookup key, a string and a modifier id for every modifier on every holder, every tick, and on 1.20.1 it also hashed the id with MD5. Apoli now works out the ids once per power and reads the value it applies straight from the entity's own attribute. A power with four modifiers went from 1.1 KB of garbage and 1.1 µs per tick to none and 0.13 µs on 1.21.1, and from 2.8 KB and 1.7 µs to 64 bytes and 0.09 µs on 1.20.1. Apoli tests the condition once per power instead of once per modifier, and it no longer scans every attribute modifier in the world when an entity is removed.
## 1.123.0
### Before you update
- The voice chat and speech powers left Apoli for a new addon, Birdsong:
action_on_speak, action_on_reply, action_on_speech, modify_speaking_range, the five voice_* conditions and the voice_* expression variables. Install Birdsong to keep them working. Without it, packs that use the apoli: ids still load, but those powers do nothing, the conditions read false and the variables read 0.loading_priority` now decides between packs for global power sets and ori...### Before you update
apoli:sneakyandapoli:share_effectsare gone, and a power that uses either one no longer loads. Both can be built from other powers.
### Removed:
apoli:sneaky and apoli:share_effectsapoli:sneaky and apoli:share_effects were both compositions of powers Apoli already has. For Sneaky, apoli:scale on apoli:visibility makes mobs notice the player from 80% of the usual distance. apoli:modify_label_render fades the nameplate and hides it past 32 blocks with an apoli:distance condition. apoli:replace_sound_emission mutes step sounds while apoli:on_block holds, and apoli:prevent_game_event stops the minecraft:step vibration. Foxes and the "Time Sneaked" statistic read vanilla's sneak flag directly, so those are the two things the composition doesn't cover.For Share Effects, an
apoli:action_over_time that runs an apoli:area_of_effect with apoli:transfer_effects does the same job. This one gives the holder's tamed pets within 8 blocks a copy of every effect the holder has, twice a second:``
json
{
"type": "apoli:action_over_time",
"interval": 10,
"entity_action": {
"type": "apoli:area_of_effect",
"radius": {
"x": 8,
"y": 2,
"z": 8
},
"bientity_condition": {
"type": "apoli:all_of",
"conditions": [
{
"type": "apoli:owner"
},
{
"type": "apoli:target_condition",
"condition": {
"type": "apoli:tamed"
}
}
]
},
"bientity_action": {
"type": "apoli:transfer_effects",
"mode": "give",
"copy": true
}
}
}
`
### Performance: apoli:attribute
Attribute powers now use less memory and CPU. They check their modifiers every tick. That is how the modifiers come back after a login or a reload, and how they follow a condition. The check used to build a lookup key, a string and a modifier id for every modifier on every holder, every tick, and on 1.20.1 it also hashed the id with MD5. Apoli now works out the ids once per power and reads the value it applies straight from the entity's own attribute. A power with four modifiers went from 1.1 KB of garbage and 1.1 µs per tick to none and 0.13 µs on 1.21.1, and from 2.8 KB and 1.7 µs to 64 bytes and 0.09 µs on 1.20.1. Apoli tests the condition once per power instead of once per modifier, and it no longer scans every attribute modifier in the world when an entity is removed.
## 1.123.0
### Before you update
- The voice chat and speech powers left Apoli for a new addon, Birdsong:
action_on_speak, action_on_reply, action_on_speech, modify_speaking_range, the five voice_* conditions and the voice_* expression variables. Install Birdsong to keep them working. Without it, packs that use the apoli: ids still load, but those powers do nothing, the conditions read false and the variables read 0.loading_priority` now decides between packs for global power sets and ori...Update the client, the server and Origins together.
### Before you update
- Custom status effects grant their powers from the source
apoli:effect/<namespace>/<path>instead of the effect's own ID. A data pack that checks or revokes those grants by source needs the new name. apoli:modify_xp_gainused to do nothing. Packs that already use it will now change experience gains.
### Added: apoli:connected_blocks
Runs a block action on every block connected to this one, nearest first, such as the rest of a tree or an ore vein. The starting block is not part of the group.
| Field | Type | Default | Description |
| --- | --- | --- | --- |
|
block_action | Block Action | required | Runs on each block in the group. ||
block_condition | Block Condition | optional | Which blocks belong to the group. Without it, the group is every block of the same type as the starting one. ||
diagonal | Boolean | true | Whether blocks that touch at an edge or corner count as connected. ||
downward | Boolean | true | Whether the search can spread downward. ||
limit | Integer | 64 | The most blocks in the group, 1 to 1024. ||
neighbor_condition | Block Condition | optional | The action only runs if a block next to the group matches this. ||
actor_condition | Entity Condition | optional | Checked on the entity behind the action before each block. The action stops the first time it fails. |Inside
block_action, count is the size of the group and index is the position of the current block. The search never loads chunks.``
json
{
"type": "apoli:connected_blocks",
"downward": false,
"limit": 256,
"neighbor_condition": {
"type": "apoli:all_of",
"conditions": [
{
"type": "apoli:in_tag",
"tag": "minecraft:leaves"
},
{
"type": "apoli:block_state",
"property": "persistent",
"value": false
}
]
},
"block_action": {
"type": "apoli:break_block",
"mine": true
}
}
`
### Added: mining as the player
apoli:break_block has a mine field. With true, the player behind the action mines the block: their tool takes durability, its enchantments apply and ores drop experience. The break is refused in spawn protection, adventure mode and claimed areas. A power does not fire again for blocks its own action breaks, so an action_on_block_break can mine more blocks without looping.
### Added: break speed that depends on a block group
apoli:modify_break_speed has a connected_blocks field that takes the same group fields as the block action. The expression variable count in the modifiers is the group's size. The group is worked out at most once per tick.
### Added: durability in expressions
durability[slot] reads how many uses the item in a slot has left. target_durability[...] and actor_durability[...]` do the same for the other entity's items.### Added: apoli:action_on_tame
Runs a bi-entity action (actor: the tamer, target:
...
Update the client, the server and Origins together.
### Before you update
- Custom status effects grant their powers from the source
apoli:effect/<namespace>/<path>instead of the effect's own ID. A data pack that checks or revokes those grants by source needs the new name. apoli:modify_xp_gainused to do nothing. Packs that already use it will now change experience gains.
### Added: apoli:connected_blocks
Runs a block action on every block connected to this one, nearest first, such as the rest of a tree or an ore vein. The starting block is not part of the group.
| Field | Type | Default | Description |
| --- | --- | --- | --- |
|
block_action | Block Action | required | Runs on each block in the group. ||
block_condition | Block Condition | optional | Which blocks belong to the group. Without it, the group is every block of the same type as the starting one. ||
diagonal | Boolean | true | Whether blocks that touch at an edge or corner count as connected. ||
downward | Boolean | true | Whether the search can spread downward. ||
limit | Integer | 64 | The most blocks in the group, 1 to 1024. ||
neighbor_condition | Block Condition | optional | The action only runs if a block next to the group matches this. ||
actor_condition | Entity Condition | optional | Checked on the entity behind the action before each block. The action stops the first time it fails. |Inside
block_action, count is the size of the group and index is the position of the current block. The search never loads chunks.``
json
{
"type": "apoli:connected_blocks",
"downward": false,
"limit": 256,
"neighbor_condition": {
"type": "apoli:all_of",
"conditions": [
{
"type": "apoli:in_tag",
"tag": "minecraft:leaves"
},
{
"type": "apoli:block_state",
"property": "persistent",
"value": false
}
]
},
"block_action": {
"type": "apoli:break_block",
"mine": true
}
}
`
### Added: mining as the player
apoli:break_block has a mine field. With true, the player behind the action mines the block: their tool takes durability, its enchantments apply and ores drop experience. The break is refused in spawn protection, adventure mode and claimed areas. A power does not fire again for blocks its own action breaks, so an action_on_block_break can mine more blocks without looping.
### Added: break speed that depends on a block group
apoli:modify_break_speed has a connected_blocks field that takes the same group fields as the block action. The expression variable count in the modifiers is the group's size. The group is worked out at most once per tick.
### Added: durability in expressions
durability[slot] reads how many uses the item in a slot has left. target_durability[...] and actor_durability[...]` do the same for the other entity's items.### Added: apoli:action_on_tame
Runs a bi-entity action (actor: the tamer, target:
...
Update the client, the server and Origins together.
### Before you update
- Custom status effects grant their powers from the source
apoli:effect/<namespace>/<path>instead of the effect's own ID. A data pack that checks or revokes those grants by source needs the new name. apoli:modify_xp_gainused to do nothing. Packs that already use it will now change experience gains.
### Added: apoli:connected_blocks
Runs a block action on every block connected to this one, nearest first, such as the rest of a tree or an ore vein. The starting block is not part of the group.
| Field | Type | Default | Description |
| --- | --- | --- | --- |
|
block_action | Block Action | required | Runs on each block in the group. ||
block_condition | Block Condition | optional | Which blocks belong to the group. Without it, the group is every block of the same type as the starting one. ||
diagonal | Boolean | true | Whether blocks that touch at an edge or corner count as connected. ||
downward | Boolean | true | Whether the search can spread downward. ||
limit | Integer | 64 | The most blocks in the group, 1 to 1024. ||
neighbor_condition | Block Condition | optional | The action only runs if a block next to the group matches this. ||
actor_condition | Entity Condition | optional | Checked on the entity behind the action before each block. The action stops the first time it fails. |Inside
block_action, count is the size of the group and index is the position of the current block. The search never loads chunks.``
json
{
"type": "apoli:connected_blocks",
"downward": false,
"limit": 256,
"neighbor_condition": {
"type": "apoli:all_of",
"conditions": [
{
"type": "apoli:in_tag",
"tag": "minecraft:leaves"
},
{
"type": "apoli:block_state",
"property": "persistent",
"value": false
}
]
},
"block_action": {
"type": "apoli:break_block",
"mine": true
}
}
`
### Added: mining as the player
apoli:break_block has a mine field. With true, the player behind the action mines the block: their tool takes durability, its enchantments apply and ores drop experience. The break is refused in spawn protection, adventure mode and claimed areas. A power does not fire again for blocks its own action breaks, so an action_on_block_break can mine more blocks without looping.
### Added: break speed that depends on a block group
apoli:modify_break_speed has a connected_blocks field that takes the same group fields as the block action. The expression variable count in the modifiers is the group's size. The group is worked out at most once per tick.
### Added: durability in expressions
durability[slot] reads how many uses the item in a slot has left. target_durability[...] and actor_durability[...]` do the same for the other entity's items.### Added: apoli:action_on_tame
Runs a bi-entity action (actor: the tamer, target:
...