migrate sim global state to ctx structure
This commit is contained in:
parent
5f75b765c3
commit
ed66382fd6
@ -223,8 +223,7 @@ void app_entry_point(void)
|
|||||||
struct sound_startup_receipt sound_sr = sound_startup(&work_sr, &asset_cache_sr, &resource_sr);
|
struct sound_startup_receipt sound_sr = sound_startup(&work_sr, &asset_cache_sr, &resource_sr);
|
||||||
struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr);
|
struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr);
|
||||||
struct phys_startup_receipt phys_sr = phys_startup();
|
struct phys_startup_receipt phys_sr = phys_startup();
|
||||||
struct sim_startup_receipt sim_sr = sim_startup(&mixer_sr, &sprite_sr, &sound_sr, &phys_sr, &host_sr);
|
struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &phys_sr, &host_sr, &window);
|
||||||
struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &sim_sr, &asset_cache_sr, &mixer_sr, &host_sr, &window);
|
|
||||||
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
|
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
|
||||||
|
|
||||||
(UNUSED)user_sr;
|
(UNUSED)user_sr;
|
||||||
|
|||||||
@ -33,7 +33,6 @@
|
|||||||
#define SPACE_CELL_BUCKETS_SQRT (256)
|
#define SPACE_CELL_BUCKETS_SQRT (256)
|
||||||
#define SPACE_CELL_SIZE 1.0f
|
#define SPACE_CELL_SIZE 1.0f
|
||||||
|
|
||||||
|
|
||||||
#define SIM_FPS 50.0
|
#define SIM_FPS 50.0
|
||||||
#define SIM_TIMESCALE 1
|
#define SIM_TIMESCALE 1
|
||||||
|
|
||||||
|
|||||||
@ -1172,7 +1172,7 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_phys_iteration)
|
|||||||
|
|
||||||
if (ctx->pre_solve_callback) {
|
if (ctx->pre_solve_callback) {
|
||||||
__profscope(pre_solve_callback);
|
__profscope(pre_solve_callback);
|
||||||
ctx->pre_solve_callback(collision_data);
|
ctx->pre_solve_callback(collision_data, ctx->pre_solve_callback_udata);
|
||||||
}
|
}
|
||||||
|
|
||||||
f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS;
|
f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS;
|
||||||
@ -1204,7 +1204,7 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_phys_iteration)
|
|||||||
|
|
||||||
if (ctx->post_solve_callback) {
|
if (ctx->post_solve_callback) {
|
||||||
__profscope(post_solve_callback);
|
__profscope(post_solve_callback);
|
||||||
ctx->post_solve_callback(collision_data);
|
ctx->post_solve_callback(collision_data, ctx->post_solve_callback_udata);
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
|
|||||||
@ -25,8 +25,8 @@ struct phys_collision_data_array {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct phys_collision_data;
|
struct phys_collision_data;
|
||||||
#define PHYS_COLLISION_CALLBACK_FUNC_DEF(name, arg) void name(struct phys_collision_data_array arg)
|
#define PHYS_COLLISION_CALLBACK_FUNC_DEF(name, arg_collision_data, arg_udata) void name(struct phys_collision_data_array arg_collision_data, void *arg_udata)
|
||||||
typedef PHYS_COLLISION_CALLBACK_FUNC_DEF(phys_collision_callback_func, data);
|
typedef PHYS_COLLISION_CALLBACK_FUNC_DEF(phys_collision_callback_func, collision_data, udata);
|
||||||
|
|
||||||
/* Structure containing data used for a single physics step */
|
/* Structure containing data used for a single physics step */
|
||||||
struct phys_ctx {
|
struct phys_ctx {
|
||||||
@ -37,6 +37,8 @@ struct phys_ctx {
|
|||||||
|
|
||||||
phys_collision_callback_func *pre_solve_callback;
|
phys_collision_callback_func *pre_solve_callback;
|
||||||
phys_collision_callback_func *post_solve_callback;
|
phys_collision_callback_func *post_solve_callback;
|
||||||
|
void *pre_solve_callback_udata;
|
||||||
|
void *post_solve_callback_udata;
|
||||||
|
|
||||||
struct sim_ent_lookup *debug_lookup;
|
struct sim_ent_lookup *debug_lookup;
|
||||||
struct v2 dbg_cursor_pos;
|
struct v2 dbg_cursor_pos;
|
||||||
|
|||||||
461
src/sim.c
461
src/sim.c
@ -1,12 +1,11 @@
|
|||||||
#include "sim.h"
|
#include "sim.h"
|
||||||
#include "sim_ent.h"
|
#include "sim_ent.h"
|
||||||
#include "sim_client.h"
|
#include "sim_client.h"
|
||||||
|
#include "sim_msg.h"
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "world.h"
|
#include "world.h"
|
||||||
#include "sprite.h"
|
#include "sprite.h"
|
||||||
#include "sound.h"
|
|
||||||
#include "mixer.h"
|
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "scratch.h"
|
#include "scratch.h"
|
||||||
#include "atomic.h"
|
#include "atomic.h"
|
||||||
@ -19,7 +18,8 @@
|
|||||||
#include "byteio.h"
|
#include "byteio.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
|
|
||||||
GLOBAL struct {
|
struct sim_ctx {
|
||||||
|
struct arena arena;
|
||||||
struct atomic_i32 sim_thread_shutdown;
|
struct atomic_i32 sim_thread_shutdown;
|
||||||
struct sys_thread sim_thread;
|
struct sys_thread sim_thread;
|
||||||
|
|
||||||
@ -48,76 +48,75 @@ GLOBAL struct {
|
|||||||
|
|
||||||
/* Tick */
|
/* Tick */
|
||||||
struct world tick;
|
struct world tick;
|
||||||
} G = ZI, DEBUG_ALIAS(G, G_sim);
|
};
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Startup
|
* Ctx
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sim_shutdown);
|
|
||||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg);
|
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg);
|
||||||
INTERNAL void reset_world(void);
|
INTERNAL void reset_world(struct sim_ctx *ctx);
|
||||||
|
|
||||||
struct sim_startup_receipt sim_startup(struct mixer_startup_receipt *mixer_sr,
|
struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
||||||
struct sprite_startup_receipt *sheet_sr,
|
struct phys_startup_receipt *phys_sr,
|
||||||
struct sound_startup_receipt *sound_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct phys_startup_receipt *phys_sr,
|
u16 host_port)
|
||||||
struct host_startup_receipt *host_sr)
|
|
||||||
{
|
{
|
||||||
(UNUSED)mixer_sr;
|
struct arena arena = arena_alloc(GIGABYTE(64));
|
||||||
(UNUSED)sheet_sr;
|
struct sim_ctx *ctx = arena_push_zero(&arena, struct sim_ctx);
|
||||||
(UNUSED)sound_sr;
|
ctx->arena = arena;
|
||||||
|
|
||||||
|
(UNUSED)sprite_sr;
|
||||||
(UNUSED)phys_sr;
|
(UNUSED)phys_sr;
|
||||||
(UNUSED)host_sr;
|
(UNUSED)host_sr;
|
||||||
|
|
||||||
G.client_store = client_store_alloc();
|
ctx->client_store = sim_client_store_alloc();
|
||||||
|
|
||||||
/* Intialize host */
|
/* Intialize host */
|
||||||
G.host = host_alloc(12345);
|
ctx->host = host_alloc(host_port);
|
||||||
|
|
||||||
/* Initialize empty world */
|
/* Initialize empty world */
|
||||||
reset_world();
|
reset_world(ctx);
|
||||||
|
|
||||||
G.sim_thread = sys_thread_alloc(&sim_thread_entry_point, NULL, LIT("[P2] Sim thread"));
|
ctx->sim_thread = sys_thread_alloc(&sim_thread_entry_point, ctx, LIT("[P2] Sim thread"));
|
||||||
app_register_exit_callback(&sim_shutdown);
|
|
||||||
|
|
||||||
return (struct sim_startup_receipt) { 0 };
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sim_shutdown)
|
void sim_ctx_release(struct sim_ctx *ctx)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
atomic_i32_eval_exchange(&G.sim_thread_shutdown, true);
|
atomic_i32_eval_exchange(&ctx->sim_thread_shutdown, true);
|
||||||
sys_thread_wait_release(&G.sim_thread);
|
sys_thread_wait_release(&ctx->sim_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Reset
|
* Reset
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL void reset_world(void)
|
INTERNAL void reset_world(struct sim_ctx *ctx)
|
||||||
{
|
{
|
||||||
if (G.tick.ent_store) {
|
if (ctx->tick.ent_store) {
|
||||||
/* Release world */
|
/* Release world */
|
||||||
world_release(&G.tick);
|
world_release(&ctx->tick);
|
||||||
/* Release bookkeeping */
|
/* Release bookkeeping */
|
||||||
space_release(G.space);
|
space_release(ctx->space);
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
sim_ent_lookup_release(&G.collision_debug_lookup);
|
sim_ent_lookup_release(&ctx->collision_debug_lookup);
|
||||||
#endif
|
#endif
|
||||||
sim_ent_lookup_release(&G.contact_lookup);
|
sim_ent_lookup_release(&ctx->contact_lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create bookkeeping */
|
/* Create bookkeeping */
|
||||||
G.contact_lookup = sim_ent_lookup_alloc(4096);
|
ctx->contact_lookup = sim_ent_lookup_alloc(4096);
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
G.collision_debug_lookup = sim_ent_lookup_alloc(4096);
|
ctx->collision_debug_lookup = sim_ent_lookup_alloc(4096);
|
||||||
#endif
|
#endif
|
||||||
G.space = space_alloc(SPACE_CELL_SIZE, SPACE_CELL_BUCKETS_SQRT);
|
ctx->space = space_alloc(SPACE_CELL_SIZE, SPACE_CELL_BUCKETS_SQRT);
|
||||||
|
|
||||||
/* Re-create world */
|
/* Re-create world */
|
||||||
world_alloc(&G.tick);
|
world_alloc(&ctx->tick);
|
||||||
G.tick.timescale = SIM_TIMESCALE;
|
ctx->tick.timescale = SIM_TIMESCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -126,15 +125,15 @@ INTERNAL void reset_world(void)
|
|||||||
|
|
||||||
/* TODO: Remove this */
|
/* TODO: Remove this */
|
||||||
|
|
||||||
INTERNAL void spawn_test_entities(void)
|
INTERNAL void spawn_test_entities(struct sim_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct sim_ent *root = sim_ent_from_handle(G.tick.ent_store, G.tick.ent_store->root);
|
struct sim_ent *root = sim_ent_from_handle(ctx->tick.ent_store, ctx->tick.ent_store->root);
|
||||||
root->mass_unscaled = F32_INFINITY;
|
root->mass_unscaled = F32_INFINITY;
|
||||||
root->inertia_unscaled = F32_INFINITY;
|
root->inertia_unscaled = F32_INFINITY;
|
||||||
|
|
||||||
/* Player */
|
/* Player */
|
||||||
struct sim_ent *player_ent = sim_ent_nil();
|
struct sim_ent *player_ent = sim_ent_nil();
|
||||||
//if (!G.extra_spawn) {
|
//if (!ctx->extra_spawn) {
|
||||||
{
|
{
|
||||||
|
|
||||||
struct sim_ent *e = sim_ent_alloc(root);
|
struct sim_ent *e = sim_ent_alloc(root);
|
||||||
@ -148,7 +147,7 @@ INTERNAL void spawn_test_entities(void)
|
|||||||
//f32 r = PI / 4;
|
//f32 r = PI / 4;
|
||||||
f32 r = 0;
|
f32 r = 0;
|
||||||
|
|
||||||
if (!G.extra_spawn) {
|
if (!ctx->extra_spawn) {
|
||||||
sim_ent_enable_prop(e, SIM_ENT_PROP_PLAYER_CONTROLLED);
|
sim_ent_enable_prop(e, SIM_ENT_PROP_PLAYER_CONTROLLED);
|
||||||
sim_ent_enable_prop(e, SIM_ENT_PROP_TEST);
|
sim_ent_enable_prop(e, SIM_ENT_PROP_TEST);
|
||||||
e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase"));
|
e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase"));
|
||||||
@ -280,7 +279,7 @@ INTERNAL void spawn_test_entities(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Camera */
|
/* Camera */
|
||||||
if (!G.extra_spawn && player_ent->valid) {
|
if (!ctx->extra_spawn && player_ent->valid) {
|
||||||
struct sim_ent *e = sim_ent_alloc(root);
|
struct sim_ent *e = sim_ent_alloc(root);
|
||||||
sim_ent_set_xform(e, XFORM_IDENT);
|
sim_ent_set_xform(e, XFORM_IDENT);
|
||||||
|
|
||||||
@ -293,18 +292,18 @@ INTERNAL void spawn_test_entities(void)
|
|||||||
e->camera_quad_xform = XFORM_TRS(.s = V2(width, height));
|
e->camera_quad_xform = XFORM_TRS(.s = V2(width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
G.extra_spawn = true;
|
ctx->extra_spawn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Release entities
|
* Release entities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL void release_entities_with_prop(enum sim_ent_prop prop)
|
INTERNAL void release_entities_with_prop(struct sim_ctx *ctx, enum sim_ent_prop prop)
|
||||||
{
|
{
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
struct sim_ent_store *store = G.tick.ent_store;
|
struct sim_ent_store *store = ctx->tick.ent_store;
|
||||||
struct space *space = G.space;
|
struct space *space = ctx->space;
|
||||||
|
|
||||||
struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *);
|
struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *);
|
||||||
u64 ents_to_release_count = 0;
|
u64 ents_to_release_count = 0;
|
||||||
@ -347,13 +346,14 @@ INTERNAL void release_entities_with_prop(enum sim_ent_prop prop)
|
|||||||
* Respond to physics collisions
|
* Respond to physics collisions
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array)
|
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, udata)
|
||||||
{
|
{
|
||||||
struct sim_ent_store *store = G.tick.ent_store;
|
struct sim_ctx *ctx = (struct sim_ctx *)udata;
|
||||||
|
struct sim_ent_store *store = ctx->tick.ent_store;
|
||||||
struct sim_ent *root = sim_ent_from_handle(store, store->root);
|
struct sim_ent *root = sim_ent_from_handle(store, store->root);
|
||||||
|
|
||||||
for (u64 i = 0; i < array.count; ++i) {
|
for (u64 i = 0; i < collision_data_array.count; ++i) {
|
||||||
struct phys_collision_data *data = &array.a[i];
|
struct phys_collision_data *data = &collision_data_array.a[i];
|
||||||
|
|
||||||
struct phys_contact_constraint *constraint = data->constraint;
|
struct phys_contact_constraint *constraint = data->constraint;
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(store, data->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(store, data->e0);
|
||||||
@ -434,7 +434,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array)
|
|||||||
* Update
|
* Update
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL void sim_update(void)
|
INTERNAL void sim_update(struct sim_ctx *ctx)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
|
|
||||||
@ -444,31 +444,31 @@ INTERNAL void sim_update(void)
|
|||||||
* Reset level if necessary
|
* Reset level if necessary
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
if (G.should_reset_level) {
|
if (ctx->should_reset_level) {
|
||||||
logf_info("Clearing level");
|
logf_info("Clearing level");
|
||||||
G.should_reset_level = false;
|
ctx->should_reset_level = false;
|
||||||
G.extra_spawn = false;
|
ctx->extra_spawn = false;
|
||||||
reset_world();
|
reset_world(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Begin frame
|
* Begin frame
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
++G.tick.tick_id;
|
++ctx->tick.tick_id;
|
||||||
|
|
||||||
G.tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, (1.0 / SIM_FPS) * G.tick.timescale));
|
ctx->tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, (1.0 / SIM_FPS) * ctx->tick.timescale));
|
||||||
G.tick.time_ns += G.tick.dt_ns;
|
ctx->tick.time_ns += ctx->tick.dt_ns;
|
||||||
|
|
||||||
f64 dt = SECONDS_FROM_NS(G.tick.dt_ns);
|
f64 dt = SECONDS_FROM_NS(ctx->tick.dt_ns);
|
||||||
f64 time = SECONDS_FROM_NS(G.tick.time_ns);
|
f64 time = SECONDS_FROM_NS(ctx->tick.time_ns);
|
||||||
G.sprite_frame_scope = sprite_scope_begin();
|
ctx->sprite_frame_scope = sprite_scope_begin();
|
||||||
G.root = sim_ent_from_handle(G.tick.ent_store, G.tick.ent_store->root);
|
ctx->root = sim_ent_from_handle(ctx->tick.ent_store, ctx->tick.ent_store->root);
|
||||||
|
|
||||||
struct sim_ent *root = G.root;
|
struct sim_ent *root = ctx->root;
|
||||||
struct sim_ent_store *ent_store = G.tick.ent_store;
|
struct sim_ent_store *ent_store = ctx->tick.ent_store;
|
||||||
struct space *space = G.space;
|
struct space *space = ctx->space;
|
||||||
struct sprite_scope *sprite_frame_scope = G.sprite_frame_scope;
|
struct sprite_scope *sprite_frame_scope = ctx->sprite_frame_scope;
|
||||||
|
|
||||||
(UNUSED)dt;
|
(UNUSED)dt;
|
||||||
(UNUSED)time;
|
(UNUSED)time;
|
||||||
@ -483,7 +483,7 @@ INTERNAL void sim_update(void)
|
|||||||
static b32 run = 0;
|
static b32 run = 0;
|
||||||
if (!run) {
|
if (!run) {
|
||||||
run = 1;
|
run = 1;
|
||||||
spawn_test_entities();
|
spawn_test_entities(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,7 +491,7 @@ INTERNAL void sim_update(void)
|
|||||||
* Release entities
|
* Release entities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
release_entities_with_prop(SIM_ENT_PROP_RELEASE_NEXT_TICK);
|
release_entities_with_prop(ctx, SIM_ENT_PROP_RELEASE_NEXT_TICK);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Activate entities
|
* Activate entities
|
||||||
@ -503,8 +503,8 @@ INTERNAL void sim_update(void)
|
|||||||
|
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE)) {
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE)) {
|
||||||
u64 atick = ent->activation_tick;
|
u64 atick = ent->activation_tick;
|
||||||
if (atick != 0 || G.tick.tick_id >= atick) {
|
if (atick != 0 || ctx->tick.tick_id >= atick) {
|
||||||
sim_ent_activate(ent, G.tick.tick_id);
|
sim_ent_activate(ent, ctx->tick.tick_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -532,7 +532,7 @@ INTERNAL void sim_update(void)
|
|||||||
|
|
||||||
struct sim_cmd_list sim_cmds = ZI;
|
struct sim_cmd_list sim_cmds = ZI;
|
||||||
{
|
{
|
||||||
struct host_event_array host_events = host_pop_events(scratch.arena, G.host);
|
struct host_event_array host_events = host_pop_events(scratch.arena, ctx->host);
|
||||||
sim_cmds_from_host_events(scratch.arena, host_events, &sim_cmds);
|
sim_cmds_from_host_events(scratch.arena, host_events, &sim_cmds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,26 +544,26 @@ INTERNAL void sim_update(void)
|
|||||||
enum sim_cmd_kind kind = cmd->kind;
|
enum sim_cmd_kind kind = cmd->kind;
|
||||||
struct host_channel_id channel_id = cmd->channel_id;
|
struct host_channel_id channel_id = cmd->channel_id;
|
||||||
|
|
||||||
struct sim_client *client = client_from_channel_id(G.client_store, channel_id);
|
struct sim_client *client = sim_client_from_channel_id(ctx->client_store, channel_id);
|
||||||
if (client->valid || host_channel_id_is_nil(channel_id)) {
|
if (client->valid || host_channel_id_is_nil(channel_id)) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
/* Cursor */
|
/* Cursor */
|
||||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||||
{
|
{
|
||||||
G.user_cursor = cmd->cursor_pos;
|
ctx->user_cursor = cmd->cursor_pos;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
/* Clear level */
|
/* Clear level */
|
||||||
case SIM_CMD_KIND_CLEAR_ALL:
|
case SIM_CMD_KIND_CLEAR_ALL:
|
||||||
{
|
{
|
||||||
G.should_reset_level = true;
|
ctx->should_reset_level = true;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
/* Spawn test */
|
/* Spawn test */
|
||||||
case SIM_CMD_KIND_SPAWN_TEST:
|
case SIM_CMD_KIND_SPAWN_TEST:
|
||||||
{
|
{
|
||||||
logf_info("Spawning (test)");
|
logf_info("Spawning (test)");
|
||||||
spawn_test_entities();
|
spawn_test_entities(ctx);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
/* Disconnect client */
|
/* Disconnect client */
|
||||||
@ -574,9 +574,9 @@ INTERNAL void sim_update(void)
|
|||||||
if (client_ent->valid) {
|
if (client_ent->valid) {
|
||||||
sim_ent_disable_prop(client_ent, SIM_ENT_PROP_PLAYER_CONTROLLED);
|
sim_ent_disable_prop(client_ent, SIM_ENT_PROP_PLAYER_CONTROLLED);
|
||||||
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_RELEASE_NEXT_TICK);
|
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_RELEASE_NEXT_TICK);
|
||||||
host_queue_disconnect(G.host, channel_id);
|
host_queue_disconnect(ctx->host, channel_id);
|
||||||
}
|
}
|
||||||
client_release(client);
|
sim_client_release(client);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -584,7 +584,7 @@ INTERNAL void sim_update(void)
|
|||||||
};
|
};
|
||||||
} else if (kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id) && !client->valid) {
|
} else if (kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id) && !client->valid) {
|
||||||
/* Connect client */
|
/* Connect client */
|
||||||
client = client_alloc(G.client_store, channel_id);
|
client = sim_client_alloc(ctx->client_store, channel_id);
|
||||||
struct sim_ent *client_ent = sim_ent_alloc(root);
|
struct sim_ent *client_ent = sim_ent_alloc(root);
|
||||||
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_PLAYER_CONTROLLED);
|
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_PLAYER_CONTROLLED);
|
||||||
client_ent->controlling_client = client->handle;
|
client_ent->controlling_client = client->handle;
|
||||||
@ -676,7 +676,7 @@ INTERNAL void sim_update(void)
|
|||||||
#endif
|
#endif
|
||||||
ent->local_collider.count = 3;
|
ent->local_collider.count = 3;
|
||||||
ent->local_collider.radius = 0.25;
|
ent->local_collider.radius = 0.25;
|
||||||
//ent->local_collider.radius = math_fabs(math_sin(G.tick.time) / 3);
|
//ent->local_collider.radius = math_fabs(math_sin(ctx->tick.time) / 3);
|
||||||
#else
|
#else
|
||||||
//ent->local_collider.radius = 0.5;
|
//ent->local_collider.radius = 0.5;
|
||||||
ent->local_collider.radius = 0.25;
|
ent->local_collider.radius = 0.25;
|
||||||
@ -729,7 +729,7 @@ INTERNAL void sim_update(void)
|
|||||||
b32 start = cmd->state == SIM_CMD_STATE_START;
|
b32 start = cmd->state == SIM_CMD_STATE_START;
|
||||||
b32 stop = cmd->state == SIM_CMD_STATE_STOP;
|
b32 stop = cmd->state == SIM_CMD_STATE_STOP;
|
||||||
|
|
||||||
/* TODO: Combine movement from multiple inputs? E.G. a sudden
|
/* TODO: Combine movement from multiple inputs? E.ctx-> a sudden
|
||||||
* start and immediate stop cmd should still move the player a
|
* start and immediate stop cmd should still move the player a
|
||||||
* tad. */
|
* tad. */
|
||||||
switch (cmd->kind) {
|
switch (cmd->kind) {
|
||||||
@ -1071,30 +1071,31 @@ INTERNAL void sim_update(void)
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
{
|
{
|
||||||
struct phys_ctx ctx = ZI;
|
struct phys_ctx phys = ZI;
|
||||||
ctx.tick_id = G.tick.tick_id;
|
phys.tick_id = ctx->tick.tick_id;
|
||||||
ctx.store = ent_store;
|
phys.store = ent_store;
|
||||||
ctx.space = space;
|
phys.space = space;
|
||||||
ctx.contact_lookup = &G.contact_lookup;
|
phys.contact_lookup = &ctx->contact_lookup;
|
||||||
ctx.pre_solve_callback = on_collision;
|
phys.pre_solve_callback = on_collision;
|
||||||
|
phys.pre_solve_callback_udata = ctx;
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
ctx.debug_lookup = &G.collision_debug_lookup;
|
phys.debug_lookup = &phys->collision_debug_lookup;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Mouse drag */
|
/* Mouse drag */
|
||||||
ctx.dbg_cursor_pos = G.user_cursor;
|
phys.dbg_cursor_pos = ctx->user_cursor;
|
||||||
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
|
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
|
||||||
if (cmd->kind == SIM_CMD_KIND_DRAG_OBJECT) {
|
if (cmd->kind == SIM_CMD_KIND_DRAG_OBJECT) {
|
||||||
if (cmd->state == SIM_CMD_STATE_START) {
|
if (cmd->state == SIM_CMD_STATE_START) {
|
||||||
ctx.dbg_start_dragging = true;
|
phys.dbg_start_dragging = true;
|
||||||
} else if (cmd->state == SIM_CMD_STATE_STOP) {
|
} else if (cmd->state == SIM_CMD_STATE_STOP) {
|
||||||
ctx.dbg_stop_dragging = true;
|
phys.dbg_stop_dragging = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step */
|
/* Step */
|
||||||
G.last_phys_iteration = phys_step(&ctx, dt, G.last_phys_iteration);
|
ctx->last_phys_iteration = phys_step(&phys, dt, ctx->last_phys_iteration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -1130,7 +1131,7 @@ INTERNAL void sim_update(void)
|
|||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_BULLET)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_BULLET)) continue;
|
||||||
|
|
||||||
if (ent->activation_tick == G.tick.tick_id) {
|
if (ent->activation_tick == ctx->tick.tick_id) {
|
||||||
struct sim_ent *src = sim_ent_from_handle(ent_store, ent->bullet_src);
|
struct sim_ent *src = sim_ent_from_handle(ent_store, ent->bullet_src);
|
||||||
struct xform src_xf = sim_ent_get_xform(src);
|
struct xform src_xf = sim_ent_get_xform(src);
|
||||||
|
|
||||||
@ -1276,6 +1277,7 @@ INTERNAL void sim_update(void)
|
|||||||
arena_temp_end(temp);
|
arena_temp_end(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Update sound emitters
|
* Update sound emitters
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -1290,7 +1292,7 @@ INTERNAL void sim_update(void)
|
|||||||
|
|
||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TEST_SOUND_EMITTER)) {
|
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TEST_SOUND_EMITTER)) {
|
||||||
struct mixer_desc desc = ent->sound_desc;
|
struct mixer_desc desc = ent->sound_desc;
|
||||||
desc.speed = G.tick.timescale;
|
desc.speed = ctx->tick.timescale;
|
||||||
|
|
||||||
desc.pos = sim_ent_get_xform(ent).og;
|
desc.pos = sim_ent_get_xform(ent).og;
|
||||||
struct sound *sound = sound_load_async(ent->sound_name, 0);
|
struct sound *sound = sound_load_async(ent->sound_name, 0);
|
||||||
@ -1304,12 +1306,13 @@ INTERNAL void sim_update(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Release entities
|
* Release entities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
release_entities_with_prop(SIM_ENT_PROP_RELEASE_THIS_TICK);
|
release_entities_with_prop(ctx, SIM_ENT_PROP_RELEASE_THIS_TICK);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Publish tick
|
* Publish tick
|
||||||
@ -1321,19 +1324,19 @@ INTERNAL void sim_update(void)
|
|||||||
/* TODO: Not like this */
|
/* TODO: Not like this */
|
||||||
struct sim_event snapshot_event = ZI;
|
struct sim_event snapshot_event = ZI;
|
||||||
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT_FULL;
|
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT_FULL;
|
||||||
snapshot_event.snapshot_data = sim_string_from_tick(temp.arena, &G.tick);
|
snapshot_event.snapshot_data = sim_string_from_tick(temp.arena, &ctx->tick);
|
||||||
|
|
||||||
struct sim_event_list l = ZI;
|
struct sim_event_list l = ZI;
|
||||||
l.first = &snapshot_event;
|
l.first = &snapshot_event;
|
||||||
l.last = &snapshot_event;
|
l.last = &snapshot_event;
|
||||||
struct string msg = sim_string_from_events(temp.arena, l);
|
struct string msg = sim_string_from_events(temp.arena, l);
|
||||||
|
|
||||||
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, msg, 0);
|
host_queue_write(ctx->host, HOST_CHANNEL_ID_ALL, msg, 0);
|
||||||
|
|
||||||
arena_temp_end(temp);
|
arena_temp_end(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
host_update(G.host);
|
host_update(ctx->host);
|
||||||
__profframe("Sim");
|
__profframe("Sim");
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -1345,281 +1348,19 @@ INTERNAL void sim_update(void)
|
|||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Sim cmd
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
struct byte_writer bw = bw_from_arena(arena);
|
|
||||||
|
|
||||||
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
|
||||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
|
||||||
u64 start = bw_pos(&bw);
|
|
||||||
|
|
||||||
bw_write_i8(&bw, cmd->kind);
|
|
||||||
bw_write_i8(&bw, cmd->state);
|
|
||||||
|
|
||||||
#if COLLIDER_DEBUG
|
|
||||||
bw_write_u32(&bw, cmd->collider_gjk_steps);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (cmd->kind) {
|
|
||||||
case SIM_CMD_KIND_PLAYER_MOVE:
|
|
||||||
{
|
|
||||||
bw_write_v2(&bw, cmd->move_dir);
|
|
||||||
bw_write_v2(&bw, cmd->aim_dir);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
|
||||||
{
|
|
||||||
bw_write_v2(&bw, cmd->cursor_pos);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 size = bw_pos(&bw) - start;
|
|
||||||
bw_write_u64(&bw_size, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bw_get_written(&bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
for (u64 i = 0; i < host_events.count; ++i) {
|
|
||||||
struct host_event host_event = host_events.events[i];
|
|
||||||
enum host_event_kind host_event_kind = host_event.kind;
|
|
||||||
switch (host_event_kind) {
|
|
||||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
|
||||||
{
|
|
||||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
|
||||||
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_CONNECT;
|
|
||||||
cmd->channel_id = host_event.channel_id;
|
|
||||||
if (cmds_out->last) {
|
|
||||||
cmds_out->last->next = cmd;
|
|
||||||
} else {
|
|
||||||
cmds_out->first = cmd;
|
|
||||||
}
|
|
||||||
cmds_out->last = cmd;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
|
||||||
{
|
|
||||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
|
||||||
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_DISCONNECT;
|
|
||||||
cmd->disconnect_reason = LIT("Connection lost");
|
|
||||||
if (cmds_out->last) {
|
|
||||||
cmds_out->last->next = cmd;
|
|
||||||
} else {
|
|
||||||
cmds_out->first = cmd;
|
|
||||||
}
|
|
||||||
cmds_out->last = cmd;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case HOST_EVENT_KIND_MSG:
|
|
||||||
{
|
|
||||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
|
||||||
while (br_bytes_left(&br) > 0) {
|
|
||||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_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 COLLIDER_DEBUG
|
|
||||||
cmd->collider_gjk_steps = br_read_u32(&br);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (cmd->kind) {
|
|
||||||
case SIM_CMD_KIND_PLAYER_MOVE:
|
|
||||||
{
|
|
||||||
cmd->move_dir = br_read_v2(&br);
|
|
||||||
cmd->aim_dir = br_read_v2(&br);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case SIM_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 (cmds_out->last) {
|
|
||||||
cmds_out->last->next = cmd;
|
|
||||||
} else {
|
|
||||||
cmds_out->first = cmd;
|
|
||||||
}
|
|
||||||
cmds_out->last = cmd;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Sim event
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
struct byte_writer bw = bw_from_arena(arena);
|
|
||||||
for (struct sim_event *event = events.first; event; event = event->next) {
|
|
||||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
|
||||||
u64 start = bw_pos(&bw);
|
|
||||||
bw_write_i8(&bw, event->kind);
|
|
||||||
|
|
||||||
switch (event->kind) {
|
|
||||||
case SIM_EVENT_KIND_SNAPSHOT_FULL:
|
|
||||||
{
|
|
||||||
bw_write_string(&bw, event->snapshot_data);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 size = bw_pos(&bw) - start;
|
|
||||||
bw_write_u64(&bw_size, size);
|
|
||||||
}
|
|
||||||
return bw_get_written(&bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
for (u64 i = 0; i < host_events.count; ++i) {
|
|
||||||
struct sim_event *sim_event = arena_push_zero(arena, struct sim_event);
|
|
||||||
struct host_event host_event = host_events.events[i];
|
|
||||||
enum host_event_kind host_event_kind = host_event.kind;
|
|
||||||
sim_event->channel_id = host_event.channel_id;
|
|
||||||
switch (host_event_kind) {
|
|
||||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
|
||||||
{
|
|
||||||
sim_event->kind = SIM_EVENT_KIND_CONNECT;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
|
||||||
{
|
|
||||||
sim_event->kind = SIM_EVENT_KIND_DISCONNECT;
|
|
||||||
sim_event->disconnect_reason = LIT("Connection lost");
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case HOST_EVENT_KIND_MSG:
|
|
||||||
{
|
|
||||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
|
||||||
while (br_bytes_left(&br) > 0) {
|
|
||||||
u64 event_size = br_read_u64(&br);
|
|
||||||
u64 event_pos_end = br_pos(&br) + event_size;
|
|
||||||
|
|
||||||
sim_event->kind = br_read_i8(&br);
|
|
||||||
switch (sim_event->kind) {
|
|
||||||
case SIM_EVENT_KIND_SNAPSHOT_FULL:
|
|
||||||
{
|
|
||||||
sim_event->snapshot_data = br_read_string(arena, &br);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(br_pos(&br) == event_pos_end);
|
|
||||||
br_seek_to(&br, event_pos_end);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (events_out->last) {
|
|
||||||
events_out->last->next = sim_event;
|
|
||||||
} else {
|
|
||||||
events_out->first = sim_event;
|
|
||||||
}
|
|
||||||
events_out->last = sim_event;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Snapshot
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
struct string sim_string_from_tick(struct arena *arena, struct world *tick)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
struct byte_writer bw = bw_from_arena(arena);
|
|
||||||
|
|
||||||
bw_write_var_uint(&bw, tick->continuity_gen);
|
|
||||||
bw_write_var_uint(&bw, tick->tick_id);
|
|
||||||
bw_write_var_sint(&bw, tick->publishtime_ns);
|
|
||||||
|
|
||||||
bw_write_f64(&bw, tick->timescale);
|
|
||||||
bw_write_var_sint(&bw, tick->dt_ns);
|
|
||||||
bw_write_var_sint(&bw, tick->time_ns);
|
|
||||||
|
|
||||||
u64 num_entities = tick->ent_store->num_reserved;
|
|
||||||
bw_write_var_uint(&bw, num_entities);
|
|
||||||
|
|
||||||
struct string entities_src = ZI;
|
|
||||||
entities_src.text = (u8 *)tick->ent_store->entities;
|
|
||||||
entities_src.len = sizeof(struct sim_ent) * num_entities;
|
|
||||||
br_write_bytes(&bw, entities_src);
|
|
||||||
|
|
||||||
return bw_get_written(&bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void sim_tick_from_string(struct string str, struct world *tick_out)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
struct byte_reader br = br_from_buffer(str);
|
|
||||||
|
|
||||||
tick_out->continuity_gen = br_read_var_uint(&br);
|
|
||||||
tick_out->tick_id = br_read_var_uint(&br);
|
|
||||||
tick_out->publishtime_ns = br_read_var_sint(&br);
|
|
||||||
|
|
||||||
tick_out->timescale = br_read_f64(&br);
|
|
||||||
tick_out->dt_ns = br_read_var_sint(&br);
|
|
||||||
tick_out->time_ns = br_read_var_sint(&br);
|
|
||||||
|
|
||||||
u64 num_entities = br_read_var_uint(&br);
|
|
||||||
arena_push_array(&tick_out->ent_store->arena, struct sim_ent, num_entities - tick_out->ent_store->num_reserved);
|
|
||||||
tick_out->ent_store->num_reserved = num_entities;
|
|
||||||
|
|
||||||
tick_out->ent_store->num_allocated = 0;
|
|
||||||
struct sim_ent *entities_src = br_seek(&br, num_entities * sizeof(struct sim_ent));
|
|
||||||
if (entities_src) {
|
|
||||||
for (u64 i = 0; i < num_entities; ++i) {
|
|
||||||
struct sim_ent *src = &entities_src[i];
|
|
||||||
struct sim_ent *dst = &tick_out->ent_store->entities[i];
|
|
||||||
if (dst->valid) {
|
|
||||||
++tick_out->ent_store->num_allocated;
|
|
||||||
}
|
|
||||||
*dst = *src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Sim thread
|
* Sim thread
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
|
||||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg)
|
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg)
|
||||||
{
|
{
|
||||||
(UNUSED)arg;
|
struct sim_ctx *ctx = (struct sim_ctx *)arg;
|
||||||
i64 last_frame_ns = 0;
|
i64 last_frame_ns = 0;
|
||||||
i64 target_dt_ns = NS_FROM_SECONDS(SIM_FPS > (0) ? (1.0 / SIM_FPS) : 0);
|
i64 target_dt_ns = NS_FROM_SECONDS(SIM_FPS > (0) ? (1.0 / SIM_FPS) : 0);
|
||||||
while (!atomic_i32_eval(&G.sim_thread_shutdown)) {
|
while (!atomic_i32_eval(&ctx->sim_thread_shutdown)) {
|
||||||
__profscope(sim_update_w_sleep);
|
__profscope(sim_update_w_sleep);
|
||||||
sleep_frame(last_frame_ns, target_dt_ns);
|
sleep_frame(last_frame_ns, target_dt_ns);
|
||||||
last_frame_ns = sys_time_ns();
|
last_frame_ns = sys_time_ns();
|
||||||
sim_update();
|
sim_update(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
121
src/sim.h
121
src/sim.h
@ -1,12 +1,8 @@
|
|||||||
#ifndef SIM_H
|
#ifndef SIM_H
|
||||||
#define SIM_H
|
#define SIM_H
|
||||||
|
|
||||||
#include "host.h"
|
struct sim_ctx;
|
||||||
|
|
||||||
struct world;
|
|
||||||
struct mixer_startup_receipt;
|
|
||||||
struct sprite_startup_receipt;
|
struct sprite_startup_receipt;
|
||||||
struct sound_startup_receipt;
|
|
||||||
struct phys_startup_receipt;
|
struct phys_startup_receipt;
|
||||||
struct host_startup_receipt;
|
struct host_startup_receipt;
|
||||||
|
|
||||||
@ -20,116 +16,13 @@ struct host_startup_receipt;
|
|||||||
#define SIM_LAYER_RELATIVE_DEFAULT 0
|
#define SIM_LAYER_RELATIVE_DEFAULT 0
|
||||||
#define SIM_LAYER_RELATIVE_WEAPON 1
|
#define SIM_LAYER_RELATIVE_WEAPON 1
|
||||||
|
|
||||||
struct sim_startup_receipt { i32 _; };
|
/* TODO: Get rid of startup receipts */
|
||||||
struct sim_startup_receipt sim_startup(struct mixer_startup_receipt *mixer_sr,
|
struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
||||||
struct sprite_startup_receipt *sheet_sr,
|
struct phys_startup_receipt *phys_sr,
|
||||||
struct sound_startup_receipt *sound_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct phys_startup_receipt *phys_sr,
|
u16 host_port);
|
||||||
struct host_startup_receipt *host_sr);
|
|
||||||
|
|
||||||
|
void sim_ctx_release(struct sim_ctx *ctx);
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Sim cmd
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
enum sim_cmd_state {
|
|
||||||
SIM_CMD_STATE_STOP = -1,
|
|
||||||
SIM_CMD_STATE_NO_CHANGE = 0,
|
|
||||||
SIM_CMD_STATE_START = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum sim_cmd_kind {
|
|
||||||
SIM_CMD_KIND_NONE,
|
|
||||||
|
|
||||||
SIM_CMD_KIND_PLAYER_MOVE,
|
|
||||||
SIM_CMD_KIND_PLAYER_FIRE,
|
|
||||||
|
|
||||||
SIM_CMD_KIND_SIM_CLIENT_CONNECT,
|
|
||||||
SIM_CMD_KIND_SIM_CLIENT_DISCONNECT,
|
|
||||||
|
|
||||||
/* Testing */
|
|
||||||
SIM_CMD_KIND_CLEAR_ALL,
|
|
||||||
SIM_CMD_KIND_SPAWN_TEST,
|
|
||||||
SIM_CMD_KIND_PAUSE,
|
|
||||||
SIM_CMD_KIND_STEP,
|
|
||||||
SIM_CMD_KIND_DRAG_OBJECT,
|
|
||||||
SIM_CMD_KIND_CURSOR_MOVE,
|
|
||||||
|
|
||||||
SIM_CMD_KIND_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sim_cmd {
|
|
||||||
enum sim_cmd_kind kind;
|
|
||||||
enum sim_cmd_state state;
|
|
||||||
struct host_channel_id channel_id;
|
|
||||||
|
|
||||||
/* SIM_CMD_KIND_PLAYER_MOVE */
|
|
||||||
struct v2 move_dir;
|
|
||||||
struct v2 aim_dir;
|
|
||||||
|
|
||||||
/* SIM_CMD_KIND_CURSOR_MOVE */
|
|
||||||
struct v2 cursor_pos;
|
|
||||||
|
|
||||||
/* SIM_CMD_KIND_PLAYER_DISCONNECT */
|
|
||||||
struct string disconnect_reason;
|
|
||||||
|
|
||||||
#if RTC
|
|
||||||
u32 collider_gjk_steps;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct sim_cmd *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sim_cmd_list {
|
|
||||||
struct sim_cmd *first;
|
|
||||||
struct sim_cmd *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds);
|
|
||||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Sim event
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
enum sim_event_kind {
|
|
||||||
SIM_EVENT_KIND_NONE,
|
|
||||||
|
|
||||||
SIM_EVENT_KIND_CONNECT,
|
|
||||||
SIM_EVENT_KIND_DISCONNECT,
|
|
||||||
SIM_EVENT_KIND_SNAPSHOT_FULL,
|
|
||||||
|
|
||||||
//SIM_EVENT_KIND_ENTITY_UPDATE,
|
|
||||||
//SIM_EVENT_KIND_ENTITY_CREATE,
|
|
||||||
//SIM_EVENT_KIND_ENTITY_DESTROY
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sim_event {
|
|
||||||
enum sim_event_kind kind;
|
|
||||||
struct host_channel_id channel_id;
|
|
||||||
|
|
||||||
struct string snapshot_data;
|
|
||||||
struct string disconnect_reason;
|
|
||||||
|
|
||||||
//struct sim_ent_handle entity;
|
|
||||||
//struct string update_data;
|
|
||||||
|
|
||||||
struct sim_event *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sim_event_list {
|
|
||||||
struct sim_event *first;
|
|
||||||
struct sim_event *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events);
|
|
||||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Snapshot
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
struct string sim_string_from_tick(struct arena *arena, struct world *tick);
|
|
||||||
void sim_tick_from_string(struct string str, struct world *tick_out);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -17,7 +17,7 @@ READONLY struct sim_client_store _g_sim_client_store_nil = { .valid = false };
|
|||||||
* Store
|
* Store
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct sim_client_store *client_store_alloc(void)
|
struct sim_client_store *sim_client_store_alloc(void)
|
||||||
{
|
{
|
||||||
struct arena arena = arena_alloc(GIGABYTE(64));
|
struct arena arena = arena_alloc(GIGABYTE(64));
|
||||||
u64 num_channel_lookup_buckets = CHANNEL_LOOKUP_BUCKETS;
|
u64 num_channel_lookup_buckets = CHANNEL_LOOKUP_BUCKETS;
|
||||||
@ -34,7 +34,7 @@ struct sim_client_store *client_store_alloc(void)
|
|||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_store_release(struct sim_client_store *store)
|
void sim_client_store_release(struct sim_client_store *store)
|
||||||
{
|
{
|
||||||
arena_release(&store->arena);
|
arena_release(&store->arena);
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ INTERNAL u64 hash_from_channel_id(struct host_channel_id channel_id)
|
|||||||
return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&channel_id));
|
return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&channel_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_client *client_from_handle(struct sim_client_store *store, struct client_handle handle)
|
struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct client_handle handle)
|
||||||
{
|
{
|
||||||
if (handle.gen != 0 && handle.idx < store->clients_reserved) {
|
if (handle.gen != 0 && handle.idx < store->clients_reserved) {
|
||||||
struct sim_client *client = &store->clients[handle.idx];
|
struct sim_client *client = &store->clients[handle.idx];
|
||||||
@ -71,7 +71,7 @@ struct sim_client *client_from_handle(struct sim_client_store *store, struct cli
|
|||||||
return client_nil();
|
return client_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_client *client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id)
|
struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id)
|
||||||
{
|
{
|
||||||
struct sim_client *res = client_nil();
|
struct sim_client *res = client_nil();
|
||||||
u64 channel_hash = hash_from_channel_id(channel_id);
|
u64 channel_hash = hash_from_channel_id(channel_id);
|
||||||
@ -86,7 +86,7 @@ struct sim_client *client_from_channel_id(struct sim_client_store *store, struct
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_client *client_alloc(struct sim_client_store *store, struct host_channel_id channel_id)
|
struct sim_client *sim_client_alloc(struct sim_client_store *store, struct host_channel_id channel_id)
|
||||||
{
|
{
|
||||||
struct sim_client *client = NULL;
|
struct sim_client *client = NULL;
|
||||||
struct client_handle handle = ZI;
|
struct client_handle handle = ZI;
|
||||||
@ -122,7 +122,7 @@ struct sim_client *client_alloc(struct sim_client_store *store, struct host_chan
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_release(struct sim_client *client)
|
void sim_client_release(struct sim_client *client)
|
||||||
{
|
{
|
||||||
struct sim_client_store *store = client_store_from_client(client);
|
struct sim_client_store *store = client_store_from_client(client);
|
||||||
client->valid = false;
|
client->valid = false;
|
||||||
|
|||||||
@ -50,12 +50,12 @@ INLINE struct sim_client_store *client_store_nil(void)
|
|||||||
return &_g_sim_client_store_nil;
|
return &_g_sim_client_store_nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_client_store *client_store_alloc(void);
|
struct sim_client_store *sim_client_store_alloc(void);
|
||||||
void client_store_release(struct sim_client_store *store);
|
void sim_client_store_release(struct sim_client_store *store);
|
||||||
struct sim_client_store *client_store_from_client(struct sim_client *client);
|
struct sim_client_store *client_store_from_client(struct sim_client *client);
|
||||||
struct sim_client *client_from_handle(struct sim_client_store *store, struct client_handle handle);
|
struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct client_handle handle);
|
||||||
struct sim_client *client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id);
|
struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id);
|
||||||
struct sim_client *client_alloc(struct sim_client_store *store, struct host_channel_id channel_id);
|
struct sim_client *sim_client_alloc(struct sim_client_store *store, struct host_channel_id channel_id);
|
||||||
void client_release(struct sim_client *client);
|
void sim_client_release(struct sim_client *client);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
265
src/sim_msg.c
Normal file
265
src/sim_msg.c
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
#include "sim_msg.h"
|
||||||
|
#include "arena.h"
|
||||||
|
#include "byteio.h"
|
||||||
|
#include "world.h"
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Sim cmd
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds)
|
||||||
|
{
|
||||||
|
__prof;
|
||||||
|
struct byte_writer bw = bw_from_arena(arena);
|
||||||
|
|
||||||
|
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
||||||
|
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||||
|
u64 start = bw_pos(&bw);
|
||||||
|
|
||||||
|
bw_write_i8(&bw, cmd->kind);
|
||||||
|
bw_write_i8(&bw, cmd->state);
|
||||||
|
|
||||||
|
#if COLLIDER_DEBUG
|
||||||
|
bw_write_u32(&bw, cmd->collider_gjk_steps);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (cmd->kind) {
|
||||||
|
case SIM_CMD_KIND_PLAYER_MOVE:
|
||||||
|
{
|
||||||
|
bw_write_v2(&bw, cmd->move_dir);
|
||||||
|
bw_write_v2(&bw, cmd->aim_dir);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||||
|
{
|
||||||
|
bw_write_v2(&bw, cmd->cursor_pos);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 size = bw_pos(&bw) - start;
|
||||||
|
bw_write_u64(&bw_size, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bw_get_written(&bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
|
||||||
|
{
|
||||||
|
__prof;
|
||||||
|
for (u64 i = 0; i < host_events.count; ++i) {
|
||||||
|
struct host_event host_event = host_events.events[i];
|
||||||
|
enum host_event_kind host_event_kind = host_event.kind;
|
||||||
|
switch (host_event_kind) {
|
||||||
|
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||||
|
{
|
||||||
|
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||||
|
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_CONNECT;
|
||||||
|
cmd->channel_id = host_event.channel_id;
|
||||||
|
if (cmds_out->last) {
|
||||||
|
cmds_out->last->next = cmd;
|
||||||
|
} else {
|
||||||
|
cmds_out->first = cmd;
|
||||||
|
}
|
||||||
|
cmds_out->last = cmd;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||||
|
{
|
||||||
|
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||||
|
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_DISCONNECT;
|
||||||
|
cmd->disconnect_reason = LIT("Connection lost");
|
||||||
|
if (cmds_out->last) {
|
||||||
|
cmds_out->last->next = cmd;
|
||||||
|
} else {
|
||||||
|
cmds_out->first = cmd;
|
||||||
|
}
|
||||||
|
cmds_out->last = cmd;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case HOST_EVENT_KIND_MSG:
|
||||||
|
{
|
||||||
|
struct byte_reader br = br_from_buffer(host_event.msg);
|
||||||
|
while (br_bytes_left(&br) > 0) {
|
||||||
|
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_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 COLLIDER_DEBUG
|
||||||
|
cmd->collider_gjk_steps = br_read_u32(&br);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (cmd->kind) {
|
||||||
|
case SIM_CMD_KIND_PLAYER_MOVE:
|
||||||
|
{
|
||||||
|
cmd->move_dir = br_read_v2(&br);
|
||||||
|
cmd->aim_dir = br_read_v2(&br);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case SIM_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 (cmds_out->last) {
|
||||||
|
cmds_out->last->next = cmd;
|
||||||
|
} else {
|
||||||
|
cmds_out->first = cmd;
|
||||||
|
}
|
||||||
|
cmds_out->last = cmd;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Sim event
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events)
|
||||||
|
{
|
||||||
|
__prof;
|
||||||
|
struct byte_writer bw = bw_from_arena(arena);
|
||||||
|
for (struct sim_event *event = events.first; event; event = event->next) {
|
||||||
|
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||||
|
u64 start = bw_pos(&bw);
|
||||||
|
bw_write_i8(&bw, event->kind);
|
||||||
|
|
||||||
|
switch (event->kind) {
|
||||||
|
case SIM_EVENT_KIND_SNAPSHOT_FULL:
|
||||||
|
{
|
||||||
|
bw_write_string(&bw, event->snapshot_data);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 size = bw_pos(&bw) - start;
|
||||||
|
bw_write_u64(&bw_size, size);
|
||||||
|
}
|
||||||
|
return bw_get_written(&bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out)
|
||||||
|
{
|
||||||
|
__prof;
|
||||||
|
for (u64 i = 0; i < host_events.count; ++i) {
|
||||||
|
struct sim_event *sim_event = arena_push_zero(arena, struct sim_event);
|
||||||
|
struct host_event host_event = host_events.events[i];
|
||||||
|
enum host_event_kind host_event_kind = host_event.kind;
|
||||||
|
sim_event->channel_id = host_event.channel_id;
|
||||||
|
switch (host_event_kind) {
|
||||||
|
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||||
|
{
|
||||||
|
sim_event->kind = SIM_EVENT_KIND_CONNECT;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||||
|
{
|
||||||
|
sim_event->kind = SIM_EVENT_KIND_DISCONNECT;
|
||||||
|
sim_event->disconnect_reason = LIT("Connection lost");
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case HOST_EVENT_KIND_MSG:
|
||||||
|
{
|
||||||
|
struct byte_reader br = br_from_buffer(host_event.msg);
|
||||||
|
while (br_bytes_left(&br) > 0) {
|
||||||
|
u64 event_size = br_read_u64(&br);
|
||||||
|
u64 event_pos_end = br_pos(&br) + event_size;
|
||||||
|
|
||||||
|
sim_event->kind = br_read_i8(&br);
|
||||||
|
switch (sim_event->kind) {
|
||||||
|
case SIM_EVENT_KIND_SNAPSHOT_FULL:
|
||||||
|
{
|
||||||
|
sim_event->snapshot_data = br_read_string(arena, &br);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(br_pos(&br) == event_pos_end);
|
||||||
|
br_seek_to(&br, event_pos_end);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events_out->last) {
|
||||||
|
events_out->last->next = sim_event;
|
||||||
|
} else {
|
||||||
|
events_out->first = sim_event;
|
||||||
|
}
|
||||||
|
events_out->last = sim_event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Snapshot
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct string sim_string_from_tick(struct arena *arena, struct world *tick)
|
||||||
|
{
|
||||||
|
__prof;
|
||||||
|
struct byte_writer bw = bw_from_arena(arena);
|
||||||
|
|
||||||
|
bw_write_var_uint(&bw, tick->continuity_gen);
|
||||||
|
bw_write_var_uint(&bw, tick->tick_id);
|
||||||
|
bw_write_var_sint(&bw, tick->publishtime_ns);
|
||||||
|
|
||||||
|
bw_write_f64(&bw, tick->timescale);
|
||||||
|
bw_write_var_sint(&bw, tick->dt_ns);
|
||||||
|
bw_write_var_sint(&bw, tick->time_ns);
|
||||||
|
|
||||||
|
u64 num_entities = tick->ent_store->num_reserved;
|
||||||
|
bw_write_var_uint(&bw, num_entities);
|
||||||
|
|
||||||
|
struct string entities_src = ZI;
|
||||||
|
entities_src.text = (u8 *)tick->ent_store->entities;
|
||||||
|
entities_src.len = sizeof(struct sim_ent) * num_entities;
|
||||||
|
br_write_bytes(&bw, entities_src);
|
||||||
|
|
||||||
|
return bw_get_written(&bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim_tick_from_string(struct string str, struct world *tick_out)
|
||||||
|
{
|
||||||
|
__prof;
|
||||||
|
struct byte_reader br = br_from_buffer(str);
|
||||||
|
|
||||||
|
tick_out->continuity_gen = br_read_var_uint(&br);
|
||||||
|
tick_out->tick_id = br_read_var_uint(&br);
|
||||||
|
tick_out->publishtime_ns = br_read_var_sint(&br);
|
||||||
|
|
||||||
|
tick_out->timescale = br_read_f64(&br);
|
||||||
|
tick_out->dt_ns = br_read_var_sint(&br);
|
||||||
|
tick_out->time_ns = br_read_var_sint(&br);
|
||||||
|
|
||||||
|
u64 num_entities = br_read_var_uint(&br);
|
||||||
|
arena_push_array(&tick_out->ent_store->arena, struct sim_ent, num_entities - tick_out->ent_store->num_reserved);
|
||||||
|
tick_out->ent_store->num_reserved = num_entities;
|
||||||
|
|
||||||
|
tick_out->ent_store->num_allocated = 0;
|
||||||
|
struct sim_ent *entities_src = br_seek(&br, num_entities * sizeof(struct sim_ent));
|
||||||
|
if (entities_src) {
|
||||||
|
for (u64 i = 0; i < num_entities; ++i) {
|
||||||
|
struct sim_ent *src = &entities_src[i];
|
||||||
|
struct sim_ent *dst = &tick_out->ent_store->entities[i];
|
||||||
|
if (dst->valid) {
|
||||||
|
++tick_out->ent_store->num_allocated;
|
||||||
|
}
|
||||||
|
*dst = *src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
112
src/sim_msg.h
Normal file
112
src/sim_msg.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#ifndef SIM_MSG_H
|
||||||
|
#define SIM_MSG_H
|
||||||
|
|
||||||
|
#include "host.h"
|
||||||
|
|
||||||
|
struct world;
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Sim cmd
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
enum sim_cmd_state {
|
||||||
|
SIM_CMD_STATE_STOP = -1,
|
||||||
|
SIM_CMD_STATE_NO_CHANGE = 0,
|
||||||
|
SIM_CMD_STATE_START = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum sim_cmd_kind {
|
||||||
|
SIM_CMD_KIND_NONE,
|
||||||
|
|
||||||
|
SIM_CMD_KIND_PLAYER_MOVE,
|
||||||
|
SIM_CMD_KIND_PLAYER_FIRE,
|
||||||
|
|
||||||
|
SIM_CMD_KIND_SIM_CLIENT_CONNECT,
|
||||||
|
SIM_CMD_KIND_SIM_CLIENT_DISCONNECT,
|
||||||
|
|
||||||
|
/* Testing */
|
||||||
|
SIM_CMD_KIND_CLEAR_ALL,
|
||||||
|
SIM_CMD_KIND_SPAWN_TEST,
|
||||||
|
SIM_CMD_KIND_PAUSE,
|
||||||
|
SIM_CMD_KIND_STEP,
|
||||||
|
SIM_CMD_KIND_DRAG_OBJECT,
|
||||||
|
SIM_CMD_KIND_CURSOR_MOVE,
|
||||||
|
|
||||||
|
SIM_CMD_KIND_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sim_cmd {
|
||||||
|
enum sim_cmd_kind kind;
|
||||||
|
enum sim_cmd_state state;
|
||||||
|
struct host_channel_id channel_id;
|
||||||
|
|
||||||
|
/* SIM_CMD_KIND_PLAYER_MOVE */
|
||||||
|
struct v2 move_dir;
|
||||||
|
struct v2 aim_dir;
|
||||||
|
|
||||||
|
/* SIM_CMD_KIND_CURSOR_MOVE */
|
||||||
|
struct v2 cursor_pos;
|
||||||
|
|
||||||
|
/* SIM_CMD_KIND_PLAYER_DISCONNECT */
|
||||||
|
struct string disconnect_reason;
|
||||||
|
|
||||||
|
#if RTC
|
||||||
|
u32 collider_gjk_steps;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct sim_cmd *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sim_cmd_list {
|
||||||
|
struct sim_cmd *first;
|
||||||
|
struct sim_cmd *last;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds);
|
||||||
|
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Sim event
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
enum sim_event_kind {
|
||||||
|
SIM_EVENT_KIND_NONE,
|
||||||
|
|
||||||
|
SIM_EVENT_KIND_CONNECT,
|
||||||
|
SIM_EVENT_KIND_DISCONNECT,
|
||||||
|
SIM_EVENT_KIND_SNAPSHOT_FULL,
|
||||||
|
|
||||||
|
//SIM_EVENT_KIND_ENTITY_UPDATE,
|
||||||
|
//SIM_EVENT_KIND_ENTITY_CREATE,
|
||||||
|
//SIM_EVENT_KIND_ENTITY_DESTROY
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sim_event {
|
||||||
|
enum sim_event_kind kind;
|
||||||
|
struct host_channel_id channel_id;
|
||||||
|
|
||||||
|
struct string snapshot_data;
|
||||||
|
struct string disconnect_reason;
|
||||||
|
|
||||||
|
//struct sim_ent_handle entity;
|
||||||
|
//struct string update_data;
|
||||||
|
|
||||||
|
struct sim_event *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sim_event_list {
|
||||||
|
struct sim_event *first;
|
||||||
|
struct sim_event *last;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events);
|
||||||
|
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Snapshot
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct string sim_string_from_tick(struct arena *arena, struct world *tick);
|
||||||
|
void sim_tick_from_string(struct string str, struct world *tick_out);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -8,13 +8,8 @@ enum sock_address_family {
|
|||||||
SOCK_ADDRESS_FAMILY_IPV6
|
SOCK_ADDRESS_FAMILY_IPV6
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sock {
|
struct sock;
|
||||||
i32 _;
|
struct sock_signal;
|
||||||
};
|
|
||||||
|
|
||||||
struct sock_signal {
|
|
||||||
i32 _;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sock_array {
|
struct sock_array {
|
||||||
struct sock **socks;
|
struct sock **socks;
|
||||||
|
|||||||
23
src/user.c
23
src/user.c
@ -2,6 +2,7 @@
|
|||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "sim.h"
|
#include "sim.h"
|
||||||
#include "sim_ent.h"
|
#include "sim_ent.h"
|
||||||
|
#include "sim_msg.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "sprite.h"
|
#include "sprite.h"
|
||||||
@ -46,9 +47,8 @@ GLOBAL struct {
|
|||||||
struct sys_thread user_thread;
|
struct sys_thread user_thread;
|
||||||
|
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
|
|
||||||
struct sys_window *window;
|
struct sys_window *window;
|
||||||
|
struct sim_ctx *sim_ctx;
|
||||||
struct host *host;
|
struct host *host;
|
||||||
|
|
||||||
/* Usage stats */
|
/* Usage stats */
|
||||||
@ -148,9 +148,10 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
struct font_startup_receipt *font_sr,
|
struct font_startup_receipt *font_sr,
|
||||||
struct sprite_startup_receipt *sprite_sr,
|
struct sprite_startup_receipt *sprite_sr,
|
||||||
struct draw_startup_receipt *draw_sr,
|
struct draw_startup_receipt *draw_sr,
|
||||||
struct sim_startup_receipt *sim_sr,
|
|
||||||
struct asset_cache_startup_receipt *asset_cache_sr,
|
struct asset_cache_startup_receipt *asset_cache_sr,
|
||||||
|
struct sound_startup_receipt *sound_sr,
|
||||||
struct mixer_startup_receipt *mixer_sr,
|
struct mixer_startup_receipt *mixer_sr,
|
||||||
|
struct phys_startup_receipt *phys_sr,
|
||||||
struct host_startup_receipt *host_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct sys_window *window)
|
struct sys_window *window)
|
||||||
{
|
{
|
||||||
@ -159,9 +160,10 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
(UNUSED)font_sr;
|
(UNUSED)font_sr;
|
||||||
(UNUSED)sprite_sr;
|
(UNUSED)sprite_sr;
|
||||||
(UNUSED)draw_sr;
|
(UNUSED)draw_sr;
|
||||||
(UNUSED)sim_sr;
|
|
||||||
(UNUSED)asset_cache_sr;
|
(UNUSED)asset_cache_sr;
|
||||||
|
(UNUSED)sound_sr;
|
||||||
(UNUSED)mixer_sr;
|
(UNUSED)mixer_sr;
|
||||||
|
(UNUSED)phys_sr;
|
||||||
(UNUSED)host_sr;
|
(UNUSED)host_sr;
|
||||||
|
|
||||||
G.arena = arena_alloc(GIGABYTE(64));
|
G.arena = arena_alloc(GIGABYTE(64));
|
||||||
@ -170,8 +172,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
world_alloc(&G.world);
|
world_alloc(&G.world);
|
||||||
|
|
||||||
//struct sock_address bind_addr = sock_address_from_any_local_interface_with_dynamic_port();
|
//struct sock_address bind_addr = sock_address_from_any_local_interface_with_dynamic_port();
|
||||||
//G.host = host_alloc(0);
|
G.host = host_alloc(0);
|
||||||
G.host = host_alloc(5920);
|
|
||||||
|
|
||||||
G.world_to_ui_xf = XFORM_IDENT;
|
G.world_to_ui_xf = XFORM_IDENT;
|
||||||
G.world_cmd_buffer = renderer_cmd_buffer_alloc();
|
G.world_cmd_buffer = renderer_cmd_buffer_alloc();
|
||||||
@ -182,6 +183,8 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
G.window = window;
|
G.window = window;
|
||||||
sys_window_register_event_callback(G.window, &window_event_callback);
|
sys_window_register_event_callback(G.window, &window_event_callback);
|
||||||
|
|
||||||
|
G.sim_ctx = sim_ctx_alloc(sprite_sr, phys_sr, host_sr, 12345);
|
||||||
|
|
||||||
G.debug_draw = true;
|
G.debug_draw = true;
|
||||||
|
|
||||||
G.user_thread = sys_thread_alloc(&user_thread_entry_point, NULL, LIT("[P1] User thread"));
|
G.user_thread = sys_thread_alloc(&user_thread_entry_point, NULL, LIT("[P1] User thread"));
|
||||||
@ -195,6 +198,10 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(user_shutdown)
|
|||||||
__prof;
|
__prof;
|
||||||
atomic_i32_eval_exchange(&G.user_thread_shutdown, true);
|
atomic_i32_eval_exchange(&G.user_thread_shutdown, true);
|
||||||
sys_thread_wait_release(&G.user_thread);
|
sys_thread_wait_release(&G.user_thread);
|
||||||
|
|
||||||
|
if (G.sim_ctx) {
|
||||||
|
sim_ctx_release(G.sim_ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -1620,10 +1627,10 @@ INTERNAL void user_update(void)
|
|||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Client data read: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1024 / 1024, 2)));
|
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Client data read: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1000 / 1000, 2)));
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Client data sent: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_sent.last_second * 8 / 1024 / 1024, 2)));
|
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Client data sent: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_sent.last_second * 8 / 1000 / 1000, 2)));
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory usage: %F MiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_committed) / 1024 / 1024, 2)));
|
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory usage: %F MiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_committed) / 1024 / 1024, 2)));
|
||||||
|
|||||||
@ -7,9 +7,10 @@ struct renderer_startup_receipt;
|
|||||||
struct font_startup_receipt;
|
struct font_startup_receipt;
|
||||||
struct sprite_startup_receipt;
|
struct sprite_startup_receipt;
|
||||||
struct draw_startup_receipt;
|
struct draw_startup_receipt;
|
||||||
struct sim_startup_receipt;
|
|
||||||
struct asset_cache_startup_receipt;
|
struct asset_cache_startup_receipt;
|
||||||
|
struct sound_startup_receipt;
|
||||||
struct mixer_startup_receipt;
|
struct mixer_startup_receipt;
|
||||||
|
struct phys_startup_receipt;
|
||||||
struct host_startup_receipt;
|
struct host_startup_receipt;
|
||||||
|
|
||||||
enum user_bind_kind {
|
enum user_bind_kind {
|
||||||
@ -54,9 +55,10 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
struct font_startup_receipt *font_sr,
|
struct font_startup_receipt *font_sr,
|
||||||
struct sprite_startup_receipt *sprite_sr,
|
struct sprite_startup_receipt *sprite_sr,
|
||||||
struct draw_startup_receipt *draw_sr,
|
struct draw_startup_receipt *draw_sr,
|
||||||
struct sim_startup_receipt *sim_sr,
|
|
||||||
struct asset_cache_startup_receipt *asset_cache_sr,
|
struct asset_cache_startup_receipt *asset_cache_sr,
|
||||||
|
struct sound_startup_receipt *sound_sr,
|
||||||
struct mixer_startup_receipt *mixer_sr,
|
struct mixer_startup_receipt *mixer_sr,
|
||||||
|
struct phys_startup_receipt *phys_sr,
|
||||||
struct host_startup_receipt *host_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct sys_window *window);
|
struct sys_window *window);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user