power_play/src/sim_client.c

179 lines
5.6 KiB
C

#include "sim_client.h"
#include "sim.h"
#include "sim_snapshot.h"
#include "host.h"
#include "arena.h"
#include "util.h"
#include "arena.h"
/* ========================== *
* Client
* ========================== */
INTERNAL u64 hash_from_channel_id(struct host_channel_id channel_id)
{
return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&channel_id));
}
struct sim_client *sim_client_from_handle(struct sim_snapshot *ss, struct sim_client_handle handle)
{
if (handle.gen != 0 && handle.idx < ss->num_clients_reserved) {
struct sim_client *client = &ss->clients[handle.idx];
if (client->handle.gen == handle.gen) {
return client;
}
}
return sim_client_nil();
}
struct sim_client *sim_client_from_channel_id(struct sim_snapshot *ss, struct host_channel_id channel_id)
{
struct sim_client *res = sim_client_nil();
u64 channel_hash = hash_from_channel_id(channel_id);
u64 bucket_index = channel_hash % ss->num_client_lookup_buckets;
struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index];
for (struct sim_client *client = sim_client_from_handle(ss, bucket->first); client->valid; client = sim_client_from_handle(ss, client->next_in_bucket)) {
if (client->channel_hash == channel_hash) {
res = client;
break;
}
}
return res;
}
struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id, enum sim_client_kind kind)
{
struct sim_client_handle handle = ZI;
struct sim_client *client = sim_client_from_handle(ss, ss->first_free_client);
if (client->valid) {
ss->first_free_client = client->next_free;
handle = client->handle;
++handle.gen;
} else {
client = arena_push(&ss->clients_arena, struct sim_client);
handle.gen = 1;
handle.idx = ss->num_clients_reserved;
++ss->num_clients_reserved;
}
++ss->num_clients_allocated;
*client = *sim_client_nil();
client->valid = true;
client->kind = kind;
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 */
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;
}
}
return client;
}
void sim_client_release(struct sim_client *client)
{
struct sim_snapshot *ss = client->ss;
client->valid = false;
++client->handle.gen;
client->next_free = ss->first_free_client;
ss->first_free_client = client->handle;
--ss->num_clients_allocated;
/* Remove from channel lookup */
if (client->kind == SIM_CLIENT_KIND_NETSIM) {
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 *prev = sim_client_from_handle(ss, client->prev_in_bucket);
struct sim_client *next = sim_client_from_handle(ss, client->next_in_bucket);
if (prev->valid) {
prev->next_in_bucket = next->handle;
} else {
bucket->first = next->handle;
}
if (next->valid) {
next->prev_in_bucket = prev->handle;
} else {
bucket->last = prev->handle;
}
}
}
/* ========================== *
* Lerp
* ========================== */
void sim_client_lerp(struct sim_client *c, struct sim_client *c0, struct sim_client *c1, f64 blend)
{
if (c0->valid && c1->valid && c0->handle.gen == c1->handle.gen) {
c0->cursor_pos = v2_lerp(c0->cursor_pos, c1->cursor_pos, blend);
c->control.move = v2_lerp(c0->control.move, c1->control.move, blend);
c->control.focus = v2_lerp(c0->control.focus, c1->control.focus, blend);
}
}
/* ========================== *
* Encode
* ========================== */
void sim_client_encode(struct bitbuff_writer *bw, struct sim_client *c0, struct sim_client *c1)
{
struct sim_snapshot *ss = c1->ss;
/* TODO: Granular delta encoding */
u64 pos = 0;
c1->ss = c0->ss;
while (pos < sizeof(*c1)) {
u64 chunk_size = min_u64(pos + 8, sizeof(*c1)) - pos;
u8 *chunk0 = (u8 *)c0 + pos;
u8 *chunk1 = (u8 *)c1 + pos;
if (MEMEQ(chunk0, chunk1, chunk_size)) {
bw_write_bit(bw, 0);
} else {
bw_write_bit(bw, 1);
u64 bits = 0;
MEMCPY(&bits, chunk1, chunk_size);
bw_write_ubits(bw, bits, 64);
}
pos += 8;
}
c1->ss = ss;
}
/* ========================== *
* Decode
* ========================== */
void sim_client_decode(struct bitbuff_reader *br, struct sim_client *e)
{
struct sim_snapshot *ss = e->ss;
u64 pos = 0;
while (pos < sizeof(*e)) {
u8 *chunk = (u8 *)e + pos;
if (br_read_bit(br)) {
u64 chunk_size = min_u64(pos + 8, sizeof(*e)) - pos;
u64 bits = br_read_ubits(br, 64);
MEMCPY(chunk, &bits, chunk_size);
}
pos += 8;
}
e->ss = ss;
}