package game import rl "vendor:raylib" import "core:fmt" import "core:os" import "core:path/filepath" import "core:mem" CELL_SIZE :: 16 CHUNK_SIZE :: 5 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) } } 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)} } } 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) 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 in &chunk.tiles { // for &tile in row { // mem.copy(transmute([^]u8)tile.tilemap_pos.x, &data[offset], size_of(int)) // offset += size_of(int) // mem.copy(transmute([^]u8)tile.tilemap_pos.y, &data[offset], size_of(int)) // offset += size_of(int) // //Color // tile.color = {} // // } // } // 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) } } 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) } } generate_chunk :: proc(pos:Vec2i) -> Chunk { chunk := Chunk {position = pos} for x in 0.. ^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 } 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..