# World Management The Hytale server supports multiple worlds within a single universe. This guide covers world management, chunk handling, and related systems. ## Universe The `Universe` is the top-level container for all worlds and global game state. ### Accessing the Universe ```java Universe universe = Universe.get(); ``` ### Universe Properties ```java // Get all loaded worlds Collection worlds = universe.getWorlds(); // Get a specific world World world = universe.getWorld("worldName"); // Get player count int playerCount = universe.getPlayerCount(); // Get all players Collection players = universe.getPlayers(); // Get player by name Player player = universe.getPlayer("PlayerName"); // Get player by UUID Player player = universe.getPlayer(uuid); ``` ## Worlds Each `World` represents a separate game environment with its own terrain, entities, and rules. ### World Properties ```java World world = universe.getWorld("default"); // Basic properties String name = world.getName(); WorldConfig config = world.getConfig(); // State boolean isPaused = world.isPaused(); long tick = world.getTick(); // Stores EntityStore entityStore = world.getEntityStore(); ChunkStore chunkStore = world.getChunkStore(); ``` ### World Configuration ```java WorldConfig config = WorldConfig.builder() .generator(myWorldGenProvider) // World generation .storage(myChunkStorageProvider) // Chunk persistence .resourceStorage(myResourceProvider) // Resource storage .worldMap(myWorldMapProvider) // World map provider .spawn(mySpawnProvider) // Spawn point provider .gameplay(gameplayConfig) // Gameplay settings .build(); ``` ## Chunks Worlds are divided into chunks for efficient loading and rendering. ### Chunk Access ```java World world = universe.getWorld("default"); // Get chunk at world coordinates Chunk chunk = world.getChunk(x, y, z); // Get chunk column (all chunks at x,z) ChunkColumn column = world.getChunkColumn(x, z); // Check if chunk is loaded boolean loaded = world.isChunkLoaded(x, y, z); ``` ### Chunk Store ```java ChunkStore chunkStore = world.getChunkStore(); // Get chunk data ChunkData data = chunkStore.getChunk(chunkX, chunkY, chunkZ); // Iterate loaded chunks chunkStore.forEachLoaded((chunkPos, chunk) -> { // Process chunk }); ``` ### Block Access ```java World world = universe.getWorld("default"); // Get block at position BlockState block = world.getBlock(x, y, z); // Set block at position world.setBlock(x, y, z, newBlockState); // Get block type BlockType type = block.getType(); ``` ## World Events ### Listening for World Events ```java // World added getEventRegistry().register(AddWorldEvent.class, event -> { World world = event.getWorld(); getLogger().info("World added: " + world.getName()); }); // World removed getEventRegistry().register(RemoveWorldEvent.class, event -> { World world = event.getWorld(); getLogger().info("World removed: " + world.getName()); }); // World started getEventRegistry().register(StartWorldEvent.class, event -> { World world = event.getWorld(); getLogger().info("World started: " + world.getName()); }); // All worlds loaded getEventRegistry().register(AllWorldsLoadedEvent.class, event -> { getLogger().info("All worlds have been loaded!"); }); // Player added to world getEventRegistry().register(AddPlayerToWorldEvent.class, event -> { Player player = event.getPlayer(); World world = event.getWorld(); getLogger().info(player.getName() + " entered " + world.getName()); }); // Player removed from world getEventRegistry().register(DrainPlayerFromWorldEvent.class, event -> { Player player = event.getPlayer(); World world = event.getWorld(); getLogger().info(player.getName() + " left " + world.getName()); }); ``` ### Keyed World Events Some events are keyed by world name: ```java // Listen for events in a specific world getEventRegistry().register(AddPlayerToWorldEvent.class, "spawn_world", event -> { // Only triggered for "spawn_world" event.getPlayer().sendMessage("Welcome to spawn!"); }); ``` ## World Generation ### World Generation Provider Implement `IWorldGenProvider` for custom world generation: ```java public class MyWorldGenProvider implements IWorldGenProvider { @Override public void generate(ChunkData chunk, int chunkX, int chunkY, int chunkZ) { // Generate terrain for this chunk for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { int height = calculateHeight(chunkX * 16 + x, chunkZ * 16 + z); for (int y = 0; y < 16; y++) { int worldY = chunkY * 16 + y; BlockState block = getBlockForPosition(worldY, height); chunk.setBlock(x, y, z, block); } } } } private int calculateHeight(int worldX, int worldZ) { // Use noise functions for terrain generation return 64 + (int)(Math.sin(worldX * 0.1) * 10); } private BlockState getBlockForPosition(int y, int surfaceHeight) { if (y > surfaceHeight) { return BlockStates.AIR; } else if (y == surfaceHeight) { return BlockStates.GRASS; } else if (y > surfaceHeight - 3) { return BlockStates.DIRT; } else { return BlockStates.STONE; } } } ``` ### Procedural Generation Utilities The `procedurallib` package provides utilities for procedural generation: ```java // Noise generation PerlinNoise noise = new PerlinNoise(seed); double value = noise.getValue(x, y, z); // Multi-octave noise FractalNoise fractal = FractalNoise.builder() .octaves(4) .persistence(0.5) .lacunarity(2.0) .build(); double terrain = fractal.getValue(x, z); ``` ## Spawn System ### Spawn Provider Implement `ISpawnProvider` for custom spawn logic: ```java public class MySpawnProvider implements ISpawnProvider { @Override public Vector3d getSpawnLocation(Player player, World world) { // Calculate spawn location for player return new Vector3d(0, 64, 0); } @Override public float getSpawnYaw(Player player, World world) { return 0.0f; } } ``` ### Built-in Spawning The `spawning` module provides entity spawning capabilities: ```java // Spawn entities based on spawn rules SpawnManager spawner = world.getSpawnManager(); // Trigger spawn checks in area spawner.checkSpawns(position, radius); ``` ## Chunk Storage ### Storage Provider Implement `IChunkStorageProvider` for custom chunk persistence: ```java public class MyChunkStorageProvider implements IChunkStorageProvider { @Override public CompletableFuture load(int x, int y, int z) { // Load chunk from storage return CompletableFuture.supplyAsync(() -> { return loadFromDatabase(x, y, z); }); } @Override public CompletableFuture save(int x, int y, int z, ChunkData data) { // Save chunk to storage return CompletableFuture.runAsync(() -> { saveToDatabase(x, y, z, data); }); } } ``` ## Teleportation ### Teleporting Players ```java Player player = getPlayer(); // Teleport to position in same world Vector3d destination = new Vector3d(100, 64, 200); player.teleport(destination); // Teleport with rotation player.teleport(destination, yaw, pitch); // Teleport to another world World targetWorld = universe.getWorld("nether"); player.teleport(targetWorld, destination); ``` ### Teleportation Events The `teleport` built-in module handles teleportation: ```java // Custom teleportation with effects TeleportManager.teleport(player, destination, new TeleportOptions() .withEffect(TeleportEffect.PARTICLES) .withSound(true)); ``` ## Portals The `portals` built-in module provides portal functionality: ```java // Create a portal Portal portal = Portal.builder() .position(sourcePosition) .destination(targetWorld, destPosition) .size(2, 3) // width, height .build(); // Register portal with world world.addPortal(portal); ``` ## Multi-World Management ### Creating Multiple Worlds ```java @Override protected void start() { Universe universe = Universe.get(); // Create custom world configurations WorldConfig spawnConfig = WorldConfig.builder() .generator(new FlatWorldGenerator()) .gameplay(GameplayConfig.CREATIVE) .build(); WorldConfig survivalConfig = WorldConfig.builder() .generator(new HytaleWorldGenerator()) .gameplay(GameplayConfig.SURVIVAL) .build(); // Register worlds (if supported) // universe.createWorld("spawn", spawnConfig); // universe.createWorld("survival", survivalConfig); } ``` ### World Transitions ```java public void sendToWorld(Player player, String worldName) { World targetWorld = Universe.get().getWorld(worldName); if (targetWorld == null) { player.sendMessage("World not found: " + worldName); return; } // Get spawn location for target world Vector3d spawn = targetWorld.getSpawnLocation(); // Teleport player player.teleport(targetWorld, spawn); } ``` ## Best Practices 1. **Cache world references** - Don't repeatedly call `Universe.get().getWorld()` in hot paths 2. **Handle world events** - Listen for world lifecycle events for initialization/cleanup 3. **Use async chunk operations** - Chunk loading/saving should be asynchronous 4. **Respect chunk boundaries** - Be aware of chunk boundaries when modifying blocks 5. **Clean up on world removal** - Handle `RemoveWorldEvent` to clean up resources 6. **Use keyed events** - Listen for world-specific events when possible 7. **Consider view distance** - Be mindful of server view distance settings 8. **Test multi-world scenarios** - Ensure your plugin works across multiple worlds