Skip to content

World System Overview

The World System manages the game universe, individual worlds, chunks, blocks, and lighting. It provides the spatial foundation for all gameplay.

  • Universe: com.hypixel.hytale.server.core.universe.Universe
  • World: com.hypixel.hytale.server.core.universe.world.World
  • WorldConfig: com.hypixel.hytale.server.core.universe.world.WorldConfig
  • EntityStore: com.hypixel.hytale.server.core.universe.world.storage.EntityStore
  • ChunkStore: com.hypixel.hytale.server.core.universe.world.storage.ChunkStore
  • ChunkUtil: com.hypixel.hytale.math.util.ChunkUtil
flowchart TB
    subgraph Universe
        subgraph Worlds
            subgraph Default["default"]
                D_ES[EntityStore]
                D_CS[ChunkStore]
                D_C[Chunks]
            end
            subgraph Nether["nether"]
                N_ES[EntityStore]
                N_CS[ChunkStore]
                N_C[Chunks]
            end
            subgraph Custom["custom"]
                C_ES[EntityStore]
                C_CS[ChunkStore]
                C_C[Chunks]
            end
        end
        PS[Player Storage]
    end

The Universe class is the top-level container for all worlds and player data. It extends JavaPlugin.

import com.hypixel.hytale.server.core.universe.Universe;
Universe universe = Universe.get();
MethodReturn TypeDescription
get()UniverseGet the singleton universe instance
getWorlds()Map<String, World>Get all loaded worlds (unmodifiable)
getWorld(String)WorldGet world by name (case-insensitive)
getWorld(UUID)WorldGet world by UUID
getDefaultWorld()WorldGet the default world
getPlayers()List<PlayerRef>Get all online players
getPlayer(UUID)PlayerRefGet player by UUID
getPlayerByUsername(String, NameMatching)PlayerRefFind player by username
getPlayerStorage()PlayerStorageAccess player data storage
getPlayerCount()intGet total online player count
Map<String, World> worlds = universe.getWorlds();
World netherWorld = universe.getWorld("nether");
World defaultWorld = universe.getDefaultWorld();
if (universe.getWorlds().containsKey("custom")) {
// world exists
}
for (PlayerRef player : universe.getPlayers()) {
// process each player
}
PlayerRef player = universe.getPlayerByUsername("username", NameMatching.DEFAULT);

Each World represents a separate game world with its own chunks, entities, and rules. World extends TickingThread and implements Executor, so it runs on its own dedicated thread.

World world = Universe.get().getWorld("default");
World world = Universe.get().getDefaultWorld();
PropertyTypeDescription
getName()StringWorld’s unique name
getSavePath()PathFilesystem path for world data
getWorldConfig()WorldConfigWorld configuration
getEntityStore()EntityStoreEntity ECS store
getChunkStore()ChunkStoreChunk ECS store
getTick()longCurrent world tick
isTicking()booleanWhether the world is ticking
isPaused()booleanWhether the world is paused
isAlive()booleanWhether the world is still running
getPlayerCount()intNumber of players in this world
String name = world.getName();
EntityStore entityStore = world.getEntityStore();
ChunkStore chunkStore = world.getChunkStore();
long tick = world.getTick();
boolean ticking = world.isTicking();
boolean paused = world.isPaused();
long seed = world.getWorldConfig().getSeed();
Collection<PlayerRef> players = world.getPlayerRefs();
int playerCount = world.getPlayerCount();
world.sendMessage(Message.raw("Hello everyone!"));
int blockId = world.getBlock(x, y, z);
BlockType blockType = world.getBlockType(x, y, z);
world.setBlock(x, y, z, blockType);

Chunks in Hytale are addressed by a long index. Use ChunkUtil to convert between block coordinates and chunk indices.

import com.hypixel.hytale.math.util.ChunkUtil;
long chunkIndex = ChunkUtil.indexChunk(chunkX, chunkZ);
WorldChunk chunk = world.getChunk(chunkIndex);
long fromBlock = ChunkUtil.indexChunkFromBlock(blockX, blockZ);
WorldChunk chunk = world.getChunk(fromBlock);
WorldChunk loaded = world.getChunkIfLoaded(chunkIndex);
CompletableFuture<WorldChunk> future = world.getChunkAsync(chunkX, chunkZ);
MethodDescription
getChunk(long)Get chunk synchronously (loads if needed)
getChunkIfLoaded(long)Get chunk only if it’s loaded and ticking
getChunkIfInMemory(long)Get chunk if it’s in memory (any state)
getChunkAsync(long)Load chunk asynchronously
getChunkAsync(int, int)Load chunk asynchronously by chunk coords
getNonTickingChunkAsync(long)Get chunk without marking it as ticking

WorldConfig defines how a world behaves.

