sim ctx decoupling progress
This commit is contained in:
parent
f6aa25760e
commit
253104b2ce
@ -132,7 +132,7 @@ void app_entry_point(struct string args_str)
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
|
||||
#if !RTC
|
||||
/* Check that test modes aren't left on by accident in release mode */
|
||||
/* Verify test modes aren't left on by accident in release mode */
|
||||
CT_ASSERT(BITBUFF_DEBUG == 0);
|
||||
CT_ASSERT(BITBUFF_TEST == 0);
|
||||
#endif
|
||||
|
||||
@ -671,6 +671,9 @@ void bitbuff_test(void)
|
||||
{ kind_ibits, .ibits = { 4, 7 } },
|
||||
{ kind_ibits, .ibits = { 1, 7 } },
|
||||
{ kind_ibits, .ibits = { 3, 3 } },
|
||||
{ kind_ibits, .ibits = { 1, 2 } },
|
||||
{ kind_ibits, .ibits = { 0, 2 } },
|
||||
{ kind_ibits, .ibits = { -1, 2 } },
|
||||
|
||||
{ kind_uv, .uv = { 0 } },
|
||||
{ kind_uv, .uv = { 100 } },
|
||||
|
||||
@ -63,7 +63,7 @@
|
||||
|
||||
/* If enabled, bitbuffs will insert/verify magic numbers & length for each read & write */
|
||||
#define BITBUFF_DEBUG 0
|
||||
#define BITBUFF_TEST 0
|
||||
#define BITBUFF_TEST RTC
|
||||
|
||||
/* ========================== *
|
||||
* Settings
|
||||
|
||||
11
src/phys.c
11
src/phys.c
@ -985,7 +985,6 @@ void phys_integrate_velocities(struct phys_ctx *ctx, f32 dt)
|
||||
{
|
||||
__prof;
|
||||
struct sim_snapshot *ss = ctx->ss;
|
||||
struct space *space = ss->space;
|
||||
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
||||
struct sim_ent *ent = &ss->ents[sim_ent_index];
|
||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||
@ -993,11 +992,6 @@ void phys_integrate_velocities(struct phys_ctx *ctx, f32 dt)
|
||||
|
||||
struct xform xf = get_derived_xform(ent, dt);
|
||||
sim_ent_set_xform(ent, xf);
|
||||
|
||||
struct space_entry *space_entry = space_entry_from_handle(space, ent->space_handle);
|
||||
if (space_entry->valid) {
|
||||
space_entry_update_aabb(space_entry, collider_aabb_from_collider(&ent->local_collider, xf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1071,7 +1065,8 @@ void phys_update_aabbs(struct phys_ctx *ctx)
|
||||
space_entry = space_entry_alloc(space, ent->handle);
|
||||
ent->space_handle = space_entry->handle;
|
||||
}
|
||||
space_entry_update_aabb(space_entry, collider_aabb_from_collider(&ent->local_collider, xf));
|
||||
struct aabb aabb = collider_aabb_from_collider(&ent->local_collider, xf);
|
||||
space_entry_update_aabb(space_entry, aabb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1141,6 +1136,8 @@ void phys_step(struct phys_ctx *ctx, f32 timestep)
|
||||
/* Integrate */
|
||||
phys_integrate_velocities(ctx, substep_dt);
|
||||
|
||||
phys_update_aabbs(ctx);
|
||||
|
||||
/* Relaxation solve */
|
||||
#if SIM_PHYSICS_ENABLE_COLLISION && SIM_PHYSICS_ENABLE_RELAXATION
|
||||
phys_solve_contacts(ctx, substep_dt, false);
|
||||
|
||||
401
src/sim.c
401
src/sim.c
@ -208,11 +208,16 @@ INTERNAL struct sim_ent *spawn_test_player(struct sim_snapshot *world)
|
||||
e->linear_ground_friction = 250;
|
||||
e->angular_ground_friction = 200;
|
||||
|
||||
e->friction = 0;
|
||||
|
||||
//e->control_force = 500;
|
||||
e->control_force = 500;
|
||||
//e->control_force_max_speed = 4;
|
||||
e->control_torque = 5000;
|
||||
|
||||
e->control_force_max_speed = 4;
|
||||
e->control_torque = 5000;
|
||||
|
||||
//e->control_torque = F32_INFINITY;
|
||||
//e->control_force_max_speed = F32_INFINITY;
|
||||
|
||||
sim_ent_enable_prop(e, SIM_ENT_PROP_PHYSICAL_DYNAMIC);
|
||||
|
||||
@ -403,7 +408,8 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, wo
|
||||
* Update
|
||||
* ========================== */
|
||||
|
||||
void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_snapshot_store *snapshot_store, struct sim_snapshot *prev_snapshot, i64 real_dt_ns, struct sim_cmd_list user_sim_cmds)
|
||||
/* Simulates and generates a snapshot at tick `prev_snapshot` + 1 for duration `real_dt_ns`. */
|
||||
struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct sim_snapshot *prev_snapshot, struct sim_cmd_frame_list input_frames, i64 real_dt_ns)
|
||||
{
|
||||
__prof;
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
@ -428,6 +434,26 @@ void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_sna
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* TODO: Remove this */
|
||||
world->space = prev_snapshot->space;
|
||||
world->contact_lookup = prev_snapshot->contact_lookup;
|
||||
if (!world->space) {
|
||||
world->space = space_alloc(1, 256);
|
||||
}
|
||||
if (!world->contact_lookup.arena.base) {
|
||||
world->contact_lookup = sim_ent_lookup_alloc(4096);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
world->real_dt_ns = max_i64(0, real_dt_ns);
|
||||
world->real_time_ns += world->real_dt_ns;
|
||||
|
||||
@ -504,50 +530,33 @@ void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_sna
|
||||
* Create user client if it doesn't exist
|
||||
* ========================== */
|
||||
|
||||
(UNUSED)user_sim_cmds;
|
||||
|
||||
|
||||
/* ========================== *
|
||||
* Process host events into sim cmds
|
||||
* Sort incoming frames by client
|
||||
* ========================== */
|
||||
|
||||
struct sim_cmd_list *client_cmds;
|
||||
struct sim_cmd_frame **client_frames;
|
||||
{
|
||||
host_update(host);
|
||||
struct host_event_array host_events = host_pop_events(scratch.arena, host);
|
||||
|
||||
struct sim_cmd_list sim_cmds = ZI;
|
||||
sim_cmds_decode(scratch.arena, host_events, &sim_cmds);
|
||||
|
||||
/* Create connecting clients */
|
||||
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
|
||||
enum sim_cmd_kind kind = cmd->kind;
|
||||
struct host_channel_id channel_id = cmd->channel_id;
|
||||
for (struct sim_cmd_frame *frame = input_frames.first; frame; frame = frame->next) {
|
||||
struct host_channel_id channel_id = frame->channel;
|
||||
struct sim_client *client = sim_client_from_channel_id(world, channel_id);
|
||||
if (!client->valid && kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id)) {
|
||||
client = sim_client_alloc(world, channel_id);
|
||||
if (!client->valid) {
|
||||
for (struct sim_cmd *cmd = frame->first; cmd; cmd = cmd->next) {
|
||||
enum sim_cmd_kind kind = cmd->kind;
|
||||
if (kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id)) {
|
||||
client = sim_client_alloc(world, channel_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Split cmds by client */
|
||||
client_cmds = arena_push_array_zero(scratch.arena, struct sim_cmd_list, world->num_clients_reserved);
|
||||
{
|
||||
struct sim_cmd *cmd = sim_cmds.first;
|
||||
while (cmd) {
|
||||
struct sim_cmd *next = cmd->next;
|
||||
struct host_channel_id channel_id = cmd->channel_id;
|
||||
struct sim_client *client = sim_client_from_channel_id(world, channel_id);
|
||||
if (client->valid) {
|
||||
struct sim_cmd_list *cmd_list = &client_cmds[client->handle.idx];
|
||||
if (cmd_list->last) {
|
||||
cmd_list->last->next = cmd;
|
||||
} else {
|
||||
cmd_list->first = cmd;
|
||||
}
|
||||
cmd_list->last = cmd;
|
||||
cmd->next = NULL;
|
||||
}
|
||||
cmd = next;
|
||||
/* Sort cmd frames by client */
|
||||
client_frames = arena_push_array_zero(scratch.arena, struct sim_cmd_frame *, world->num_clients_reserved);
|
||||
for (struct sim_cmd_frame *frame = input_frames.first; frame; frame = frame->next) {
|
||||
struct sim_client *client = sim_client_from_channel_id(world, frame->channel);
|
||||
if (client->valid && frame->tick == world->tick) {
|
||||
client_frames[client->handle.idx] = frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -557,30 +566,27 @@ void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_sna
|
||||
* ========================== */
|
||||
|
||||
/* Process client cmds */
|
||||
u64 oldest_client_ack_tick = world->tick;
|
||||
u64 oldest_client_ack = world->tick;
|
||||
for (u64 i = 0; i < world->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &world->clients[i];
|
||||
if (client->valid) {
|
||||
struct host_channel_id channel_id = client->channel_id;
|
||||
struct sim_cmd_list cmds = client_cmds[client->handle.idx];
|
||||
struct sim_cmd_frame *frame = client_frames[client->handle.idx];
|
||||
if (client->valid && frame) {
|
||||
struct sim_control *control = &client->control;
|
||||
|
||||
client->dbg_drag_start = false;
|
||||
client->dbg_drag_stop = false;
|
||||
|
||||
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
||||
if (cmd->ack_tick > client->ack_tick) {
|
||||
client->ack_tick = cmd->ack_tick;
|
||||
}
|
||||
if (frame->ack > client->ack) {
|
||||
client->ack = frame->ack;
|
||||
}
|
||||
|
||||
for (struct sim_cmd *cmd = frame->first; cmd; cmd = cmd->next) {
|
||||
enum sim_cmd_kind kind = cmd->kind;
|
||||
b32 start = cmd->state == SIM_CMD_STATE_START;
|
||||
b32 stop = cmd->state == SIM_CMD_STATE_STOP;
|
||||
switch (kind) {
|
||||
/* TODO: Combine movement from multiple inputs? E.ctx-> a sudden
|
||||
* start and immediate stop cmd should still move the player a
|
||||
* tad. */
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
case SIM_CMD_KIND_CLIENT_CONTROL:
|
||||
{
|
||||
struct v2 move = cmd->move_dir;
|
||||
struct v2 focus = cmd->aim_dir;
|
||||
@ -590,34 +596,22 @@ void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_sna
|
||||
}
|
||||
control->move = move;
|
||||
control->focus = focus;
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_PLAYER_FIRE:
|
||||
{
|
||||
/* TODO: Allow sub-tick firing (start & stop on same tick should still fire for one tick */
|
||||
b32 firing = control->firing;
|
||||
if (start) {
|
||||
firing = true;
|
||||
}
|
||||
if (stop) {
|
||||
firing = false;
|
||||
}
|
||||
control->firing = firing;
|
||||
} break;
|
||||
|
||||
/* Cursor */
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
control->firing = cmd->is_firing;
|
||||
client->cursor_pos = cmd->cursor_pos;
|
||||
|
||||
if (cmd->is_firing) {
|
||||
DEBUGBREAKABLE;
|
||||
}
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_DRAG_OBJECT:
|
||||
case SIM_CMD_KIND_DRAG_OBJECT_START:
|
||||
{
|
||||
if (cmd->state == SIM_CMD_STATE_START) {
|
||||
client->dbg_drag_start = true;
|
||||
} else if (cmd->state == SIM_CMD_STATE_STOP) {
|
||||
client->dbg_drag_stop = true;
|
||||
}
|
||||
client->dbg_drag_start = true;
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_DRAG_OBJECT_STOP:
|
||||
{
|
||||
client->dbg_drag_stop = true;
|
||||
} break;
|
||||
|
||||
/* Clear level */
|
||||
@ -640,7 +634,6 @@ void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_sna
|
||||
/* Disconnect client */
|
||||
case SIM_CMD_KIND_SIM_CLIENT_DISCONNECT:
|
||||
{
|
||||
host_queue_disconnect(host, channel_id);
|
||||
sim_client_release(client);
|
||||
} break;
|
||||
|
||||
@ -648,8 +641,8 @@ void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_sna
|
||||
};
|
||||
}
|
||||
|
||||
if (client->ack_tick < oldest_client_ack_tick || oldest_client_ack_tick == 0) {
|
||||
oldest_client_ack_tick = client->ack_tick;
|
||||
if (client->ack < oldest_client_ack || oldest_client_ack == 0) {
|
||||
oldest_client_ack = client->ack;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1375,57 +1368,52 @@ void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_sna
|
||||
* Publish tick
|
||||
* ========================== */
|
||||
|
||||
#if 0
|
||||
struct sim_cmd_queue_list output_cmds = ZI;
|
||||
for (u64 i = 0; i < world->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &world->clients[i];
|
||||
if (client->valid) {
|
||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
u64 ss0_tick = client->ack_tick;
|
||||
u64 ss1_tick = world->tick;
|
||||
struct sim_snapshot *ss0 = sim_snapshot_from_tick(snapshot_store, ss0_tick);
|
||||
struct sim_snapshot *ss0 = sim_snapshot_from_tick(snapshot_store, client->ack);
|
||||
struct sim_snapshot *ss1 = world;
|
||||
ss0_tick = ss0->tick; /* In case ack tick is no longer in store we need to do a full resend */
|
||||
|
||||
struct sim_event_list l = ZI;
|
||||
struct sim_event snapshot_event = ZI;
|
||||
|
||||
/* Create & encode snapshot event */
|
||||
/* Create & encode snapshot cmd */
|
||||
{
|
||||
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT;
|
||||
snapshot_event.tick = world->tick;
|
||||
snapshot_event.snapshot_tick_start = ss0_tick;
|
||||
snapshot_event.snapshot_tick_end = ss1_tick;
|
||||
struct sim_cmd *cmd = arena_push(arena, struct sim_cmd);
|
||||
cmd->kind = SIM_CMD_KIND_SNAPSHOT;
|
||||
cmd->tick = world->tick;
|
||||
cmd->snapshot_tick_start = ss0->tick;
|
||||
cmd->snapshot_tick_end = ss1->tick;
|
||||
|
||||
{
|
||||
struct bitbuff_writer bw = bw_from_bitbuff(encoder_bitbuff);
|
||||
sim_snapshot_encode(&bw, ss0, ss1, client);
|
||||
snapshot_event.snapshot_encoded = bw_get_written(temp.arena, &bw);
|
||||
cmd->snapshot_encoded = bw_get_written(temp.arena, &bw);
|
||||
}
|
||||
|
||||
if (l.last) {
|
||||
l.last->next = &snapshot_event;
|
||||
if (output_cmds.last) {
|
||||
output_cmds.last->next = cmd;
|
||||
} else {
|
||||
l.first = &snapshot_event;
|
||||
output_cmds.first = cmd;
|
||||
}
|
||||
l.last = &snapshot_event;
|
||||
output_cmds.last = cmd;
|
||||
}
|
||||
|
||||
/* Encode events */
|
||||
struct string events_msg = ZI;
|
||||
/* Encode cmds */
|
||||
struct string cmds_msg = ZI;
|
||||
{
|
||||
struct bitbuff_writer bw = bw_from_bitbuff(encoder_bitbuff);
|
||||
sim_events_encode(&bw, l);
|
||||
events_msg = bw_get_written(temp.arena, &bw);
|
||||
sim_cmds_encode(&bw, output_cmds, 0);
|
||||
cmds_msg = bw_get_written(temp.arena, &bw);
|
||||
}
|
||||
|
||||
host_queue_write(host, client->channel_id, events_msg, 0);
|
||||
host_queue_write(host, client->channel_id, cmds_msg, 0);
|
||||
|
||||
arena_temp_end(temp);
|
||||
}
|
||||
}
|
||||
|
||||
host_update(host);
|
||||
__profframe("Sim");
|
||||
#endif
|
||||
|
||||
/* ========================== *
|
||||
* End frame cache scopes
|
||||
@ -1434,45 +1422,58 @@ void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_sna
|
||||
sprite_scope_end(sprite_frame_scope);
|
||||
|
||||
scratch_end(scratch);
|
||||
return world;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Sim cmd
|
||||
* Cmd frame
|
||||
* ========================== */
|
||||
|
||||
void sim_cmds_encode(struct bitbuff_writer *bw, struct sim_cmd_list cmds, u64 ack_tick)
|
||||
void sim_cmd_frames_encode(struct bitbuff_writer *bw, struct sim_cmd_frame_list frames, u64 ack_tick)
|
||||
{
|
||||
__prof;
|
||||
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
||||
bw_write_ibits(bw, cmd->kind, 8);
|
||||
bw_write_ibits(bw, cmd->state, 8);
|
||||
for (struct sim_cmd_frame *frame = frames.first; frame; frame = frame->next) {
|
||||
bw_write_uv(bw, frame->tick);
|
||||
bw_write_uv(bw, ack_tick);
|
||||
|
||||
for (struct sim_cmd *cmd = frame->first; cmd; cmd = cmd->next) {
|
||||
bw_write_bit(bw, 1);
|
||||
bw_write_ibits(bw, cmd->kind, 8);
|
||||
|
||||
#if COLLIDER_DEBUG
|
||||
bw_write_ubits(bw, cmd->collider_gjk_steps, 32);
|
||||
bw_write_ubits(bw, cmd->collider_gjk_steps, 32);
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
{
|
||||
bw_write_f32(bw, cmd->move_dir.x);
|
||||
bw_write_f32(bw, cmd->move_dir.y);
|
||||
bw_write_f32(bw, cmd->aim_dir.x);
|
||||
bw_write_f32(bw, cmd->aim_dir.y);
|
||||
} break;
|
||||
switch (cmd->kind) {
|
||||
case SIM_CMD_KIND_CLIENT_CONTROL:
|
||||
{
|
||||
bw_write_f32(bw, cmd->move_dir.x);
|
||||
bw_write_f32(bw, cmd->move_dir.y);
|
||||
bw_write_f32(bw, cmd->aim_dir.x);
|
||||
bw_write_f32(bw, cmd->aim_dir.y);
|
||||
bw_write_f32(bw, cmd->cursor_pos.x);
|
||||
bw_write_f32(bw, cmd->cursor_pos.y);
|
||||
bw_write_bit(bw, cmd->is_firing);
|
||||
#if COLLIDER_DEBUG
|
||||
cmd->collider_gjk_steps = br_read_ubits(&br, 32);
|
||||
#endif
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
bw_write_f32(bw, cmd->cursor_pos.x);
|
||||
bw_write_f32(bw, cmd->cursor_pos.y);
|
||||
} break;
|
||||
case SIM_CMD_KIND_SNAPSHOT:
|
||||
{
|
||||
bw_write_uv(bw, cmd->snapshot_tick_start);
|
||||
bw_write_uv(bw, cmd->snapshot_tick_end);
|
||||
bw_write_string(bw, cmd->snapshot_encoded);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
bw_write_bit(bw, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void sim_cmds_decode(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
|
||||
void sim_cmd_frames_decode(struct arena *arena, struct host_event_array host_events, struct sim_cmd_frame_list *frames_out)
|
||||
{
|
||||
__prof;
|
||||
for (u64 i = 0; i < host_events.count; ++i) {
|
||||
@ -1481,148 +1482,100 @@ void sim_cmds_decode(struct arena *arena, struct host_event_array host_events, s
|
||||
switch (host_event_kind) {
|
||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||
{
|
||||
/* Create a stand-alone cmd frame for connecting */
|
||||
struct sim_cmd_frame *frame = arena_push_zero(arena, struct sim_cmd_frame);
|
||||
frame->channel = host_event.channel_id;
|
||||
|
||||
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;
|
||||
|
||||
frame->first = cmd;
|
||||
frame->last = cmd;
|
||||
|
||||
if (frames_out->last) {
|
||||
frames_out->last->next = frame;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
frames_out->first = frame;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
frames_out->last = frame;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||
{
|
||||
/* Create a stand-alone cmd frame for disconnecting */
|
||||
struct sim_cmd_frame *frame = arena_push_zero(arena, struct sim_cmd_frame);
|
||||
frame->channel = host_event.channel_id;
|
||||
|
||||
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;
|
||||
|
||||
frame->first = cmd;
|
||||
frame->last = cmd;
|
||||
|
||||
if (frames_out->last) {
|
||||
frames_out->last->next = frame;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
frames_out->first = frame;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
frames_out->last = frame;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_MSG:
|
||||
{
|
||||
struct bitbuff bb = bitbuff_from_string(host_event.msg);
|
||||
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
||||
while (br_num_bits_left(&br) > 0) {
|
||||
|
||||
struct sim_cmd_frame *frame = arena_push_zero(arena, struct sim_cmd_frame);
|
||||
frame->channel = host_event.channel_id;
|
||||
frame->tick = br_read_uv(&br);
|
||||
frame->ack = br_read_uv(&br);
|
||||
|
||||
while (br_read_bit(&br)) {
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
cmd->kind = br_read_ibits(&br, 8);
|
||||
cmd->channel_id = host_event.channel_id;
|
||||
cmd->state = br_read_ibits(&br, 8);
|
||||
cmd->ack_tick = br_read_uv(&br);
|
||||
#if COLLIDER_DEBUG
|
||||
cmd->collider_gjk_steps = br_read_ubits(&br, 32);
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
case SIM_CMD_KIND_CLIENT_CONTROL:
|
||||
{
|
||||
cmd->move_dir.x = br_read_f32(&br);
|
||||
cmd->move_dir.y = br_read_f32(&br);
|
||||
cmd->aim_dir.x = br_read_f32(&br);
|
||||
cmd->aim_dir.y = br_read_f32(&br);
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
cmd->cursor_pos.x = br_read_f32(&br);
|
||||
cmd->cursor_pos.y = br_read_f32(&br);
|
||||
cmd->is_firing = br_read_bit(&br);
|
||||
#if COLLIDER_DEBUG
|
||||
cmd->collider_gjk_steps = br_read_ubits(&br, 32);
|
||||
#endif
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Sim event
|
||||
* ========================== */
|
||||
|
||||
void sim_events_encode(struct bitbuff_writer *bw, struct sim_event_list events)
|
||||
{
|
||||
__prof;
|
||||
for (struct sim_event *event = events.first; event; event = event->next) {
|
||||
bw_write_uv(bw, event->tick);
|
||||
bw_write_ibits(bw, event->kind, 8);
|
||||
|
||||
switch (event->kind) {
|
||||
case SIM_EVENT_KIND_SNAPSHOT:
|
||||
{
|
||||
bw_write_uv(bw, event->snapshot_tick_start);
|
||||
bw_write_uv(bw, event->snapshot_tick_end);
|
||||
bw_write_string(bw, event->snapshot_encoded);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sim_events_decode(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 bitbuff bb = bitbuff_from_string(host_event.msg);
|
||||
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
||||
while (br_num_bits_left(&br) > 0) {
|
||||
sim_event->tick = br_read_uv(&br);
|
||||
sim_event->kind = br_read_ibits(&br, 8);
|
||||
switch (sim_event->kind) {
|
||||
case SIM_EVENT_KIND_SNAPSHOT:
|
||||
case SIM_CMD_KIND_SNAPSHOT:
|
||||
{
|
||||
sim_event->snapshot_tick_start = br_read_uv(&br);
|
||||
sim_event->snapshot_tick_end = br_read_uv(&br);
|
||||
sim_event->snapshot_encoded = br_read_string(arena, &br);
|
||||
cmd->snapshot_tick_start = br_read_uv(&br);
|
||||
cmd->snapshot_tick_end = br_read_uv(&br);
|
||||
cmd->snapshot_encoded = br_read_string(arena, &br);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (frame->last) {
|
||||
frame->last->next = cmd;
|
||||
} else {
|
||||
frame->first = cmd;
|
||||
}
|
||||
frame->last = cmd;
|
||||
}
|
||||
|
||||
if (frames_out->last) {
|
||||
frames_out->last->next = frame;
|
||||
} else {
|
||||
frames_out->first = frame;
|
||||
}
|
||||
frames_out->last = frame;
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (events_out->last) {
|
||||
events_out->last->next = sim_event;
|
||||
} else {
|
||||
events_out->first = sim_event;
|
||||
}
|
||||
events_out->last = sim_event;
|
||||
}
|
||||
}
|
||||
|
||||
120
src/sim.h
120
src/sim.h
@ -23,8 +23,7 @@ enum sim_cmd_state {
|
||||
enum sim_cmd_kind {
|
||||
SIM_CMD_KIND_NONE,
|
||||
|
||||
SIM_CMD_KIND_PLAYER_CONTROL,
|
||||
SIM_CMD_KIND_PLAYER_FIRE,
|
||||
SIM_CMD_KIND_CLIENT_CONTROL,
|
||||
|
||||
SIM_CMD_KIND_SIM_CLIENT_CONNECT,
|
||||
SIM_CMD_KIND_SIM_CLIENT_DISCONNECT,
|
||||
@ -34,74 +33,88 @@ enum sim_cmd_kind {
|
||||
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_DRAG_OBJECT_START,
|
||||
SIM_CMD_KIND_DRAG_OBJECT_STOP,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SIM_CMD_KIND_CONNECT,
|
||||
SIM_CMD_KIND_DISCONNECT,
|
||||
SIM_CMD_KIND_SNAPSHOT,
|
||||
|
||||
//SIM_CMD_KIND_ENTITY_UPDATE,
|
||||
//SIM_CMD_KIND_ENTITY_CREATE,
|
||||
//SIM_CMD_KIND_ENTITY_DESTROY
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SIM_CMD_KIND_COUNT
|
||||
};
|
||||
|
||||
struct sim_cmd {
|
||||
enum sim_cmd_kind kind;
|
||||
enum sim_cmd_state state;
|
||||
struct host_channel_id channel_id;
|
||||
u64 ack_tick;
|
||||
struct sim_cmd *next;
|
||||
|
||||
/* Cmd metadata */
|
||||
enum sim_cmd_kind kind;
|
||||
u64 tick;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* SIM_CMD_KIND_CLIENT_CONTROL */
|
||||
|
||||
/* SIM_CMD_KIND_PLAYER_CONTROL */
|
||||
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;
|
||||
b32 is_firing;
|
||||
|
||||
#if RTC
|
||||
u32 collider_gjk_steps;
|
||||
#endif
|
||||
|
||||
struct sim_cmd *next;
|
||||
};
|
||||
|
||||
struct sim_cmd_list {
|
||||
struct sim_cmd *first;
|
||||
struct sim_cmd *last;
|
||||
};
|
||||
|
||||
/* ========================== *
|
||||
* Event
|
||||
* ========================== */
|
||||
|
||||
enum sim_event_kind {
|
||||
SIM_EVENT_KIND_NONE,
|
||||
|
||||
SIM_EVENT_KIND_CONNECT,
|
||||
SIM_EVENT_KIND_DISCONNECT,
|
||||
SIM_EVENT_KIND_SNAPSHOT,
|
||||
|
||||
//SIM_EVENT_KIND_ENTITY_UPDATE,
|
||||
//SIM_EVENT_KIND_ENTITY_CREATE,
|
||||
//SIM_EVENT_KIND_ENTITY_DESTROY
|
||||
};
|
||||
|
||||
struct sim_event {
|
||||
u64 tick;
|
||||
enum sim_event_kind kind;
|
||||
struct host_channel_id channel_id;
|
||||
/* ====================================================================== */
|
||||
/* SIM_CMD_KIND_CLIENT_DISCONNECT */
|
||||
|
||||
struct string disconnect_reason;
|
||||
|
||||
/* SIM_EVENT_KIND_SNAPSHOT */
|
||||
/* =========================================================== */
|
||||
/* SIM_CMD_KIND_SNAPSHOT */
|
||||
|
||||
u64 snapshot_tick_start;
|
||||
u64 snapshot_tick_end;
|
||||
struct string snapshot_encoded; /* Delta encoded snapshot containing changes between start & end ticks */
|
||||
|
||||
struct sim_event *next;
|
||||
/* Delta encoded snapshot containing changes between start & end ticks */
|
||||
struct string snapshot_encoded;
|
||||
};
|
||||
|
||||
struct sim_event_list {
|
||||
struct sim_event *first;
|
||||
struct sim_event *last;
|
||||
/* Represents all cmds generated by a user/sim for a particular channel in a single tick. */
|
||||
struct sim_cmd_frame {
|
||||
struct host_channel_id channel; /* Sender's channel id (if this cmd frame was received by a host) */
|
||||
u64 tick; /* Sender's tick (this will always be 0 for user -> local sim cmds) */
|
||||
u64 ack; /* Sender's last received cmd frame tick from dst channel */
|
||||
|
||||
struct sim_cmd *first;
|
||||
struct sim_cmd *last;
|
||||
|
||||
struct sim_cmd_frame *next;
|
||||
};
|
||||
|
||||
struct sim_cmd_frame_list {
|
||||
struct sim_cmd_frame *first;
|
||||
struct sim_cmd_frame *last;
|
||||
};
|
||||
|
||||
/* ========================== *
|
||||
@ -168,21 +181,18 @@ void sim_ctx_release(struct sim_ctx *ctx);
|
||||
struct host;
|
||||
struct bitbuff;
|
||||
struct sim_snapshot;
|
||||
void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_snapshot_store *snapshot_store, struct sim_snapshot *prev_snapshot, i64 real_dt_ns, struct sim_cmd_list user_sim_cmds);
|
||||
struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct sim_snapshot *prev_snapshot, struct sim_cmd_frame_list input_frames, i64 real_dt_ns);
|
||||
|
||||
/* ========================== *
|
||||
* Event & cmd encode/decode
|
||||
* Cmd frame encode / decode
|
||||
* ========================== */
|
||||
|
||||
/* TODO: Move this */
|
||||
|
||||
#include "host.h"
|
||||
|
||||
void sim_cmds_encode(struct bitbuff_writer *bw, struct sim_cmd_list cmds, u64 ack_tick);
|
||||
void sim_cmds_decode(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
|
||||
|
||||
void sim_events_encode(struct bitbuff_writer *bw, struct sim_event_list events);
|
||||
void sim_events_decode(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
|
||||
void sim_cmd_frames_encode(struct bitbuff_writer *bw, struct sim_cmd_frame_list frames, u64 ack_tick);
|
||||
void sim_cmd_frames_decode(struct arena *arena, struct host_event_array host_events, struct sim_cmd_frame_list *frames_out);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ struct sim_client {
|
||||
struct sim_client_handle prev_in_bucket;
|
||||
|
||||
/* This is the last tick we know that this client has received */
|
||||
u64 ack_tick;
|
||||
u64 ack;
|
||||
|
||||
struct v2 cursor_pos;
|
||||
struct sim_ent_handle camera_ent;
|
||||
|
||||
@ -50,19 +50,6 @@ struct sim_snapshot {
|
||||
/* FIXME: Remove this */
|
||||
struct space *space;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* FIXME: Encode / decode*/
|
||||
|
||||
u64 phys_iteration;
|
||||
|
||||
/* This is the oldest tick stored in ctx that we need to hold a reference to for delta encoding */
|
||||
u64 oldest_client_ack_tick;
|
||||
|
||||
/* Bookkeeping structures */
|
||||
/* TODO: Store in snapshot for determinism */
|
||||
struct sim_ent_lookup contact_lookup;
|
||||
@ -79,6 +66,19 @@ struct sim_snapshot {
|
||||
|
||||
|
||||
|
||||
/* FIXME: Encode / decode */
|
||||
|
||||
u64 phys_iteration;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
286
src/user.c
286
src/user.c
@ -215,7 +215,13 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
||||
G.connect_address_str = string_copy(&G.arena, connect_address_str);
|
||||
}
|
||||
#else
|
||||
(UNUSED)connect_address_str;
|
||||
connect_address_str = STRING(0, 0);
|
||||
if (connect_address_str.len == 0) {
|
||||
G.connect_address_str = LIT("127.0.0.1:12345");
|
||||
G.local_sim_thread = sys_thread_alloc(&user_local_sim_thread_entry_point, G.local_sim_ctx, LIT("[P8] Local sim thread"));
|
||||
} else {
|
||||
G.connect_address_str = string_copy(&G.arena, connect_address_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
G.debug_draw = true;
|
||||
@ -368,16 +374,16 @@ INTERNAL SORT_COMPARE_FUNC_DEF(ent_draw_order_cmp, arg_a, arg_b, udata)
|
||||
|
||||
|
||||
|
||||
INTERNAL void queue_sim_cmd(struct arena *arena, struct sim_cmd_list *list, struct sim_cmd src)
|
||||
INTERNAL void queue_sim_cmd(struct arena *arena, struct sim_cmd_frame *frame, struct sim_cmd src)
|
||||
{
|
||||
struct sim_cmd *cmd = arena_push(arena, struct sim_cmd);
|
||||
*cmd = src;
|
||||
if (list->last) {
|
||||
list->last->next = cmd;
|
||||
if (frame->last) {
|
||||
frame->last->next = cmd;
|
||||
} else {
|
||||
list->first = cmd;
|
||||
frame->first = cmd;
|
||||
}
|
||||
list->last = cmd;
|
||||
frame->last = cmd;
|
||||
}
|
||||
|
||||
|
||||
@ -413,21 +419,29 @@ INTERNAL void user_update(void)
|
||||
G.screen_size = sys_window_get_size(G.window);
|
||||
|
||||
struct sprite_scope *sprite_frame_scope = sprite_scope_begin();
|
||||
struct sim_cmd_list cmd_list = ZI;
|
||||
struct sim_cmd_frame cmd_frame = ZI;
|
||||
|
||||
/* ========================== *
|
||||
* Process host events into sim events
|
||||
* Process host events into sim cmds
|
||||
* ========================== */
|
||||
|
||||
struct sim_event_list sim_events = ZI;
|
||||
struct sim_cmd_frame incoming_cmd_frame = ZI;
|
||||
{
|
||||
host_update(G.host);
|
||||
struct host_event_array host_events = host_pop_events(scratch.arena, G.host);
|
||||
sim_events_decode(scratch.arena, host_events, &sim_events);
|
||||
|
||||
struct sim_cmd_frame_list l = ZI;
|
||||
sim_cmd_frames_decode(scratch.arena, host_events, &l);
|
||||
for (struct sim_cmd_frame *frame = l.first; frame; frame = frame->next) {
|
||||
if (frame->tick == 0 || frame->tick > incoming_cmd_frame.tick) {
|
||||
incoming_cmd_frame = *frame;
|
||||
incoming_cmd_frame.next = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Process sim events
|
||||
* Process sim cmd frame
|
||||
* ========================== */
|
||||
|
||||
{
|
||||
@ -439,27 +453,26 @@ INTERNAL void user_update(void)
|
||||
last_try_connect = now;
|
||||
}
|
||||
|
||||
for (struct sim_event *event = sim_events.first; event; event = event->next) {
|
||||
u64 event_tick = event->tick;
|
||||
enum sim_event_kind kind = event->kind;
|
||||
for (struct sim_cmd *cmd = incoming_cmd_frame.first; cmd; cmd = cmd->next) {
|
||||
enum sim_cmd_kind kind = cmd->kind;
|
||||
|
||||
switch (kind) {
|
||||
case SIM_EVENT_KIND_CONNECT:
|
||||
case SIM_CMD_KIND_CONNECT:
|
||||
{
|
||||
last_try_connect = F64_INFINITY;
|
||||
} break;
|
||||
|
||||
case SIM_EVENT_KIND_DISCONNECT:
|
||||
case SIM_CMD_KIND_DISCONNECT:
|
||||
{
|
||||
last_try_connect = 0;
|
||||
} break;
|
||||
|
||||
case SIM_EVENT_KIND_SNAPSHOT:
|
||||
case SIM_CMD_KIND_SNAPSHOT:
|
||||
{
|
||||
/* TODO: Only read newest tick event */
|
||||
if (event_tick > G.world->tick) {
|
||||
u64 ss0_tick = event->snapshot_tick_start;
|
||||
u64 ss1_tick = event->snapshot_tick_end;
|
||||
/* TODO: Only read newest tick cmd */
|
||||
if (cmd->snapshot_tick_end > G.world->tick) {
|
||||
u64 ss0_tick = cmd->snapshot_tick_start;
|
||||
u64 ss1_tick = cmd->snapshot_tick_end;
|
||||
struct sim_snapshot *ss0 = sim_snapshot_from_tick(G.sim_snapshot_store, ss0_tick);
|
||||
struct sim_snapshot *ss1 = sim_snapshot_from_tick(G.sim_snapshot_store, ss1_tick);
|
||||
if (ss0->tick == ss0_tick) {
|
||||
@ -467,7 +480,7 @@ INTERNAL void user_update(void)
|
||||
ss1 = sim_snapshot_alloc(G.sim_snapshot_store, ss0, ss1_tick);
|
||||
ss1->received_at_ns = G.real_time_ns;
|
||||
|
||||
struct bitbuff bb = bitbuff_from_string(event->snapshot_encoded);
|
||||
struct bitbuff bb = bitbuff_from_string(cmd->snapshot_encoded);
|
||||
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
||||
sim_snapshot_decode(&br, ss1);
|
||||
}
|
||||
@ -492,10 +505,10 @@ INTERNAL void user_update(void)
|
||||
G.local_sim_last_known_time_ns = newest_snapshot->real_time_ns;
|
||||
G.local_sim_last_known_tick = newest_snapshot->tick;
|
||||
|
||||
/* This is the ack tick that we know the sim has received our ack of.
|
||||
/* This is the the tick that we know the sim has received our ack of.
|
||||
* Therefore we must keep it around or else risk the server sending us
|
||||
* a snapshot delta for a snapshot we've released. */
|
||||
u64 oldest_possible_delta_base_tick = sim_client_from_handle(newest_snapshot, newest_snapshot->local_client)->ack_tick;
|
||||
u64 oldest_possible_delta_base_tick = sim_client_from_handle(newest_snapshot, newest_snapshot->local_client)->ack;
|
||||
|
||||
/* Predict local sim time based on last received snapshot time,
|
||||
* then smooth it out to prevent sudden jumps in rendering due
|
||||
@ -1424,36 +1437,23 @@ INTERNAL void user_update(void)
|
||||
}
|
||||
struct v2 input_aim_dir = v2_sub(G.world_cursor, sim_ent_get_xform(local_player).og);
|
||||
|
||||
/* Queue cursor move cmd */
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_CURSOR_MOVE,
|
||||
.cursor_pos = G.world_cursor
|
||||
});
|
||||
|
||||
/* Queue player input cmd */
|
||||
/* Queue player control cmd */
|
||||
if (!G.debug_camera) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_PLAYER_CONTROL,
|
||||
i32 fire_presses = G.bind_states[USER_BIND_KIND_FIRE].num_presses - G.bind_states[USER_BIND_KIND_FIRE].num_releases;
|
||||
queue_sim_cmd(scratch.arena, &cmd_frame, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_CLIENT_CONTROL,
|
||||
.move_dir = input_move_dir,
|
||||
.aim_dir = input_aim_dir
|
||||
});
|
||||
}
|
||||
|
||||
/* Queue player fire cmd */
|
||||
i32 fire_presses = G.bind_states[USER_BIND_KIND_FIRE].num_presses - G.bind_states[USER_BIND_KIND_FIRE].num_releases;
|
||||
if (!G.debug_camera && fire_presses) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_PLAYER_FIRE,
|
||||
.state = fire_presses > 0 ? SIM_CMD_STATE_START : SIM_CMD_STATE_STOP
|
||||
.aim_dir = input_aim_dir,
|
||||
.cursor_pos = G.world_cursor,
|
||||
.is_firing = fire_presses > 0
|
||||
});
|
||||
}
|
||||
|
||||
/* Queue physics drag cmd */
|
||||
i32 drag_presses = G.bind_states[USER_BIND_KIND_DEBUG_DRAG].num_presses - G.bind_states[USER_BIND_KIND_DEBUG_DRAG].num_releases;
|
||||
if (drag_presses) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_DRAG_OBJECT,
|
||||
.state = drag_presses > 0 ? SIM_CMD_STATE_START : SIM_CMD_STATE_STOP
|
||||
if (drag_presses != 0) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_frame, (struct sim_cmd) {
|
||||
.kind = drag_presses > 0 ? SIM_CMD_KIND_DRAG_OBJECT_START : SIM_CMD_KIND_DRAG_OBJECT_STOP,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1478,7 +1478,7 @@ INTERNAL void user_update(void)
|
||||
{
|
||||
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_CLEAR];
|
||||
if (state.num_presses) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_frame, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_CLEAR_ALL
|
||||
});
|
||||
}
|
||||
@ -1488,7 +1488,7 @@ INTERNAL void user_update(void)
|
||||
{
|
||||
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_PAUSE];
|
||||
if (state.num_presses) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_frame, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_PAUSE
|
||||
});
|
||||
}
|
||||
@ -1498,7 +1498,7 @@ INTERNAL void user_update(void)
|
||||
{
|
||||
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_STEP];
|
||||
for (u32 i = 0; i < state.num_presses_and_repeats; ++i) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_frame, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_STEP
|
||||
});
|
||||
}
|
||||
@ -1508,7 +1508,7 @@ INTERNAL void user_update(void)
|
||||
{
|
||||
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_SPAWN];
|
||||
if (state.num_presses) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
queue_sim_cmd(scratch.arena, &cmd_frame, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_SPAWN_TEST
|
||||
});
|
||||
}
|
||||
@ -1628,8 +1628,12 @@ INTERNAL void user_update(void)
|
||||
|
||||
/* Publish sim cmds */
|
||||
{
|
||||
struct sim_cmd_frame_list l = ZI;
|
||||
l.first = &cmd_frame;
|
||||
l.last = &cmd_frame;
|
||||
|
||||
struct bitbuff_writer bw = bw_from_bitbuff(&G.encoder_bitbuff);
|
||||
sim_cmds_encode(&bw, cmd_list, G.local_sim_last_known_tick);
|
||||
sim_cmd_frames_encode(&bw, l, G.local_sim_last_known_tick);
|
||||
struct string cmds_str = bw_get_written(scratch.arena, &bw);
|
||||
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, cmds_str, 0);
|
||||
}
|
||||
@ -1778,56 +1782,186 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_thread_entry_point, arg)
|
||||
|
||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
|
||||
{
|
||||
|
||||
#if 0
|
||||
struct host_listen_address local_listen_addr = host_listen_address_from_local_name(LIT("LOCAL_SIM"));
|
||||
struct host_listen_address net_listen_addr = host_listen_address_from_net_port(12345);
|
||||
//struct host *host = host_alloc();
|
||||
/* TODO: Host system should allocate & copy string stored in local_listen_addr */
|
||||
//host_listen(host, local_listen_addr);
|
||||
//host_listen(host, net_listen_addr);
|
||||
#else
|
||||
struct host *host = host_alloc(12345);
|
||||
#endif
|
||||
|
||||
struct bitbuff encoder_bitbuff = bitbuff_alloc(GIGABYTE(64));
|
||||
struct sim_snapshot_store *ss_store = sim_snapshot_store_alloc();
|
||||
struct sim_snapshot_store *snapshot_store = sim_snapshot_store_alloc();
|
||||
|
||||
|
||||
|
||||
(UNUSED)arg;
|
||||
|
||||
|
||||
struct sim_ctx *ctx = (struct sim_ctx *)arg;
|
||||
|
||||
#if 1
|
||||
|
||||
struct sim_snapshot *prev_ss = sim_snapshot_nil();
|
||||
|
||||
i64 last_tick_ns = 0;
|
||||
i64 target_dt_ns = NS_FROM_SECONDS(1) / SIM_TICKS_PER_SECOND;;
|
||||
while (!atomic_i32_eval(&G.local_sim_thread_shutdown)) {
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
{
|
||||
__profscope(local_sim_sleep);
|
||||
sleep_frame(last_tick_ns, target_dt_ns);
|
||||
last_tick_ns = sys_time_ns();
|
||||
}
|
||||
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
/* Copy user sim cmds */
|
||||
struct sim_cmd_list user_sim_cmds = ZI;
|
||||
|
||||
|
||||
/* TODO: Remove this */
|
||||
{
|
||||
struct sys_lock lock = sys_mutex_lock_s(&G.user_sim_cmds_arena);
|
||||
for (struct sim_cmd *cmd = G.user_sim_cmds.first; cmd; cmd = cmd->next) {
|
||||
struct sim_cmd *dst = arena_push(scratch.arena, struct sim_cmd);
|
||||
*dst = *cmd;
|
||||
dst->next = NULL;
|
||||
if (user_sim_cmds.last) {
|
||||
user_sim_cmds.last->next = dst;
|
||||
u64 keep_count = 40;
|
||||
u64 keep_tick = prev_ss->tick > keep_count ? prev_ss->tick - keep_count : 0;
|
||||
|
||||
struct sim_snapshot *remss = sim_snapshot_from_tick(snapshot_store, snapshot_store->first_tick);
|
||||
while (remss->valid) {
|
||||
u64 next_tick = remss->next_tick;
|
||||
if (remss->tick < keep_tick) {
|
||||
sim_snapshot_release(remss);
|
||||
} else {
|
||||
user_sim_cmds.first = dst;
|
||||
break;
|
||||
}
|
||||
user_sim_cmds.last = dst;
|
||||
remss = sim_snapshot_from_tick(snapshot_store, next_tick);
|
||||
}
|
||||
sys_mutex_unlock(&lock);
|
||||
}
|
||||
sim_step(host, &encoder_bitbuff, snapshot_store, snapshot, target_dt_ns, user_sim_cmds);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct sim_cmd_frame_list input_frames = ZI;
|
||||
{
|
||||
host_update(host);
|
||||
struct host_event_array host_events = host_pop_events(scratch.arena, host);
|
||||
sim_cmd_frames_decode(scratch.arena, host_events, &input_frames);
|
||||
}
|
||||
|
||||
/* Automatically set all user cmd frames to current local sim tick */
|
||||
/* FIXME: Only do this for local user cmds */
|
||||
{
|
||||
for (struct sim_cmd_frame *frame = input_frames.first; frame; frame = frame->next) {
|
||||
frame->tick = prev_ss->tick + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step */
|
||||
struct sim_snapshot *ss = sim_step(snapshot_store, prev_ss, input_frames, target_dt_ns);
|
||||
|
||||
/* Publish snapshot cmds */
|
||||
u64 oldest_ack_tick = 0;
|
||||
for (u64 i = 0; i < ss->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &ss->clients[i];
|
||||
if (client->valid) {
|
||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
if (oldest_ack_tick == 0 || client->ack < oldest_ack_tick) {
|
||||
oldest_ack_tick = client->ack;
|
||||
}
|
||||
|
||||
struct sim_snapshot *ss0 = sim_snapshot_from_tick(snapshot_store, client->ack);
|
||||
struct sim_snapshot *ss1 = ss;
|
||||
|
||||
/* Create & encode snapshot cmd */
|
||||
struct sim_cmd snapshot_cmd = ZI;
|
||||
{
|
||||
snapshot_cmd.kind = SIM_CMD_KIND_SNAPSHOT;
|
||||
snapshot_cmd.tick = ss->tick;
|
||||
snapshot_cmd.snapshot_tick_start = ss0->tick;
|
||||
snapshot_cmd.snapshot_tick_end = ss1->tick;
|
||||
{
|
||||
struct bitbuff_writer bw = bw_from_bitbuff(&encoder_bitbuff);
|
||||
sim_snapshot_encode(&bw, ss0, ss1, client);
|
||||
snapshot_cmd.snapshot_encoded = bw_get_written(temp.arena, &bw);
|
||||
}
|
||||
}
|
||||
|
||||
struct sim_cmd_frame snapshot_cmd_frame = ZI;
|
||||
snapshot_cmd_frame.first = &snapshot_cmd;
|
||||
snapshot_cmd_frame.last = &snapshot_cmd;
|
||||
|
||||
struct sim_cmd_frame_list cmd_frames = ZI;
|
||||
cmd_frames.first = &snapshot_cmd_frame;
|
||||
cmd_frames.last = &snapshot_cmd_frame;
|
||||
|
||||
/* Encode cmds */
|
||||
struct string cmds_msg = ZI;
|
||||
{
|
||||
struct bitbuff_writer bw = bw_from_bitbuff(&encoder_bitbuff);
|
||||
/* FIXME: Ack tick */
|
||||
sim_cmd_frames_encode(&bw, cmd_frames, 0);
|
||||
cmds_msg = bw_get_written(temp.arena, &bw);
|
||||
}
|
||||
|
||||
host_queue_write(host, client->channel_id, cmds_msg, 0);
|
||||
|
||||
arena_temp_end(temp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send host messages */
|
||||
host_update(host);
|
||||
__profframe("Local sim");
|
||||
|
||||
scratch_end(scratch);
|
||||
|
||||
prev_ss = ss;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
i64 last_tick_ns = 0;
|
||||
i64 target_dt_ns = NS_FROM_SECONDS(1) / SIM_TICKS_PER_SECOND;;
|
||||
while (!atomic_i32_eval(&G.local_sim_thread_shutdown)) {
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
{
|
||||
__profscope(local_sim_sleep);
|
||||
sleep_frame(last_tick_ns, target_dt_ns);
|
||||
last_tick_ns = sys_time_ns();
|
||||
}
|
||||
|
||||
struct sim_cmd_frame user_frame = ZI;
|
||||
user_frame.tick = prev_ss->tick + 1;
|
||||
user_frame.ack = prev_ss->tick;
|
||||
|
||||
/* Read cmds from host */
|
||||
host_update(host);
|
||||
struct host_event_array host_events = host_pop_events(scratch.arena, host);
|
||||
sim_cmds_decode(scratch.arena, host_events, &sim_cmds);
|
||||
|
||||
/* Step */
|
||||
struct sim_snapshot *ss = sim_step(ss_store, prev_ss, user_cmds, target_dt_ns);
|
||||
|
||||
/* Encode & enqueue sim_cmd frames */
|
||||
for (struct sim_cmd_frame *f = output_cmds.first; f; f = f->next) {
|
||||
struct host_channel_id channel_id = f->dst_channel;
|
||||
struct string cmd_frame_msg = ZI;
|
||||
struct bitbuff_writer bw = bw_from_bitbuff(&encoder_bitbuff);
|
||||
sim_cmd_frame_encode(&bw, q);
|
||||
cmd_frame_msg = bw_get_written(temp.arena, &bw);
|
||||
host_queue_write(host, channel_id, cmd_frame_msg, 0);
|
||||
}
|
||||
|
||||
/* Send host messages */
|
||||
//host_update(host);
|
||||
__profframe("Local sim");
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
sim_snapshot_store_release(ss_store);
|
||||
|
||||
sim_snapshot_store_release(snapshot_store);
|
||||
bitbuff_release(&encoder_bitbuff);
|
||||
host_release(host);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user