Release notes
LeanCore Changelog
ActiveHytale • Latest version 1.7.0
Changelog version 1.7.0
Added
- Content-aware zone dormancy: LeanCore now samples built-content density per zone (chests, benches, and other block entities) and biases dormancy timers and eviction order toward keeping content-rich zones loaded longer, even when idle. On by default
- Hot/simulation radius governance: under heap pressure LeanCore can trim the server-side ticking radius, separate from client view radius so there is no view pop-in, cutting simulation cost on top of the existing view-radius trims. On by default, with the same grace window as the view-radius governor
- Per-chunk unload truth: engine chunk eviction is now counted exactly on the world thread instead of inferred from net loaded-chunk deltas, so the learning signal for “this unload stuck” is far cleaner. On by default
Changed
- Per-world reads (hot zones, chunk-set diff, content scan) are batched into a single world-thread dispatch per tick, reducing dispatch overhead
- Hot-radius changes are now logged, so the ticking-radius governor reports its target the way the view-radius governor already does
- Learning persistence schema bumped to v9 (adds a per-zone content score); older v7 and v8 snapshots are read and upgraded automatically
Fixed
- Zone reuse stats are now immutable for safe cross-thread reads, false-cut counters are atomic, and the per-world chunk-set tracker no longer retains snapshots for worlds that went away
- Dormancy aging no longer advances its clock when a per-world fan-out only partially completes under load, so idle zones still cool on time
- Runtime shutdown is guarded against double execution, so a restart cannot run the save and teardown path twice
- World-thread tasks that throw are now logged instead of being silently swallowed
- Content-rich zones now persist even before they reach the normal visit threshold
Notes
- New
LeanCore.jsonkeys are added on first run: per-chunk unload truth, content model, and hot-radius governance default to on. Set them to false to keep 1.6.x behavior - Existing
LeanCore.jsonandlearning.state.gzare kept and upgraded in place; no manual migration
Changelog version 1.6.1
Changed
- Internal cleanup: removed dead code (unused snapshot type, unused dormancy/profile helpers, legacy persistence writers). No behavior change
Fixed
- Thread safety: heap-spread sampling, regional entity pressure, engine unload polling, chunk saturation, dormancy player positions, and solo motion now reuse the position sampled on the world thread or run inside a world-thread dispatch, instead of reading player transforms or chunk stores off the world thread
- Dispatch timeouts respected: a timed-out world task no longer advances policy state or over-reports unloaded chunks; the action just retries next tick
- Admin tools work with the HUD off:
/leancore heatmapand/leancore zone pin|unpin|pinsno longer requirehudFeatureEnabled, so admins can use them with the HUD disabled (the default)
Notes
- No config, command, or API changes since 1.6.0; existing
LeanCore.jsonandlearning.state.gzare kept as-is - Drop-in upgrade from 1.6.0; still requires Hytale server >=0.5.6
Changelog version 1.6.0
Added
- Player motion model (
motionModelEnabled, on by default): per-player velocity and confidence with a predicted position over a short horizon - Predictive zone retention: chunk unload is biased away from where players are heading; zones inside a player’s current or predicted view are never eviction candidates (protected cone)
- Reuse-distance + survival model (
zoneReuseModelEnabled, on by default): learns which zones get revisited and scales dormancy thresholds per zone; persisted with prune/TTL - Always-on diagnostics (
diagnosticLogEnabled, on by default): startup/shutdown summaries and[diag]decision logs for every profile, so the server log alone explains what the mod did and why - Cinematic view boost (
motionViewRadiusBoostEnabled, opt-in / off by default): smoothly raises view distance for fast movers - Learning snapshot schema v8: adds player motion features and zone reuse stats; reads v7 snapshots
Changed
- Dormancy unload ranking measures distance to a zone’s nearest chunk (AABB edge), not the zone center, for more accurate eviction
- Learning persistence runs on a dedicated single-writer thread, separate from the runtime tick
- Fresh
LeanCore.jsonships 1.6.0 defaults: motion model and reuse model on; cinematic boost off
Fixed
- Multi-world safety: per-world fan-out merges only on success and respects a per-tick budget; world-thread affinity corrected so one world never ages or unloads another’s zones
- Race-free persistence: single-writer flush with unique temp files; thread-safe motion features and activity classifier; symmetric codec read/write caps
- Chunk streaming smoothness: cinematic view boost stays off by default because rewriting the client view radius every tick churns chunk loading and stutters on the current engine
Removed
LeanCoreAPIpublic surface (now internal only)
Notes
- Requires Hytale server >=0.5.6
- Solo/LITE defaults stay smooth: the motion and reuse models do not change view radius or chunk rate on their own; the cinematic boost is opt-in
- Residual chunk-load stutter on fast movement is engine-side (pre-load hooks) and outside the mod’s reach
Changelog version 1.5.0
Added
- LITE memory governor on solo embedded (
liteMemoryGovernorEnabled, default on): view scaling, zone demotion, and unload sweeps withoutgovernEnabled - Adaptive view-radius in LITE (
liteViewRadiusEnabled): COMFORT stays at 100% until chunk or heap pressure; gentle cuts in WATCH; aggressive only in TIGHT/CRITICAL - AFK chunk unload in LITE (
liteUnloadEnabled): reclaims distant dormant/frozen zones when idle; probe gate still applies; nounloadEnabledrequired on solo - LITE learning (
liteLearningEnabled, default on): demand model + gzip persistence on solo; no policy bandit or holdout in LITE - Lite config keys:
liteViewPressureThreshold,liteViewComfortCapScale,liteViewWatchScale,liteViewTightScale,liteViewCriticalScale,liteMinClientViewRadius,liteViewRadiusLoginGraceSeconds,liteUnloadIdleSeconds,liteUnloadMaxChunksPerSweep - Dual pressure signals in LITE: JVM heap tier plus chunk saturation (
loaded / view budget) /leancore savings: lite governor block (preset, tier, lite flags, zone/chunk counters)/leancore status: lite govern/view/learning/unload flags and lite unload gate line/leancore learn: LITE footer clarifies demand-only learning on solo
Changed
- Solo profile LITE now runs a full lite governor tick on the world thread (not dormancy sampling only)
- Fresh
LeanCore.jsonships 1.5.0 defaults (lite*Enabled=true, STANDARD/FULL paths still off until you enable them) - Learning persistence interval defaults remain conservative for STANDARD/FULL; LITE flushes on its own path when
liteLearningEnabledis on
Fixed
- World-thread dispatch scoped per world (
GovernorWorldContext); inline dispatch only when the target world matches - LITE governor tick runs entirely inside
world.execute - Learning load hardening: invalid
learning.state.gzquarantined; codec validation on read LeanCore.jsonsanitization: invalid JSON quarantined, atomic save, caps on view/unload tuning keys
Notes
- LITE unload still needs
/leancore probewhenunloadProbeGateEnabledis true (default) - LITE unload sweeps only run when heap tier is WATCH or worse and distant zones are dormant; COMFORT + low spread is normal with zero unload counts
- STANDARD/FULL behavior unchanged:
governEnabled,learningEnabled,unloadEnabledas before - Set
embeddedStandardProfile: trueonly for dev dogfood of STANDARD on solo
Changelog version 1.4.1
Added
- Unload probe gate (
unloadProbeGateEnabled, default on): policy chunk unload stays blocked until/leancore probepasses; gate line on/leancore status;probePassedAtMssaved toLeanCore.json - gcHint session metrics in
/leancore savingswhengcHintEnabledis on (hint count and last hint age)
Changed
/leancore statusshows solo LITE diagnostics (adaptive tick, govern/learning/unload flags, unload gate line)/leancore probepersists pass timestamp on success and confirms when the unload gate opens/leancore learnreports learning flush status (flushErr, last flush time); v7 load/flush IO errors log to server
Fixed
- Governor defers unload, view-radius, and regional pressure when the primary world is missing (heap sampling and learning updates continue)
Notes
- Chunk unload on STANDARD/FULL still needs
governEnabled+unloadEnabled+ successful probe when the gate is enabled - Set
unloadProbeGateEnabled: falseonly if you intentionally override the safety gate - View-radius on embedded solo unchanged: requires
dedicatedServerMode: true
Changelog version 1.4.0
Added
-
Learning snapshot v7 (
learning.state.gz): gzip binary format; migrates legacy textlearning.stateon first flush -
Profile pruning:
learningMaxPersistedPlayers(default 512) andlearningPlayerTtlDays(default 90) -
embeddedStandardProfile: solo embedded STANDARD (15s) withoutdedicatedServerMode/ FULL 5s tick -
World dispatch layer:
WorldDispatch,GovernorWorldContext,RuntimeGuardfor HytaleTickingThreadsemantics -
gcHintEnabled: optional experimental LITE idle GC hint (off by default)
Changed
-
Daemon
LeanCore-runtimescheduler; shutdown hooks onShutdownEvent -
Governor ticks: coalesced
world.execute(one pending tick; scheduler no longer blocks up to 5s) -
Policy apply + chunk unload run inline when
world.isInThread() -
HUD overlays removed on shutdown; webhook HTTP client uses daemon executor
Fixed
-
Zombie
java.exeafter closing embedded Hytale with dedicated-style config (nestedworld.execute+ blocking wait stranded tasks on the world queue;TickingThreadkept JVM alive afterShutdown completed!) -
View-radius on embedded solo still requires
dedicatedServerMode: true(by design)
Notes
- Enable
unloadEnabledonly after/leancore probebaseline
Changelog version 1.3.0
Added
/leancore savings: session JVM heap peak, baseline, delta, governor state, and cumulative zone/chunk actions with measured vs estimated labelsDedicatedBootstrap: one-time preset on first dedicated boot (governEnabled,viewRadiusGovernanceEnabled,learningEnabled;unloadEnabledstays off)- 10-minute view-radius grace after dedicated runtime start
Changed
ZoneDormancyMap: incremental refresh without full map rebuild; stale zone pruneOnlineLinearDemandModel: per-update weight decay (0.9995) for playstyle changeschunkUnloadEventTracking: engine unload counts via world-thread polling (no ECSChunkUnloadEventlistener)- STANDARD/FULL governor tick dispatched on the world thread
Fixed
- Crash on profile FULL / dedicated preset (
Assert not in threadin engine chunk unload) from off-threadChunkStoreaccess and unsafe unload event registration - Regional pressure probe (
S4) no longer readsChunkStorefrom the scheduler thread
Notes
/leancore savingsis JVM heap only — not OS/VPS RSS- Set
dedicatedBootstrapEnabled: falseto skip the auto-preset - CurseForge build must include post-
53c801fthread-safety commits onmain
Changelog version 1.2.2
Added
- Policy blacklist persistence in
learning.stateschema v5 (rollback bans survive restart whenlearningEnabledis on) /leancore learnreportslearning=v5and active blacklist count
Changed
LeanCore.jsonread/write uses UTF-8 encoding- Governor blacklist state owned by
LearningStoreviaPolicyBlacklistTracker
Fixed
- FIGHTER stuck after exploring — explore activity pulses, zone discovery records EXPLORE, combat EMA decays when moving or switching roles
Notes
- Blacklist persistence requires
learningEnabled: true - v4
learning.stateupgrades automatically; blacklist is empty until the next policy rollback
Changelog version 1.2.1
First public 1.2.x release (includes Activity Sense from 1.2.0 plus 1.2.1 fixes). No separate 1.2.0 file on CurseForge.
Added
-
Activity Sense (ML): online multiclass softmax classifier trained from live ECS events
-
Block/tool context classifier: item id, gather type, and block group label breaks/places (MINE, CHOP, FARM, BUILD)
-
New playstyle labels:
MINER,LUMBERJACK,FARMERalongside existing behaviors -
Per-activity EMA features: mine, wood, farm, build, craft, combat rolling windows
-
Combat signal listener: FIGHTER only from damage events, not generic block breaks
-
Craft signal:
CraftRecipeEvent.Prefeeds craft activity -
Demand feature schema v2 (
demandDim=11) with activity-specific EMAs -
/leancore learn player: activity EMAs andactivityModel=SOFTMAXstatus -
Block break/place classify cache and per-item gather-type cache
-
Recent activity window for fast MINER / LUMBERJACK / BUILDER switches
-
Dirty flush for
learning.statewhen learning is enabled -
Unit tests for activity classifier, posterior, and role switching
Changed
-
Behavior posterior uses ML softmax as primary path; EMA fallback before warm-up
-
learning.stateschema v4: persists activity classifier + per-player activity EMAs (migrates from v3) -
/leancore learnreportsfeatureSchema=v2when demand model is active -
Activity EMA half-life 20s with cross-inhibition on role change
-
ML training throttled; LITE profile skips chunk probe on dormancy refresh
-
Hatchet and Hytale wood blocks classified before pickaxe heuristics
Fixed
-
Mining with pickaxe no longer tagged as FIGHTER
-
Slow role change after switching from mining to chopping (e.g. Hatchet)
-
EMA decay on solo LITE during block events
-
Stutter from per-break classify + ML train on ECS thread
Notes
-
Activity ML runs in-process on the server JVM (no client mod)
-
Heuristic teacher bootstraps softmax until
updates >= 8 -
Primary KPI: server JVM heap, not client FPS
-
Upgrade from 1.1.1 directly to 1.2.1
Changelog version 1.2.0
Added
-
Activity Sense (ML): online multiclass softmax classifier trained from live ECS events
-
Block/tool context classifier: item id, gather type, and block group label breaks/places (MINE, CHOP, FARM, BUILD)
-
New playstyle labels:
MINER,LUMBERJACK,FARMERalongside existing behaviors -
Per-activity EMA features: mine, wood, farm, build, craft, combat rolling windows
-
Combat signal listener: FIGHTER only from damage events, not generic block breaks
-
Craft signal:
CraftRecipeEvent.Prefeeds craft activity -
Demand feature schema v2 (
demandDim=11) with activity-specific EMAs -
/leancore learn player: activity EMAs andactivityModel=SOFTMAXstatus -
Unit tests for block classifier, activity model, and behavior posterior
Changed
-
Behavior posterior uses ML softmax as primary path; EMA fallback before warm-up
-
learning.stateschema v4: persists activity classifier + per-player activity EMAs -
/leancore learnreportsfeatureSchema=v2when demand model is active
Fixed
- Mining with pickaxe no longer tagged as FIGHTER — breaks weighted by tool/block context
Notes
-
Activity ML runs in-process on the server JVM (no client mod)
-
Heuristic teacher bootstraps softmax until
updates >= 8 -
Primary KPI remains server JVM heap, not client FPS
Changelog version 1.1.0
Added
-
Scaled runtime profiles on embedded hosts:
LITE(solo),STANDARD(friends),FULL(dedicated) -
localHostModeAUTO (default): light dormancy tick on solo; scales when friends join -
Regional entity probe (S4): zone-level entity counts via
EntityChunkin/leancore probe -
ChunkUnloadEventtracking (opt-in): policy sweep vs engine unload counters in/leancore learn -
OnlineLinearDemandModel: learned retention demand blended with activity features (feature schema v1) -
LeanCoreAPI: query memory tier, pin/unpin zones, player snapshots for other mods -
Holdout cohort (10%): bandit learns from treatment players; holdout players skip view-radius cuts
-
Unit tests for runtime profiles, activation policy, feature normalization, and demand model
Changed
-
Runtime uses
HytaleServer.SCHEDULED_EXECUTORwith 30s initial delay on local worlds -
Safer defaults:
governEnabled=false,viewRadiusGovernanceEnabled=false, HUD/learning off by default -
View-radius governance disabled on embedded solo even when governor is enabled
-
Policy applier only applies view-radius when policy actually changes (throttled)
-
/leancore statusshows active runtime profile (LITE/STANDARD/FULL) -
/leancore learnshowsfeatureSchema=v1, demand model status, and unload attribution
Fixed
-
Embedded local worlds no longer stutter from a heavy 5s background tick + HUD + learning loop
-
Chunk-unload event tracking off by default (avoids engine thread assert on some worlds)
Notes
-
Primary KPI remains server JVM heap, not client FPS or GPU
-
Solo: keep
localHostMode: AUTO. Dedicated:dedicatedServerMode: truethen tune governor
Changelog version 1.0.0
Added
- First stable public release (
1.0.0) - Memory governor with COMFORT → CRITICAL tiers, rollback, and contextual policy learning
- Spatial dormancy map (HOT / WARM / DORMANT / FROZEN) and chunk unload sweeps
- Per-player retention demand from live activity features
- Server-calibrated heap quantiles and
learning.statepersistence (schema v3) - Admin HUD (
/leancore hud on|off|status) — opt-in, group and permission gated - Zone heatmap (
/leancore heatmap [limit]) - Zone pin overrides (
/leancore zone pin|unpin|pins) - Optional CRITICAL webhook (
criticalWebhookUrl, generic JSON) - Bundled server asset pack for HUD UI
Notes
- Primary KPI is server JVM heap, not client FPS