OptionTypeDescription
seedlongWorld generation seed
gameTimeInstantCurrent game time
isTickingbooleanWhether chunks tick
isBlockTickingbooleanWhether blocks tick
isPvpEnabledbooleanWhether PvP is enabled
isFallDamageEnabledbooleanWhether fall damage is active
isGameTimePausedbooleanWhether day/night cycle is paused
worldGenProviderIWorldGenProviderWorld generator
chunkStorageProviderIChunkStorageProviderChunk storage type
spawnProviderISpawnProviderSpawn location logic
gameplayConfigStringGameplayConfig asset reference
forcedWeatherStringForced weather type
gameModeGameModeDefault gamemode
ProviderKeyDescription
FlatWorldGenProvider"Flat"Flat world generation
VoidWorldGenProvider"Void"Empty void world (default)
DummyWorldGenProvider"Dummy"No generation
ProviderKeyDescription
DefaultChunkStorageProvider"Hytale"Default file-based storage
EmptyChunkStorageProvider"Empty"No persistence
IndexedStorageChunkStorageProvider"IndexedStorage"Optimized indexed storage
MigrationChunkStorageProvider"Migration"Migration support
RocksDbChunkStorageProvider"RocksDB"RocksDB-based storage with LZ4/ZSTD compression
ProviderKeyDescription
GlobalSpawnProvider"Global"Single spawn point for all
IndividualSpawnProvider"Individual"Per-player spawn points
FitToHeightMapSpawnProvider"FitToHeightMap"Spawn on terrain surface

Each world has two ECS stores:

For world entities (players, mobs, items):

EntityStore entityStore = world.getEntityStore();
Store<EntityStore> store = entityStore.getStore();
Holder<EntityStore> holder = EntityStore.REGISTRY.newHolder();
holder.addComponent(positionType, new PositionComponent(x, y, z));
Ref<EntityStore> ref = store.addEntity(holder, AddReason.SPAWN);

For chunk-level data (blocks, sections, lighting, environment):

ChunkStore chunkStore = world.getChunkStore();
Store<ChunkStore> store = chunkStore.getStore();
getEventRegistry().register(StartWorldEvent.class, event -> {
World world = event.getWorld();
});
getEventRegistry().register(AddWorldEvent.class, event -> {
World world = event.getWorld();
});
getEventRegistry().register(RemoveWorldEvent.class, event -> {
World world = event.getWorld();
});
getEventRegistry().register(AllWorldsLoadedEvent.class, event -> {
// server fully initialized
});
getEventRegistry().register(AddPlayerToWorldEvent.class, event -> {
World world = event.getWorld();
PlayerRef player = event.getPlayerRef();
});
getEventRegistry().register(DrainPlayerFromWorldEvent.class, event -> {
World world = event.getWorld();
PlayerRef player = event.getPlayerRef();
});

Chunks in Hytale are 32x320x32 block columns divided into 10 sections of 32x32x32:

flowchart TB
    subgraph Chunk["Chunk Column (32 x 320 x 32)"]
        S0["Section 0 (y: 0-31)"]
        S1["Section 1 (y: 32-63)"]
        S2["Section 2 (y: 64-95)"]
        SD["..."]
        S9["Section 9 (y: 288-319)"]
    end

    S0 --> S1 --> S2 --> SD --> S9

These are defined in ChunkUtil:

ConstantValueDescription
SIZE32Chunk width/depth (X and Z)
HEIGHT320Total chunk height (Y)
HEIGHT_SECTIONS10Number of vertical sections
BITS5Bit shift for coordinate conversion (2^5 = 32)
SIZE_BLOCKS32768Blocks per section (32^3)
MIN_Y0Minimum Y coordinate
MIN_ENTITY_Y-32Minimum entity Y coordinate
import com.hypixel.hytale.math.util.ChunkUtil;
int chunkX = ChunkUtil.chunkCoordinate(blockX);
int chunkZ = ChunkUtil.chunkCoordinate(blockZ);
int localX = blockX & 31;
int localZ = blockZ & 31;
long index = ChunkUtil.indexChunk(chunkX, chunkZ);
long index = ChunkUtil.indexChunkFromBlock(blockX, blockZ);
int chunkX = ChunkUtil.xOfChunkIndex(index);
int chunkZ = ChunkUtil.zOfChunkIndex(index);
boolean isBorder = ChunkUtil.isBorderBlock(localX, localZ);
long index = ChunkUtil.indexChunk(chunkX, chunkZ);
WorldChunk chunk = world.getChunk(index);
WorldChunk loaded = world.getChunkIfLoaded(index);
if (loaded != null) {
// safe to read blocks
}
world.getChunkAsync(chunkX, chunkZ).thenAccept(chunk -> {
// chunk is now available
});

WorldChunk implements BlockAccessor and provides block-level access:

int blockId = chunk.getBlock(x, y, z);
BlockState state = chunk.getState(x, y, z);
short height = chunk.getHeight(localX, localZ);
chunk.markNeedsSaving();
BlockType blockType = BlockType.getAssetMap().get("Rock_Stone");
BlockType type = world.getBlockType(x, y, z);
int blockId = world.getBlock(x, y, z);
world.setBlock(x, y, z, blockType);

Worlds run on their own dedicated thread. All world modifications must happen on this thread. World implements Executor, so you can schedule work on it directly.

world.execute(() -> {
world.setBlock(x, y, z, blockType);
});
CompletableFuture.runAsync(() -> {
// runs on world's thread
}, world);
  1. Check chunk loading — always verify chunks are loaded before accessing blocks
  2. Use async loading — use getChunkAsync() to avoid blocking
  3. Run on the correct thread — world operations must happen on the world’s thread via execute() or by submitting to the world as an Executor
  4. Cache block types — store BlockType references instead of looking them up repeatedly
  5. Use ChunkUtil — always use ChunkUtil for coordinate conversions; remember chunk size is 32, not 16