
Sable: Destructive
Sable: Destructive makes Sable physics blocks actually break. Real kinetic energy, inertial penetration, density-aware self-damage, radial shockwaves on heavy hits — fast hammers dig deep into dirt, soft hammers shatter against stone, big drops radiate.
- Загрузки
- 6K
- Подписчики
- 31
- Обновлён
- 19 мая 2026 г.
- Лицензия
- MIT
Опубликован 24 апреля 2026 г.
Sable: Destructive
Sable: Destructive is a NeoForge 1.21.1 add-on for Sable that turns physics blocks into something that can actually be destroyed. Crash a ship into the ground, set off a creeper next to a flying base, or drop an end crystal on a tank — Sable sub-levels now react to violence the way they should: chunks fly off, weak materials pulverize, and reinforced ones hold.
What it does
Out of the box, Sable gives you beautifully simulated physics blocks, but they are effectively indestructible. This add-on plugs directly into Sable's collision and explosion callbacks and decides, on every meaningful impact, whether the affected blocks should:
- DETACH — break off into a smaller, independent physics sub-level (default ~90% of impacts). The piece keeps flying, tumbling, and colliding on its own.
- VANISH — pulverize into particles + sound, with a fancy multi-layer effect (default ~10% of impacts). Used when the energy is high enough to truly shatter the material.
The choice between the two is not a flat dice roll. It is biased by real physics:
- Kinetic energy at the contact point (mass × v²) vs. material toughness.
- Block brittleness (leaves and grass shatter; obsidian and netherite resist).
- A safety speed ceiling so absurdly fast impacts don't spawn endless sub-levels.
You see the underlying numbers right in-game with F3 + H:
Mass: 540 kg
Impact strength: 20 m/s
Features
- ✅ Full impact handling for all 1.21.1 blocks, with a sensible mass + toughness table.
- ✅ Modded blocks default to the fragile end (clay-tier) so unknown blocks don't become indestructible bricks.
- ✅ Vanilla explosions are routed through the same path: TNT, creepers, end crystals, beds-in-the-Nether all damage Sable sub-levels.
- ✅ World terrain is also affected, but only via VANISH (never DETACH), so the world never turns into a runaway physics sim. There's a config flag to restrict damage to sub-level blocks only.
- ✅ Fancy VANISH effect: 3-layer particles (block-dust with the actual block texture, POOF, CRIT chips) + block break sound + soft "whump", with hard per-tick budgets so 500 simultaneous breaks don't tank your FPS.
- ✅ Crash-safe: every native call into Sable is wrapped, deferred to safe inter-tick windows, and guarded against
NaN/Inf, mid-step mutation, and cross-parent cluster errors. Years of "Minecraft just closed without a log" — fixed. - ✅ Cluster detach: blocks can break off in chunks, not strictly one at a time, for cinematic damage.
- ✅ Runtime command system — no restart, no config file editing required.
- ✅ Persistent config (since 1.2.0) at
config/sabledestructive-common.toml. Every value set via/sable-dv set …survives restarts, and editing the TOML on disk hot-reloads within ~250 ms. - ✅ Hand-tuned block table (since 1.2.0): ~70 of the most relevant 1.21.1 blocks — every wood species and the full stone family — carry their own mass and toughness instead of being lumped into one "wood" or "stone" bucket. Cherry is softer than oak. Mossy bricks crack a hair sooner than fresh ones. Slabs/stairs/walls/fences/doors/trapdoors/signs each get their own row. Other vanilla blocks continue to use the existing classification pipeline.
- ✅ Inertial penetration (since 1.1.0): impacts no longer stop at the first block. The attacker's kinetic energy is drained block-by-block along the motion direction by each consumed block's break cost (
0.5 · m · v_thr²). An obsidian hammer punches a deep crater into dirt and only chips the surface of stone, automatically. - ✅ Real damage (since 1.2.0): default damage roughly doubled, speed scales penetration depth and energy budget, and density actually matters — soft attackers no longer pretend to break hard surfaces.
- ✅ Self-damage (since 1.2.0): when the attacker is much softer than the defender, the defender survives AND the attacker erodes its own contact face. Copper hammer vs obsidian wall: copper sheds, wall stands.
- ✅ Real sub-level mass (1.6.0): the break decision and shockwave magnitude now read each sub-level's actual mass (kg) straight from Sable's own
ServerSubLevel#getMassTracker()— the same number Rapier uses for the physics body. Pre-1.6.0 every attacker was hard-coded to 2 t for break purposes, so a 100 kg flying chunk and a 500 t fortress felt identical. Now a fortress crushes obsidian from inertia while a thrown cobble bounces off stone. The structural-toughness gate also gets asqrt(refMass / realMass)relief factor, floored at 10×, so a 100 t crusher made of packed dirt pulverises stone but a Jell-O sub-level at any mass still can't peel bedrock. - ✅ Shockwave (rebuilt in 1.5.0, mass-driven in 1.6.0): only fires for genuinely substantial contacts. Magnitude is now driven by the real sub-level mass × an average-toughness constant (replacing the old 6-neighbour flood-fill, which capped at 1500 blocks and underestimated big ships). One radial dust burst plus a tall, slowly-rising semi-transparent dust column (mushroom shape, ~25% alpha, settles over 2–3 s) plus one heavy thud, with per-source dedup and a per-tick particle budget. Radius and toughness ceiling both scale with the cube root of magnitude — small waves rip leaves, giant waves carve a real crater. In DETACHING mode the wave still emits visuals and sound but only damages foliage.
- ✅ Universal toughness gates (1.5.0): every mode, DETACHING included, now applies four hard gates before any break can happen — infinite toughness (bedrock, barrier, command block, end portal frame, structure block) is rejected, vanilla
getDestroySpeed < 0is rejected, attacker-vs-defender toughness ratio is enforced (a 20-unit attacker cannot break a 120-unit defender no matter how fast it goes — it erodes its own contact face instead), and a raw speed-vs-breakSpeedMsgate filters out trivial bumps. Bedrock inside a sub-level is now actually unbreakable. - ✅ Spherical cluster detach (1.5.0): the cluster planner used to grow with a FIFO BFS, which on flat single-layer hulls produced 6-block-long strips along the surface. The new planner uses a distance-ordered priority queue and a hard Chebyshev radius cap of
ceil(cbrt(targetSize))around the seed, so clusters stay roughly spherical even on thin plating and a single-block contact can never spawn a line. - ✅ Localized tooltip (1.5.0): the F3+H
Toughness: N units/Toughness: indestructibleline uses translation keys and ships with English, Russian, German, Spanish, French, Portuguese (Brazil), Japanese, and Simplified Chinese. - ✅ Dot-product incidence (since 1.4.0): glancing blows actually glance. Damage scales with
(v · n)² / |v|²— a sideways scrape on a wall deals a fraction of a head-on hit at the same speed, with a configurable floor so it never reaches zero. - ✅ Collision modes (since 1.4.0, cleaned up in 1.5.0): one command swaps the entire collision behaviour. Three canonical modes:
/sable-dv mode delete— destruction only (VANISH, no new sub-levels spawn)./sable-dv mode detaching— default. Clean chunks peel off, nothing structural is silently deleted, world terrain is never touched, the shockwave only damages foliage./sable-dv mode delete-detaching— combo: seed peels off AND the inertial chain chews extra blocks deeper into the strike. Persistent across restarts.
Commands
All commands require op level 2.
/sable-dv on enable the system
/sable-dv off disable the system
/sable-dv toggle flip enabled
/sable-dv status current enabled state
/sable-dv mode show current collision mode
/sable-dv mode delete blocks only get destroyed
/sable-dv mode detaching default — clean chunks peel off
/sable-dv mode delete-detaching combo: seed detaches + chain breaks
/sable-dv config list list every tunable + current value
/sable-dv config get <name> read one value
/sable-dv config set <name> <value>
/sable-dv config reset <name>
Tunables include chanceDetach, chanceVanish, physicsBiasStrength, minBreakSpeed, absoluteMaxSpeed, detachSafeSpeedCeiling, maxDetachesPerSecond, maxActiveDetachedSubLevels, effects, fancyVanishEffect, affectOnlySubLevelBlocks, and many more.
Performance
Designed to stay quiet when nothing is happening, and not to fall over when everything is happening:
- Lock-free offer queue with atomic size counter and epoch-XOR dedup ring (8192 entries).
- Per-tick caps: 1024 offers, 600 vanish particles, 32 vanish effects.
- Spatial + temporal dedup on effects so big breaks don't audio-clip.
- Auto-scaling under backpressure; falls back to vanilla
levelEvent(2001)if the fancy pipeline is overloaded. - DETACH is always deferred to a safe tick boundary — never executed while Sable's physics system is mid-step.
Requirements
- Minecraft 1.21.1
- NeoForge 21.1.227+
- Sable 1.1.3+ (required dependency — the add-on does literally nothing without it)
- Sable's bundled libraries (Sable Companion, Veil) — these ship inside Sable's jar; you do not need to install them separately.
Compatibility
- Server + client. Effects are client-side; the destruction logic itself runs server-side.
- Should be compatible with most other mods. Modded blocks are auto-classified into a safe fragile tier.
Known limitations
- Bedrock, barriers, and unbreakable blocks are skipped (by design —
BlockToughness.Entry.UNBREAKABLEand the universal toughness gates make sure they survive even inside sub-levels). - Block entities (chests, furnaces, Create cogwheels, Mekanism cables, etc.) ARE broken since 1.6.1 but only via the VANISH path — peeling them into a new sub-level is opt-in via
allowBlockEntityDetach=trueand may corrupt mod-side network state. - Detach respects Sable's parent boundaries — clusters never cross sub-levels.
Addon API (since 1.1.0)
Sable: Destructive ships a small, stable, SemVer-covered public API so other mods can teach it about their blocks. Unknown modded blocks otherwise fall back to a deliberately fragile clay-tier default — register an entry and your block participates in real impact / explosion physics with the mass and toughness you choose.
The entire API lives in a single class: com.destroynautics.sabledestructive.api.SableDestructiveAPI. Anything outside that package is internal and may change between versions.
Quick example
@Mod("examplemod")
public class ExampleMod {
public ExampleMod(IEventBus bus) {
bus.addListener(this::onCommonSetup);
}
private void onCommonSetup(FMLCommonSetupEvent e) {
// Direct Block reference (recommended, type-safe):
SableDestructiveAPI.register(
ExampleBlocks.MITHRIL_BLOCK.get(),
8500.0, // mass in kg
SableDestructiveAPI.Tier.NETHERITE);
// By ResourceLocation (works even if the target Block class isn't loaded —
// useful for optional cross-mod compat):
SableDestructiveAPI.register(
ResourceLocation.fromNamespaceAndPath("othermod", "arcane_brick"),
3000.0,
SableDestructiveAPI.Tier.STONE);
// Custom raw values (advanced):
SableDestructiveAPI.register(
ExampleBlocks.FOAM_PANEL.get(),
40.0, // very light (kg)
0.8); // very fragile (~8 toughness units)
// Bedrock-equivalent:
SableDestructiveAPI.registerUnbreakable(ExampleBlocks.WARDSTONE.get());
}
}
Tier presets
Use SableDestructiveAPI.Tier instead of magic numbers — your blocks then stay balanced relative to vanilla as the mod's defaults evolve.
| Tier | Toughness (units) | Vanilla example |
|---|---|---|
PAPER |
10 | flowers, candles |
LEAF |
15 | leaves, vines |
EARTH |
20 | dirt, sand, gravel |
CLOTH |
30 | wool, hay, cobwebs |
SOFT |
40 | sponge, slime, snow |
CLAY |
60 | clay, ice, terracotta |
WOOD |
120 | logs, planks |
STONE |
200 | stone, cobble |
HARD_STONE |
280 | deepslate |
METAL_SOFT |
340 | gold, copper |
METAL |
420 | iron, anvil |
GEM |
520 | diamond, emerald |
OBSIDIAN |
700 | obsidian |
NETHERITE |
1000 | netherite, ancient debris |
REINFORCED |
2000 | reinforced deepslate |
UNBREAKABLE |
∞ | bedrock, barrier |
Method reference
// Register / override
SableDestructiveAPI.register(Block, double massKg, double breakSpeedMs)
SableDestructiveAPI.register(Block, double massKg, Tier tier)
SableDestructiveAPI.registerUnbreakable(Block)
// By ResourceLocation (optional cross-mod compat)
SableDestructiveAPI.register(ResourceLocation, double massKg, double breakSpeedMs)
SableDestructiveAPI.register(ResourceLocation, double massKg, Tier tier)
SableDestructiveAPI.registerUnbreakable(ResourceLocation)
// Inspect / remove
boolean SableDestructiveAPI.isRegistered(Block)
void SableDestructiveAPI.unregister(Block)
// Read-only queries (e.g. for your own tooltips / ballistics)
double SableDestructiveAPI.getMassKg(BlockState)
double SableDestructiveAPI.getBreakSpeedMs(BlockState)
double SableDestructiveAPI.getToughnessUnits(BlockState) // m/s × 10
Notes
- Thread-safe. Call from any thread; safe during mod loading and at runtime.
- Last write wins. Re-registering the same block replaces the previous entry.
- Idempotent. Multiple calls with the same arguments are harmless.
- Mass is in kilograms; the block is a 1m³ cube. Mass affects explosion kick scaling and diagnostics, not the break decision itself — that one is purely break-speed (m/s).
- F3+H tooltip displays
Toughness: N unitswhereN = breakSpeedMs × 10.
Soft dependency setup
Add Sable: Destructive as an optional runtime dependency in your neoforge.mods.toml so your mod loads either way:
[[dependencies.examplemod]]
modId = "sabledestructive"
type = "optional"
versionRange = "[1.1.0,)"
ordering = "AFTER"
side = "BOTH"
Then guard your registration call so it doesn't NoClassDefFoundError when Sable: Destructive isn't installed:
if (ModList.get().isLoaded("sabledestructive")) {
ExampleSableCompat.register(); // wraps the SableDestructiveAPI calls
}
Credits
- Author / code: Xylos_Official
- Visuals: Viaquelt
- Built on top of: Sable by ryanhcode
MIT License
Ченджлог
1.7.2Релиз1.21.1 · 19 мая 2026 г.
Built against Sable 1.2.2 (the API surface we use is stable from 1.1.3 → 1.2.2 — no source changes required, this is a recompile + diagnostics release).
What's new
Startup self-check. The very first INFO line in the log now reads
[Sable: Destructive] addon=1.7.2 sable=1.2.2(orsable=NOT LOADEDwith a loud warning if Sable is missing). Future API-mismatch reports become a two-line paste instead of a full log dump./sable-dv diag— live counters for "is the shockwave alive?":- Server waves emitted + packets actually sent
- BreakQueue throughput (offered / processed / pending / dropped by capacity vs. dedup)
- SubLevelMassResolver cache hit/miss/fallback rates
- Detected Sable runtime version
The command also prints a hint based on what it sees:
- Zero waves → magnitude / mass gate is filtering everything.
Lower
shockwaveMinMagnitudeorshockwaveMinAttackerMassUnits. - Waves but zero packets → no players inside
shockwaveClientHorizonBlocks. Stand closer or raise it. - Both non-zero → server is healthy; if the client sees nothing, install the addon CLIENT-side too.
Compiled against Sable 1.2.2 (
libs/sable-neoforge-1.21.1-1.2.2.jar). The 1.1.3-onlycompileOnly/localRuntimeentries inbuild.gradlewere swapped over so the IDE dev-runtime now matches the version most users have installed via Modrinth.
Crash report note (NOT Sable: Destructive)
- The Create / Registrate
chocolate_bucketNPE crash users have been seeing is a known Create 6.0.10 bootstrap-ordering bug. Our mod is not in that stack trace — we don't subscribe toRegisterEventor touch Create, Registrate, items, fluids, or advancements. Typical fix: remove duplicate Aeronautics jars (bundled + standalone), or redownload the Create jar if corrupt.
Requirements
- Minecraft 1.21.1, NeoForge 21.1.227+, Sable 1.1.3 or newer (tested on 1.2.2 — earlier 1.1.x still loads at runtime, only the registered Sable APIs we use need to exist).
MIT License
1.6.1Релиз1.21.1 · 19 мая 2026 г.
Hotfix for "модовые блоки не ломаются" — the callback was silently
skipping every block with an attached BlockEntity, which is the
overwhelming majority of modded machinery (Create cogwheels and
shafts, Mekanism cables, Applied Energistics buses, every chest /
furnace / hopper, etc.). That made the addon visually a no-op
against most non-vanilla builds.
Why it was skipped originally
- Pre-1.6.1 the callback assumed BE teardown was always fragile — Sable's sub-level assembler doesn't preserve BE NBT cleanly, and peeling a half-built contraption can corrupt its kinetic-network state on the modded side.
What changed
allowBlockEntityBreaks(new, defaulttrue). BE-bearing blocks ARE now broken on contact. The block is removed via an explicitlevel.removeBlockEntity(pos)BEFORE thesetBlock(AIR), so the BE's saved NBT is discarded cleanly and no vanilla on-remove side-effect can throw out of the callback.allowBlockEntityDetach(new, defaultfalse). Even when BE breaks are allowed, the outcome is forced to VANISH — never DETACH. Reason: Sable's assembler doesn't carry BE NBT into the new sub-level, so peeling a Create gearbox would instantly desync its kinetic network. VANISH discards the BE cleanly. Set totrueif you want the experimental "peel BEs too" behaviour (expect cosmetic issues on Create/Mekanism).safeSetAirnow explicitly removes any attached BlockEntity before airing the cell. Catches any throwable from the BE's own remove handler (Create kinetic teardown, Mekanism cable rebuild, etc.) so a third-party mod's on-remove bug can never escape into Sable's native bridge.
Compatibility
- Set
allowBlockEntityBreaks=falseinconfig/sabledestructive-common.tomlto restore the pre-1.6.1 "skip every BE block" behaviour. - All other 1.6.0 knobs and behaviour unchanged.
Requirements
- Minecraft 1.21.1, NeoForge 21.1.227+, Sable 1.1.3+
MIT License
1.6.0Релиз1.21.1 · 19 мая 2026 г.
The whole break/shockwave pipeline now reads each Sable sub-level's
ACTUAL mass (in kg) from Sable's own MassData tracker instead of
treating every attacker as a hard-coded 2000 kg "default ship". Per
the Sable wiki, every block carries a sable:mass property (kpg);
ServerSubLevel#getMassTracker().getMass() returns the sum that the
physics pipeline itself uses for Rapier. We just read it.
This single change fixes the long-standing complaint that "a tiny flying chunk feels exactly as heavy as a 5000-block ship": below, the same 12 m/s impact now produces three very different outcomes depending on the attacker's real mass.
What is new
SubLevelMassResolver— single source of truth for per-sub-level mass. O(1) per call (queriesServerSubLevel#getMassTracker()), per-tick identity-keyed cache, defensive fallback todefaultAttackerMassKgon any Sable-side failure. Hard-capped atsubLevelMassHardCapKg = 1e8 kgto prevent a corrupted physics tick from making the energy budget infinite.Mass-aware kinetic-energy budget.
BreakResolver.shouldBreakStatewas already a kinetic-energy formula, but it was always fed 2000 kg. Now it sees the real attacker mass, so:- A 100 kg flying cobblestone at 12 m/s = 7 200 J → bounces off stone (budget 18 kJ).
- A 50 t small ship at 12 m/s = 3.6 MJ → punches stone wide open.
- A 500 t fortress at 6 m/s = 9 MJ → grinds through obsidian. The reduced-mass term µ = m1·m2/(m1+m2) means a feather-light attacker still cannot pulverize a heavy defender — the math collapses to the attacker's own KE budget.
Mass-aware structural-toughness gate. The "soft attacker can't pierce hard defender" rule (
attackerToughnessRatio) now has a mass relief factor: the required attacker toughness is scaled bysqrt(massToughnessReferenceKg / realMass), floored atmassToughnessReliefFloor. A 100 t crusher made of packed dirt WILL pulverize stone purely from inertia; a thrown dirt clump won't. Defaults:massToughnessReferenceKg = 4000,massToughnessReliefFloor = 0.1(so at most a 10× relief — a fully soft Jell-O sub-level can never bypass the gate entirely).Shockwave magnitude now uses the same real mass. The bespoke flood-fill (
computeAttackerMassUnits, O(N) up to 1500 blocks per emit) is no longer the primary path — whenuseSubLevelMass=truewe feed Sable's mass tracker ×shockwaveAvgToughnessUnits(= 120, i.e. V_STONE × 10) so all existing magnitude thresholds keep their meaning. Flood-fill remains as the fallback for the unlikely case where the mass tracker has not been built yet. Net result: shockwave emission is now O(1) per impact and reflects the real ship size, not a 6-neighbour sample of it.New persistent config knobs (TOML hot-reload as usual):
useSubLevelMass(bool, default true)subLevelMassHardCapKg(kg, default 1e8)massToughnessReferenceKg(kg, default 4000)massToughnessReliefFloor(×, default 0.1)shockwaveAvgToughnessUnits(units, default 120)
What is fixed
"Two tiny dirt blocks shouldn't break obsidian by being heavy" — was actually still happening for SHIP-vs-OBSIDIAN because the callback was hard-coding 2000 kg. With real mass, a 200 kg dirt fragment now correctly fails the gate AND fails the energy budget.
Heavy ships landing softly used to bounce indefinitely because every contact was rated at 2000 kg @ low speed = 144 kJ, below every threshold. They now report their real mass, so a 100 t ship setting down at 4 m/s = 800 kJ punches through dirt/wood as expected.
Shockwave was firing inconsistently for big builds because the flood-fill capped at
shockwaveMassFloodCap = 1500blocks underestimated ships larger than that. The real mass tracker has no such cap.
Backward compatibility
useSubLevelMass=falserestores the pre-1.6.0 behaviour exactly (hardcodeddefaultAttackerMassKg, flood-fill for shockwave).- All existing config keys preserved with the same defaults.
BreakResolver.shouldBreakState(...)signature unchanged.ShockwaveEffect.emit(level, center, energy)overload kept; a newemit(level, center, energy, attackerMassKgHint)overload is preferred by callers that already have the resolved mass.
Requirements
- Minecraft 1.21.1
- NeoForge 21.1.227+
- Sable 1.1.3+ (uses
ServerSubLevel#getMassTracker())
Credits
- Code: Xylos_Official
- Visuals: Viaquelt
- Built on top of Sable by ryanhcode
MIT License
1.5.0Релиз1.21.1 · 19 мая 2026 г.
A major rework of the damage pipeline and the shockwave effect. This release responds to two specific 1.4.0 reports:
- "блоки АБСОЛЮТНО все пропадают" — in DETACHING mode (the default), a routing bug silently turned almost every contact into a VANISH instead of a real sub-level peel.
- "звуковые волны после 1.4.0 пропали" — the shockwave was
gated behind
mode != DETACHING, so with the default mode it never fired at all.
Both are fixed, and the underlying systems were reworked rather than patched.
What is new
DETACH-FIRST damage. Block contacts now peel from the parent sub-level into a fresh physics body by default. VANISH is reserved for genuinely tiny debris (and for the explicit
/sable-dv mode delete). ThechanceDetachdefault is now 0.92 /chanceVanish0.08.World terrain is no longer touched in DETACHING mode. In 1.4.0 a routing bug sent the world side of every contact pair down a branch that VANISH'd the terrain — that was the "all blocks disappear" report. The actual mechanic:
- Sable invokes
BlockSubLevelCollisionCallbackONLY for sub-level blocks (never for world terrain), so there is no world-side classification to do. The earlier 1.5.0 attempt added an explicitgetContaining(level, plotPos)check that always returnednullbecause plot-region coords are disjoint from world coords — that mis-classified 100% of contacts as "world terrain" and silently skipped them, so destruction stopped happening altogether. Removed. - DETACHING mode now reliably peels every qualifying contact.
- DELETE / DELETE_DETACHING are unchanged.
- Sable invokes
Real shockwave model. Triggered only when a BIG, HEAVY object lands at speed — not by small bumps. Three independent gates:
- Approach speed ≥
shockwaveMinApproachSpeed(default 12 m/s) - Impact energy ≥
shockwaveMinEnergy(default 2 MJ) - Attacker mass ≥
shockwaveMinAttackerMassUnits(default 400 000 — equivalent to ~200 stone blocks of summed mass × toughness around the contact point) - Combined magnitude ≥
shockwaveMinMagnitude(default 1.5 MJ) A single cobble flying around can never produce a wave. A five-thousand-block stone ship hitting the ground at 6 m/s does.
- Approach speed ≥
Shockwave fires in EVERY mode. In 1.4.0 it was buried inside the inertial-penetration block, which itself ran only when
mode != DETACHING. The emission is now outside that gate so big landings produce dust + a heavy thud regardless of mode.Shockwave visuals/audio optimized. One radial dust burst (replacing three expanding rings), a rising dust column at the impact point, a single heavy "thud" sound — instead of three layered sand/wool/explosion sounds. Per-source dedup window, per-second global rate-limit, and a per-tick particle budget so back-to-back impacts cannot tank FPS.
Magnitude drives radius AND ceiling. Radius scales as
cbrt(magnitude / reference) × radiusMultiplier. The toughness ceiling on what the wave can break scales with the same factor and falls off linearly to the radius edge, so a small wave only rips leaves and dirt while a giant landing carves a real crater into stone.
What is fixed
Bedrock and other unbreakable blocks are now actually safe inside sub-levels. The DETACHING branch used to bypass every break gate, which meant a physics bedrock could be peeled by any contact. The callback now applies four universal gates (in EVERY mode, DETACHING included):
- Reject if defender toughness is infinite (bedrock, barrier, command block, end portal frame, structure block, …).
- Reject if vanilla
getDestroySpeed < 0. - Reject if attacker toughness ×
attackerToughnessRatiois below defender toughness (a 20-unit block cannot break a 120-unit block by ramming it at any speed — the soft attacker erodes its own contact face instead). - Reject if approach speed ×
collisionStrengthMultiplieris below the defender's break-speed threshold. The shockwave damage pass now also skips infinite-toughness blocks, so a giant landing never carves a hole in bedrock.
Cluster detach no longer produces long strips. The BFS used a FIFO deque + shuffled directions, so on a flat 1-block-thick hull the only available neighbours were tangential and the chunk grew along the surface as a line — the user's "ломается полосками длинным" report. The planner now uses a distance- ordered priority queue and a hard Chebyshev radius cap of
ceil(cbrt(targetSize))around the seed. Clusters stay spherical even on thin surfaces, and a single-block contact can never spawn a 6-long row.Shockwave gates relaxed back to sane gameplay levels. The previous defaults (12 m/s, 2 MJ, 400 000 mass-units, 1.5 MJ magnitude) were tuned for the broken pre-fix 1.5.0 build and made the wave effectively unreachable. New defaults:
shockwaveMinApproachSpeed= 5 m/sshockwaveMinEnergy= 100 000 JshockwaveMinAttackerMassUnits= 50 000 (~25 stone blocks)shockwaveMinMagnitude= 200 000 Small bumps still don't trigger because the per-source dedup window (250 ms), per-second cap (6/s), and real flood-fill of the attacker's mass × toughness filter out everything that isn't a substantial body landing.
Shockwave decision no longer pre-gated in the callback. The callback used
defaultAttackerMassKg(2000 kg) for the pre- energy check, which never crossed the threshold at gameplay speeds, soShockwaveEffect.emit()was never called. The pre-gate is removed; the effect's own real-mass gates decide.Shockwave dust completely redone. Old build used POOF + a single block-dust grain per ring point — opaque and short-lived. New build:
- Radial low-altitude burst pushed outward with small outward velocity (CLOUD particles mixed with tinted ground-coloured BLOCK dust).
- A tall, narrow, slowly-rising dust column at the impact point, scaling with radius — the "поднимается вверх" mushroom you wanted.
- CLOUD particles render with naturally semi-transparent edges (~25% alpha) and live 2–3 s before fading, giving the "медленно оседает" look without us having to ship a custom particle texture. The dust now reads as real impact dust rather than the old three-band ring spam.
DETACHING mode never destroys structural blocks via the shockwave. The wave still emits visuals + sound in DETACHING, but the damage pass is foliage-only (plants and leaves) — consistent with "DETACHING = nothing is destroyed".
minBreakSpeedraised 6 → 10 m/s. The old default let tiny bumps register as full break candidates, which combined with the missing toughness gate produced the "блоки ломаются от малого шороха" report. Combined with the new toughness gate above, light contacts are now properly ignored.Toughness tooltip is now translatable. The F3+H "Toughness: N units" line uses
Component.translatableand ships with eight languages: English, Russian, German, Spanish, French, Portuguese (Brazil), Japanese, and Simplified Chinese.
Previous 1.5.0 fixes (kept):
- DETACHING world-side regression fixed (see above).
- Per-tick detach drain budget corrected (÷20+1).
- Inertial chain cursor sync.
CONSECUTIVE_ERRORS→ AtomicInteger.- Lifecycle hooks clear ShockwaveEffect + VanishEffect caches.
Compatibility
- Old 1.x worlds load as-is. New 1.5.0 shockwave fields are added to the TOML on next save (reflective config — no manual migration needed).
- Mode names unchanged:
delete,detaching,delete-detaching. Default stilldetaching. - Addon API unchanged;
API_VERSIONremains 1.
Requirements
- Minecraft 1.21.1
- NeoForge 21.1.227+
- Sable 1.1.3+
Credits
- Code: Xylos_Official
- Visuals: Viaquelt
- Built on top of Sable by ryanhcode
MIT License
1.4.0Релиз1.21.1 · 19 мая 2026 г.
The command /sable-dv mode <name> switches the behavior of the collision system as a whole. The default mode is now detaching.
What is there
/sable-dv mode delete- blocks only break (VANISH). No new sub-levels. The inertial chain works, and the world breaks through VANISH./sable-dv mode default— alias todetaching(new default)./sable-dv mode detaching— new default behavior. The hit detaches the block from the parent sub-level and spawns a separate sub-world that inherits the speed and flies apart in different directions. Nothing is destroyed — the pieces are physically detached. Self-damage and inertial chain are disabled. The world (terrain) breaks through VANISH (the world cannot be torn off as a sub-level)./sable-dv mode delete-detaching— combo: the starting block detaches, the inertial chain additionally breaks the blocks deeper. Maximum chaos.
What is fixed
- Shockwaves (shockwave) no longer trigger at every sneeze. Now there are two independent thresholds:
- Minimum approach speed (
shockwaveMinApproachSpeed, default 18 m/s) - cuts off settle/jitter contacts. - Minimum energy (
shockwaveMinEnergy, default 8 MJ instead of 250 kJ) - cuts off light impacts. - The shockwave system itself is now disabled by default
(
shockwaveEnabled = false). To enable it, use/sable-dv set shockwaveEnabled true.
- Minimum approach speed (
- Epic Shatter on Impact - A boulder thrown into a mountain now really shatters:
- On a hard impact, the cluster collapses to single blocks (small pieces instead of a single large brick).
- Each broken piece has a random spread along all axes + a random rotation, scaled by the approach velocity.
- Kick limits raised:
detachKickScale 0.4 → 1.5,detachMaxKickSpeed 6.0 → 25.0. - New parameters
detachShatterScatter(default 6.0) anddetachSpinScatter(default 6.0) - adjustable scatter and spin.
What is removed
- The typo
delete-detachinggis no longer accepted. Only canonical names:delete,default,detaching,delete-detaching.
Compatibility
- Old 1.3.0 worlds are loaded as is. If TOML had
collisionMode = "default"— behavior is nowdetaching(by new default). - Mod API (Addon API) has not changed, API_VERSION remains 1.
Requirements
- Minecraft 1.21.1
- NeoForge 21.1.227+
- Sable 1.1.3+
Authors
- Code: Xylos_Official
- Visual part: Viaquelt
- Based on Sable by ryanhcode
License MIT
1.3.0Релиз1.21.1 · 25 апреля 2026 г.
Heavy hits now radiate. When a big sub-level slams the ground hard enough, a stylised shockwave rolls outward from the contact point — dust ring, "пшшш" sweep sound, then graded damage by distance.
What changed
New: Shockwave effect. Triggered when total impact kinetic energy passes shockwaveMinEnergy (default 250 kJ ≈ 4000 kg @ 11 m/s). Bigger impacts produce bigger waves — radius scales as sqrt(E / shockwaveReferenceEnergy) × shockwaveRadiusMultiplier, hard-capped at shockwaveMaxRadius.
3-tier graded damage:
- Plants & flowers: trampled out to the full radius. Tall grass, saplings, ferns, mushrooms, sugar cane, lily pads, sweet berry bushes, glow lichen, moss carpets, nether sprouts, roots — all of these get flattened.
- Leaves: 35% per-block break chance inside the inner 70% of the radius (linear falloff with distance).
- Weak blocks: only on really heavy hits (≥ 5 MJ by default). 60% chance per block inside the inner 35%, restricted to structurally weak blocks (snow, fire, carpets, candles, redstone wire, vines, wool, hay, cobwebs, torches, ladders) AND capped at shockwaveBlockToughnessCeiling. Nothing serious gets griefed.
Visual: 3 expanding rings of POOF + CLOUD particles plus a single block-dust burst sampled from the actual ground colour underneath the impact, so a wave on grass looks green-brown and a wave on sand looks tan.
Audio: layered SAND_BREAK + WOOL_BREAK + low-pitched explosion for the satisfying "пшшш … thump" sweep.
Crash-safety: shockwave never spawns sub-levels, never touches tile entities, never breaks bedrock-class blocks, all mutations wrapped in try/catch. Failure of the visual pipeline never blocks the destruction pipeline.
New tuning knobs (all auto-persisted to config/sabledestructive-common.toml, all live-reloadable):
- shockwaveEnabled (default true)
- shockwaveMinEnergy (default 250000.0)
- shockwaveReferenceEnergy (default 1000000.0)
- shockwaveRadiusMultiplier (default 6.0)
- shockwaveMaxRadius (default 32)
- shockwaveVerticalRange (default 3)
- shockwavePlantChance (default 1.0)
- shockwavePlantRadiusFraction (default 1.0)
- shockwaveLeafChance (default 0.35)
- shockwaveLeafRadiusFraction (default 0.7)
- shockwaveBlockChance (default 0.6)
- shockwaveBlockRadiusFraction (default 0.35)
- shockwaveBlockEnergyThreshold (default 5000000.0)
- shockwaveBlockToughnessCeiling (default 30.0)
- shockwaveParticlesPerBlock (default 18)
- shockwaveMaxParticles (default 800)
- shockwaveSoundVolume (default 1.0)
Compatibility
- No breaking changes for end users. Existing 1.2.0 worlds load as-is. The Addon API is unchanged (API_VERSION still 1).
- To completely disable: /sable-dv set shockwaveEnabled false
- To raise the threshold so only enormous hits trigger: /sable-dv set shockwaveMinEnergy 5000000.0
Requirements
- Minecraft 1.21.1
- NeoForge 21.1.227+
- Sable 1.1.3+
Credits
- Code: Xylos_Official
- Visuals: Viaquelt
- Built on top of Sable by ryanhcode
License
- MIT
1.2.0Релиз1.21.1 · 25 апреля 2026 г.
1.1.0 introduced inertial penetration but kept the per-block thresholds conservative — collisions still felt cosmetic. 1.2.0 retunes the damage model from the ground up so impacts feel like impacts.
What changed
Default damage is roughly doubled across the board.
- collisionEnergyMultiplier 1.0 → 2.0
- collisionStrengthMultiplier 1.0 → 1.5
- penetrationEnergyMultiplier 1.0 → 0.6 (each consumed block costs less, so chains run further on the same energy)
- maxPenetrationDepth 16 → 32
- defaultAttackerMassKg 2000 → 4000
Speed actually matters now. Two new knobs scale the penetration walk by approach speed:
- penetrationSpeedEnergyBonus = 0.02 → +2% kinetic-energy budget per m/s above minBreakSpeed. At 50 m/s above the gate that's +100% budget — fast hits chain dramatically further.
- penetrationDepthPerMs = 0.25 → each m/s above minBreakSpeed extends the depth cap by 0.25 blocks. At 80 m/s a hammer can chain ~18 blocks past the static cap.
Density actually matters now. The callback no longer hands attackerHardness=0 to BreakResolver — it now passes V_WOOD as a sensible default sub-level toughness plus the configured defaultAttackerMassKg. The asymmetry rule (attackerToughnessRatio) finally engages: a wooden cog smacked into stone won't shatter the stone, an iron block into wood will.
Self-damage. New: when the attacker is much softer than the defender (attacker toughness < defender · selfDamageThreshold, default 0.6), the defender survives AND the attacker erodes its own contact face for up to selfDamageMaxBlocks (default 4) blocks. A copper hammer slamming an obsidian wall now sheds copper from itself instead of the wall doing nothing — finally that "soft bounces off hard" feel.
All chain-broken AND self-damage blocks always VANISH (never DETACH) — same crash-safety rule as 1.1.0.
New tuning knobs (all auto-persisted to config/sabledestructive-common.toml, all live-reloadable):
- selfDamageThreshold (default 0.6)
- selfDamageMaxBlocks (default 4)
- penetrationSpeedEnergyBonus (default 0.02)
- penetrationDepthPerMs (default 0.25)
Tweaked defaults (existing knobs):
- collisionEnergyMultiplier 1.0 → 2.0
- collisionStrengthMultiplier 1.0 → 1.5
- penetrationEnergyMultiplier 1.0 → 0.6
- maxPenetrationDepth 16 → 32
- defaultAttackerMassKg 2000.0 → 4000.0
Compatibility
- No breaking changes for end users. Existing 1.1.0 worlds load as-is. The Addon API is unchanged (API_VERSION still 1).
- To restore 1.1.0 feel exactly, set the five "tweaked defaults" above back to their previous values via /sable-dv set.
- To completely disable inertial chains and self-damage: /sable-dv set inertialPenetrationEnabled false /sable-dv set selfDamageMaxBlocks 0
Requirements
- Minecraft 1.21.1
- NeoForge 21.1.227+
- Sable 1.1.3+
Credits
- Code: Xylos_Official
- Visuals: Viaquelt
- Built on top of Sable by ryanhcode
License
- MIT
1.1.0Релиз1.21.1 · 25 апреля 2026 г.
This is a big quality-of-life pass on top of 1.0.0. The destruction system now feels meaningful instead of cosmetic: a heavy hammer actually digs into the ground, dirt yields deeper craters than stone, modded blocks have a clean integration path, and every tunable you change at runtime survives a server restart.
New — Inertial Penetration
- Impacts no longer stop at the first block. The attacker's kinetic energy is drained block-by-block along the motion direction by each consumed block's break cost (0.5 · m_def · v_threshold²).
- An obsidian hammer punches a deep crater into dirt and only chips the surface of stone — automatically, no per-block scripting.
- Chain-broken blocks always VANISH. Only the FIRST contact block may DETACH, because spawning new sub-levels mid-walk is the historic native-crash trigger and is intentionally forbidden here.
- Stops on tile entities, indestructible blocks, world bounds, energy exhaustion, or maxPenetrationDepth.
- New knobs: inertialPenetrationEnabled (default true), maxPenetrationDepth (16), penetrationEnergyMultiplier (1.0), defaultAttackerMassKg (2000.0).
New — Public Addon API
- com.destroynautics.sabledestructive.api.SableDestructiveAPI lets other mods register their own blocks into the destruction system with custom mass and toughness — no more falling back to the fragile clay-tier default for unknown modded blocks.
- Register by Block instance (type-safe) or by ResourceLocation (works even if the target Block class isn't loaded — ideal for optional cross-mod compat).
- Tier presets matching the internal scale: PAPER, LEAF, EARTH, CLOTH, SOFT, CLAY, WOOD, STONE, HARD_STONE, METAL_SOFT, METAL, GEM, OBSIDIAN, NETHERITE, REINFORCED, UNBREAKABLE.
- registerUnbreakable(Block / ResourceLocation) — bedrock-equivalent shortcut.
- Read-only queries: getMassKg, getBreakSpeedMs, getToughnessUnits — useful for your own tooltips or ballistics.
- isRegistered / unregister for runtime control.
- Thread-safe, idempotent, last-write-wins.
- API_VERSION = 1, covered by SemVer. Anything outside the api package is internal and may change without notice.
New — Persistent Config
- Tunables now live in config/sabledestructive-common.toml. Every value set via /sable-dv set … survives server restarts.
- Live auto-reload: edit the TOML on disk and the change applies within ~250 ms — no restart, no command, no reconnect.
- /sable-dv config reset now actually restores defaults (was a no-op in 1.0.0).
- Config writes are debounced and the watcher ignores its own writes, so toggling values from chat doesn't trigger a redundant reload.
New — Hand-Tuned Block Table
- ~70 of the most relevant 1.21.1 blocks — every wood species and the full stone family — carry their own hand-tuned mass and toughness rather than being lumped into a generic "wood" or "stone" bucket.
- Cherry is softer than oak. Mangrove is denser than spruce. Mossy bricks crack a hair sooner than fresh ones. Slabs, stairs, walls, fences, doors, trapdoors, signs and pressure plates each get their own entry.
- All other vanilla blocks continue to use the existing classification pipeline (tag → registry path → vanilla material), so behaviour is unchanged for blocks not in the override table.
Tweaks
- Modded blocks default break-speed halved (2.0 m/s → 1.0 m/s) — even more fragile than vanilla leaves, encouraging addons to register explicit values via the new API.
- Modded max break-speed cap halved (V_CLAY → V_CLAY / 2) — modded blocks can no longer silently rival vanilla wood without explicit registration.
Tooltip
- F3+H now shows "Toughness: N units" instead of "Mass: X kg / Impact strength: Y m/s". Mass is no longer surfaced in the tooltip — it's an internal physics input, not a durability measure. N = break-speed × 10.
Documentation
- Full API documentation added to the long Modrinth description, including a soft-dependency setup snippet for neoforge.mods.toml.
- New sections covering Persistent Config, the Block Toughness table, and Inertial Penetration semantics.
License
- Switched from All-Rights-Reserved to MIT.
No breaking changes for end users. Existing 1.0.0 worlds load as-is. Disable inertial penetration with /sable-dv set inertialPenetrationEnabled false to restore the pre-1.1.0 "one block per contact" behaviour.
Requirements
- Minecraft 1.21.1
- NeoForge 21.1.227+
- Sable 1.1.3+
Credits
- Code: Xylos_Official
- Visuals: Viaquelt
- Built on top of Sable by ryanhcode
License
- MIT
Комментарии
Загружаем…