Astral Realms Documentation Help

AstralStacker Overview

AstralStacker reduces server load from spawner farms by merging identical spawner-spawned mobs and dropped items into single visual entities that track an amount counter, instead of leaving hundreds of individual entities loaded. It depends on AstralCore, AstralTown, and CoreProtect (hard dependencies in plugin.yml).

Where it runs

On onEnable, AstralStacker checks whether the current server's group (AstralPaperAPI.serverInformation() .group()) is in enabled-groups; if not — and the server isn't in the DEVELOPMENT environment, which forces the plugin active for testing — none of the services, listeners, or commands are registered and the plugin is effectively inert beyond registering the spawners item-stack supplier (see Spawner items), which is always registered regardless of group.

Startup classification

At enable time, AstralStacker compares the current wall-clock time (Europe/Paris) against normal-restart-hour using circular distance (so an hour near midnight still matches). If the server started within 30 minutes of that hour, the boot is treated as a normal (scheduled) restart; otherwise it's an abnormal boot (e.g. a crash or manual restart). This isNormalStartup flag changes how ChunkLoadListener treats stacks left over from the previous session — see Chunk persistence & TTL.

Services

Service

Responsibility

StackService

Orchestrates the other two services; runs a cleanup task every 2s (marks dead/missing stacks for removal) and a slower sync task every 3s (proximity re-merge, location tracking, TTL chunk-marking).

EntityStackService

Tracks mob stacks in per-chunk Long2ObjectOpenHashMap indexes; handles creation, proximity merge, damage distribution, and butchering.

ItemStackService

Tracks item stacks the same way; handles creation, merge, manual pickup, and 5-minute despawn.

Both stack services key entities by UUID and index them per-chunk (plus the 8 surrounding chunks) so proximity lookups never scan the whole world. All stacking state is owned by the main thread — event handlers and both scheduler tasks run synchronously, so the services use plain (non-concurrent) fastutil maps.

Stack persistence

Every stacked entity carries two PersistentDataContainer keys (namespaced to the plugin):

Key

Type

Purpose

astral_stack

Long

The plugin's pluginStartTime at the moment the stack was created — used as a session marker and to block renaming (see Mechanics).

amount_stack

Integer

The current stack amount. Written on every addToStack/setAmount call, never throttled — the display name update is throttled, but persistence isn't.

Entity stacks additionally store max_health (the original mob's max-health attribute, cached once so repeated reloads don't re-derive it) and, for mob death handling, use this to run one mob's worth of health as a per-stack damage pool (see Damage & death).

Where to go next

  • Configurationconfig.yml.

  • Mechanics — entity stacking, item stacking, chunk persistence/TTL, spawner items.

  • Commands/astralstacker, /stackill.

Last modified: 25 July 2026