1.0.1
Compatibility
Changes
StateStream Changelog
1.0.1 — Multi-loader support, critical fixes, major performance pass
Loader support
- NEW: Native NeoForge build (
statestream-neoforge-1.0.1.jar) targeting NeoForge26.1.2.65-beta. - NEW: Native Quilt support via
quilt.mod.json(also runs under Quilt's Fabric compatibility layer). - Refactored project into a loader-agnostic core (
com.statestream.*) with separate entrypoints per loader (StateStreamFabric,StateStreamNeoForge). - Three distinct jars now shipped: Fabric, Quilt, NeoForge.
Critical bug fixes
- Fixed silent data corruption when Y > 255. The previous position encoding masked Y to 8 bits, which collided for any block above Y=255 (Overworld extends to Y=320). The registry is now split per-section using section-local Y (4 bits) — collisions are mathematically impossible. New test
allEncodingsUniqueWithinSectionverifies every (x, z, ly) tuple produces a unique encoding. - Fixed registry corruption on every block placement and break.
onBlockChangedwas always receivingnullfor the old BlockState, which caused:- Duplicate entries when replacing a tickable block with another tickable block
- Phantom entries (never removed) when a tickable block was destroyed
- Tick loop wasting cycles on positions that no longer held tickable blocks
- Old state is now captured at HEAD via a ThreadLocal and consumed at RETURN.
- Added the
/statestream enable <module>and/statestream disable <module>commands that the Modrinth description promised but didn't actually exist. Includes tab-completion for module names.
New feature: per-section tickable index with bitmap skip
The biggest performance win in this release. Each loaded chunk now keeps:
- One sorted
short[]per section containing only tickable positions - A 64-bit
nonEmptyMaskwhere bit s is set iff section s has at least one tickable block - The total tickable count for stats
The random-tick loop walks the mask using Long.numberOfTrailingZeros + mask & (mask-1) — empty sections are skipped at the cost of a single CPU instruction. On a typical Overworld chunk with tickables in only 3 of 24 sections, this is roughly an 8× reduction in section iterations per tick.
Probability parity with vanilla is preserved exactly: each section still rolls randomTickSpeed picks of nextInt(4096) and a tickable block still has P=1/4096 per roll.
Performance fixes
AtomicLongcache counters replaced withLongAdder— eliminatesLOCK CMPXCHGcontention on the per-call hot path.- Block state IDs are now cached on the BlockState itself via a
@Uniquemixin field onBlockBehaviour$BlockStateBase. First read pays aReference2IntOpenHashMap.getInt(); every subsequent read is a single field load. Without this, the cache was doing a hashmap lookup to save a field lookup — a net loss. onBlockChangedno longer allocates aHashSetper mutation. It now does CAS-based sorted-array binary insertion/removal. Lock-free, single allocation for the new array only.onChunkLoaditeratesLevelChunkSectionarrays directly instead of callingchunk.getBlockState()~98 000 times viaBlockPos.betweenClosed. Empty sections are skipped at O(1).UpdateCuller.shouldSuppressnow has an O(1) empty-set early exit and an O(1)Blockreference check (couldSuppressSource) that skips Identifier allocation entirely when the source block isn't involved in any pair. Internal storage switched fromSet<String>toMap<Identifier, Set<Identifier>>— no moretoString()+ concatenation per call.- Tick loop now uses a single reusable
BlockPos.MutableBlockPosinstead of allocating oneBlockPosper ticked block per tick. - Cache verification moved from per-call to one-shot at
populate(). The hot path no longer pays for verification overhead. Long2ObjectOpenHashMapcandidacy preserved viaConcurrentHashMap<Long, ChunkEntry>— Long boxes are short-lived and escape-analysis-friendly.
Code quality
- JSON parsing in
UpdateCullernow uses Gson (with the hand-rolled string parser kept as a fallback for hostile input). - Config paths resolved via
FabricLoader.getConfigDir()/FMLPaths.CONFIGDIR.get()on the respective loader, with astatestream.config.dirsystem property as the loader-agnostic bridge. - Mod version now read via Fabric's / NeoForge's
ModContainerAPI instead of a hand-rolled JSON parser. fabric.mod.jsonenvironment changed from"*"to"server"— the mod is no longer required on the client.
Tests
- Updated for the new section-local encoding API (
encodePos(x, z, ly)+ matchingdecodeX/Z/LocalY). - New test
allEncodingsUniqueWithinSectionproving the Y-collision bug cannot recur. - New test
nonEmptyMaskMatchesSectionContentscovering the bitmap-walk semantics. - Counter assertions updated from
AtomicLong.get()toLongAdder.sum().
Internal
- New
BlockStateIdHolderinterface implemented on every BlockState viaBlockStateBaseMixin. - New
ReactiveTickRegistry.ChunkEntryimmutable struct (per-section arrays + bitmap + count + minY). - New
com.statestream.fabricpackage with the Fabric-specific entrypoint. - New
neoforge/Gradle subproject usingnet.neoforged.moddev2.0.141.
1.0.0 — Initial release
- JIT BlockState Inlining (
BlockStateCache) - Update Culling (
UpdateCuller) - Reactive Block Ticking (
ReactiveTickRegistry) - Per-module fallback handler — any unexpected error disables the offending module and restores vanilla behavior
- TOML config with independent toggles for each module
/statestream stats,status,reload,benchmarkcommands- Fabric loader for MC 26.1.2
Optional dependencies
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:od7oK36g:pU6kr1Lg"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:od7oK36g:pU6kr1Lg"
}

