diff --git a/res/noise.dat b/res/noise.dat deleted file mode 100644 index ec3a838f..00000000 --- a/res/noise.dat +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fa44d9037fe9294c0dbc6b01b0b1e10bc4acf1f3c3df9807dd439c3de49f214 -size 8388584 diff --git a/src/app.c b/src/app.c index d3b11c49..b874aaaa 100644 --- a/src/app.c +++ b/src/app.c @@ -322,7 +322,6 @@ void app_entry_point(struct string args_str) struct sock_startup_receipt sock_sr = sock_startup(); struct host_startup_receipt host_sr = host_startup(&sock_sr); struct resource_startup_receipt resource_sr = resource_startup(); - struct rng_startup_receipt rng_sr = rng_startup(&resource_sr); struct renderer_startup_receipt renderer_sr = renderer_startup(&window); struct work_startup_receipt work_sr = work_startup(worker_count); struct asset_cache_startup_receipt asset_cache_sr = asset_cache_startup(&work_sr); @@ -339,7 +338,6 @@ void app_entry_point(struct string args_str) (UNUSED)user_sr; (UNUSED)playback_sr; - (UNUSED)rng_sr; /* Show window */ sys_window_show(&window); diff --git a/src/rng.c b/src/rng.c index 12cc321e..e3723c3d 100644 --- a/src/rng.c +++ b/src/rng.c @@ -1,111 +1,26 @@ #include "rng.h" #include "sys.h" -#include "resource.h" -#include "arena.h" -GLOBAL struct { - struct arena arena; - u64 *noise; - u64 noise_count; -} G = ZI, DEBUG_ALIAS(G, G_rng); - -/* ========================== * - * Generate random number file - * (unused function) - * ========================== */ - -#if 0 -INTERNAL void gen_random_file(struct string path, u32 count) -{ - { - /* Clear file */ - struct sys_file f = sys_file_open_write(path); - sys_file_write(f, STRING(0, 0)); - sys_file_close(f); - } - struct sys_file f = sys_file_open_append(path); - for (u32 i = 0; i < count; ++i) { - u64 rand = rng_rand_u64(); - sys_file_write(f, STRING_FROM_STRUCT(&rand)); - } - sys_file_close(f); -} -#endif - -/* ========================== * - * Startup - * ========================== */ - -struct rng_startup_receipt rng_startup(struct resource_startup_receipt *resource_sr) -{ - (UNUSED)resource_sr; - struct string noise_path = LIT("res/noise.dat"); - if (resource_exists(noise_path)) { - struct resource r = resource_open(noise_path); - G.noise_count = r.data.len / sizeof(*G.noise); - G.arena = arena_alloc(sizeof(u64) * G.noise_count); - G.noise = arena_push_array(&G.arena, u64, G.noise_count); - MEMCPY(G.noise, r.data.text, r.data.len); - resource_close(r); - } else { - sys_panic(LIT("Failed to locate pre-computed noise resource")); - } - return (struct rng_startup_receipt) { 0 }; -} - -/* ========================== * - * Rand - * ========================== */ - -u32 rng_rand_u32(void) +u32 rng_true_u32(void) { u32 v = 0; - sys_rand(STRING_FROM_STRUCT(&v)); + sys_true_rand(STRING_FROM_STRUCT(&v)); return v; } -u64 rng_rand_u64(void) +u64 rng_true_u64(void) { u64 v = 0; - sys_rand(STRING_FROM_STRUCT(&v)); + sys_true_rand(STRING_FROM_STRUCT(&v)); return v; } -f32 rng_rand_f32(f32 range_start, f32 range_end) +f32 rng_true_f32(f32 range_start, f32 range_end) { - return ((f32)rng_rand_u32() / (f32)U32_MAX) * (range_end - range_start) + range_start; + return ((f32)rng_true_u32() / (f32)U32_MAX) * (range_end - range_start) + range_start; } -f64 rng_rand_f64(f64 range_start, f64 range_end) +f64 rng_true_f64(f64 range_start, f64 range_end) { - return ((f64)rng_rand_u64() / (f64)U64_MAX) * (range_end - range_start) + range_start; -} - -/* ========================== * - * Noise - * Functions that return a deterministic pre-computed random number based on the provided seed - * - * NOTE: Noise pattern repeats after period depending on how much noise data exists in noise.dat - * ========================== */ - -/* TODO: Use deterministic prng rather than embedded data */ - -u32 rng_noise_u32(u64 seed) -{ - return (u32)G.noise[seed % G.noise_count]; -} - -u64 rng_noise_u64(u64 seed) -{ - return G.noise[seed % G.noise_count]; -} - -f32 rng_noise_f32(u64 seed, f32 range_start, f32 range_end) -{ - return ((f32)rng_noise_u32(seed) / (f32)U32_MAX) * (range_end - range_start) + range_start; -} - -f32 rng_noise_f64(u64 seed, f64 range_start, f64 range_end) -{ - return ((f64)rng_noise_u64(seed) / (f64)U64_MAX) * (range_end - range_start) + range_start; + return ((f64)rng_true_u64() / (f64)U64_MAX) * (range_end - range_start) + range_start; } diff --git a/src/rng.h b/src/rng.h index 7a2abfc7..2a68a7b4 100644 --- a/src/rng.h +++ b/src/rng.h @@ -1,22 +1,10 @@ #ifndef RNG_H #define RNG_H -struct resource_startup_receipt; - -/* Startup */ -struct rng_startup_receipt { i32 _; }; -struct rng_startup_receipt rng_startup(struct resource_startup_receipt *resource_sr); - /* Rand */ -u32 rng_rand_u32(void); -u64 rng_rand_u64(void); -f32 rng_rand_f32(f32 range_start, f32 range_end); -f64 rng_rand_f64(f64 range_start, f64 range_end); - -/* Noise */ -u32 rng_noise_u32(u64 seed); -u64 rng_noise_u64(u64 seed); -f32 rng_noise_f32(u64 seed, f32 range_start, f32 range_end); -f32 rng_noise_f64(u64 seed, f64 range_start, f64 range_end); +u32 rng_true_u32(void); +u64 rng_true_u64(void); +f32 rng_true_f32(f32 range_start, f32 range_end); +f64 rng_true_f64(f64 range_start, f64 range_end); #endif diff --git a/src/sim_ent.h b/src/sim_ent.h index 2e1062f4..81591383 100644 --- a/src/sim_ent.h +++ b/src/sim_ent.h @@ -381,20 +381,6 @@ INLINE b32 sim_ent_is_valid_and_active(struct sim_ent *ent) return ent->valid && sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE); } -#if 0 -INLINE b32 sim_ent_should_simulate(struct sim_ent *ent) -{ - b32 res = false; - if (sim_ent_is_valid_and_active(ent)) { - res = true; - if (sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_DST) && !sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_PREDICT)) { - res = false; - } - } - return res; -} -#else - INLINE b32 sim_ent_should_predict(struct sim_ent *ent) { return sim_ent_id_eq(ent->predictor, ent->ss->local_client_ent); @@ -415,7 +401,6 @@ INLINE b32 sim_ent_should_simulate(struct sim_ent *ent) return res; } -#endif /* ========================== * * Ent functions * ========================== */ diff --git a/src/sim_step.c b/src/sim_step.c index bbba5535..2fd201b5 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -51,14 +51,15 @@ void sim_accel_reset(struct sim_snapshot *ss, struct sim_accel *accel) /* TODO: Remove this */ -INTERNAL void spawn_test_entities(struct sim_snapshot *world, struct v2 offset) +INTERNAL void spawn_test_entities(struct sim_step_ctx *ctx, struct v2 offset) { + struct sim_snapshot *world = ctx->world; struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID); root->mass_unscaled = F32_INFINITY; root->inertia_unscaled = F32_INFINITY; /* Enemy */ - { + if (ctx->is_master) { struct sim_ent *e = sim_ent_alloc_sync_src(root); struct v2 pos = V2(1, -2); @@ -73,7 +74,7 @@ INTERNAL void spawn_test_entities(struct sim_snapshot *world, struct v2 offset) e->layer = SIM_LAYER_SHOULDERS; sim_ent_enable_prop(e, SIM_ENT_PROP_PHYSICAL_DYNAMIC); - e->mass_unscaled = 10; + e->mass_unscaled = 1; e->inertia_unscaled = 10; e->linear_ground_friction = 250; e->angular_ground_friction = 200; @@ -127,8 +128,9 @@ INTERNAL void spawn_test_entities(struct sim_snapshot *world, struct v2 offset) #endif } -INTERNAL struct sim_ent *spawn_test_player(struct sim_snapshot *world) +INTERNAL struct sim_ent *spawn_test_player(struct sim_step_ctx *ctx) { + struct sim_snapshot *world = ctx->world; struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID); /* Player */ @@ -226,8 +228,9 @@ INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_snapshot *world, st return camera_ent; } -INTERNAL void test_clear_level(struct sim_snapshot *world) +INTERNAL void test_clear_level(struct sim_step_ctx *ctx) { + struct sim_snapshot *world = ctx->world; for (u64 j = 0; j < world->num_ents_reserved; ++j) { struct sim_ent *ent = &world->ents[j]; if (ent->valid) { @@ -296,7 +299,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, st /* Create test blood */ /* TODO: Remove this */ { - struct xform xf = XFORM_TRS(.t = point, .r = rng_rand_f32(0, TAU)); + struct xform xf = XFORM_TRS(.t = point, .r = rng_true_f32(0, TAU)); struct sim_ent *decal = sim_ent_alloc_sync_src(root); decal->sprite = sprite_tag_from_path(LIT("res/graphics/blood.ase")); decal->sprite_tint = RGBA_32_F(1, 1, 1, 0.25f); @@ -305,10 +308,10 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, st f32 perp_range = 0.5; struct v2 linear_velocity = v2_mul(normal, 0.5); - linear_velocity = v2_add(linear_velocity, v2_mul(v2_perp(normal), rng_rand_f32(-perp_range, perp_range))); + linear_velocity = v2_add(linear_velocity, v2_mul(v2_perp(normal), rng_true_f32(-perp_range, perp_range))); f32 angular_velocity_range = 5; - f32 angular_velocity = rng_rand_f32(-angular_velocity_range, angular_velocity_range); + f32 angular_velocity = rng_true_f32(-angular_velocity_range, angular_velocity_range); sim_ent_enable_prop(decal, SIM_ENT_PROP_PHYSICAL_KINEMATIC); sim_ent_set_linear_velocity(decal, linear_velocity); @@ -509,7 +512,6 @@ void sim_step(struct sim_step_ctx *ctx) } } - /* Dereference hovered ent */ client_ent->client_hovered_ent = cmd_ent->cmd_hovered_ent; u32 flags = control->flags; @@ -523,8 +525,8 @@ void sim_step(struct sim_step_ctx *ctx) } } if (flags & SIM_CONTROL_FLAG_CLEAR_ALL) { - if (!(old_control.flags & SIM_CONTROL_FLAG_CLEAR_ALL)) { - test_clear_level(world); + if (is_master && !(old_control.flags & SIM_CONTROL_FLAG_CLEAR_ALL)) { + test_clear_level(ctx); } } if (flags & SIM_CONTROL_FLAG_SPAWN_TEST) { @@ -533,7 +535,7 @@ void sim_step(struct sim_step_ctx *ctx) u32 count = 1; f32 spread = 1; for (u32 j = 0; j < count; ++j) { - spawn_test_entities(world, V2(0, (((f32)j / (f32)count) - 0.5) * spread)); + spawn_test_entities(ctx, V2(0, (((f32)j / (f32)count) - 0.5) * spread)); } } } @@ -554,7 +556,7 @@ void sim_step(struct sim_step_ctx *ctx) /* FIXME: Ents never released when client disconnects */ struct sim_ent *control_ent = sim_ent_from_id(world, ent->client_control_ent); if (!control_ent->valid) { - control_ent = spawn_test_player(world); + control_ent = spawn_test_player(ctx); control_ent->predictor = ent->id; sim_ent_enable_prop(control_ent, SIM_ENT_PROP_CONTROLLED); ent->client_control_ent = control_ent->id; diff --git a/src/sys.h b/src/sys.h index 5f3da107..733f3180 100644 --- a/src/sys.h +++ b/src/sys.h @@ -442,7 +442,7 @@ struct string sys_get_clipboard_text(struct arena *arena); * Util * ========================== */ -void sys_rand(struct string b); +void sys_true_rand(struct string b); u32 sys_num_logical_processors(void); void sys_exit(void); void sys_panic(struct string msg); diff --git a/src/sys_win32.c b/src/sys_win32.c index a0386ec8..26aa12b6 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -1856,7 +1856,7 @@ struct string sys_get_clipboard_text(struct arena *arena) * RNG * ========================== */ -void sys_rand(struct string b) +void sys_true_rand(struct string b) { BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (PUCHAR)b.text, b.len, 0); } diff --git a/src/uid.c b/src/uid.c index db82f763..749df386 100644 --- a/src/uid.c +++ b/src/uid.c @@ -6,7 +6,7 @@ struct uid uid_rand(void) { struct uid res = ZI; - sys_rand(STRING_FROM_STRUCT(&res)); + sys_true_rand(STRING_FROM_STRUCT(&res)); return res; } diff --git a/src/user.c b/src/user.c index f369f33a..0605aed7 100644 --- a/src/user.c +++ b/src/user.c @@ -750,11 +750,10 @@ INTERNAL void user_update(void) i64 frequency_ns = NS_FROM_SECONDS(0.01f); f32 shake = ent->shake; if (shake > 0) { - u64 basis = ent->id.uid.lo; - u64 angle_seed0 = basis + (u64)(G.ss_blended->sim_time_ns / frequency_ns); + u64 angle_seed0 = ent->id.uid.lo + (u64)(G.ss_blended->sim_time_ns / frequency_ns); u64 angle_seed1 = angle_seed0 + 1; - f32 angle0 = rng_noise_f32(angle_seed0, 0, TAU); - f32 angle1 = rng_noise_f32(angle_seed1, 0, TAU); + f32 angle0 = ((f32)mix64(angle_seed0) / (f32)U64_MAX) * TAU; + f32 angle1 = ((f32)mix64(angle_seed1) / (f32)U64_MAX) * TAU; struct v2 vec0 = v2_with_len(v2_from_angle(angle0), shake); /* NOTE: vec1 not completely accurate since shake can change between frames, just a prediction */ @@ -2303,11 +2302,11 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) i64 num_predict_ticks = math_round_to_int64(rtt_tick_ratio) + 2; step_end_tick = step_base_tick + num_predict_ticks; compute_timescale = 1.1; - } else if (cmds_ahead_on_master > 4) { - /* Slow down time to bring sim time closer to master time */ + } else if (cmds_ahead_on_master > 3) { + /* Slow down simulation rate to bring sim time closer to master time */ compute_timescale = 0.9; - } else if (cmds_ahead_on_master < 2) { - /* Speed up time to give master more inputs to work with */ + } else if (cmds_ahead_on_master < 1) { + /* Speed up simulation rate to give master more inputs to work with */ compute_timescale = 1.1; } else { compute_timescale = 1; diff --git a/src/util.h b/src/util.h index e2cb0916..6a9b9419 100644 --- a/src/util.h +++ b/src/util.h @@ -15,8 +15,6 @@ * Hash utils * ========================== */ -/* TODO: Replace with better hash functions */ - /* FNV-1a parameters for different hash sizes: * https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters */ @@ -32,20 +30,22 @@ INLINE u64 hash_fnv64(u64 seed, struct string s) return hash; } -#if 0 -#define HASH_FNV128_BASIS U128(0x6C62272E07BB0142, 0x62B821756295C58D) -INLINE u128 hash_fnv128(u128 seed, struct string s) +/* ========================== * + * Bit mixing + * ========================== */ + +/* Based on Jon Maiga's "mx3" + * (https://jonkagstrom.com/mx3/mx3_rev2.html) + */ + +INLINE u64 mix64(u64 x) { - /* FIXME: Verify MSVC version of 128 is same */ - u128 hash = seed; - for (u64 i = 0; i < s.len; ++i) { - u8 c = (u8)s.text[i]; - hash = u128_xor_u8(hash, c); - hash = u128_mul(hash, U128(0x1000000, 0x000000000000013B)); - } - return hash; + x = (x ^ (x >> 32)) * 0xbea225f9eb34556d; + x = (x ^ (x >> 29)) * 0xbea225f9eb34556d; + x = (x ^ (x >> 32)) * 0xbea225f9eb34556d; + x = (x ^ (x >> 29)); + return x; } -#endif /* ========================== * * Merge sort @@ -119,7 +119,7 @@ INLINE void merge_sort(void *items, u64 item_count, u64 item_size, sort_compare_ /* ========================== * * Fixed Dict * - * Simple fixed bin-count string->value chaining dict for generic use + * Simple fixed-bin-count string -> pointer chaining hash table for generic use * ========================== */ struct fixed_dict_entry {