StatestreamСкачатьСкачатьСкачать
ВЕРСИИ (3)
release
Statestream 1.0.1
1.0.124 мая 2026 г.940Minecraft: 26.1, 26.1.1, 26.1.2forge, neoforge
release
Statestream 1.0.1
1.0.124 мая 2026 г.930Minecraft: 26.1, 26.1.1, 26.1.2fabric, forge, quilt
Что нового
# 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 NeoForge `26.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 `allEncodingsUniqueWithinSection` verifies every (x, z, ly) tuple produces a unique encoding.
- **Fixed registry corruption on every block placement and break.** `onBlockChanged` was always receiving `null` for 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 `nonEmptyMask` where 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
- `AtomicLong` cache counters replaced with `LongAdder` — eliminates `LOCK CMPXCHG` contention on the per-call hot path.
- Block state IDs are now cached on the BlockState itself via a `@Unique` mixin field on `BlockBehaviour$BlockStateBase`. First read pays a `Reference2IntOpenHashMap.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.
- `onBlockChanged` no longer allocates a `HashSet` per mutation. It now does CAS-based sorted-array binary insertion/removal. Lock-free, single allocation for the new array only.
- `onChunkLoad` iterates `LevelChunkSection` arrays directly instead of calling `chunk.getBlockState()` ~98 000 times via `BlockPos.betweenClosed`. Empty sections are skipped at O(1).
- `UpdateCuller.shouldSuppress` now has an O(1) empty-set early exit and an O(1) `Block` reference check (`couldSuppressSource`) that skips Identifier allocation entirely when the source block isn't involved in any pair. Internal storage switched from `Set<String>` to `Map<Identifier, Set<Identifier>>` — no more `toString()` + concatenation per call.
- Tick loop now uses a single reusable `BlockPos.MutableBlockPos` instead of allocating one `BlockPos` per ticked block per tick.
- Cache verification moved from per-call to one-shot at `populate()`. The hot path no longer pays for verification overhead.
- `Long2ObjectOpenHashMap` candidacy preserved via `ConcurrentHashMap<Long, ChunkEntry>` — Long boxes are short-lived and escape-analysis-friendly.
### Code quality
- JSON parsing in `UpdateCuller` now 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 a `statestream.config.dir` system property as the loader-agnostic bridge.
- Mod version now read via Fabric's / NeoForge's `ModContainer` API instead of a hand-rolled JSON parser.
- `fabric.mod.json` environment 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)` + matching `decodeX/Z/LocalY`).
- New test `allEncodingsUniqueWithinSection` proving the Y-collision bug cannot recur.
- New test `nonEmptyMaskMatchesSectionContents` covering the bitmap-walk semantics.
- Counter assertions updated from `AtomicLong.get()` to `LongAdder.sum()`.
### Internal
- New `BlockStateIdHolder` interface implemented on every BlockState via `BlockStateBaseMixin`.
- New `ReactiveTickRegistry.ChunkEntry` immutable struct (per-section arrays + bitmap + count + minY).
- New `com.statestream.fabric` package with the Fabric-specific entrypoint.
- New `neoforge/` Gradle subproject using `net.neoforged.moddev` 2.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`, `benchmark` commands
- Fabric loader for MC 26.1.2
release
1.0.0
1.0.014 мая 2026 г.125Minecraft: 26.1, 26.1.1, 26.1.2fabric, forge