268 lines
6.7 KiB
Odin
268 lines
6.7 KiB
Odin
package game
|
|
|
|
import rl "vendor:raylib"
|
|
import "core:fmt"
|
|
import "core:os"
|
|
import "core:path/filepath"
|
|
|
|
CELL_SIZE :: 16
|
|
CHUNK_SIZE :: 32
|
|
WORLD_DATA_PATH :: "data/worlds"
|
|
|
|
World :: struct {
|
|
data_dir: string,
|
|
chunks: map[Vec2i]Chunk
|
|
}
|
|
|
|
Chunk :: struct #packed {
|
|
position: Vec2i,
|
|
tiles: [CHUNK_SIZE][CHUNK_SIZE]Tile,
|
|
}
|
|
|
|
create_world :: proc(name:string) -> 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),
|
|
}
|
|
}
|
|
|
|
load_world :: proc(name:string) -> 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),
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
serialize_chunk :: proc(c:^Chunk) -> []byte {
|
|
data : [dynamic]byte
|
|
|
|
// Position
|
|
pos_bytes := serialize_vec2i(c.position)
|
|
append(&data, ..pos_bytes[:])
|
|
|
|
// Tiles
|
|
for y in 0..<CHUNK_SIZE {
|
|
for x in 0..<CHUNK_SIZE {
|
|
tile_bytes := serialize_tile(c.tiles[x][y])
|
|
fmt.printfln("Serialized tile size: %v", len(tile_bytes))
|
|
append(&data, ..tile_bytes[:])
|
|
}
|
|
}
|
|
|
|
fmt.printfln("Serialized chunk size: %v", len(data)) // Print final serialized size
|
|
fmt.printfln("Before serialization, Chunk position: %v", c.position)
|
|
return data[:]
|
|
}
|
|
|
|
|
|
deserialize_chunk :: proc(data: []byte) -> Chunk {
|
|
chunk: Chunk
|
|
|
|
// Position
|
|
chunk.position = deserialize_vec2i(data[0:8])
|
|
|
|
// Tiles
|
|
offset := 8
|
|
tile_size := size_of(Tile)
|
|
|
|
// Check total expected size of data
|
|
expected_size := offset + (CHUNK_SIZE * CHUNK_SIZE * tile_size)
|
|
if len(data) != expected_size {
|
|
fmt.printfln("Error: Data size mismatch. Expected size: %v, Actual size: %v", expected_size, len(data))
|
|
fmt.printfln("Chunk position: %v", chunk.position)
|
|
|
|
return chunk // Return empty or invalid chunk to handle the error.
|
|
}
|
|
|
|
for y in 0..<CHUNK_SIZE {
|
|
for x in 0..<CHUNK_SIZE {
|
|
start := offset + (y * CHUNK_SIZE + x) * tile_size
|
|
end := start + tile_size
|
|
|
|
fmt.printfln("Start:%v, End:%v", start, end)
|
|
|
|
if end > len(data) {
|
|
fmt.printfln("Out of bounds access. Start:%v, End:%v | Data Length: %v", start, end, len(data))
|
|
break
|
|
}
|
|
|
|
chunk.tiles[x][y] = deserialize_tile(data[start:end])
|
|
}
|
|
}
|
|
|
|
fmt.printfln("Expected chunk size: %v | Serialized chunk data size: %v", size_of(Chunk), len(data))
|
|
|
|
return chunk
|
|
}
|
|
|
|
|
|
save_chunk :: proc(c:^Chunk, w:^World) {
|
|
chunk_dir := fmt.tprintf("%v/%v", w.data_dir, "chunks")
|
|
if !os.is_dir(chunk_dir) {
|
|
os.make_directory(chunk_dir)
|
|
}
|
|
|
|
filename := fmt.tprintf("%v/%v_%v.chunk", chunk_dir, c.position.x, c.position.y)
|
|
|
|
data := serialize_chunk(c)
|
|
|
|
fmt.printfln("Writing chunk data: %v bytes", len(data))
|
|
|
|
|
|
err := os.write_entire_file_or_err(filename, data)
|
|
|
|
if err != nil {
|
|
fmt.printfln("Failed to save chunk: %v", err)
|
|
}
|
|
}
|
|
|
|
load_chunk :: proc(pos:Vec2i, w:^World) -> Chunk {
|
|
chunk_dir := fmt.tprintf("%v/%v", w.data_dir, "chunks")
|
|
if !os.is_dir(chunk_dir) {
|
|
|
|
}
|
|
|
|
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("Chunk %v file does not exist, creating new chunk", pos)
|
|
return generate_chunk(pos)
|
|
}
|
|
|
|
return deserialize_chunk(data)
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
|
|
generate_chunk :: proc(pos:Vec2i) -> Chunk {
|
|
chunk := Chunk {position = pos}
|
|
|
|
for x in 0..<CHUNK_SIZE {
|
|
for y in 0..<CHUNK_SIZE {
|
|
chunk.tiles[x][y] = Tile {
|
|
type = .FOLIAGE,
|
|
tilemap_pos = {0,2},
|
|
interaction = .NOTHING,
|
|
resource = .NOTHING,
|
|
color = rl.GREEN
|
|
}
|
|
}
|
|
}
|
|
|
|
center_pos := Vec2i{CHUNK_SIZE/2, CHUNK_SIZE/2}
|
|
// set_chunk_tile(&chunk, tree_tile, center_pos)
|
|
|
|
return chunk
|
|
}
|
|
|
|
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 {
|
|
chunk_pos := vec2_to_vec2i({pos.x / CHUNK_SIZE, pos.y / CHUNK_SIZE})
|
|
return chunk_pos
|
|
}
|
|
|
|
get_local_chunk_pos :: proc(pos:Vec2i) -> Vec2i {
|
|
return Vec2i {
|
|
(pos.x % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE,
|
|
(pos.y % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE,
|
|
}
|
|
}
|
|
|
|
get_world_tile :: proc(w:^World, pos:Vec2i) -> ^Tile {
|
|
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
|
|
}
|
|
|
|
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, tile.color)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// draw_world :: proc(w:^World) {
|
|
// for x in 0..< len(w.grid) {
|
|
// for y in 0..< len(w.grid) {
|
|
// tile := w.grid[x][y]
|
|
// posX := x * TILE_SIZE
|
|
// posY := y * TILE_SIZE
|
|
|
|
// if tile.type != .NOTHING {
|
|
// draw_tile(tile.tilemap_pos, {f32(posX), f32(posY)}, tile.color)
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|