Compatibility
Minecraft: Java Edition
Platforms
Supported environments
Tags
Creators
Details
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.
- ✅ 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.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
- 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
@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
License
MIT.


