
Список изменений
Allium v0.2.14a
Wiki: https://github.com/castledking/Allium/wiki
Highlights
- Slime Jump bounces for real — Landing on a slime mob now cancels the fall damage and launches you back up. In v0.2.13a the bounce velocity was set inside the
EntityDamageEventhandler, and the server wiped it the moment the event finished, so the bounce never happened (and you still took damage). The velocity is now applied on the next tick, and the damage is cancelled outright instead of halved. - The Mob Disarmer covers more of the mob book — Endermen's carried block is stripped and dropped as a guaranteed item, and sulfur cubes are sheared through Paper's vanilla path so the absorbed block always comes out. A disarmed mob is also blocked from picking its own equipment back up for two minutes, ending the loop where a zombie re-equipped its sword before the pieces had finished rolling.
- Both charged tools are far less suicidal — The break chance on the first two uses dropped from 5% to 3%, and the "risky" final use from 25% to 5% on the Mob Disarmer and Phantom Obliterator alike.
- Dropping idle handcuffs no longer eaten — Dropping a cuff family with nobody restrained used to spam "No one is currently restrained by you." and consume the drop. Now only the family that is actively restraining someone is intercepted as the release/cancel control; an idle family drops like any other item.
- Command visibility rules pinned by tests — The tab-complete filtering was extracted into pure functions and is now covered by unit tests that fix the relationship between the execution list and the tab-completion list.
Technical Details
Slime Jump bounces for real
SlimeJump previously listened for fall damage, multiplied it by damageReductionFactor, and set the player's velocity synchronously inside the handler. Two things were wrong:
- The server applies its own landing velocity after the damage event completes, so any velocity set in the handler was overwritten before the next tick. The bounce never actually happened — all the code did was halve the fall damage.
- The damage reduction silently depended on a
damageReductionFactorthat was not exposed in config, and the "cushioned" message fired only once per player for the lifetime of the server process.
The listener now works the way the feature implies:
- When a player takes fall damage while a slime mob sits within the 2-block check radius below them, the
EntityDamageEventis cancelled entirely — no damage is taken. - The bounce velocity is computed from the damage that would have been taken (
damage × bounceMultiplier, capped atmaxBounceVelocity, currently 0.2 and 2.0), preserving 80% of horizontal momentum. - The velocity is applied via
SchedulerAdapter-freeplugin.getServer().getScheduler().runTask(...)on the next tick, after the server's landing logic has finished, so the launch survives.
The damageReductionFactor field and constructor parameter were removed; the registration in PluginStart and the default constructor were updated to match.
Mob Disarmer: new targets
The disarm gate used to require EntityEquipment with something on it, which excluded two mobs whose loot lives outside that system:
| Target | What changed |
|---|---|
| Enderman | getCarriedBlock() is read, the block is cleared with setCarriedBlock(null), and it is dropped as an item with a guaranteed 100% chance — it was never in EntityEquipment, so an enderman carrying grass was previously "empty". |
| Sulfur cube (Chaos Cubed, MC 26.2) | SulfurCube#shear() is called through Paper's vanilla shearing path, but only when readyToBeSheared() says natural shears would work. The cube's absorbed block drops at 100% with the usual sounds and effects; an empty cube is left untouched and no charge is spent. |
Both are counted in the "piece(s) removed" report the tool prints after a disarm.
Two minutes of no pickup
MobPickupSuppression (new, items/impl/) stops a freshly disarmed mob from re-equipping the same drops. It writes a mob_disarmer_pickup_blocked_until epoch-millis deadline into the mob's persistent data container when the Disarmer fires, and MobDisarmerListener cancels EntityPickupItemEvent for non-player entities at HIGHEST priority while that deadline is in the future. Once it passes, the key is removed and the mob behaves normally.
The deadline is in the PDC rather than a map, so it survives plugin restarts, and the code deliberately leaves the mob's vanilla CanPickUpLoot flag untouched — that flag varies by mob type and spawn path, and rewriting it would be a permanent behavioural change for the entity.
Gentler tools
Both charged tools from v0.2.13a had their break chances softened:
| Use | Before | After |
|---|---|---|
| First and second uses | 5% | 3% |
| Final (last charge) use | 25% | 5% |
The design rationale is unchanged — the last use is still riskier so players cannot safely reset the recharge timer — but a 25% chance of destroying a fully-charged tool on the final swing was too punishing.
Handcuff drop behaviour
onPlayerDropItem filters the restrained players by the family of the dropped cuffs (staff vs claim). Previously, dropping a family with nobody restrained sent "No one is currently restrained by you." and cancelled the drop — which meant a player restraining someone with the staff family could not drop an idle claim-cuff stack, and vice versa. That early-return is now a plain return, so only the family that is actively restraining someone is treated as the release/cancel control, and idle cuffs drop like any other item.
Command visibility rules, now pure and tested
The PlayerCommandSendEvent filtering was split out of onCommandSend into two static, side-effect-free functions — shouldAllowTabComplete(List<CommandGroup>, String) and filterRootCommands(...) — with CommandGroup loosened to package-private so tests can construct real groups. The extracted code is behaviour-identical; the new CommandVisibilityRulesTest pins down the intended semantics:
- A whitelist group's executable commands stay hidden from tab completion unless they are also listed in the group's
tabCompletes— being allowed to run a command no longer implies it is visible. tabCompletescan expose a command that is not in the execution list at all.- Blacklist tab rules hide roots independently of the command rules.
Verification
The Maven suite passes with 170 tests, up from 161. Four new test classes:
| Test | Coverage |
|---|---|
EndermanCarriedBlockTest (2) | stripCarriedBlock clears and returns the carried block, and ignores empty-handed endermen |
MobPickupSuppressionTest (2) | Pickups are cancelled up to the two-minute deadline and allowed once it expires; a persisted deadline survives a plugin restart |
SulfurCubeShearingTest (2) | A cube with ejectable content is sheared exactly once; an empty cube is left untouched |
CommandVisibilityRulesTest (3) | Whitelist executable commands stay hidden unless tab-listed; tab-listing exposes independently; blacklist tab rules hide independently |
The Slime Jump bounce, the enderman strip, the sulfur-cube shear and the handcuff drop behaviour need a live Paper/Canvas server (the bounce in particular is a server-timing fix) and were verified in game rather than by unit test.
