clean up world loading logic and add chunk occupancy masks

This commit is contained in:
Tuomas Katajisto 2026-09-18 23:28:43 +03:00
parent 595df5aed5
commit e601e5e85d
4 changed files with 48 additions and 130 deletions

View File

@ -168,28 +168,15 @@ process_completed_fetch :: (req: *Fetch_Request, data: []u8) {
array_add(*g_asset_manager.loadedPacks, pack);
case .WORLD;
is_json := data.count > 0 && data[0] == #char "{";
if is_json {
json_copy := NewArray(data.count, u8, false);
memcpy(json_copy.data, data.data, data.count);
chunks_req: Fetch_Request;
chunks_req.type = .WORLD_CHUNKS;
chunks_req.priority = req.priority;
chunks_req.world_name = req.world_name;
chunks_req.path = sprint("%/worlds/%/chunks.bin", GAME_RESOURCES_DIR, req.world_name);
chunks_req.world_json_data = json_copy;
array_add(*g_asset_manager.queue, chunks_req);
} else {
world, ok := load_world_from_data(data);
if ok {
set_loaded_world(world);
rdm_loader_enqueue_world(*get_current_world().world);
shgrid_loader_enqueue_world(*get_current_world().world);
log_info("Loaded world (legacy): %", req.world_name);
} else {
log_error("Failed to parse world '%'", req.world_name);
}
}
json_copy := NewArray(data.count, u8, false);
memcpy(json_copy.data, data.data, data.count);
chunks_req: Fetch_Request;
chunks_req.type = .WORLD_CHUNKS;
chunks_req.priority = req.priority;
chunks_req.world_name = req.world_name;
chunks_req.path = sprint("%/worlds/%/chunks.bin", GAME_RESOURCES_DIR, req.world_name);
chunks_req.world_json_data = json_copy;
array_add(*g_asset_manager.queue, chunks_req);
case .WORLD_CHUNKS;
json_data := req.world_json_data;

View File

@ -1 +1,2 @@
#load "colliders.jai";
#load "worldphysics.jai";

View File

@ -0,0 +1,15 @@
is_trile_collision :: (fx: float, fy: float, fz: float) -> bool {
x := cast(s32)fx;
y := cast(s32)fy;
z := cast(s32)fz;
world := get_current_world();
key := world_to_chunk_coord(x, y, z);
chunk := table_find_pointer(*world.world.chunks, key);
if !chunk then return false;
lx, ly, lz := world_to_local(x, y, z);
print("% % %\n", lx, ly, lz);
return chunk.occupancy_mask[lx][ly][lz];
}

View File

@ -59,6 +59,8 @@ Chunk :: struct {
coord: Chunk_Key;
groups: [..]Chunk_Trile_Group;
occupancy_mask : [32][32][32]bool;
sh_probe_grid: sg_image; // 192x4096 RGBA16F 2D texture (2 probes/trile/axis)
sh_valid: bool;
sh_dirty: bool;
@ -97,6 +99,26 @@ World :: struct {
rdm_lookup : [..]Rdm_Atlas_Entry; // populated by bake (Step 5) and by loader (Step 6)
}
calculate_and_set_chunk_occupancy_mask :: (chunk: *Chunk) {
print("Calculating occupancy mask for chunk %\n", chunk.coord);
// Clear it first:
for i: 0..15 {
for j: 0..15 {
for k: 0..15 {
chunk.occupancy_mask[i][j][k] = false;
}
}
}
for group: chunk.groups {
// @ToDo: Handle non-colliding triles by getting the
// trile data here and continuing if it's non-colliding.
for instance : group.instances {
chunk.occupancy_mask[instance.x][instance.y][instance.z] = true;
}
}
}
rdm_get_atlas_rect :: (world: *World, x: s32, y: s32, z: s32) -> (Vector4, bool) {
for world.rdm_lookup {
if it.x == x && it.y == y && it.z == z then return it.atlas_rect, true;
@ -776,6 +798,7 @@ load_world_from_json :: (json_str: string, chunk_bin: []u8) -> (World, bool) {
group.average_pos = gavg;
array_add(*chunk.groups, group);
}
calculate_and_set_chunk_occupancy_mask(*chunk);
table_set(*world.chunks, chunk.coord, chunk);
}
@ -813,114 +836,6 @@ load_world_from_json :: (json_str: string, chunk_bin: []u8) -> (World, bool) {
return world, true;
}
load_world_from_data :: (data: []u8) -> (World, bool) {
world: World;
cursor: s64 = 0;
if data.count < size_of(u32) + size_of(u16) {
log_error("World file too small");
return world, false;
}
// Header
magic := read_value(data, *cursor, u32);
if magic != WORLD_MAGIC {
log_error("Invalid world file magic");
return world, false;
}
version := read_value(data, *cursor, u16);
if version != 1 && version != 2 && version != 3 {
log_error("Unsupported world version: %", version);
return world, false;
}
name_len := cast(s64) read_value(data, *cursor, u16);
world.name = read_string(data, *cursor, name_len);
// World config
conf_bin := read_value(data, *cursor, World_Config_Binary);
world.conf = world_config_from_binary(*conf_bin);
num_chunks := read_value(data, *cursor, u32);
// Read chunk table
Chunk_Table_Entry :: struct {
coord: Chunk_Key;
offset: u32;
size: u32;
}
chunk_table: [..]Chunk_Table_Entry;
chunk_table.allocator = temp;
for i: 0..cast(s64)num_chunks-1 {
entry: Chunk_Table_Entry;
entry.coord.x = read_value(data, *cursor, s32);
entry.coord.y = read_value(data, *cursor, s32);
entry.coord.z = read_value(data, *cursor, s32);
entry.offset = read_value(data, *cursor, u32);
entry.size = read_value(data, *cursor, u32);
array_add(*chunk_table, entry);
}
// Read chunk data
for entry: chunk_table {
chunk_cursor: s64 = cast(s64) entry.offset;
chunk: Chunk;
chunk.coord = entry.coord;
num_types := read_value(data, *chunk_cursor, u16);
for t: 0..cast(s64)num_types-1 {
group: Chunk_Trile_Group;
gname_len := cast(s64) read_value(data, *chunk_cursor, u16);
group.trile_name = read_string(data, *chunk_cursor, gname_len);
count := cast(s64) read_value(data, *chunk_cursor, u16);
for i: 0..count-1 {
inst := read_value(data, *chunk_cursor, Trile_Instance);
array_add(*group.instances, inst);
}
array_add(*chunk.groups, group);
}
table_set(*world.chunks, chunk.coord, chunk);
}
if chunk_table.count > 0 {
last := chunk_table[chunk_table.count - 1];
cursor = cast(s64)(last.offset + last.size);
}
if version >= 2 && cursor < data.count {
num_emitters := cast(s64) read_value(data, *cursor, u16);
for i: 0..num_emitters-1 {
inst: Particle_Emitter_Instance;
name_len := cast(s64) read_value(data, *cursor, u16);
inst.definition_name = read_string(data, *cursor, name_len);
inst.position.x = read_value(data, *cursor, float);
inst.position.y = read_value(data, *cursor, float);
inst.position.z = read_value(data, *cursor, float);
inst.active = true;
array_add(*world.emitter_instances, inst);
}
}
if version >= 3 && cursor < data.count {
num_notes := cast(s64) read_value(data, *cursor, u16);
for i: 0..num_notes-1 {
note: Editor_Note;
text_len := cast(s64) read_value(data, *cursor, u16);
note.text = read_string(data, *cursor, text_len);
note.position.x = read_value(data, *cursor, s32);
note.position.y = read_value(data, *cursor, s32);
note.position.z = read_value(data, *cursor, s32);
array_add(*world.notes, note);
}
}
return world, true;
}
World_Config :: struct {
// All of the @Notes are for the autoedit functionality.
skyBase : Vector3 = .{0.38, 0.81, 0.95}; @Color