diff --git a/src/ase.c b/src/ase.c index 7a425165..aba7408d 100644 --- a/src/ase.c +++ b/src/ase.c @@ -647,7 +647,10 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct buff br_seek(&br, sizeof(u8) * 3); u16 str_len = br_read_u16(&br); - u8 *str_bytes = br_read_raw(&br, str_len); + u8 *str_bytes = br_seek(&br, str_len); + if (!str_bytes) { + str_len = 0; + } layer->name = (struct string) { str_len, arena_push_array(scratch.arena, u8, str_len) @@ -898,7 +901,10 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct buff br_seek(&br, 13); u16 str_len = br_read_u16(&br); - u8 *str_bytes = br_read_raw(&br, str_len); + u8 *str_bytes = br_seek(&br, str_len); + if (!str_bytes) { + str_len = 0; + } span->name = (struct string) { str_len, arena_push_array(arena, u8, str_len) @@ -923,7 +929,10 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct buff struct string name; { u16 str_len = br_read_u16(&br); - u8 *str_bytes = br_read_raw(&br, str_len); + u8 *str_bytes = br_seek(&br, str_len); + if (!str_bytes) { + str_len = 0; + } name = (struct string) { str_len, arena_push_array(arena, u8, str_len) diff --git a/src/byteio.c b/src/byteio.c index 9b50d4b6..f73b5737 100644 --- a/src/byteio.c +++ b/src/byteio.c @@ -6,37 +6,73 @@ * Writer * ========================== */ -INTERNAL b32 write_check_overflow(struct byte_writer *bw, u64 amount) +INTERNAL b32 write_check_overflow(struct byte_writer *bw, i64 amount) { b32 overflowed = bw->overflowed; - i64 new_space_left = (bw->at + amount) - (bw->buff.data + bw->buff.size); - if (!overflowed && new_space_left < 0) { - if (bw->arena) { - arena_push_array(bw->arena, u8, -new_space_left); - bw->buff.size += -new_space_left; - /* Writer memory should be contiguous in arena */ - ASSERT((bw->buff.data + bw->buff.size) == (bw->arena->base + bw->arena->pos)); - } else { - bw->overflowed = true; - overflowed = true; + if (overflowed || amount < 0) { + overflowed = true; + bw->overflowed = true; + } else { + u8 *end = bw->buff.data + bw->buff.size; + u8 *new_pos = bw->at + amount; + i64 new_space_left = end - new_pos; + if (new_space_left < 0) { + struct arena *arena = bw->arena; + if (arena) { + if ((arena->base + arena->pos) == end) { + arena_push_array(arena, u8, -new_space_left); + bw->buff.size += -new_space_left; + } else { + /* Writer memory must be contiguous in arena */ + overflowed = true; + bw->overflowed = true; + } + } else { + overflowed = true; + bw->overflowed = true; + } } } ASSERT(!overflowed); return overflowed; } -INTERNAL void write_unsafe(struct byte_writer *bw, void *v, u64 size) +INTERNAL void write(struct byte_writer *bw, void *v, u64 size) { + if (write_check_overflow(bw, size)) { + return; + } MEMCPY(bw->at, v, size); bw->at += size; } -INTERNAL void write(struct byte_writer *bw, void *v, u64 size) +struct byte_writer bw_from_buffer(struct buffer buff) { - if (write_check_overflow(bw, sizeof(v))) { - return; - } - write_unsafe(bw, v, size); + struct byte_writer bw = ZI; + bw.buff = buff; + bw.at = buff.data; + return bw; +} + +/* Returns a writer that will allocate to arena instead of overflowing (writes must stay contiguous in arena) */ +struct byte_writer bw_from_arena(struct arena *arena) +{ + struct byte_writer bw = ZI; + bw.arena = arena; + bw.buff.data = arena->base + arena->pos; + bw.buff.size = 0; + bw.at = bw.buff.data; + return bw; +} + +/* Seeks forward and returns a new writer pointing to the skipped bytes */ +struct byte_writer bw_branch(struct byte_writer *bw, u64 size) +{ + struct buffer buff = BUFFER(size, bw->at); + struct byte_writer branch = bw_from_buffer(buff); + bw_seek(bw, size); + branch.overflowed = bw->overflowed; + return branch; } void bw_seek(struct byte_writer *bw, u64 amount) @@ -49,9 +85,8 @@ void bw_seek(struct byte_writer *bw, u64 amount) void bw_seek_to(struct byte_writer *bw, u64 pos) { - if (pos > bw->buff.size) { - ASSERT(false); - bw->overflowed = true; + if (write_check_overflow(bw, (i64)pos - (i64)(bw->at - bw->buff.data))) { + return; } bw->at = bw->buff.data + pos; } @@ -113,140 +148,137 @@ void bw_write_var_sint(struct byte_writer *bw, i64 v) bw_write_i64(bw, v); } +void bw_write_f32(struct byte_writer *bw, f32 v) +{ + write(bw, &v, sizeof(v)); +} + +void bw_write_f64(struct byte_writer *bw, f64 v) +{ + write(bw, &v, sizeof(v)); +} + +void bw_write_v2(struct byte_writer *bw, struct v2 v) +{ + bw_write_f32(bw, v.x); + bw_write_f32(bw, v.y); +} + /* ========================== * * Reader * ========================== */ -INTERNAL b32 read_check_overflow(struct byte_reader *br, u64 amount) +INTERNAL b32 read_check_overflow(struct byte_reader *br, i64 amount) { - if (br->overflowed || br->at + amount > br->buff.data + br->buff.size) { + b32 overflowed = br->overflowed; + if (overflowed || amount < 0 || (br->at + amount) > (br->buff.data + br->buff.size) ){ ASSERT(false); br->overflowed = true; - return true; + overflowed = true; } - return false; + return overflowed; } -void br_seek(struct byte_reader *br, u64 amount) -{ - if (read_check_overflow(br, amount)) { - return; - } - br->at += amount; -} - -void br_seek_to(struct byte_reader *br, u64 pos) -{ - if (pos > br->buff.size) { - ASSERT(false); - br->overflowed = true; - } - br->at = br->buff.data + pos; -} - -INTERNAL void *read_unsafe(struct byte_reader *br, u64 size) -{ - void *prev = br->at; - br->at += size; - return prev; -} - -/* Will return NULL on overflow */ -void *br_read_raw(struct byte_reader *br, u64 size) +INTERNAL void read(struct byte_reader *br, void *dst, u64 size) { if (read_check_overflow(br, size)) { - return NULL; + MEMZERO(dst, size); } - return read_unsafe(br, size); + MEMCPY(dst, br->at, size); + br->at += size; } -/* Will not read any data on overflow */ +struct byte_reader br_from_buffer(struct buffer buff) +{ + struct byte_reader br = ZI; + br.buff = buff; + br.at = buff.data; + return br; +} + +/* Returns pointer to old position, or NULL on overflow */ +void *br_seek(struct byte_reader *br, u64 amount) +{ + void *ptr = NULL; + if (read_check_overflow(br, amount)) { + return ptr; + } + ptr = br->at; + br->at += amount; + return ptr; +} + +/* Returns pointer to old position, or NULL on overflow */ +void *br_seek_to(struct byte_reader *br, u64 pos) +{ + void *ptr = NULL; + if (read_check_overflow(br, (i64)pos - (i64)(br->at - br->buff.data))) { + return ptr; + } + ptr = br->at; + br->at = br->buff.data + pos; + return ptr; +} + +/* Will fill buff with zeroes on overflow */ void br_read_to_buffer(struct byte_reader *br, struct buffer buff) { - if (read_check_overflow(br, buff.size)) { - return; - } - u8 *bytes = read_unsafe(br, buff.size); - MEMCPY(buff.data, bytes, buff.size); + read(br, buff.data, buff.size); } u8 br_read_u8(struct byte_reader *br) { - if (read_check_overflow(br, sizeof(u8))) { - return 0; - } - u8 res = 0; - MEMCPY(&res, read_unsafe(br, sizeof(u8)), sizeof(u8)); + u8 res; + read(br, &res, sizeof(res)); return res; } u16 br_read_u16(struct byte_reader *br) { - if (read_check_overflow(br, sizeof(u16))) { - return 0; - } - u16 res = 0; - MEMCPY(&res, read_unsafe(br, sizeof(u16)), sizeof(u16)); + u16 res; + read(br, &res, sizeof(res)); return res; } u32 br_read_u32(struct byte_reader *br) { - if (read_check_overflow(br, sizeof(u32))) { - return 0; - } - u32 res = 0; - MEMCPY(&res, read_unsafe(br, sizeof(u32)), sizeof(u32)); + u32 res; + read(br, &res, sizeof(res)); return res; } u64 br_read_u64(struct byte_reader *br) { - if (read_check_overflow(br, sizeof(u64))) { - return 0; - } - u64 res = 0; - MEMCPY(&res, read_unsafe(br, sizeof(u64)), sizeof(u64)); + u64 res; + read(br, &res, sizeof(res)); return res; } i8 br_read_i8(struct byte_reader *br) { - if (read_check_overflow(br, sizeof(i8))) { - return 0; - } - i8 res = 0; - MEMCPY(&res, read_unsafe(br, sizeof(i8)), sizeof(i8)); + i8 res; + read(br, &res, sizeof(res)); return res; } i16 br_read_i16(struct byte_reader *br) { - if (read_check_overflow(br, sizeof(i16))) { - return 0; - } i16 res = 0; - MEMCPY(&res, read_unsafe(br, sizeof(i16)), sizeof(i16)); + read(br, &res, sizeof(res)); return res; } i32 br_read_i32(struct byte_reader *br) { - if (read_check_overflow(br, sizeof(i32))) { - return 0; - } i32 res = 0; - MEMCPY(&res, read_unsafe(br, sizeof(i32)), sizeof(i32)); + read(br, &res, sizeof(res)); return res; } i64 br_read_i64(struct byte_reader *br) { - if (read_check_overflow(br, sizeof(i64))) { - return 0; - } - i64 res = 0; - MEMCPY(&res, read_unsafe(br, sizeof(i64)), sizeof(i64)); + i64 res; + read(br, &res, sizeof(res)); return res; } @@ -261,3 +293,25 @@ i64 br_read_var_sint(struct byte_reader *br) /* TODO: real varint read */ return br_read_i64(br); } + +f32 br_read_f32(struct byte_reader *br) +{ + f32 res; + read(br, &res, sizeof(res)); + return res; +} + +f64 br_read_f64(struct byte_reader *br) +{ + f64 res; + read(br, &res, sizeof(res)); + return res; +} + +struct v2 br_read_v2(struct byte_reader *br) +{ + struct v2 res; + res.x = br_read_f32(br); + res.y = br_read_f32(br); + return res; +} diff --git a/src/byteio.h b/src/byteio.h index dea6ac81..3ab67def 100644 --- a/src/byteio.h +++ b/src/byteio.h @@ -15,62 +15,12 @@ struct byte_reader { }; /* ========================== * - * Constructor utils + * Writer * ========================== */ -INLINE struct byte_writer bw_from_buffer(struct buffer buff) -{ - struct byte_writer bw = ZI; - bw.buff = buff; - bw.at = buff.data; - return bw; -} - -INLINE struct byte_writer bw_from_arena(struct arena *arena) -{ - struct byte_writer bw = ZI; - bw.arena = arena; - bw.buff.data = arena->base; - bw.buff.size = 0; - bw.at = bw.buff.data; - return bw; -} - -INLINE struct byte_reader br_from_buffer(struct buffer buff) -{ - struct byte_reader br = ZI; - br.buff = buff; - br.at = buff.data; - return br; -} - -INLINE struct byte_writer bw_copy(struct byte_writer *bw) -{ - return *bw; -} - -INLINE struct byte_reader br_copy(struct byte_reader *br) -{ - return *br; -} - -/* Generate a buffer struct containing written bytes only */ -INLINE struct buffer bw_get_written_buffer(struct byte_writer *bw) -{ - struct buffer buff = ZI; - buff.data = bw->buff.data; - buff.size = bw->at - bw->buff.data; - return buff; -} - -INLINE u64 bw_pos(struct byte_reader *bw) -{ - return bw->at - bw->buff.data; -} - -/* ========================== * - * Write - * ========================== */ +struct byte_writer bw_from_buffer(struct buffer buff); +struct byte_writer bw_from_arena(struct arena *arena); +struct byte_writer bw_branch(struct byte_writer *bw, u64 size); void bw_seek(struct byte_writer *bw, u64 amount); void bw_seek_to(struct byte_writer *bw, u64 pos); @@ -86,18 +36,36 @@ void bw_write_i32(struct byte_writer *bw, i32 v); void bw_write_i64(struct byte_writer *bw, i64 v); void bw_write_var_uint(struct byte_writer *bw, u64 v); void bw_write_var_sint(struct byte_writer *bw, i64 v); +void bw_write_f32(struct byte_writer *bw, f32 v); +void bw_write_f64(struct byte_writer *bw, f64 v); +void bw_write_v2(struct byte_writer *bw, struct v2 v); + +/* Returns a buffer containing written bytes only */ +INLINE struct buffer bw_get_written(struct byte_writer *bw) +{ + struct buffer buff = ZI; + buff.data = bw->buff.data; + buff.size = bw->at - bw->buff.data; + return buff; +} + +INLINE u64 bw_pos(struct byte_writer *bw) +{ + return bw->at - bw->buff.data; +} /* ========================== * - * Read + * Reader * ========================== */ -void br_seek(struct byte_reader *br, u64 amount); -void br_seek_to(struct byte_reader *br, u64 pos); - -/* Will not read any data on overflow */ + /* Will fill struct with zeroes on overflow */ #define br_read_to_struct(br_ptr, var_ptr) (br_read_to_buffer(br_ptr, BUFFER(sizeof(*var_ptr), (u8 *)var_ptr))) -void *br_read_raw(struct byte_reader *br, u64 size); +struct byte_reader br_from_buffer(struct buffer buff); + +void *br_seek(struct byte_reader *br, u64 amount); +void *br_seek_to(struct byte_reader *br, u64 pos); + void br_read_to_buffer(struct byte_reader *br, struct buffer buff); u8 br_read_u8(struct byte_reader *br); u16 br_read_u16(struct byte_reader *br); @@ -109,6 +77,9 @@ i32 br_read_i32(struct byte_reader *br); i64 br_read_i64(struct byte_reader *br); u64 br_read_var_uint(struct byte_reader *br); i64 br_read_var_sint(struct byte_reader *br); +f32 br_read_f32(struct byte_reader *br); +f64 br_read_f64(struct byte_reader *br); +struct v2 br_read_v2(struct byte_reader *br); INLINE u64 br_bytes_left(const struct byte_reader *br) { diff --git a/src/game.c b/src/game.c index 224edbfe..9b23bb05 100644 --- a/src/game.c +++ b/src/game.c @@ -14,6 +14,7 @@ #include "collider.h" #include "rng.h" #include "space.h" +#include "byteio.h" GLOBAL struct { struct atomic_i32 game_thread_shutdown; @@ -31,9 +32,10 @@ GLOBAL struct { b32 extra_spawn; b32 should_reset_level; - /* Game thread input */ - struct sys_mutex game_cmds_mutex; - struct arena game_cmds_arena; + /* Game input */ + struct sys_mutex game_input_mutex; + struct arena game_input_arena; + struct entity *root; /* Bookkeeping structures */ @@ -69,9 +71,9 @@ struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr, (UNUSED)sound_sr; (UNUSED)phys_sr; - /* Initialize game cmd storage */ - G.game_cmds_mutex = sys_mutex_alloc(); - G.game_cmds_arena = arena_alloc(GIGABYTE(64)); + /* Initialize game input storage */ + G.game_input_mutex = sys_mutex_alloc(); + G.game_input_arena = arena_alloc(GIGABYTE(64)); /* Initialize empty world */ reset_world(); @@ -95,34 +97,6 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(game_shutdown) sys_thread_wait_release(&G.game_thread); } -/* ========================== * - * Game cmd - * ========================== */ - -INTERNAL void push_cmds(struct game_cmd_array cmd_array) -{ - struct sys_lock lock = sys_mutex_lock_e(&G.game_cmds_mutex); - struct game_cmd *cmds = arena_push_array(&G.game_cmds_arena, struct game_cmd, cmd_array.count); - MEMCPY(cmds, cmd_array.cmds, cmd_array.count * sizeof(*cmds)); - sys_mutex_unlock(&lock); -} - -INTERNAL struct game_cmd_array pop_cmds(struct arena *arena) -{ - struct game_cmd_array array = ZI; - if (G.game_cmds_arena.pos > 0) { - struct sys_lock lock = sys_mutex_lock_e(&G.game_cmds_mutex); - struct buffer game_cmds_buff = arena_to_buffer(&G.game_cmds_arena); - arena_align(arena, alignof(struct game_cmd)); - array.cmds = (struct game_cmd *)arena_push_array(arena, u8, game_cmds_buff.size); - array.count = game_cmds_buff.size / sizeof(struct game_cmd); - MEMCPY(array.cmds, game_cmds_buff.data, game_cmds_buff.size); - arena_reset(&G.game_cmds_arena); - sys_mutex_unlock(&lock); - } - return array; -} - /* ========================== * * Reset * ========================== */ @@ -480,7 +454,7 @@ INTERNAL void publish_game_tick(void) sys_mutex_unlock(&lock); } -INTERNAL void game_update(struct game_cmd_array game_cmds) +INTERNAL void game_update(struct game_cmd_list game_cmds) { __prof; @@ -537,14 +511,12 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) * Process global game cmds * ========================== */ - for (u64 cmd_index = 0; cmd_index < game_cmds.count; ++cmd_index) { - struct game_cmd cmd = game_cmds.cmds[cmd_index]; - - switch (cmd.kind) { + for (struct game_cmd *cmd = game_cmds.first; cmd; cmd = cmd->next) { + switch (cmd->kind) { /* Cursor */ case GAME_CMD_KIND_CURSOR_MOVE: { - G.user_cursor = cmd.cursor_pos; + G.user_cursor = cmd->cursor_pos; } break; /* Clear level */ @@ -735,19 +707,18 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct v2 focus = ent->control.focus; b32 firing = entity_has_prop(ent, ENTITY_PROP_TRIGGERING_EQUIPPED); - for (u64 i = 0; i < game_cmds.count; ++i) { - struct game_cmd cmd = game_cmds.cmds[i]; - b32 start = cmd.state == GAME_CMD_STATE_START; - b32 stop = cmd.state == GAME_CMD_STATE_STOP; + for (struct game_cmd *cmd = game_cmds.first; cmd; cmd = cmd->next) { + b32 start = cmd->state == GAME_CMD_STATE_START; + b32 stop = cmd->state == GAME_CMD_STATE_STOP; /* TODO: Combine movement from multiple inputs? E.G. a sudden * start and immediate stop cmd should still move the player a * tad. */ - switch (cmd.kind) { + switch (cmd->kind) { case GAME_CMD_KIND_PLAYER_MOVE: { - move = cmd.move_dir; - focus = cmd.aim_dir; + move = cmd->move_dir; + focus = cmd->aim_dir; } break; case GAME_CMD_KIND_PLAYER_FIRE: @@ -1094,12 +1065,11 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) /* Mouse drag */ ctx.dbg_cursor_pos = G.user_cursor; - for (u64 i = 0; i < game_cmds.count; ++i) { - struct game_cmd cmd = game_cmds.cmds[i]; - if (cmd.kind == GAME_CMD_KIND_DRAG_OBJECT) { - if (cmd.state == GAME_CMD_STATE_START) { + for (struct game_cmd *cmd = game_cmds.first; cmd; cmd = cmd->next) { + if (cmd->kind == GAME_CMD_KIND_DRAG_OBJECT) { + if (cmd->state == GAME_CMD_STATE_START) { ctx.dbg_start_dragging = true; - } else if (cmd.state == GAME_CMD_STATE_STOP) { + } else if (cmd->state == GAME_CMD_STATE_STOP) { ctx.dbg_stop_dragging = true; } } @@ -1342,50 +1312,116 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) } /* ========================== * - * Game thread + * Game cmd * ========================== */ -INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg) +struct buffer game_string_from_cmds(struct arena *arena, struct game_cmd_list *cmds) { - struct temp_arena scratch = scratch_begin_no_conflict(); + struct byte_writer bw = bw_from_arena(arena); - (UNUSED)arg; - i64 last_frame_ns = 0; - i64 target_dt_ns = NS_FROM_SECONDS(GAME_FPS > (0) ? (1.0 / GAME_FPS) : 0); - while (!atomic_i32_eval(&G.game_thread_shutdown)) { - __profscope(game_update_w_sleep); - struct temp_arena temp = arena_temp_begin(scratch.arena); - sleep_frame(last_frame_ns, target_dt_ns); - last_frame_ns = sys_time_ns(); - { - struct game_cmd_array game_cmds = pop_cmds(temp.arena); - if (!G.paused) { - game_update(game_cmds); - } - /* Check for pause / next frame cmds */ - for (u64 i = 0; i < game_cmds.count; ++i) { - struct game_cmd cmd = game_cmds.cmds[i]; - switch (cmd.kind) { - case GAME_CMD_KIND_PAUSE: { - G.paused = !G.paused; - } break; + for (struct game_cmd *cmd = cmds->first; cmd; cmd = cmd->next) { + struct byte_writer bw_size = bw_branch(&bw, sizeof(u64)); + u64 start = bw_pos(&bw); - case GAME_CMD_KIND_STEP: { - if (G.paused) { - G.paused = false; - game_update(game_cmds); - G.paused = true; - } - } break; + bw_write_i8(&bw, cmd->kind); + bw_write_i8(&bw, cmd->state); - default: break; - } - } +#if RTC + bw_write_u32(&bw, cmd->collider_gjk_steps); +#endif + + switch (cmd->kind) { + case GAME_CMD_KIND_PLAYER_MOVE: + { + bw_write_v2(&bw, cmd->move_dir); + bw_write_v2(&bw, cmd->aim_dir); + } break; + + case GAME_CMD_KIND_CURSOR_MOVE: + { + bw_write_v2(&bw, cmd->cursor_pos); + } break; + + default: break; } - arena_temp_end(temp); + + u64 size = bw_pos(&bw) - start; + if (size > 100) { + DEBUGBREAKABLE; + } + bw_write_u64(&bw_size, size); } - scratch_end(scratch); + return bw.buff; +} + +struct game_cmd_list game_cmds_from_string(struct arena *arena, struct buffer str) +{ + struct game_cmd_list l = ZI; + + struct byte_reader br = br_from_buffer(str); + while (br_bytes_left(&br) > 0) { + struct game_cmd *cmd = arena_push_zero(arena, struct game_cmd); + u64 cmd_size = br_read_u64(&br); + u64 cmd_pos_end = br_pos(&br) + cmd_size; + + cmd->kind = br_read_i8(&br); + cmd->state = br_read_i8(&br); + +#if RTC + cmd->collider_gjk_steps = br_read_u32(&br); +#endif + + switch (cmd->kind) { + case GAME_CMD_KIND_PLAYER_MOVE: + { + cmd->move_dir = br_read_v2(&br); + cmd->aim_dir = br_read_v2(&br); + } break; + + case GAME_CMD_KIND_CURSOR_MOVE: + { + cmd->cursor_pos = br_read_v2(&br); + } break; + + default: break; + } + + ASSERT(br_pos(&br) == cmd_pos_end); + br_seek_to(&br, cmd_pos_end); + + if (l.last) { + l.last->next = cmd; + } else { + l.first = cmd; + } + l.last = cmd; + } + return l; +} + +/* ========================== * + * Game cmd + * ========================== */ + +INTERNAL void push_input_string(struct buffer input) +{ + struct sys_lock lock = sys_mutex_lock_e(&G.game_input_mutex); + u8 *dst = arena_push_array(&G.game_input_arena, u8, input.size); + MEMCPY(dst, input.data, input.size); + sys_mutex_unlock(&lock); +} + +INTERNAL struct buffer pop_input_string(struct arena *arena) +{ + struct buffer buff = ZI; + struct sys_lock lock = sys_mutex_lock_e(&G.game_input_mutex); + buff.size = G.game_input_arena.pos; + buff.data = arena_push_array(arena, u8, buff.size); + MEMCPY(buff.data, G.game_input_arena.base, buff.size); + arena_reset(&G.game_input_arena); + sys_mutex_unlock(&lock); + return buff; } /* ========================== * @@ -1410,7 +1446,56 @@ u64 game_get_latest_tick_continuity_gen(void) return atomic_u64_eval(&G.prev_tick_continuity_gen); } -void game_push_cmds(struct game_cmd_array cmd_array) +void game_push_cmds_string(struct buffer str) { - push_cmds(cmd_array); + push_input_string(str); +} + +/* ========================== * + * Game thread + * ========================== */ + +INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg) +{ + struct temp_arena scratch = scratch_begin_no_conflict(); + + (UNUSED)arg; + i64 last_frame_ns = 0; + i64 target_dt_ns = NS_FROM_SECONDS(GAME_FPS > (0) ? (1.0 / GAME_FPS) : 0); + while (!atomic_i32_eval(&G.game_thread_shutdown)) { + __profscope(game_update_w_sleep); + struct temp_arena temp = arena_temp_begin(scratch.arena); + sleep_frame(last_frame_ns, target_dt_ns); + last_frame_ns = sys_time_ns(); + { + struct buffer input_str = pop_input_string(temp.arena); + struct game_cmd_list cmds = game_cmds_from_string(temp.arena, input_str); + if (!G.paused) { + game_update(cmds); + } + /* Check for pause / next frame cmds */ + for (struct game_cmd *cmd = cmds.first; cmd; cmd = cmd->next) { + switch (cmd->kind) { + case GAME_CMD_KIND_PAUSE: + { + G.paused = !G.paused; + } break; + + case GAME_CMD_KIND_STEP: + { + if (G.paused) { + G.paused = false; + game_update(cmds); + G.paused = true; + } + } break; + + default: break; + } + } + } + arena_temp_end(temp); + } + + scratch_end(scratch); } diff --git a/src/game.h b/src/game.h index fca9f68b..21735f55 100644 --- a/src/game.h +++ b/src/game.h @@ -7,8 +7,25 @@ struct sprite_startup_receipt; struct sound_startup_receipt; struct phys_startup_receipt; +/* Absolute layers */ +#define GAME_LAYER_FLOOR_DECALS -300 +#define GAME_LAYER_BULLETS -200 +#define GAME_LAYER_TRACERS -100 +#define GAME_LAYER_SHOULDERS 0 + +/* Relative layers */ +#define GAME_LAYER_RELATIVE_DEFAULT 0 +#define GAME_LAYER_RELATIVE_WEAPON 1 + +struct game_startup_receipt { i32 _; }; +struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr, + struct sprite_startup_receipt *sheet_sr, + struct sound_startup_receipt *sound_sr, + struct phys_startup_receipt *phys_sr); + + /* ========================== * - * Game cmd + * Game CMD * ========================== */ enum game_cmd_state { @@ -48,33 +65,25 @@ struct game_cmd { #if RTC u32 collider_gjk_steps; #endif + + struct game_cmd *next; }; -struct game_cmd_array { - struct game_cmd *cmds; - u64 count; +struct game_cmd_list { + struct game_cmd *first; + struct game_cmd *last; }; -/* Absolute layers */ -#define GAME_LAYER_FLOOR_DECALS -300 -#define GAME_LAYER_BULLETS -200 -#define GAME_LAYER_TRACERS -100 -#define GAME_LAYER_SHOULDERS 0 +/* ========================== * + * Interface + * ========================== */ -/* Relative layers */ -#define GAME_LAYER_RELATIVE_DEFAULT 0 -#define GAME_LAYER_RELATIVE_WEAPON 1 - -struct game_startup_receipt { i32 _; }; -struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr, - struct sprite_startup_receipt *sheet_sr, - struct sound_startup_receipt *sound_sr, - struct phys_startup_receipt *phys_sr); +struct buffer game_string_from_cmds(struct arena *arena, struct game_cmd_list *cmds); +struct game_cmd_list game_cmds_from_string(struct arena *arena, struct buffer str); void game_get_latest_tick(struct world *dest); u64 game_get_latest_tick_id(void); u64 game_get_latest_tick_continuity_gen(void); - -void game_push_cmds(struct game_cmd_array cmd_array); +void game_push_cmds_string(struct buffer str); #endif diff --git a/src/tar.c b/src/tar.c index ab99393d..6fd80c9e 100644 --- a/src/tar.c +++ b/src/tar.c @@ -93,10 +93,11 @@ struct tar_archive tar_parse(struct arena *arena, struct buffer data, struct str struct string file_size_oct_str = { .len = 11, .text = header.file_size }; u64 file_size = str_oct_to_u64(file_size_oct_str); - struct buffer file_data = { - .size = file_size, - .data = br_read_raw(&br, file_size) - }; + u8 *file_data_ptr = br_seek(&br, file_size); + if (!file_data_ptr) { + file_size = 0; + } + struct buffer file_data = BUFFER(file_size, file_data_ptr); /* Skip sector padding */ u64 remaining = (512 - (file_size % 512)) % 512; diff --git a/src/user.c b/src/user.c index 59d353da..77e1cf24 100644 --- a/src/user.c +++ b/src/user.c @@ -360,48 +360,30 @@ INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns) * User -> game communication * ========================== */ -struct game_cmd_node { - struct game_cmd cmd; - struct game_cmd_node *next; -}; - -struct game_cmd_list { - struct game_cmd_node *first; - struct game_cmd_node *last; -}; - -INTERNAL void queue_game_cmd(struct arena *arena, struct game_cmd_list *list, struct game_cmd cmd) +INTERNAL void queue_game_cmd(struct arena *arena, struct game_cmd_list *list, struct game_cmd src) { - struct game_cmd_node *node = arena_push_zero(arena, struct game_cmd_node); - node->cmd = cmd; + struct game_cmd *cmd = arena_push(arena, struct game_cmd); + *cmd = src; if (list->last) { - list->last->next = node; + list->last->next = cmd; } else { - list->first = node; + list->first = cmd; } - list->last = node; + list->last = cmd; } INTERNAL void pubilsh_game_cmds(struct game_cmd_list *list) { struct temp_arena scratch = scratch_begin_no_conflict(); - - /* Construct array */ - struct game_cmd_array array = { .cmds = arena_dry_push(scratch.arena, struct game_cmd) }; - for (struct game_cmd_node *node = list->first; node; node = node->next) { - struct game_cmd *cmd = arena_push(scratch.arena, struct game_cmd); - *cmd = node->cmd; - ++array.count; - } - - /* Push array to game thread */ - if (array.count > 0) { - game_push_cmds(array); - } - + struct buffer buff = game_string_from_cmds(scratch.arena, list); + game_push_cmds_string(buff); scratch_end(scratch); } +/* ========================== * + * Debug draw + * ========================== */ + /* TODO: remove this (testing) */ INTERNAL void debug_draw_xform(struct xform xf, u32 color_x, u32 color_y) {