All versions
0.0.5
Release
SLib 0.0.5last month 93
Compatibility
Minecraft: Java Edition
1.20.1–1.20.6
Platform
Forge
Supported environments
Client and server
Changes
Patch 0.0.5
Fixes
- Fixed network packet id allocation depending on mod load order. Collision resolution used “first namespace wins preferred base”, so client and dedicated server could map the same consumer packet to different wire ids while
PROTOCOL_VERSIONstill matched. Packet ids are now a pure FNV-1a ofmodId + packetName(stable, order-independent); real hash collisions fail loud at register time. - Fixed network protocol version still being decorative for consumer packet maps. Channel protocol bumped to
1.1with the deterministic id scheme so mismatched Slib builds refuse the handshake instead of silently mis-dispatching. - Fixed
Network.registerSafeholdingINSTANCE_LOCKacross ForgemessageBuilder(...).add(). That reintroduced the dedicated-server / Refresh Trades style deadlock class the earlier “register outside Slib locks” hardening claimed to remove. Forge registration runs without Slib locks again. - Fixed
nextIdcommittingID_TO_*maps before channel registration. A failedadd()left permanent id holes and “registered” log lines for packets that never existed on the channel. Registration is now reserve → Forge add → commit, with full rollback on failure. - Fixed safe C2S handlers being unable to see
ServerPlayer. The recommendedConsumer<T>path dropped sender after the null-sender check, so real auth/rate-limit code was forced onto the unsafe Netty-thread overload. AddedNetwork.ServerPlayerHandler<T>and a typedregisterClientToServer(..., ServerPlayerHandler)that stillenqueueWorks on the main thread and re-checks the sender is alive. - Fixed
freezeRegistrationnever being called by Slib. Late/asymmetric consumer registration could still skew maps after common setup. Freeze now runs onFMLLoadCompleteEvent.unfreezeRegistrationis gated behind-Dslib.network.allowUnfreeze=true(debug only). - Fixed
sendToAllTrackingNPE when the supplier returned null, and addedsendToAllTrackingAndSelffor tracking sets that exclude the entity itself. - Fixed
sendToChunkdocumentation drift: code correctly usesgetChunkNow(no force-load); unloaded chunks drop the packet instead of pulling chunks. - Fixed
PacketGuard.tryAcquirerate/cooldown TOCTOU. Concurrent Netty/main-thread calls could both pass check-then-put. Rate and cooldown now use atomicConcurrentHashMap.compute, with rollback of a same-tick rate commit if cooldown rejects. - Fixed
PacketGuard.DEFAULT_MAX_DISTANCE_SQname lying about units (value was linear blocks, then squared). Renamed toDEFAULT_MAX_DISTANCE(legacy constant kept deprecated) and sanitize non-finite constructor distances. - Fixed
PacketGuard.markRefreshednever callingmaybeCleanup(docs claimed both paths cleaned). - Fixed
SnapshotGuard.sanitizeNbtignoringmaxBytes/ depth fail flags and fully copying unbounded byte/int/long arrays. Over-limit tags now reject to empty; arrays are capped; depth is hard-capped at 512. - Fixed JSON open-string / open-bracket bypass of string-length and malformed checks, and fail-open helpers (
depth < 1/bytes < 1used to return true). - Fixed
SnapshotGuarddepth walks doing unbounded width work before size reject (CPU DoS in the guard). Size is checked first; depth walks are iterative with node budget and map/list caps. - Fixed
Permissions.isOptreating any ops-list entry as OP (including level 1). Ops-list fallback now requires entry level ≥ 2 (still acceptshasPermissions(2)). - Fixed UI animations running only on
ClientTickEvent(~20 Hz), so hover/slide felt stepped.AnimationTickeradvances onRenderTickEventwith wall-clock delta. - Fixed
AnimationRunner.cancelwiping or not flushing the current value. Cancel now freezes the live value intoLAST; full wipe isforget(Toast/Ripple dispose use forget). - Fixed
Drawer.togglekeying off visibility mid-close (could re-close instead of re-open). Toggle uses open-intent only. - Fixed
Toastfirst-tick lifetime skew, invisible entries holding queue slots after near-zero dismiss, and Binding mid-fire double-notify / permanentbindlistener leaks (unbind+ emit snapshot). - Fixed
Layout.stackignoring section padding (used onlyminHeight). - Fixed
Slider/Stepperinverted min/max and zero step leaving steppers dead. - Fixed
ScrollContainerkinetic step treatingdeltaMs == 0as a full step, and content not translating with scroll offset (renderContent(GuiGraphics, ...)). - Fixed
Modalbeing a singleton without Esc/key trap. Modal is now a stack withclose/closeAll,trapsKey, and Esc handling. - Fixed
EventBus.offleaving empty handler lists forever (map growth on long-lived buses). - Fixed foliage grass impulse spam: continuous disturbance applied
punchevery frame and exploded spring energy. Blades only punch on rising force deltas. - Fixed foliage wind height boost unbounded with world Y (high trees/canopies got insane amplitude). Height contribution is capped; entity push uses a separate entity-safe sample path without foliage height stacking.
- Fixed
WindUvignoringWindField.gustiness/turbulence(gust was hard-coded 0.55; turbulence unused). Shader/UV path now matches field parameters and clamps amplitude. - Fixed leaf ground contact hardcoded at
y = 0.02(leaves “landed” mid-air or through terrain).LeafCard.groundYis set from heightmap viaCanopy.groundY(...); expired settled leaves can be culled viaisExpired. - Fixed canopy per-tick
groundY = min(groundY, y - radius)which ratcheted ground into the canopy / blocks. That clamp was removed; terrain height is authoritative. - Fixed foliage disturbance list races and step spam from render-tick walk tracking. Pulses use COW list, nearby step/dash pulses merge, and player step is distance+cooldown throttled.
- Fixed foliage full O(n log n) distance sort every frame. Sort is dirty/every-8-frames; far LOD skips; frame budget hard-caps work.
- Fixed double wind authority: server
WorldWindno longer stompsFoliage.global().wind(); only the client drive path pushes foliage targets. Server wind is per-dimension (Map<ResourceKey, WorldWind>), not one shared singleton multi-ticked by everyServerLevel. - Fixed client/server wind seed divergence (
"client".hashCode()vs"server".hashCode()). Weather macro now uses world/dimension seed material, not side string. - Fixed wind direction wander rewriting targets every tick (permanent heading random walk). Integration only blends current dir toward weather targets.
- Fixed light-animal “strange flight”: living entities were pushed by both
LivingTickEventandblowNearby(and again under multi-player AABBs). Single even-tickblowNearbypath only; once-per-entity-per-gameTime gate; air scale reduced; livingvy/ horizontal caps; rabbit no longer fakessetOnGround(false);hurtMarkedremoved from wind. - Fixed item drop physics stacking: join no longer force-ticks motion (track only); items excluded from living light-entity path; multi-player de-dupe; softer ground friction (0.92 vs 0.72×vanilla); wind skipped when settled; flat render only when truly on ground (not slow free-fall); 3D item models no longer paper-flat on XP=90°.
- Fixed foliage “doing nothing in world”: sim was API-only with no spawn/render.
WorldFoliageBridgeauto-registers grass/canopies near the player; overlay + debris renderers draw results; dimension change clears sim caches. - Fixed Boost cancelling all schedules on any single
LevelEvent.Unload(nether hop wiped overworld work). Unload is scoped: client only clears tick-batcher/frame samples when fully leaving a world (mc.level == null); player logout cancels only that player’s schedules. - Fixed Boost schedule map races: future removed by identity when the timer fires, so a re-entrant
schedule(same key)cannot leave a stale future or drop a newer one. Player schedules keep reverse indexes (schedulesByPlayer/playersBySchedule) and drop them on fire, cancel, and logout. - Fixed
Boost.offloadswallowing Failover skips as success. Isolated modules complete exceptionally withModuleSkippedException; real crashes still go throughFailover.handleCrashand hop work onto the worker pool (scheduler never runs heavy work). - Fixed
TickBatcher.shouldRunalways returning true (no batch gate).shouldRunis now once-per-tick (batch=1);shouldRunEverykeeps N-tick cadence. Composite keys use\0separators; map is access-order LRU + TTL eviction. - Fixed
FrameMonitorhealth using raw last sample / wrong partial-tick feed. Samples are wall-clock nanos betweenRenderLevelStageEvent.AFTER_SKYframes; health/degraded use p95 against ~18ms / ~28ms budgets; running sum avoids O(n) average recompute. - Fixed
Registrydisconnect cleanups holding a singleRunnableper player (second register overwrote first). Cleanups are a multi-list;clearPlayerStateruns every registered cleanup and everyPacketGuard.clearPlayer. - Fixed
PacketGuard.disposeleaving rate/cooldown maps populated after unregister. Dispose nowclearAlls then unregisters. - Fixed WindSync sticky remote authority after leaving multiplayer (client kept server wind forever) and per-dimension send throttle never cleaning up. Logout/
LoggingOutclears remote authority + foliage; dim unload and server stop clearLAST_SEND. - Fixed double-send wind snapshot when
sendDimensionwas called twice on the same gameTime (broken& 7re-send path). Same-tick send is skipped once only. - Fixed SBS Failover game-time only advancing from client ticks / ad-hoc callers.
ServerBootstrapends each server tick withFailover.updateGameTime(server tick count)so cooldowns expire on dedicated servers. - Fixed
ScissorClipvs deferredGuiGraphicsbatching: text/fills escaped clip afterpop. Addedpush/pop(GuiGraphics, …)thatflush()before changing GL scissor; SearchBar/Dropdown/Drawer/Scroll/Ripple/WarningScreen use it. Framebuffer scissor is clamped to FB bounds. - Fixed Modal ghost trap after last
close(): residual backdrop/panel anim keptisOpen/trapsClick/trapsKeytrue with empty stack. Input now gates onblocksInput()/ open-intent + stack; paint uses a closing snapshot until anim ends; Esc/keys only while blocking. - Fixed “stupid slider”: drag/click set value immediately (no ease lag); programmatic
setValuestill eases. Hover stays hot while dragging; NaN clamped. - Fixed Dropdown outside-click swallowing the event (
return true); now closes andreturn falselike SearchBar. SearchBar/Dropdown respectactive/visible. - Fixed
RoundedButtonflatgfx.fill+radius()==0+ deadprimaryWithHoverOutline. Buttons use SDFRounded.draw/ outline / soft hover glow and real corner radius fromStyle/Theme.RADIUS_BUTTON. - Fixed Sidebar null
StyleNPE and deadonSelect(addedhandleClick); hover anim ids keyed on label content, not ephemeral array identity. - Fixed AnimationTicker inventing
16mswhen runner delta is 0 (Toast/Tooltip/Ripple ran faster than animations). Shared wall-clock: skip UX tick when delta is 0. Animation callback exceptions no longer abort the whole runner tick. - Fixed Toast off-screen queue entries burning
durationMsnever shown: only the firstMAX_VISIBLEslots age; waiting entries hold until a slot frees. Near-invisible progress no longer occupies a paint slot. - Fixed ScrollContainer
renderContent(Runnable)path without pose translate and unpaired scissor risk; translate whenGuiGraphicsis present; content hit helperstoContentX/Y/toViewX/Y; velocity from actual offset;scrollBykills fling. - Fixed Drawer lacking trap/Esc/
BoundsAPI; open-intent gates input; scissor flush path for content. - Fixed SDF rounded outline UV/pad and thin-ring alpha; fill AA pad;
Metrics.pixelScaleFno longer hard-caps 1–4;Fonts.lineHeight(Role)uses role metrics (TITLE/BUTTON 16, BODY 13, …). - Fixed
Style.withEasing(null)NPE path. - Fixed keyboard access on Slider (arrows/Home/End), Toggle (Space/Enter), Stepper (± keys), Dropdown (Esc/Enter/arrows + wheel scroll).
- Fixed Dropdown long lists overflowing the screen: max visible rows, scroll offset, flip above header near bottom edge; defensive options copy.
- Fixed SearchBar missing max length (default 256), shift-click / drag selection, caret blink reset on re-focus.
- Fixed Stepper dead value animation / no hold-to-repeat; min width; NaN clamp.
- Fixed Binding same-value re-fire dirty loop and
setSilentmid-fire; observe registers after successful init. - Fixed RippleEffect concurrent list (COW + snapshot tick).
- Fixed StateMachine re-entrancy from enter/exit (
pendingqueue),resetlifecycle,Objects.equalsstate compare, null guards. - Fixed KeyboardShortcut bind not normalizing modifiers; null handler rejected; Binding public
modifiers()/key()/toString(). - Fixed Layout: explicit
gap>=0honored (auto min gap only whengap<0); realbottomReserve; DISTRIBUTE leftover into gaps; null sections; clamp min>max. - Fixed SafeArea
splitHorizontalnegative gap; ProgressBar partial-fill contrast + scissor fill; Card/StatRow font-metric layout / overflow scissor. - Stripped UTF-8 BOM from all
assets/slib/font/*.jsonFontSets.
Improvements
- Added
en.antinimus.slib.api.physics— foliage + world wind + light entity/item motion (not a full rigid-body engine).WindField/WorldWind(rolling gusts, weather blend, wetness, per-dimension server state)WindSync(slib:windS2C) — server broadcasts strength/dir/gust/turb/wet/phase every 10 ticks; client snaps to authority in MPWindPush— soft slide for light living entities (rabbits, chickens, bees, silverfish, endermites, small animals)ItemPhysics+FlatItemEntityRenderer— ground settle, no perpetual spin, optional wind slideGrassBlade/GrassClump(spring-damper bend, tip lag, squash, stomp, base Y, biome grass tint)LeafCard/Canopy(attached → loose → falling → settled, biome leaf color, shed)FoliageDisturbance(step / dash / burst / explosion)FoliageSim+Foliagefacade (global sim, quality, weather, walk, punch, overlay toggles)WindUvpure helpers for vertex/shader paths (shaderUniforms,vertexWindX/Z,grassWave,leafFlutter)FoliageTickerauto client render-tick (focus, walk, auto quality)FoliageBudget/FoliageFocusLOD + per-frame capsWorldFoliageBridge— auto-scan grass/leaves near player; Falling Leaves / leavestorm / etc. detected → Slib does not shed or draw competing debrisFoliageAtlas+ textured renderers — block-atlas grass/leaf sprites (cross-plane blades, tinted leaves; not solid-color “soap”)FoliageOverlayRenderer/LeafDebrisRenderer— world-visible bent grass and falling/loose/settled leaves
- Network:
registrationFingerprint(), modId namespace validation, safer tracking send helpers. - UX: Modal stack, Binding
unbind, Scroll translate helper, StateMachine self-transition side-effect fix. - Boost/Bootstrap:
Boost.shutdownonServerStoppingEvent(pools + schedules), scoped client unload, multi disconnect cleanups, frame samples on real frames not ticks, Failover server-tick clock.
UI / Sync
- Slib main channel protocol is
1.1. Client and server must both run 0.0.5+ forslib:main. - Additional
slib:windchannel for world-wind snapshots (independent of packet allocator slots; does not useNetwork.namespace("slib")which remains reserved). - Consumer packet registration order no longer affects wire ids on
slib:main; register the same(modId, packet class simple name + [C2S|S2C])pair on both sides. - Prefer
dependencies.slibrange[0.0.5,0.1.0)if you need foliage physics, deterministic packet ids, wind sync, or the network/security hardenings above.[0.0.1,0.1.0)still loads older consumers that only need earlier API, but mixed 0.0.4/0.0.5 main-channel ends will fail handshake on purpose. - Foliage auto-tick is client-only and disabled while paused / no level. Consumers can
Foliage.setAutoTick(false)and driveFoliage.tick(dt)themselves. - World foliage auto-spawn/shed:
Foliage.setWorldFoliageAuto/Foliage.setSlibLeafShed/Foliage.setOverlayEnabled. Overlay uses vanilla block-atlas textures + biome tints so it stays sharp under ModernUI and does not require Sodium/Iris vertex hooks (those remain optional future work).
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:CfkGe24d:3o9ndnHf"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:CfkGe24d:3o9ndnHf"
}

