242 lines
6.9 KiB
Odin
242 lines
6.9 KiB
Odin
package game
|
|
|
|
import rl "vendor:raylib"
|
|
import "core:fmt"
|
|
import "core:os"
|
|
import "core:path/filepath"
|
|
import "core:mem"
|
|
import "core:math"
|
|
|
|
CELL_SIZE :: 16
|
|
CHUNK_SIZE :: 32
|
|
WORLD_DATA_PATH :: "data/worlds"
|
|
|
|
World :: struct {
|
|
data_dir: string,
|
|
chunks: map[Vec2i]Chunk,
|
|
seed: i64
|
|
}
|
|
|
|
Chunk :: struct #packed {
|
|
position: Vec2i,
|
|
tiles: [CHUNK_SIZE][CHUNK_SIZE]Tile,
|
|
biome_id:u32,
|
|
}
|
|
|
|
create_world :: proc(name:string, seed:i64) -> World {
|
|
data_dir := fmt.tprintf("%v/%v", WORLD_DATA_PATH, name)
|
|
if !os.is_dir(data_dir) {
|
|
fmt.printfln("Data dir: %v does not exist", data_dir)
|
|
os.make_directory(data_dir)
|
|
}
|
|
|
|
chunk_dir := fmt.tprintf("%v/%v", data_dir, "chunks")
|
|
if !os.is_dir(chunk_dir) {
|
|
os.make_directory(chunk_dir)
|
|
}
|
|
|
|
return World {
|
|
data_dir = data_dir,
|
|
chunks = make(map[Vec2i]Chunk),
|
|
seed = seed
|
|
}
|
|
}
|
|
|
|
load_world :: proc(name:string, seed:i64) -> World {
|
|
dir := fmt.tprintf("%v/%v", WORLD_DATA_PATH, name)
|
|
if !os.is_dir(dir) {
|
|
panic("Couldnt load world")
|
|
}
|
|
|
|
return World {
|
|
data_dir = dir,
|
|
chunks = make(map[Vec2i]Chunk),
|
|
seed = seed
|
|
}
|
|
}
|
|
|
|
save_world :: proc(w:^World) {
|
|
if !os.is_dir(w.data_dir) {
|
|
panic("World has invalid data_path")
|
|
}
|
|
|
|
// fmt.printfln("Saving world %v", w.data_dir)
|
|
|
|
for chunk in w.chunks {
|
|
save_chunk(get_chunk(w, chunk), w)
|
|
}
|
|
}
|
|
|
|
save_chunk :: proc(c:^Chunk, w:^World) {
|
|
chunk_dir := fmt.tprintf("%v/%v", w.data_dir, "chunks")
|
|
filename := fmt.tprintf("%v/%v_%v.chunk", chunk_dir, c.position.x, c.position.y)
|
|
|
|
// fmt.printfln("Saving chunk: %v", filename)
|
|
|
|
data := make([dynamic]u8)
|
|
|
|
// Append Position
|
|
for byte in transmute([size_of(int)]u8)c.position.x {append(&data, byte)}
|
|
for byte in transmute([size_of(int)]u8)c.position.y {append(&data, byte)}
|
|
|
|
// Append Tiles
|
|
for row in &c.tiles {
|
|
for tile in row {
|
|
for byte in transmute([size_of(int)]u8)tile.tilemap_pos.x {append(&data, byte)}
|
|
for byte in transmute([size_of(int)]u8)tile.tilemap_pos.y {append(&data, byte)}
|
|
for byte in transmute([4]u8)tile.color {append(&data, byte)}
|
|
for byte in transmute([size_of(TileType)]u8)tile.type {append(&data, byte)}
|
|
for byte in transmute([size_of(InteractionType)]u8)tile.interaction {append(&data, byte)}
|
|
for byte in transmute([size_of(ResourceType)]u8)tile.resource {append(&data, byte)}
|
|
}
|
|
}
|
|
|
|
// Biome ID
|
|
for byte in transmute([size_of(u32)]u8)c.biome_id {append(&data, byte)}
|
|
|
|
err := os.write_entire_file_or_err(filename, data[:])
|
|
|
|
}
|
|
|
|
load_chunk :: proc(pos:Vec2i, w:^World) -> Chunk {
|
|
chunk_dir := fmt.tprintf("%v/%v", w.data_dir, "chunks")
|
|
filename := fmt.tprintf("%v/%v_%v.chunk", chunk_dir, pos.x, pos.y)
|
|
|
|
data, err := os.read_entire_file_from_filename_or_err(filename)
|
|
if err != nil {
|
|
// fmt.printfln("No chunk %v found, generating new chunk", pos)
|
|
chunk := generate_chunk(pos, w.seed)
|
|
save_chunk(&chunk, w)
|
|
return chunk
|
|
}
|
|
|
|
chunk: Chunk
|
|
offset := 0
|
|
|
|
// Load Position
|
|
mem.copy(transmute([^]u8)&chunk.position.x, &data[offset], size_of(int))
|
|
offset += size_of(int)
|
|
mem.copy(transmute([^]u8)&chunk.position.y, &data[offset], size_of(int))
|
|
offset += size_of(int)
|
|
|
|
// Load tiles
|
|
for row_index := 0; row_index < len(chunk.tiles); row_index += 1 {
|
|
for tile_index := 0; tile_index < len(chunk.tiles[row_index]); tile_index += 1 {
|
|
tile := &chunk.tiles[row_index][tile_index] // Get address of tile
|
|
mem.copy(&tile.tilemap_pos.x, &data[offset], size_of(int))
|
|
offset += size_of(int)
|
|
mem.copy(&tile.tilemap_pos.y, &data[offset], size_of(int))
|
|
offset += size_of(int)
|
|
|
|
// Load color
|
|
color_temp: [4]u8
|
|
mem.copy(&color_temp, &data[offset], 4)
|
|
tile.color = color_temp
|
|
offset += 4
|
|
|
|
mem.copy(&tile.type, &data[offset], size_of(TileType))
|
|
offset += size_of(TileType)
|
|
mem.copy(&tile.interaction, &data[offset], size_of(InteractionType))
|
|
offset += size_of(InteractionType)
|
|
mem.copy(&tile.resource, &data[offset], size_of(ResourceType))
|
|
offset += size_of(ResourceType)
|
|
}
|
|
}
|
|
|
|
// Load Biome ID
|
|
mem.copy(transmute([^]u8)&chunk.biome_id, &data[offset], size_of(u32))
|
|
offset += size_of(u32)
|
|
|
|
return chunk
|
|
|
|
}
|
|
|
|
unload_chunk :: proc(pos:Vec2i, w:^World) {
|
|
_, exists := w.chunks[pos]
|
|
if exists {
|
|
save_chunk(get_chunk(w, pos), w)
|
|
delete_key(&w.chunks, pos)
|
|
}
|
|
}
|
|
|
|
|
|
get_chunk :: proc(w:^World, chunk_pos:Vec2i) -> ^Chunk {
|
|
chunk, exists := w.chunks[chunk_pos]
|
|
if !exists {
|
|
w.chunks[chunk_pos] = load_chunk(chunk_pos, w)
|
|
}
|
|
return &w.chunks[chunk_pos]
|
|
}
|
|
|
|
get_chunk_from_world_pos :: proc(w:^World, pos:rl.Vector2) -> ^Chunk {
|
|
chunk_pos := world_pos_to_chunk_pos(pos)
|
|
return get_chunk(w, chunk_pos)
|
|
}
|
|
|
|
world_pos_to_chunk_pos :: proc(pos:rl.Vector2) -> Vec2i {
|
|
|
|
x := int(math.floor(pos.x / CHUNK_SIZE))
|
|
y := int(math.floor(pos.y / CHUNK_SIZE))
|
|
return Vec2i{x,y}
|
|
}
|
|
|
|
get_local_chunk_pos :: proc(pos:Vec2i) -> Vec2i {
|
|
x := (pos.x % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE
|
|
y := (pos.y % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE
|
|
|
|
return Vec2i{x,y}
|
|
}
|
|
|
|
get_world_tile :: proc(w:^World, pos:Vec2i) -> ^Tile {
|
|
chunk_x := int(math.floor(f32(pos.x) / f32(CHUNK_SIZE)))
|
|
chunk_y := int(math.floor(f32(pos.y) / f32(CHUNK_SIZE)))
|
|
chunk_pos := Vec2i{chunk_x, chunk_y}
|
|
|
|
local_x := (pos.x % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE
|
|
local_y := (pos.y % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE
|
|
local_pos := Vec2i{local_x, local_y}
|
|
|
|
chunk := get_chunk(w, chunk_pos)
|
|
return get_chunk_tile(chunk, local_pos)
|
|
|
|
// chunk_pos := world_pos_to_chunk_pos(vec2i_to_vec2(pos))
|
|
// local_pos := get_local_chunk_pos(pos)
|
|
//
|
|
// chunk := get_chunk(w, chunk_pos)
|
|
|
|
// return get_chunk_tile(chunk, local_pos)
|
|
}
|
|
|
|
get_chunk_tile :: proc(c:^Chunk, pos:Vec2i) -> ^Tile {
|
|
return &c.tiles[pos.x][pos.y]
|
|
}
|
|
|
|
set_chunk_tile :: proc(c:^Chunk, t:Tile, pos:Vec2i) {
|
|
c.tiles[pos.x][pos.y] = t
|
|
}
|
|
|
|
set_tile :: proc(w:^World, t:Tile, p:Vec2i) {
|
|
chunk := get_chunk_from_world_pos(w, vec2i_to_vec2(p))
|
|
|
|
set_chunk_tile(chunk, t, get_local_chunk_pos(p))
|
|
|
|
save_chunk(chunk, w)
|
|
}
|
|
|
|
draw_world :: proc(w:^World) {
|
|
for chunk_pos, chunk in w.chunks {
|
|
for x in 0..<CHUNK_SIZE {
|
|
for y in 0..<CHUNK_SIZE {
|
|
tile := chunk.tiles[x][y]
|
|
world_x := chunk_pos.x * CHUNK_SIZE + x
|
|
world_y := chunk_pos.y * CHUNK_SIZE + y
|
|
pos := rl.Vector2{f32(world_x * CELL_SIZE), f32(world_y * CELL_SIZE)}
|
|
|
|
if tile.type != .NOTHING {
|
|
draw_tile(vec2i_to_vec2(tile.tilemap_pos), pos, rl.Color(tile.color))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|