From 187d6d32e71aface08c1c486874901ecc9b160c1 Mon Sep 17 00:00:00 2001 From: ubq323 Date: Tue, 16 Apr 2024 12:34:18 +0100 Subject: fix chunkloading and unloading on client --- client/pictures.ha | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 client/pictures.ha (limited to 'client/pictures.ha') diff --git a/client/pictures.ha b/client/pictures.ha new file mode 100644 index 0000000..1db3954 --- /dev/null +++ b/client/pictures.ha @@ -0,0 +1,145 @@ +use fmt; +use net; + +use sdl2; + +use drawing::{picture,pos,CHUNKSIZE}; +use drawing; +use packet_reader; + +type picture_mgr = struct { + pictures: []picture_c, + requests: []pos, +}; + +type picture_c = struct { + picture, + surface: *sdl2::SDL_Surface, +}; + + +fn is_picture_visible(camera_pos: pos, pic_pos: pos) bool = { + const s_min: pos = camera_pos; + const s_max: pos = (camera_pos.0 + WIN_W, camera_pos.1 + WIN_H); + const p_min: pos = pic_pos; + const p_max: pos = (pic_pos.0 + CHUNKSIZE: i32, pic_pos.1 + CHUNKSIZE: i32); + return (s_min.0 <= p_max.0 && s_max.0 >= p_min.0) + && (s_min.1 <= p_max.1 && s_max.1 >= p_min.1); +}; + +fn find_picture_by_pos(pmgr: *picture_mgr, world_pos: pos) + nullable *picture = { + for (const pic &.. pmgr.pictures) { + if (pic.world_pos.0 == world_pos.0 + && pic.world_pos.1 == world_pos.1) { + return pic; + }; + }; + return null; +}; + +// called when a new chunkdata packet comes in +fn enact_chunkdata(pmgr: *picture_mgr, + packet: packet_reader::packet_sendchunk, + camera_pos: pos, +) void = { + assert(packet.world_pos.0 % CHUNKSIZE == 0 + && packet.world_pos.1 % CHUNKSIZE == 0, + "bad chunk world pos"); + assert(len(packet.chunk_data) == CHUNKSIZE*CHUNKSIZE, + "bad chunk data size"); + + const surf = sdl2::SDL_CreateRGBSurface(0, + CHUNKSIZE, CHUNKSIZE, 32, 0xff0000, 0xff00, 0xff, 0)!; + append(pmgr.pictures, picture_c { + w = CHUNKSIZE, + h = CHUNKSIZE, + d = (surf.pixels as *opaque: *[*]u32), + world_pos = packet.world_pos, + surface = surf, + }); + + const p = &pmgr.pictures[len(pmgr.pictures)-1]; + p.d[..p.w*p.h] = packet.chunk_data[..]; + + // delete extant request + for (let i = 0z; i < len(pmgr.requests); i += 1) { + const rc = pmgr.requests[i]; + if (rc.0 == packet.world_pos.0 && rc.1 == packet.world_pos.1) { + delete(pmgr.requests[i]); + break; + }; + }; +}; + +fn floor_div(a: i32, b: i32) i32 = { + if (a < 0) return -1-floor_div(-(a+1),b); + return a / b; +}; + + +fn is_request_inflight(pmgr: *picture_mgr, world_pos: pos) bool = { + for (const rc .. pmgr.requests) + if (rc.0 == world_pos.0 && rc.1 == world_pos.1) + return true; + return false; +}; + +// called on startup and on camera movement +// for each loaded chunk not visible, unload it +// for each chunk that should be visible that isn't loaded +// and which hasn't already been requested, +// request it. +fn process_chunk_loadedness( + pmgr: *picture_mgr, + conn: net::socket, + camera_pos: pos, +) void = { + + // unload all invisible chunks + for (let i1 = len(pmgr.pictures); i1 > 0; i1 -= 1) { + const i = i1 - 1; + const pic = pmgr.pictures[i]; + if (!is_picture_visible(camera_pos, pic.world_pos)) { + fmt::printfln("## unloading {},{}", pic.world_pos.0, pic.world_pos.1)!; + delete(pmgr.pictures[i]); + }; + }; + + + const x0 = CHUNKSIZE*floor_div(camera_pos.0,CHUNKSIZE); + const y0 = CHUNKSIZE*floor_div(camera_pos.1,CHUNKSIZE); + + // use a 3x3 window for 'chunks that might need to be loaded' + for (let dx = 0i32; dx < 3; dx += 1) { + for (let dy = 0i32; dy < 3; dy += 1) { + const world_pos = (x0 + CHUNKSIZE*dx, y0 + CHUNKSIZE*dy): pos; + const visible = is_picture_visible(camera_pos, world_pos); + const loaded = !(find_picture_by_pos(pmgr, world_pos) is null); + const requested = is_request_inflight(pmgr, world_pos); + + if (!visible) { + fmt::printfln("\tnot visible {},{}", world_pos.0, world_pos.1)!; + continue; + }; + if (loaded) { + fmt::printfln("\talready loaded {},{}", world_pos.0, world_pos.1)!; + continue; + }; + if (requested) { + fmt::printfln("\tnot requesting again {},{}", world_pos.0, world_pos.1)!; + continue; + }; + + fmt::printfln("!! requesting {},{}", world_pos.0, world_pos.1)!; + packet_reader::send(conn, world_pos: packet_reader::packet_reqchunk)!; + append(pmgr.requests, world_pos); + }; + }; +}; + + +fn perform_drawop(pmgr: *picture_mgr, op: drawing::op) void = { + for (const pic &.. pmgr.pictures) + drawing::perform(pic, op); +}; -- cgit v1.2.3