prediction progress

This commit is contained in:
jacob 2025-02-19 17:32:24 -06:00
parent cb05b707f0
commit 4172808fe2
8 changed files with 1001 additions and 908 deletions

View File

@ -16,6 +16,10 @@
* *
* Rolling window for message reassembly. * Rolling window for message reassembly.
* This would remove the need for random access message buffers. * This would remove the need for random access message buffers.
*
* Connection timeouts.
*
* Challenges to verify receiving address.
*/ */
#define PACKET_MAGIC 0xd9e3b8b6 #define PACKET_MAGIC 0xd9e3b8b6

View File

@ -519,27 +519,30 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
struct sim_cmd_frame **client_frames; struct sim_cmd_frame **client_frames;
{ {
/* Create connecting clients */ /* 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) { for (struct sim_cmd_frame *frame = input_frames.first; frame; frame = frame->next) {
struct sim_client *client; struct sim_client *client;
if (frame->sender_is_local) { if (!frame->sender_is_local) {
client = sim_client_from_handle(world, world->local_client);
if (!client->valid) {
client = sim_client_alloc(world, HOST_CHANNEL_ID_NIL, SIM_CLIENT_KIND_LOCAL);
world->local_client = client->handle;
}
} else {
client = sim_client_from_channel_id(world, frame->sender_channel); client = sim_client_from_channel_id(world, frame->sender_channel);
if (!client->valid) { if (!client->valid) {
for (struct sim_cmd *cmd = frame->first; cmd; cmd = cmd->next) { for (struct sim_cmd *cmd = frame->first; cmd; cmd = cmd->next) {
enum sim_cmd_kind kind = cmd->kind; enum sim_cmd_kind kind = cmd->kind;
if (kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(frame->sender_channel)) { 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_NETSIM); client = sim_client_alloc(world, frame->sender_channel, SIM_CLIENT_KIND_SIM_SLAVE);
break; break;
} }
} }
} }
} }
} }
}
/* Sort cmd frames by client */ /* Sort cmd frames by client */
client_frames = arena_push_array_zero(scratch.arena, struct sim_cmd_frame *, world->num_clients_reserved); 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) { for (struct sim_cmd_frame *frame = input_frames.first; frame; frame = frame->next) {
@ -549,12 +552,13 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
} else { } else {
client = sim_client_from_channel_id(world, frame->sender_channel); client = sim_client_from_channel_id(world, frame->sender_channel);
} }
if (client->valid && frame->tick == world->tick) { if (client->valid) {
client_frames[client->handle.idx] = frame; client_frames[client->handle.idx] = frame;
} }
} }
} }
if (world->is_master) {
/* ========================== * /* ========================== *
* Process client sim cmds * Process client sim cmds
* ========================== */ * ========================== */
@ -1369,57 +1373,8 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
* ========================== */ * ========================== */
release_entities_with_prop(world, SIM_ENT_PROP_RELEASE_THIS_TICK); release_entities_with_prop(world, SIM_ENT_PROP_RELEASE_THIS_TICK);
/* ========================== *
* Publish tick
* ========================== */
#if 0
struct sim_cmd_queue_list output_cmds = ZI;
for (u64 i = 0; i < ss_blended->num_clients_reserved; ++i) {
struct sim_client *client = &ss_blended->clients[i];
if (client->valid) {
struct temp_arena temp = arena_temp_begin(scratch.arena);
struct sim_snapshot *ss0 = sim_snapshot_from_tick(snapshot_store, client->ack);
struct sim_snapshot *ss1 = ss_blended;
/* Create & encode snapshot cmd */
{
struct sim_cmd *cmd = arena_push(arena, struct sim_cmd);
cmd->kind = SIM_CMD_KIND_SNAPSHOT;
cmd->tick = ss_blended->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);
cmd->snapshot_encoded = bw_get_written(temp.arena, &bw);
} }
if (output_cmds.last) {
output_cmds.last->next = cmd;
} else {
output_cmds.first = cmd;
}
output_cmds.last = cmd;
}
/* Encode cmds */
struct string cmds_msg = ZI;
{
struct bitbuff_writer bw = bw_from_bitbuff(encoder_bitbuff);
sim_cmds_encode(&bw, output_cmds, 0);
cmds_msg = bw_get_written(temp.arena, &bw);
}
host_queue_write(host, client->channel_id, cmds_msg, 0);
arena_temp_end(temp);
}
}
#endif
/* ========================== * /* ========================== *
* End frame * End frame
@ -1451,12 +1406,12 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
* Cmd frame * Cmd frame
* ========================== */ * ========================== */
void sim_cmd_frames_encode(struct bitbuff_writer *bw, struct sim_cmd_frame_list frames, u64 ack_tick) void sim_cmd_frames_encode(struct bitbuff_writer *bw, struct sim_cmd_frame_list frames)
{ {
__prof; __prof;
for (struct sim_cmd_frame *frame = frames.first; frame; frame = frame->next) { for (struct sim_cmd_frame *frame = frames.first; frame; frame = frame->next) {
bw_write_uv(bw, frame->tick); bw_write_uv(bw, frame->tick);
bw_write_uv(bw, ack_tick); bw_write_uv(bw, frame->ack);
for (struct sim_cmd *cmd = frame->first; cmd; cmd = cmd->next) { for (struct sim_cmd *cmd = frame->first; cmd; cmd = cmd->next) {
bw_write_bit(bw, 1); bw_write_bit(bw, 1);

View File

@ -131,7 +131,7 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
#include "host.h" #include "host.h"
void sim_cmd_frames_encode(struct bitbuff_writer *bw, struct sim_cmd_frame_list frames, u64 ack_tick); 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); void sim_cmd_frames_decode(struct arena *arena, struct host_event_array host_events, struct sim_cmd_frame_list *frames_out);

View File

@ -57,30 +57,13 @@ struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel
} }
++ss->num_clients_allocated; ++ss->num_clients_allocated;
*client = *sim_client_nil(); *client = *sim_client_nil();
client->ss = ss;
client->valid = true; client->valid = true;
client->kind = kind; client->kind = kind;
client->handle = handle; client->handle = handle;
if (kind == SIM_CLIENT_KIND_NETSIM) {
ASSERT(!host_channel_id_is_nil(channel_id));
u64 channel_hash = hash_from_channel_id(channel_id);
client->channel_id = channel_id;
client->channel_hash = channel_hash;
/* Insert into channel lookup */ /* Insert into channel lookup */
u64 bucket_index = channel_hash % ss->num_client_lookup_buckets; sim_client_set_channel_id(client, channel_id);
struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index];
{
struct sim_client *prev_in_bucket = sim_client_from_handle(ss, bucket->last);
if (prev_in_bucket->valid) {
prev_in_bucket->next_in_bucket = client->handle;
client->prev_in_bucket = prev_in_bucket->handle;
} else {
bucket->first = client->handle;
}
bucket->last = client->handle;
}
}
return client; return client;
} }
@ -95,7 +78,16 @@ void sim_client_release(struct sim_client *client)
--ss->num_clients_allocated; --ss->num_clients_allocated;
/* Remove from channel lookup */ /* Remove from channel lookup */
if (client->kind == SIM_CLIENT_KIND_NETSIM) { sim_client_set_channel_id(client, HOST_CHANNEL_ID_NIL);
}
void sim_client_set_channel_id(struct sim_client *client, struct host_channel_id channel_id)
{
struct sim_snapshot *ss = client->ss;
struct host_channel_id old_channel_id = client->channel_id;
/* Remove from channel lookup */
if (!host_channel_id_is_nil(old_channel_id)) {
u64 bucket_index = client->channel_hash % ss->num_client_lookup_buckets; u64 bucket_index = client->channel_hash % ss->num_client_lookup_buckets;
struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index]; struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index];
struct sim_client *prev = sim_client_from_handle(ss, client->prev_in_bucket); struct sim_client *prev = sim_client_from_handle(ss, client->prev_in_bucket);
@ -111,6 +103,25 @@ void sim_client_release(struct sim_client *client)
bucket->last = prev->handle; bucket->last = prev->handle;
} }
} }
/* Insert into channel lookup */
u64 channel_hash = hash_from_channel_id(channel_id);
client->channel_id = channel_id;
client->channel_hash = channel_hash;
if (!host_channel_id_is_nil(channel_id)) {
u64 bucket_index = channel_hash % ss->num_client_lookup_buckets;
struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index];
{
struct sim_client *prev_in_bucket = sim_client_from_handle(ss, bucket->last);
if (prev_in_bucket->valid) {
prev_in_bucket->next_in_bucket = client->handle;
client->prev_in_bucket = prev_in_bucket->handle;
} else {
bucket->first = client->handle;
}
bucket->last = client->handle;
}
}
} }
/* ========================== * /* ========================== *

View File

@ -10,8 +10,8 @@ struct sim_snapshot;
enum sim_client_kind { enum sim_client_kind {
SIM_CLIENT_KIND_INVALID, SIM_CLIENT_KIND_INVALID,
SIM_CLIENT_KIND_LOCAL, SIM_CLIENT_KIND_SIM_SLAVE,
SIM_CLIENT_KIND_NETSIM SIM_CLIENT_KIND_SIM_MASTER
}; };
struct sim_client_lookup_bucket { struct sim_client_lookup_bucket {
@ -60,6 +60,7 @@ struct sim_client *sim_client_from_handle(struct sim_snapshot *ss, struct sim_cl
struct sim_client *sim_client_from_channel_id(struct sim_snapshot *ss, struct host_channel_id channel_id); struct sim_client *sim_client_from_channel_id(struct sim_snapshot *ss, struct host_channel_id channel_id);
struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id, enum sim_client_kind kind); struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id, enum sim_client_kind kind);
void sim_client_release(struct sim_client *client); void sim_client_release(struct sim_client *client);
void sim_client_set_channel_id(struct sim_client *client, struct host_channel_id channel_id);
/* ========================== * /* ========================== *
* Lerp * Lerp

View File

@ -194,6 +194,7 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct
++store->num_ticks; ++store->num_ticks;
/* Copy src info */ /* Copy src info */
ss->is_master = src->is_master;
ss->real_dt_ns = src->real_dt_ns; ss->real_dt_ns = src->real_dt_ns;
ss->real_time_ns = src->real_time_ns; ss->real_time_ns = src->real_time_ns;
ss->world_timescale = src->world_timescale; ss->world_timescale = src->world_timescale;
@ -272,6 +273,8 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct
} else { } else {
store->last_tick = tick; store->last_tick = tick;
} }
ss->next_tick = prev->next_tick;
ss->prev_tick = prev->tick;
prev->next_tick = ss->tick; prev->next_tick = ss->tick;
} else { } else {
struct sim_snapshot *first = sim_snapshot_from_tick(store, store->first_tick); struct sim_snapshot *first = sim_snapshot_from_tick(store, store->first_tick);
@ -281,6 +284,7 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct
} else { } else {
store->last_tick = tick; store->last_tick = tick;
} }
ss->next_tick = store->first_tick;
store->first_tick = tick; store->first_tick = tick;
} }
} }
@ -435,10 +439,13 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *sto
* Encode * Encode
* ========================== */ * ========================== */
void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_snapshot *ss0, struct sim_snapshot *ss1, struct sim_client *client) void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_client *receiver, struct sim_snapshot *ss0, struct sim_snapshot *ss1)
{ {
__prof; __prof;
/* TODO: Don't encode this */
bw_write_bit(bw, ss1->is_master);
bw_write_iv(bw, ss1->real_dt_ns); bw_write_iv(bw, ss1->real_dt_ns);
bw_write_iv(bw, ss1->real_time_ns); bw_write_iv(bw, ss1->real_time_ns);
@ -449,8 +456,8 @@ void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_snapshot *ss0, st
bw_write_uv(bw, ss1->continuity_gen); bw_write_uv(bw, ss1->continuity_gen);
bw_write_uv(bw, ss1->phys_iteration); bw_write_uv(bw, ss1->phys_iteration);
bw_write_uv(bw, client->handle.gen); bw_write_uv(bw, receiver->handle.gen);
bw_write_uv(bw, client->handle.idx); bw_write_uv(bw, receiver->handle.idx);
/* Clients */ /* Clients */
if (ss1->num_clients_allocated == ss0->num_clients_allocated) { if (ss1->num_clients_allocated == ss0->num_clients_allocated) {
@ -505,6 +512,9 @@ void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss)
{ {
__prof; __prof;
/* TODO: Don't encode this */
ss->is_master = br_read_bit(br);
ss->real_dt_ns = br_read_iv(br); ss->real_dt_ns = br_read_iv(br);
ss->real_time_ns = br_read_iv(br); ss->real_time_ns = br_read_iv(br);

View File

@ -42,6 +42,9 @@ struct sim_snapshot {
struct arena arena; struct arena arena;
/* Is this snapshot created by the master sim */
b32 is_master;
/* Time of local snapshot publish to user */ /* Time of local snapshot publish to user */
i64 publish_dt_ns; i64 publish_dt_ns;
i64 publish_time_ns; i64 publish_time_ns;
@ -132,7 +135,7 @@ struct sim_snapshot *sim_snapshot_from_tick(struct sim_snapshot_store *store, u6
struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *store, struct sim_snapshot *ss0, struct sim_snapshot *ss1, f64 blend); struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *store, struct sim_snapshot *ss0, struct sim_snapshot *ss1, f64 blend);
/* Encode / decode */ /* Encode / decode */
void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_snapshot *ss0, struct sim_snapshot *ss1, struct sim_client *client); 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); void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss);

View File

@ -199,6 +199,9 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
G.arena = arena_alloc(GIGABYTE(64)); G.arena = arena_alloc(GIGABYTE(64));
/* TODO: Remove this */
G.connect_address_str = string_copy(&G.arena, connect_address_str);
/* Snapshot store */ /* Snapshot store */
G.unblended_snapshot_store = sim_snapshot_store_alloc(); G.unblended_snapshot_store = sim_snapshot_store_alloc();
G.blended_snapshot_store = sim_snapshot_store_alloc(); G.blended_snapshot_store = sim_snapshot_store_alloc();
@ -228,25 +231,7 @@ 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);
/* TODO: Remove this */
#if 0
connect_address_str = STRING(0, 0);
if (connect_address_str.len == 0) {
G.local_sim_ctx = sim_ctx_alloc(sprite_sr, phys_sr, host_sr, sim_snapshot_sr, 12345);
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")); 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);
}
#else
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; G.debug_draw = true;
@ -1477,10 +1462,10 @@ INTERNAL void user_update(void)
pos.y += spacing; pos.y += spacing;
#endif #endif
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Read from local sim: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1000 / 1000, 3))); draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Read from host: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1000 / 1000, 3)));
pos.y += spacing; pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Send to local sim: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_sent.last_second * 8 / 1000 / 1000, 3))); draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Sent from host: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_sent.last_second * 8 / 1000 / 1000, 3)));
pos.y += spacing; pos.y += spacing;
pos.y += spacing; pos.y += spacing;
@ -1733,10 +1718,30 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
#endif #endif
(UNUSED)arg; (UNUSED)arg;
struct bitbuff encoder_bitbuff = bitbuff_alloc(GIGABYTE(64)); b32 is_master = false;
struct sim_snapshot_store *snapshot_store = sim_snapshot_store_alloc(); 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));
struct sim_snapshot_store *local_snapshot_store = sim_snapshot_store_alloc();
struct sim_snapshot_store *remote_snapshot_store = sim_snapshot_store_alloc();
u64 oldest_needed_remote_tick = 0;
u64 remote_ack = 0;
(UNUSED)remote_ack;
struct sim_snapshot *local_ss_prev = sim_snapshot_nil();
struct sim_snapshot *prev_ss = sim_snapshot_nil();
i64 last_publish_ns = 0; i64 last_publish_ns = 0;
i64 last_tick_ns = 0; i64 last_tick_ns = 0;
@ -1752,15 +1757,16 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
/* Release old snapshots */ /* Release old snapshots */
/* TODO: Remove this */ /* TODO: Remove this */
{ {
u64 keep_count = 50; u64 keep_count = 100;
u64 keep_tick = prev_ss->tick > keep_count ? prev_ss->tick - keep_count : 0; u64 keep_tick = local_ss_prev->tick > keep_count ? local_ss_prev->tick - keep_count : 0;
if (keep_tick > 0) { if (keep_tick > 0) {
sim_snapshot_store_release_ticks_in_range(snapshot_store, 0, keep_tick); sim_snapshot_store_release_ticks_in_range(local_snapshot_store, 0, keep_tick);
} }
} }
/* Retrieve cmds */ /* Retrieve cmds */
struct sim_cmd_frame_list input_cmds = ZI; struct sim_cmd_frame_list input_cmds = ZI;
struct sim_cmd_frame *user_cmd_frame;
{ {
/* Grab cmds from host */ /* Grab cmds from host */
{ {
@ -1770,11 +1776,10 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
} }
/* Generate user sim cmd from user thread */ /* Generate user sim cmd from user thread */
struct sim_cmd_frame *user_cmd_frame;
{ {
struct sys_lock lock = sys_mutex_lock_e(&G.user_sim_cmd_mutex); struct sys_lock lock = sys_mutex_lock_e(&G.user_sim_cmd_mutex);
user_cmd_frame = arena_push_zero(scratch.arena, struct sim_cmd_frame); user_cmd_frame = arena_push_zero(scratch.arena, struct sim_cmd_frame);
user_cmd_frame->tick = prev_ss->tick + 1; user_cmd_frame->tick = local_ss_prev->tick + 1;
user_cmd_frame->ack = G.user_sim_cmd_ack; user_cmd_frame->ack = G.user_sim_cmd_ack;
user_cmd_frame->sender_is_local = true; user_cmd_frame->sender_is_local = true;
@ -1794,14 +1799,71 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
input_cmds.last = user_cmd_frame; input_cmds.last = user_cmd_frame;
} }
for (struct sim_cmd_frame *frame = input_cmds.first; frame; frame = frame->next) {
/* FIXME: Verify cmd is from master */
if (!is_master && !frame->sender_is_local) {
struct sim_cmd *snapshot_cmd = NULL;
/* Grab newest snapshot cmd */
for (struct sim_cmd *cmd = frame->first; cmd; cmd = cmd->next) {
if (cmd->kind == SIM_CMD_KIND_SNAPSHOT && (!snapshot_cmd || cmd->snapshot_tick_end > snapshot_cmd->snapshot_tick_end)) {
snapshot_cmd = cmd;
}
}
/* Decode newest snapshot cmd */
if (snapshot_cmd && snapshot_cmd->snapshot_tick_end > remote_snapshot_store->last_tick) {
remote_ack = frame->ack;
u64 ss0_tick = snapshot_cmd->snapshot_tick_start;
u64 ss1_tick = snapshot_cmd->snapshot_tick_end;
struct sim_snapshot *ss0 = sim_snapshot_from_tick(remote_snapshot_store, ss0_tick);
struct sim_snapshot *ss1 = sim_snapshot_from_tick(remote_snapshot_store, ss1_tick);
if (ss0->tick == ss0_tick) {
if (!ss1->valid) {
/* Decode remote snapshot */
ss1 = sim_snapshot_alloc(remote_snapshot_store, ss0, ss1_tick);
struct bitbuff bb = bitbuff_from_string(snapshot_cmd->snapshot_encoded);
struct bitbuff_reader br = br_from_bitbuff(&bb);
sim_snapshot_decode(&br, ss1);
if (ss0->tick > oldest_needed_remote_tick) {
oldest_needed_remote_tick = ss0->tick;
}
/* Set master client channel id */
for (u64 i = 0; i < ss1->num_clients_reserved; ++i) {
struct sim_client *client = &ss1->clients[i];
if (client->valid && client->kind == SIM_CLIENT_KIND_SIM_MASTER) {
sim_client_set_channel_id(client, frame->sender_channel);
}
}
local_ss_prev = sim_snapshot_alloc(local_snapshot_store, ss1, ss1_tick + 20);
}
} else {
/* User should always have src tick present */
ASSERT(false);
}
}
}
}
/* Release old remote ticks */
if (oldest_needed_remote_tick > 0) {
sim_snapshot_store_release_ticks_in_range(remote_snapshot_store, 0, oldest_needed_remote_tick - 1);
}
/* Step */ /* Step */
struct sim_snapshot *ss = sim_step(snapshot_store, prev_ss, input_cmds, target_dt_ns); struct sim_snapshot *local_ss = sim_step(local_snapshot_store, local_ss_prev, input_cmds, target_dt_ns);
local_ss->is_master = is_master;
/* Publish snapshot to user */ /* Publish snapshot to user */
/* TODO: Double buffer */ /* TODO: Double buffer */
{ {
struct sys_lock lock = sys_mutex_lock_e(&G.local_sim_ss_mutex); struct sys_lock lock = sys_mutex_lock_e(&G.local_sim_ss_mutex);
struct sim_snapshot *pub_ss = sim_snapshot_alloc(G.local_sim_ss_store, ss, ss->tick); struct sim_snapshot *pub_ss = sim_snapshot_alloc(G.local_sim_ss_store, local_ss, local_ss->tick);
sim_snapshot_store_release_ticks_in_range(G.local_sim_ss_store, 0, pub_ss->tick - 1); sim_snapshot_store_release_ticks_in_range(G.local_sim_ss_store, 0, pub_ss->tick - 1);
i64 publish_ns = sys_time_ns(); i64 publish_ns = sys_time_ns();
pub_ss->publish_dt_ns = publish_ns - last_publish_ns; pub_ss->publish_dt_ns = publish_ns - last_publish_ns;
@ -1810,19 +1872,20 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
sys_mutex_unlock(&lock); sys_mutex_unlock(&lock);
} }
/* Publish snapshot cmds to networked clients */ if (local_ss->is_master) {
/* Publish snapshot cmds to slave clients */
u64 oldest_ack_tick = 0; u64 oldest_ack_tick = 0;
for (u64 i = 0; i < ss->num_clients_reserved; ++i) { for (u64 i = 0; i < local_ss->num_clients_reserved; ++i) {
struct sim_client *client = &ss->clients[i]; struct sim_client *client = &local_ss->clients[i];
if (client->valid && client->kind == SIM_CLIENT_KIND_NETSIM) { if (client->valid && client->kind == SIM_CLIENT_KIND_SIM_SLAVE) {
struct temp_arena temp = arena_temp_begin(scratch.arena); struct temp_arena temp = arena_temp_begin(scratch.arena);
if (oldest_ack_tick == 0 || client->ack < oldest_ack_tick) { if (oldest_ack_tick == 0 || client->ack < oldest_ack_tick) {
oldest_ack_tick = client->ack; oldest_ack_tick = client->ack;
} }
struct sim_snapshot *ss0 = sim_snapshot_from_tick(snapshot_store, client->ack); struct sim_snapshot *ss0 = sim_snapshot_from_tick(local_snapshot_store, client->ack);
struct sim_snapshot *ss1 = ss; struct sim_snapshot *ss1 = local_ss;
/* Create & encode snapshot cmd */ /* Create & encode snapshot cmd */
struct sim_cmd snapshot_cmd = ZI; struct sim_cmd snapshot_cmd = ZI;
@ -1832,12 +1895,14 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
snapshot_cmd.snapshot_tick_end = ss1->tick; snapshot_cmd.snapshot_tick_end = ss1->tick;
{ {
struct bitbuff_writer bw = bw_from_bitbuff(&encoder_bitbuff); struct bitbuff_writer bw = bw_from_bitbuff(&encoder_bitbuff);
sim_snapshot_encode(&bw, ss0, ss1, client); sim_snapshot_encode(&bw, client, ss0, ss1);
snapshot_cmd.snapshot_encoded = bw_get_written(temp.arena, &bw); snapshot_cmd.snapshot_encoded = bw_get_written(temp.arena, &bw);
} }
} }
struct sim_cmd_frame snapshot_cmd_frame = ZI; struct sim_cmd_frame snapshot_cmd_frame = ZI;
snapshot_cmd_frame.tick = ss1->tick;
snapshot_cmd_frame.ack = client->ack;
snapshot_cmd_frame.first = &snapshot_cmd; snapshot_cmd_frame.first = &snapshot_cmd;
snapshot_cmd_frame.last = &snapshot_cmd; snapshot_cmd_frame.last = &snapshot_cmd;
@ -1849,8 +1914,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
struct string cmds_msg = ZI; struct string cmds_msg = ZI;
{ {
struct bitbuff_writer bw = bw_from_bitbuff(&encoder_bitbuff); struct bitbuff_writer bw = bw_from_bitbuff(&encoder_bitbuff);
/* FIXME: Ack tick */ sim_cmd_frames_encode(&bw, cmd_frames);
sim_cmd_frames_encode(&bw, cmd_frames, 0);
cmds_msg = bw_get_written(temp.arena, &bw); cmds_msg = bw_get_written(temp.arena, &bw);
} }
@ -1859,17 +1923,62 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
arena_temp_end(temp); arena_temp_end(temp);
} }
} }
} else {
/* Publish user cmd to master client */
for (u64 i = 0; i < local_ss->num_clients_reserved; ++i) {
struct sim_client *client = &local_ss->clients[i];
if (client->valid && client->kind == SIM_CLIENT_KIND_SIM_MASTER) {
struct temp_arena temp = arena_temp_begin(scratch.arena);
user_cmd_frame->ack = remote_snapshot_store->last_tick;
user_cmd_frame->sender_is_local = false;
struct sim_cmd_frame_list l = ZI;
l.first = user_cmd_frame;
l.last = user_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, l);
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 */ /* Send host messages */
host_update(host); host_update(host);
__profframe("Local sim"); __profframe("Local sim");
scratch_end(scratch); {
/* Update network usage stats */
prev_ss = ss; i64 stat_now_ns = sys_time_ns();
G.client_bytes_read.last_second_end = host->bytes_received;
G.client_bytes_sent.last_second_end = host->bytes_sent;
if (stat_now_ns - G.last_second_reset_ns > NS_FROM_SECONDS(1)) {
G.last_second_reset_ns = stat_now_ns;
G.client_bytes_read.last_second = G.client_bytes_read.last_second_end - G.client_bytes_read.last_second_start;
G.client_bytes_sent.last_second = G.client_bytes_sent.last_second_end - G.client_bytes_sent.last_second_start;
G.client_bytes_read.last_second_start = G.client_bytes_read.last_second_end;
G.client_bytes_sent.last_second_start = G.client_bytes_sent.last_second_end;
}
} }
sim_snapshot_store_release(snapshot_store); scratch_end(scratch);
if (local_ss->is_master) {
local_ss_prev = local_ss;
}
}
sim_snapshot_store_release(local_snapshot_store);
bitbuff_release(&encoder_bitbuff); bitbuff_release(&encoder_bitbuff);
host_release(host); host_release(host);
} }