prediction progress
This commit is contained in:
parent
b8119c9ef9
commit
044fc1db9d
167
src/sim.c
167
src/sim.c
@ -372,8 +372,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, wo
|
||||
* Update
|
||||
* ========================== */
|
||||
|
||||
/* 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)
|
||||
void sim_step(struct sim_snapshot *world, struct sim_snapshot_list cmd_snapshots, i64 real_dt_ns)
|
||||
{
|
||||
__prof;
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
@ -382,8 +381,6 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
||||
* Begin frame
|
||||
* ========================== */
|
||||
|
||||
struct sim_snapshot *world = sim_snapshot_alloc(snapshot_store, prev_snapshot, prev_snapshot->tick + 1);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -422,19 +419,6 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
||||
//sys_sleep_precise(rng_rand_f32(0, 0.050));
|
||||
//sys_sleep_precise(0.050);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
world->phys_iteration = prev_snapshot->phys_iteration;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
world->real_dt_ns = max_i64(0, real_dt_ns);
|
||||
world->real_time_ns += world->real_dt_ns;
|
||||
|
||||
@ -455,6 +439,7 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
||||
|
||||
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE);
|
||||
|
||||
if (world->is_master) {
|
||||
/* ========================== *
|
||||
* Spawn test entities
|
||||
* ========================== */
|
||||
@ -508,85 +493,41 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Create user client if it doesn't exist
|
||||
* Create / update client ents
|
||||
* ========================== */
|
||||
|
||||
for (struct sim_snapshot_list_node *n = cmd_snapshots.first; n; n = n->next) {
|
||||
struct sim_snapshot *cmd_snapshot = n->ss;
|
||||
struct sim_client_handle client_handle = cmd_snapshot->producer_client;
|
||||
struct sim_ent *client_ent = sim_ent_from_client_handle(world, client_handle);
|
||||
|
||||
/* Create client ent if it doesn't exist */
|
||||
if (!client_ent->valid) {
|
||||
client_ent = sim_ent_alloc(root);
|
||||
client_ent->client_handle = client_handle;
|
||||
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_CLIENT);
|
||||
if (cmd_snapshot->producer_client_is_local) {
|
||||
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_LOCAL_CLIENT);
|
||||
}
|
||||
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_ACTIVE);
|
||||
}
|
||||
|
||||
client_ent->client_control = cmd_snapshot->control;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Sort incoming frames by client
|
||||
* Process client cmds
|
||||
* ========================== */
|
||||
|
||||
struct sim_cmd_frame **client_frames;
|
||||
{
|
||||
/* Create connecting clients */
|
||||
if (world->is_master) {
|
||||
/* Create local client if it doesn't exist */
|
||||
struct sim_client *local_client = sim_client_from_handle(world, world->local_client);
|
||||
if (!local_client->valid) {
|
||||
local_client = sim_client_alloc(world, HOST_CHANNEL_ID_NIL, SIM_CLIENT_KIND_SIM_MASTER);
|
||||
world->local_client = local_client->handle;
|
||||
}
|
||||
/* Create slave sim clients */
|
||||
for (struct sim_cmd_frame *frame = input_frames.first; frame; frame = frame->next) {
|
||||
struct sim_client *client;
|
||||
if (!frame->sender_is_local) {
|
||||
client = sim_client_from_channel_id(world, frame->sender_channel);
|
||||
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(frame->sender_channel)) {
|
||||
client = sim_client_alloc(world, frame->sender_channel, SIM_CLIENT_KIND_SIM_SLAVE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
if (frame->sender_is_local) {
|
||||
client = sim_client_from_handle(world, world->local_client);
|
||||
} else {
|
||||
client = sim_client_from_channel_id(world, frame->sender_channel);
|
||||
}
|
||||
if (client->valid) {
|
||||
client_frames[client->handle.idx] = frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (u64 i = 0; i < world->num_ents_reserved; ++i) {
|
||||
struct sim_ent *ent = &world->ents[i];
|
||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CLIENT)) {
|
||||
ent->client_dbg_drag_start = false;
|
||||
ent->client_dbg_drag_stop = false;
|
||||
|
||||
if (world->is_master) {
|
||||
/* ========================== *
|
||||
* Process client sim cmds
|
||||
* ========================== */
|
||||
|
||||
/* Process client cmds */
|
||||
u64 oldest_client_ack = world->tick;
|
||||
for (u64 i = 0; i < world->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &world->clients[i];
|
||||
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;
|
||||
|
||||
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;
|
||||
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_CLIENT_CONTROL:
|
||||
{
|
||||
struct sim_control old_control = client->control;
|
||||
struct sim_control old_control = ent->client_control;
|
||||
struct sim_control *control = &ent->client_control;
|
||||
*control = cmd->control;
|
||||
if (v2_len_sq(control->move) > 1) {
|
||||
/* Cap movement vector magnitude at 1 */
|
||||
@ -595,22 +536,22 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
||||
|
||||
/* Determine cursor pos from focus */
|
||||
{
|
||||
struct sim_ent_handle control_ent_handle = client->control_ent;
|
||||
struct sim_ent_handle control_ent_handle = ent->control_ent;
|
||||
struct sim_ent *control_ent = sim_ent_from_handle(world, control_ent_handle);
|
||||
if (control_ent->valid || sim_ent_handle_eq(control_ent_handle, SIM_ENT_NIL_HANDLE)) {
|
||||
/* Only update cursor pos if focus ent is valid (or nil) */
|
||||
client->cursor_pos = v2_add(sim_ent_get_xform(control_ent).og, client->control.focus);
|
||||
ent->client_cursor_pos = v2_add(sim_ent_get_xform(control_ent).og, ent->client_control.focus);
|
||||
}
|
||||
}
|
||||
|
||||
u32 flags = control->flags;
|
||||
if (flags & SIM_CONTROL_FLAG_DRAGGING) {
|
||||
if (!(old_control.flags & SIM_CONTROL_FLAG_DRAGGING)) {
|
||||
client->dbg_drag_start = true;
|
||||
ent->client_dbg_drag_start = true;
|
||||
}
|
||||
} else {
|
||||
if (old_control.flags & SIM_CONTROL_FLAG_DRAGGING) {
|
||||
client->dbg_drag_stop = true;
|
||||
ent->client_dbg_drag_stop = true;
|
||||
}
|
||||
}
|
||||
if (flags & SIM_CONTROL_FLAG_CLEAR_ALL) {
|
||||
@ -628,43 +569,29 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
/* Disconnect client */
|
||||
case SIM_CMD_KIND_SIM_CLIENT_DISCONNECT:
|
||||
{
|
||||
sim_client_release(client);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
};
|
||||
}
|
||||
|
||||
if (client->ack < oldest_client_ack || oldest_client_ack == 0) {
|
||||
oldest_client_ack = client->ack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Create client ents
|
||||
* Create client player ents
|
||||
* ========================== */
|
||||
|
||||
for (u64 i = 0; i < world->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &world->clients[i];
|
||||
if (client->valid) {
|
||||
for (u64 i = 0; i < world->num_ents_reserved; ++i) {
|
||||
struct sim_ent *ent = &world->ents[i];
|
||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CLIENT)) {
|
||||
/* FIXME: Ents never released when client disconnects */
|
||||
struct sim_ent *player_ent = sim_ent_from_handle(world, client->control_ent);
|
||||
struct sim_ent *player_ent = sim_ent_from_handle(world, ent->client_player_ent);
|
||||
if (!player_ent->valid) {
|
||||
player_ent = spawn_test_player(world);
|
||||
sim_ent_enable_prop(player_ent, SIM_ENT_PROP_CONTROLLED);
|
||||
client->control_ent = player_ent->handle;
|
||||
player_ent->controlling_client = client->handle;
|
||||
ent->client_player_ent = player_ent->handle;
|
||||
player_ent->controlling_client = ent->handle;
|
||||
}
|
||||
struct sim_ent *camera_ent = sim_ent_from_handle(world, client->camera_ent);
|
||||
struct sim_ent *camera_ent = sim_ent_from_handle(world, ent->client_camera_ent);
|
||||
if (!camera_ent->valid) {
|
||||
camera_ent = spawn_test_player_camera(world, player_ent);
|
||||
client->camera_ent = camera_ent->handle;
|
||||
ent->client_camera_ent = camera_ent->handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -678,9 +605,9 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||
|
||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
|
||||
struct sim_client *client = sim_client_from_handle(world, ent->controlling_client);
|
||||
if (client->valid) {
|
||||
ent->control = client->control;
|
||||
struct sim_ent *client_ent = sim_client_from_handle(world, ent->controlling_client);
|
||||
if (client_ent->valid) {
|
||||
ent->control = client_ent->client_control;
|
||||
/* TODO: Move this */
|
||||
if (ent->control.flags & SIM_CONTROL_FLAG_FIRING) {
|
||||
sim_ent_enable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
|
||||
|
||||
101
src/sim.h
101
src/sim.h
@ -9,34 +9,9 @@ struct host_startup_receipt;
|
||||
struct sim_snapshot_startup_receipt;
|
||||
|
||||
/* ========================== *
|
||||
* Cmd
|
||||
* Control
|
||||
* ========================== */
|
||||
|
||||
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_CLIENT_CONTROL,
|
||||
|
||||
SIM_CMD_KIND_SIM_CLIENT_CONNECT,
|
||||
SIM_CMD_KIND_SIM_CLIENT_DISCONNECT,
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
enum sim_control_flag {
|
||||
SIM_CONTROL_FLAG_NONE = 0,
|
||||
SIM_CONTROL_FLAG_FIRING = 1 << 0,
|
||||
@ -56,84 +31,22 @@ struct sim_control {
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct sim_cmd {
|
||||
struct sim_cmd *next;
|
||||
|
||||
/* Cmd metadata */
|
||||
enum sim_cmd_kind kind;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* SIM_CMD_KIND_CLIENT_CONTROL */
|
||||
|
||||
struct sim_control control;
|
||||
|
||||
#if RTC
|
||||
u32 collider_gjk_steps;
|
||||
#endif
|
||||
|
||||
/* ====================================================================== */
|
||||
/* SIM_CMD_KIND_CLIENT_DISCONNECT */
|
||||
|
||||
struct string disconnect_reason;
|
||||
|
||||
/* =========================================================== */
|
||||
/* SIM_CMD_KIND_SNAPSHOT */
|
||||
|
||||
u64 snapshot_tick_start;
|
||||
u64 snapshot_tick_end;
|
||||
|
||||
/* Delta encoded snapshot containing changes between start & end ticks */
|
||||
struct string snapshot_encoded;
|
||||
};
|
||||
|
||||
/* Represents all cmds generated by a user/sim for a particular channel in a single tick. */
|
||||
struct sim_cmd_frame {
|
||||
struct host_channel_id sender_channel; /* Sender's channel ID will be nil if sender_is_local = true */
|
||||
b32 sender_is_local;
|
||||
|
||||
u64 tick; /* The tick that this cmd frame is meant to execute on */
|
||||
u64 ack; /* Sender's last received cmd frame tick */
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/* ========================== *
|
||||
* Layers
|
||||
* ========================== */
|
||||
|
||||
/* Absolute layers */
|
||||
#define SIM_LAYER_FLOOR_DECALS -300
|
||||
#define SIM_LAYER_BULLETS -200
|
||||
#define SIM_LAYER_TRACERS -100
|
||||
#define SIM_LAYER_SHOULDERS 0
|
||||
#define SIM_LAYER_FLOOR_DECALS (-300)
|
||||
#define SIM_LAYER_BULLETS (-200)
|
||||
#define SIM_LAYER_TRACERS (-100)
|
||||
#define SIM_LAYER_SHOULDERS (0)
|
||||
|
||||
/* Relative layers */
|
||||
#define SIM_LAYER_RELATIVE_DEFAULT 0
|
||||
#define SIM_LAYER_RELATIVE_WEAPON 1
|
||||
#define SIM_LAYER_RELATIVE_DEFAULT (0)
|
||||
#define SIM_LAYER_RELATIVE_WEAPON (1)
|
||||
|
||||
struct sim_snapshot;
|
||||
struct sim_snapshot_store;
|
||||
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);
|
||||
|
||||
/* ========================== *
|
||||
* Cmd frame encode / decode
|
||||
* ========================== */
|
||||
|
||||
/* TODO: Move this */
|
||||
|
||||
#include "host.h"
|
||||
|
||||
void sim_cmd_frames_encode(struct bitbuff_writer *bw, struct sim_cmd_frame_list frames);
|
||||
void sim_cmd_frames_decode(struct arena *arena, struct host_event_array host_events, struct sim_cmd_frame_list *frames_out);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -202,6 +202,7 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct
|
||||
ss->world_time_ns = src->world_time_ns;
|
||||
ss->continuity_gen = src->continuity_gen;
|
||||
ss->local_client = src->local_client;
|
||||
ss->phys_iteration = src->phys_iteration;
|
||||
|
||||
/* Copy client lookup buckets */
|
||||
if (src->num_client_lookup_buckets > 0) {
|
||||
|
||||
@ -4,15 +4,17 @@
|
||||
#include "sim_ent.h"
|
||||
#include "sim_client.h"
|
||||
|
||||
#if 0
|
||||
enum sim_snapshot_flag {
|
||||
SIM_SNAPSHOT_FLAG_NONE = 0,
|
||||
|
||||
/* The snapshot contains client control data */
|
||||
SIM_SNAPSHOT_FLAG_CONTROL = (1 << 0),
|
||||
|
||||
/* TODO: Remove this */
|
||||
struct space;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* The snapshot contains entity state data */
|
||||
SIM_SNAPSHOT_FLAG_STATE = (1 << 1)
|
||||
};
|
||||
#endif
|
||||
|
||||
struct sim_snapshot_store {
|
||||
b32 valid;
|
||||
@ -33,6 +35,7 @@ struct sim_snapshot_store {
|
||||
struct sim_snapshot {
|
||||
b32 valid;
|
||||
u64 tick;
|
||||
u64 ack;
|
||||
struct sim_snapshot_store *store;
|
||||
struct sim_snapshot *next_free;
|
||||
struct sim_snapshot *next_in_bucket;
|
||||
@ -42,6 +45,14 @@ struct sim_snapshot {
|
||||
|
||||
struct arena arena;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* SIM_SNAPSHOT_FLAG_CONTROL */
|
||||
|
||||
struct sim_control control;
|
||||
|
||||
/* ====================================================================== */
|
||||
/* SIM_SNAPSHOT_FLAG_STATE */
|
||||
|
||||
/* Was this snapshot created by the master sim */
|
||||
b32 is_master;
|
||||
|
||||
@ -86,6 +97,14 @@ struct sim_snapshot {
|
||||
u64 num_ents_reserved;
|
||||
};
|
||||
|
||||
#if 0
|
||||
struct sim_snapshot_encoded {
|
||||
u64 base_tick;
|
||||
u64 tick;
|
||||
struct string data; /* Contains snapshot deltas for `tick` from `base_tick` */
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ========================== *
|
||||
* Startup
|
||||
* ========================== */
|
||||
@ -138,5 +157,4 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *sto
|
||||
void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_client *receiver, struct sim_snapshot *ss0, struct sim_snapshot *ss1);
|
||||
void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
339
src/user.c
339
src/user.c
@ -88,7 +88,6 @@ GLOBAL struct {
|
||||
/* User -> local sim */
|
||||
struct sys_mutex user_sim_cmd_mutex;
|
||||
struct sim_control user_sim_cmd_control;
|
||||
struct v2 user_sim_cmd_control_cursor_pos;
|
||||
u64 last_user_sim_cmd_gen;
|
||||
u64 user_sim_cmd_gen;
|
||||
u64 user_sim_cmd_ack;
|
||||
@ -1704,6 +1703,9 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_thread_entry_point, arg)
|
||||
* Local sim thread
|
||||
* ========================== */
|
||||
|
||||
#if 1
|
||||
|
||||
|
||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
|
||||
{
|
||||
#if 0
|
||||
@ -1731,6 +1733,337 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct bitbuff msg_writer_bb = bitbuff_alloc(GIGABYTE(64));
|
||||
struct bitbuff snapshot_writer_bb = bitbuff_alloc(GIGABYTE(64));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct sim_client_store *store = sim_client_store_alloc();
|
||||
struct sim_client *local_client = sim_client_alloc(store, SIM_CLIENT_KIND_LOCAL_SIM);
|
||||
struct sim_client *user_client = sim_client_alloc(store, SIM_CLIENT_KIND_USER);
|
||||
struct sim_client *master_client = sim_client_nil();
|
||||
|
||||
u64 step_tick = 0;
|
||||
i64 last_publish_ns = 0;
|
||||
i64 last_tick_ns = 0;
|
||||
i64 step_dt_ns = NS_FROM_SECONDS(1) / SIM_TICKS_PER_SECOND;
|
||||
i64 compute_dt_ns = step_dt_ns;
|
||||
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();
|
||||
}
|
||||
++step_tick;
|
||||
|
||||
/* Create user cmd snapshot */
|
||||
{
|
||||
struct sim_snapshot *prev_user_cmd_ss = sim_snapshot_from_tick(user_client, user_client->last_tick);
|
||||
struct sim_snapshot *user_cmd_ss = sim_snapshot_alloc(user_client, prev_user_cmd_ss, step_tick);
|
||||
struct sys_lock lock = sys_mutex_lock_e(&G.user_sim_cmd_mutex);
|
||||
user_cmd_ss->ack = G.user_sim_cmd_ack;
|
||||
user_cmd_ss->control = G.user_sim_cmd_control;
|
||||
++G.user_sim_cmd_gen;
|
||||
sys_mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
/* Read net snapshots */
|
||||
{
|
||||
host_update(host);
|
||||
struct host_event_array host_events = host_pop_events(scratch.arena, host);
|
||||
for (u64 i = 0; i < host_events.count; ++i) {
|
||||
struct host_event *event = &host_events.events[i];
|
||||
struct host_channel_id channel_id = event->channel_id;
|
||||
struct sim_client *client = sim_client_from_channel_id(store, channel_id);
|
||||
switch (event->kind) {
|
||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||
{
|
||||
/* Create sim client */
|
||||
if (!client->valid) {
|
||||
/* TODO: Master challenge */
|
||||
if (is_master) {
|
||||
client = sim_client_alloc(store, SIM_CLIENT_KIND_SLAVE_SIM);
|
||||
} else {
|
||||
client = sim_client_alloc(store, SIM_CLIENT_KIND_MASTER_SIM);
|
||||
master_client = client;
|
||||
}
|
||||
sim_client_set_channel_id(client, channel_id);
|
||||
}
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_CHANNEL_MSG:
|
||||
{
|
||||
if (client->valid) {
|
||||
struct bitbuff msg_bb = bitbuff_from_string(event->msg);
|
||||
struct bitbuff_reader msg_br = br_from_bitbuff(&msg_bb);
|
||||
|
||||
u64 ack = br_read_uv(&msg_br);
|
||||
u64 reverse_ack = br_read_uv(&msg_br);
|
||||
if (ack > client->ack) {
|
||||
client->ack = ack;
|
||||
}
|
||||
if (reverse_ack > client->reverse_ack) {
|
||||
client->reverse_ack = reverse_ack;
|
||||
}
|
||||
|
||||
/* Read snapshots */
|
||||
struct string encoded_tmp = ZI;
|
||||
encoded_tmp.len = br_read_uv(&msg_br);
|
||||
encoded_tmp.text = br_read_bytes_raw(&msg_br, encoded_tmp.len);
|
||||
if (!encoded_tmp.text) {
|
||||
encoded_tmp.len = 0;
|
||||
}
|
||||
while (encoded_tmp.len > 0) {
|
||||
struct bitbuff decoder_bb = bitbuff_from_string(encoded_tmp);
|
||||
struct bitbuff_reader decoder_br = br_from_bitbuff(&decoder_bb);
|
||||
u64 base_tick = br_read_uv(&decoder_br);
|
||||
u64 tick = br_read_uv(&decoder_br);
|
||||
if (client->kind == SIM_CLIENT_KIND_MASTER_SIM) {
|
||||
if (tick > client->last_tick) {
|
||||
struct sim_snapshot *base_ss = sim_snapshot_from_tick(client, base_tick);
|
||||
if (base_ss->tick == base_tick) {
|
||||
struct sim_snapshot *ss = sim_snapshot_alloc(client, base_ss, tick);
|
||||
sim_snapshot_decode(&decoder_br, ss);
|
||||
} else {
|
||||
/* We do not have the base tick that the incoming tick is delta encoded from */
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* TODO: Limit range of incoming cmd ticks */
|
||||
if (tick == client->last_tick + 1) {
|
||||
struct sim_snapshot *base_ss = sim_snapshot_from_tick(client, base_tick);
|
||||
if (base_ss->tick == base_tick) {
|
||||
struct sim_snapshot *ss = sim_snapshot_alloc(client, base_ss, tick);
|
||||
sim_snapshot_decode(&decoder_br, ss);
|
||||
} else {
|
||||
/* We do not have the base tick that the incoming tick is delta encoded from */
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
encoded_tmp.len = br_read_uv(&msg_br);
|
||||
encoded_tmp.text = br_read_bytes_raw(&msg_br, encoded_tmp.len);
|
||||
if (!encoded_tmp.text) {
|
||||
encoded_tmp.len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Release unneeded snapshots */
|
||||
u64 oldest_client_ack = 0;
|
||||
for (u64 i = 0; i < store->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &store->clients[i];
|
||||
enum sim_client_kind kind = client->kind;
|
||||
if (client->valid && kind != SIM_CLIENT_KIND_LOCAL_SIM) {
|
||||
u64 ack = client->ack;
|
||||
u64 reverse_ack = client->reverse_ack;
|
||||
if (reverse_ack > 1) {
|
||||
sim_client_release_snapshot_ticks_in_range(client, 0, reverse_ack - 1);
|
||||
}
|
||||
if (ack < oldest_client_ack || oldest_client_ack == 0) {
|
||||
oldest_client_ack = ack;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (oldest_client_ack > 1) {
|
||||
sim_client_release_snapshot_ticks_in_range(local_client, 0, oldest_client_ack - 1);
|
||||
}
|
||||
|
||||
/* Pick client snapshot cmds to feed to sim step */
|
||||
struct sim_snapshot_list client_step_cmds = ZI;
|
||||
for (u64 i = 0; i < store->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &store->clients[i];
|
||||
enum sim_client_kind kind = client->kind;
|
||||
if (client->valid && kind != SIM_CLIENT_KIND_LOCAL_SIM && kind != SIM_CLIENT_KIND_MASTER_SIM) {
|
||||
struct sim_snapshot *cmd_snapshot = sim_snapshot_from_closest_tick_lte(client, step_tick);
|
||||
struct sim_snapshot_list_node *n = arena_push_zero(scratch.arena, struct sim_snapshot_list_node);
|
||||
n->ss = cmd_snapshot;
|
||||
if (client_step_cmds.last) {
|
||||
client_step_cmds.last->next = n;
|
||||
} else {
|
||||
client_step_cmds.first = n;
|
||||
}
|
||||
client_step_cmds.last = n;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create step snapshot */
|
||||
struct sim_snapshot *step_ss;
|
||||
if (is_master) {
|
||||
struct sim_snapshot *prev_step_ss = sim_snapshot_from_tick(local_client, step_tick - 1);
|
||||
step_ss = sim_snapshot_alloc(local_client, prev_step_ss, step_tick);
|
||||
} else {
|
||||
struct sim_snapshot *newest_master_ss = sim_snapshot_from_tick(master_client, master_client->last_tick);
|
||||
step_ss = sim_snapshot_alloc(local_client, newest_master_ss, step_tick);
|
||||
}
|
||||
|
||||
/* Step */
|
||||
sim_step(step_ss, client_step_cmds, step_dt_ns);
|
||||
|
||||
/* Publish snapshot to clients */
|
||||
for (u64 i = 0; i < store->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &store->clients[i];
|
||||
struct bitbuff_writer msg_bw = bw_from_bitbuff(&msg_writer_bb);
|
||||
if (client->valid) {
|
||||
switch (client->kind) {
|
||||
case SIM_CLIENT_KIND_SLAVE_SIM:
|
||||
{
|
||||
struct sim_snapshot *base_ss = sim_snapshot_from_tick(client, client->ack);
|
||||
if (base_ss->tick == client->ack) {
|
||||
/* Encode single master state sanpshot snapshot */
|
||||
struct bitbuff_writer snapshot_bw = bw_from_bitbuff(&snapshot_writer_bb);
|
||||
bw_write_uv(&snapshot_bw, base_ss->tick);
|
||||
bw_write_uv(&snapshot_bw, step_ss->tick);
|
||||
sim_snapshot_encode(&snapshot_bw, client, base_ss, step_ss);
|
||||
|
||||
struct string encoded_tmp = ZI;
|
||||
encoded_tmp.len = bw_num_bytes_written(&snapshot_bw);
|
||||
encoded_tmp.text = bw_get_written_raw(&snapshot_bw);
|
||||
|
||||
u64 ack = client->last_tick;
|
||||
u64 reverse_ack = client->ack;
|
||||
bw_write_uv(&msg_bw, ack);
|
||||
bw_write_uv(&msg_bw, reverse_ack);
|
||||
bw_write_uv(&msg_bw, encoded_tmp.len);
|
||||
bw_write_bytes(&msg_bw, encoded_tmp);
|
||||
bw_write_uv(&msg_bw, 0);
|
||||
} else {
|
||||
/* We do not have the client's ack tick to delta encode from */
|
||||
ASSERT(false);
|
||||
}
|
||||
} break;
|
||||
|
||||
case SIM_CLIENT_KIND_MASTER_SIM:
|
||||
{
|
||||
u64 ack = client->last_tick;
|
||||
struct sim_snapshot *base_ss = sim_snapshot_from_tick(client, base_tick);
|
||||
if (base_ss->tick == base_tick) {
|
||||
u64 ack = client->last_tick;
|
||||
u64 reverse_ack = client->ack;
|
||||
bw_write_uv(&bw, ack);
|
||||
bw_write_uv(&bw, reverse_ack);
|
||||
/* Write all user cmd snapshots since last client ack */
|
||||
struct sim_snapshot *send_ss = sim_snapshot_from_tick(user_client, base_ss->tick + 1);
|
||||
while (send_ss->valid) {
|
||||
struct bitbuff_writer snapshot_bw = bw_from_bitbuff(&snapshot_writer_bb);
|
||||
bw_write_uv(&snapshot_bw, base_ss->tick);
|
||||
bw_write_uv(&snapshot_bw, step_ss->tick);
|
||||
sim_snapshot_encode(&snapshot_bw, client, base_ss, step_ss);
|
||||
bw_write_uv(&msg_bw, encoded_tmp.len);
|
||||
bw_write_bytes(&msg_bw, encoded_tmp);
|
||||
}
|
||||
bw_write_uv(&msg_bw, 0);
|
||||
} else {
|
||||
/* We do not have the client's ack tick to delta encode from */
|
||||
ASSERT(false);
|
||||
}
|
||||
} break;
|
||||
|
||||
case SIM_CLIENT_KIND_USER:
|
||||
{
|
||||
/* TODO: Double buffer */
|
||||
struct sys_lock lock = sys_mutex_lock_e(&G.local_to_user_snapshot_mutex);
|
||||
struct sim_snapshot *pub_ss = sim_snapshot_alloc(G.local_to_user_snapshot_client, step_ss, step_ss->tick);
|
||||
i64 publish_ns = sys_time_ns();
|
||||
pub_ss->publish_dt_ns = publish_ns - last_publish_ns;
|
||||
pub_ss->publish_time_ns = publish_ns;
|
||||
last_publish_ns = publish_ns;
|
||||
sys_mutex_unlock(&lock);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
host_update(host);
|
||||
__profframe("Local sim");
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
sim_snapshot_store_release(store);
|
||||
bitbuff_release(&snapshot_writer_bb);
|
||||
bitbuff_release(&msg_writer_bb);
|
||||
host_release(host);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
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
|
||||
(UNUSED)arg;
|
||||
|
||||
b32 is_master = false;
|
||||
if (G.connect_address_str.len > 0) {
|
||||
struct sock_address addr = sock_address_from_string(G.connect_address_str);
|
||||
host_queue_connect_to_address(host, addr);
|
||||
} else {
|
||||
is_master = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct bitbuff encoder_bitbuff = bitbuff_alloc(GIGABYTE(64));
|
||||
|
||||
@ -1768,7 +2101,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
|
||||
struct sim_cmd_frame_list input_cmds = ZI;
|
||||
struct sim_cmd_frame *user_cmd_frame;
|
||||
{
|
||||
/* Grab cmds from host */
|
||||
/* Grab snapshots from host */
|
||||
{
|
||||
host_update(host);
|
||||
struct host_event_array host_events = host_pop_events(scratch.arena, host);
|
||||
@ -1983,3 +2316,5 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
|
||||
bitbuff_release(&encoder_bitbuff);
|
||||
host_release(host);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user