World
The GameWorld is the container for all environmental data in Terrarum, including terrain, fluids, lighting, weather, and time. Each GameWorld represents a single playable dimension or planet.
Overview
A GameWorld consists of:
- Block Layers — Terrain, walls, ores, and fluids
- World Time — Day/night cycle and calendar
- Environmental Properties — Gravity, temperature, lighting
- Metadata — Dimensions, spawn points, creation time
- Weather System — Wind, precipitation, and atmospheric effects
- Wirings — Electrical/conduit connections between blocks
Creating a World
World Construction
To create a new world programmatically:
val world = GameWorld(
width = 8192, // Width in tiles
height = 2048, // Height in tiles
creationTIME_T = App.getTIME_T(),
lastPlayTIME_T = App.getTIME_T()
)
World Dimensions
World dimensions are measured in tiles. Common world sizes:
- Small: 4096 × 1024
- Medium: 8192 × 2048
- Large: 16384 × 4096
- Massive: 32768 × 8192
The engine supports millions of tiles through its chunked loading system.
Important: Dimensions must be positive integers. Worlds cannot be resized after creation.
World Indices
Each world has a unique UUID:
val worldIndex: UUID // Unique identifier for this world
This index distinguishes worlds in multi-world save games.
Block Layers
GameWorld uses multiple specialised layers to store different types of blocks:
Layer Types
layerTerrain
Foreground blocks that provide collision and form the main playable surface:
val layerTerrain: BlockLayerGenericI16
- Stores 16-bit block IDs
- Provides collision for actors
- Rendered in front of walls
layerWall
Background wall blocks:
val layerWall: BlockLayerGenericI16
- Stores 16-bit block IDs
- Typically non-solid
- Rendered behind terrain
- Affects lighting propagation
layerOres
Ore deposits overlaid on terrain blocks:
val layerOres: BlockLayerOresI16I8
- Stores 16-bit ore type + 8-bit ore coverage
- Rendered as overlay on terrain blocks
- Shares damage values with terrain
layerFluids
Fluid simulation data:
val layerFluids: BlockLayerFluidI16F16
- Stores 16-bit fluid type + 16-bit fluid amount
- Uses cellular automata for flow simulation
- Fluids have viscosity, colour, and density
Accessing Blocks
Block layers use tile coordinates (integers):
// Get a terrain block
val blockID: ItemID = world.getTileFromTerrain(x, y)
// Set a terrain block
world.setTileTerrain(x, y, blockID, false)
// Get a wall block
val wallID: ItemID = world.getTileFromWall(x, y)
// Set a wall block
world.setTileWall(x, y, wallID, false)
Coordinates:
- x — Horizontal tile position (0 to width-1)
- y — Vertical tile position (0 to height-1)
- Origin — Top-left corner is (0, 0)
Block Damage
Blocks can be partially damaged:
val terrainDamages: HashArray<Float> // 0.0 = undamaged, 1.0 = destroyed
val wallDamages: HashArray<Float>
Damage is indexed by block address (computed from x, y coordinates).
Chunk System
Worlds are divided into chunks for efficient storage and generation:
Chunk Dimensions
val CHUNK_W = 128 // Chunk width in tiles
val CHUNK_H = 128 // Chunk height in tiles
Chunks enable:
- Lazy Generation — Generate terrain on-demand as players explore
- Memory Efficiency — Only load visible/nearby chunks
- Save Optimisation — Only save modified chunks
Chunk Flags
Each chunk has a byte of flags:
val chunkFlags: Array<ByteArray>
Chunk flags track:
- Generation status
- Modification state
- Active/inactive state
The world generates partially during creation, then generates additional chunks as needed during gameplay, enabling fast world creation even for massive world sizes.
Tile Number Mapping
GameWorld maintains bidirectional mappings between block names (ItemIDs) and internal numbers:
// Name to number (for setting blocks)
val tileNameToNumberMap: HashMap<ItemID, Int>
// Number to name (for getting blocks)
val tileNumberToNameMap: HashArray<ItemID>
Special Tile Numbers
- 0 —
Block.AIR(empty space) - 1 —
Block.UPDATE(triggers block update) - 65535 —
Block.NOT_GENERATED(chunk not yet generated)
This mapping system allows worlds to persist blocks even when mods are added or removed, using the dynamicToStaticTable for remapping.
Spawn Points
Player Spawn
The tilewise coordinates where players initially appear:
var spawnX: Int
var spawnY: Int
// Convenience property
var spawnPoint: Point2i
Portal Point
Optional alternative spawn point (e.g., for teleportation):
var portalPoint: Point2i?
World Time
GameWorld includes a sophisticated time system:
val worldTime: WorldTime
Time Units
WorldTime uses seconds as the base unit:
const val SECOND_SEC = 1L
const val MINUTE_SEC = 60L
const val HOUR_SEC = 3600L
const val DAY_SEC = 86400L
Calendar System
The world uses a 360-day calendar:
- 12 months of 30 days each
- Days are 24 hours
- Year 125 (EPOCH) is the default starting year
Time Properties
worldTime.timeDelta // Seconds elapsed since last update
worldTime.TIME_T // Total seconds since epoch
Celestial Calculations
WorldTime calculates sun/moon positions and phases:
worldTime.solarNoonTime // Time of solar noon today
worldTime.lunarPhase // Current moon phase (0.0-1.0)
worldTime.eclipticLongitude // Sun's position on ecliptic
The time system simulates realistic seasons, equinoxes, and solstices.
Day/Night Cycle
The day/night cycle affects:
- Global lighting (
world.globalLight) - Actor behaviour (day/night AI changes)
- Block properties (dynamic light sources)
Environmental Properties
Gravity
Gravitational acceleration vector:
var gravitation: Vector2 = DEFAULT_GRAVITATION
Default gravity is approximately 9.8 m/s² downward. Currently, only downward gravity is supported.
Global Light
The baseline lighting level for the world:
var globalLight: Cvec // RGB+UV colour vector
Global light represents:
- Sunlight during day
- Moonlight/starlight at night
- Ambient light in caves (typically near-zero)
Global light is additive with block luminosity when calculating the final lightmap.
Average Temperature
The world's baseline temperature in Kelvin:
var averageTemperature: Float = 288f // 15°C
This affects environmental generation and could be used for climate simulation.
Weather System
GameWorld includes a weather simulation:
var weatherbox: Weatherbox
Weatherbox
The weatherbox manages:
- Current weather type (clear, rain, snow, fog, etc.)
- Wind direction and speed (with temporal smoothing)
- Precipitation intensity
- Atmospheric effects
Weather types are defined in the WeatherCodex.
Wind
Wind is simulated with temporal coherence using control points:
weatherbox.windDir // Wind direction (0.0-1.0 representing angles)
weatherbox.windSpeed // Wind speed (m/s)
Both properties use a point-interpolation system (pM3, pM2, pM1, p0, p1, p2, p3) for smooth transitions.
Wiring and Conduits
GameWorld supports wire/conduit networks for connecting devices:
val wirings: HashedWirings
Wire Types
Multiple wire types can occupy the same tile position:
- Electrical wires
- Fluid pipes
- Logic gates
- Data cables
Each wire type is stored separately in the wirings hash map.
Wire Connections
Wires connect in four directions (up, down, left, right) using bit flags:
// Connection bit positions
WIRE_POS_MAP = [1, 2, 4, 8] // Up, Right, Down, Left
Dynamic Items
Worlds can have dynamic item inventories that persist:
internal val dynamicItemInventory: ItemTable
This stores items that are unique to this world (e.g., procedurally generated equipment).
Game Rules
Arbitrary world-specific configuration:
val gameRules: KVHashMap
Game rules can store custom world settings such as:
- Difficulty modifiers
- Gameplay options
- World-specific flags
World Lifecycle
Creation Time
internal var creationTime: Long // Unix timestamp
Records when the world was first created.
Play Time
internal var lastPlayTime: Long // Last time the world was played
internal var totalPlayTime: Long // Cumulative play time in seconds
These track how long the world has been played.
Disposal
When switching worlds or exiting, dispose of the world properly:
world.dispose()
This frees:
- Block layer memory
- Chunk data
- Cached resources
Warning: Once disposed, a world cannot be used again. Set world.disposed flag to prevent accidental access.
Advanced Topics
SimpleGameWorld
For small, fixed-size worlds (e.g., mini-games), use SimpleGameWorld:
class SimpleGameWorld(width: Int, height: Int) : GameWorld(width, height)
SimpleGameWorld stores all data in a single file rather than using chunked storage.
Random Seeds
Worlds store 128 random seeds for deterministic generation:
val randSeeds: LongArray // 256 longs = 128 128-bit seeds
Specific ranges are reserved:
- Seeds 0-1: Roguelike randomiser
- Seeds 2-3: Weather mixer
- Seeds 4+: Available for custom use
Generator Seed
The primary seed used for world generation:
var generatorSeed: Long
This seed determines the initial terrain, caves, ores, and structures.
Best Practises
- Always check bounds before accessing blocks:
x in 0 until world.width - Use spawn points rather than hardcoding coordinates
- Dispose worlds when switching or exiting to prevent memory leaks
- Update world time every frame using
worldTime.timeDelta - Respect chunk boundaries when implementing generation algorithms
- Use tile number mapping for mod compatibility
- Set appropriate global light for the world's environment
Common Patterns
Iterating Over Visible Tiles
val camera: WorldCamera = ...
for (y in camera.yTileStart until camera.yTileEnd) {
for (x in camera.xTileStart until camera.xTileEnd) {
val block = world.getTileFromTerrain(x, y)
// Process block
}
}
Finding Safe Spawn Point
fun findSafeSpawnY(world: GameWorld, x: Int): Int {
for (y in 0 until world.height) {
val terrain = world.getTileFromTerrain(x, y)
val above = world.getTileFromTerrain(x, y - 1)
if (BlockCodex[terrain].isSolid && !BlockCodex[above].isSolid) {
return y - 1 // One tile above solid ground
}
}
return world.spawnY // Fallback
}
Checking Block Properties
fun isBlockSolid(world: GameWorld, x: Int, y: Int): Boolean {
val blockID = world.getTileFromTerrain(x, y)
return BlockCodex[blockID]?.isSolid ?: false
}
See Also
- Glossary — World-related terminology
- Save and Load — Persisting worlds to disk
- Modules:Blocks — Defining custom blocks
- Modules:Weather — Creating weather types
- Development:RAW — Data-driven world generation