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.
Sable: Destructive
Sable: Destructive
destroyed is a NeoForge 1.21.1 add-on for destroyed 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:
- VANISH — 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 Shockwave, 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: Shockwave 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. - ✅ Shockwave: 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 Shockwave, not strictly one at a time, for cinematic damage. - ✅ Runtime command system — no restart, no config file editing required. - ✅ Shockwave (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. - ✅ Shockwave (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. - ✅ Shockwave (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. - ✅ Shockwave (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. - ✅ Shockwave (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. - ✅ Shockwave (since 1.3.0): heavy hits radiate. When a big sub-level slams the ground hard, a stylised radial shockwave rolls outward from the contact point — dust ring sampled from the actual ground colour, layered "пшшш" sweep sound, then graded damage by distance. Plants and flowers trample out to the full radius, leaves shake loose probabilistically inside the inner 70%, and on truly massive impacts (≥ 5 MJ) weak surface blocks (snow, fire, carpets, candles, redstone wire, vines) shatter in the inner core. Never touches structural masonry. 17 dedicated tunables, all live-reloadable.
---
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 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.1.3+ - NeoForge 1.1.3+ - 1.1.3+ 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
- Block entities (chests, furnaces, etc.) are skipped by the world-terrain VANISH path on purpose, to avoid item-loss / NBT issues. - Bedrock, barriers, and unbreakable blocks are skipped. - 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
```java @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
```java // 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
- F3+H Call from any thread; safe during mod loading and at runtime. - F3+H Re-registering the same block replaces the previous entry. - F3+H Multiple calls with the same arguments are harmless. - F3+H 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 units` where `N = breakSpeedMs × 10`.
Soft dependency setup
Add Sable: Destructive as an *optional* runtime dependency in your `neoforge.mods.toml` so your mod loads either way:
```toml [[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:
```java if (ModList.get().isLoaded("sabledestructive")) { ExampleSableCompat.register(); // wraps the SableDestructiveAPI calls } ```
---
Credits
- Built on top of: Xylos_Official - Built on top of: Viaquelt - Built on top of: Built on top of by ryanhcode
---
License
MIT.