rename 'game' -> 'sim'
This commit is contained in:
parent
b9ec028bfa
commit
4cbc6b6d59
10
src/app.c
10
src/app.c
@ -5,7 +5,7 @@
|
||||
#include "sys.h"
|
||||
#include "work.h"
|
||||
#include "user.h"
|
||||
#include "game.h"
|
||||
#include "sim.h"
|
||||
#include "playback.h"
|
||||
#include "log.h"
|
||||
#include "resource.h"
|
||||
@ -139,8 +139,8 @@ void app_entry_point(void)
|
||||
{
|
||||
/* FIXME: Switch this on to utilize all cores. Only decreasing worker count for testing purposes. */
|
||||
#if !PROFILING && !RTC
|
||||
/* 1. User thread, Input thread
|
||||
* 2. Game thread
|
||||
/* 1. User thread
|
||||
* 2. Sim thread
|
||||
* 3. Playback thread
|
||||
*/
|
||||
u32 num_reserved_cores = 3;
|
||||
@ -223,8 +223,8 @@ void app_entry_point(void)
|
||||
struct sound_startup_receipt sound_sr = sound_startup(&work_sr, &asset_cache_sr, &resource_sr);
|
||||
struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr);
|
||||
struct phys_startup_receipt phys_sr = phys_startup();
|
||||
struct game_startup_receipt game_sr = game_startup(&mixer_sr, &sprite_sr, &sound_sr, &phys_sr, &host_sr);
|
||||
struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &game_sr, &asset_cache_sr, &mixer_sr, &host_sr, &window);
|
||||
struct sim_startup_receipt sim_sr = sim_startup(&mixer_sr, &sprite_sr, &sound_sr, &phys_sr, &host_sr);
|
||||
struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &sim_sr, &asset_cache_sr, &mixer_sr, &host_sr, &window);
|
||||
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
|
||||
|
||||
(UNUSED)user_sr;
|
||||
|
||||
30
src/config.h
30
src/config.h
@ -34,26 +34,26 @@
|
||||
#define SPACE_CELL_SIZE 1.0f
|
||||
|
||||
|
||||
#define GAME_FPS 50.0
|
||||
#define GAME_TIMESCALE 1
|
||||
#define SIM_FPS 50.0
|
||||
#define SIM_TIMESCALE 1
|
||||
|
||||
#define GAME_PHYSICS_SUBSTEPS 4
|
||||
#define GAME_PHYSICS_ENABLE_WARM_STARTING 1
|
||||
#define GAME_PHYSICS_ENABLE_RELAXATION 1
|
||||
#define GAME_PHYSICS_ENABLE_TOI 1
|
||||
#define SIM_PHYSICS_SUBSTEPS 4
|
||||
#define SIM_PHYSICS_ENABLE_WARM_STARTING 1
|
||||
#define SIM_PHYSICS_ENABLE_RELAXATION 1
|
||||
#define SIM_PHYSICS_ENABLE_TOI 1
|
||||
|
||||
#define GAME_PHYSICS_ENABLE_COLLISION 1
|
||||
#define GAME_SPAWN_TESTENT 0
|
||||
#define GAME_PLAYER_AIM 1
|
||||
#define SIM_PHYSICS_ENABLE_COLLISION 1
|
||||
#define SIM_SPAWN_TESTENT 0
|
||||
#define SIM_PLAYER_AIM 1
|
||||
|
||||
//#define GAME_MAX_LINEAR_VELOCITY 500
|
||||
//#define GAME_MAX_ANGULAR_VELOCITY (TAU * 20)
|
||||
#define GAME_MAX_LINEAR_VELOCITY F32_INFINITY
|
||||
#define GAME_MAX_ANGULAR_VELOCITY F32_INFINITY
|
||||
//#define SIM_MAX_LINEAR_VELOCITY 500
|
||||
//#define SIM_MAX_ANGULAR_VELOCITY (TAU * 20)
|
||||
#define SIM_MAX_LINEAR_VELOCITY F32_INFINITY
|
||||
#define SIM_MAX_ANGULAR_VELOCITY F32_INFINITY
|
||||
|
||||
/* How many ticks back in time should the user blend between?
|
||||
* <Delay ms> = <USER_INTERP_OFFSET_TICK_RATIO> * <Game tick rate>
|
||||
* E.g: At 1.5, the user thread will render 75ms back in time (if game thread runs at 50FPS)
|
||||
* <Delay ms> = <USER_INTERP_OFFSET_TICK_RATIO> * <Sim tick rate>
|
||||
* E.g: At 1.5, the user thread will render 75ms back in time (if sim thread runs at 50FPS)
|
||||
*/
|
||||
#define USER_INTERP_OFFSET_TICK_RATIO 1.1
|
||||
#define USER_INTERP_ENABLED 1
|
||||
|
||||
@ -391,8 +391,8 @@ void entity_set_xform(struct entity *ent, struct xform xf);
|
||||
void entity_set_local_xform(struct entity *ent, struct xform xf);
|
||||
|
||||
/* Movement */
|
||||
INLINE void entity_set_linear_velocity(struct entity *ent, struct v2 velocity) { ent->linear_velocity = v2_clamp_len(velocity, GAME_MAX_LINEAR_VELOCITY); }
|
||||
INLINE void entity_set_angular_velocity(struct entity *ent, f32 velocity) { ent->angular_velocity = clamp_f32(velocity, -GAME_MAX_ANGULAR_VELOCITY, GAME_MAX_ANGULAR_VELOCITY); }
|
||||
INLINE void entity_set_linear_velocity(struct entity *ent, struct v2 velocity) { ent->linear_velocity = v2_clamp_len(velocity, SIM_MAX_LINEAR_VELOCITY); }
|
||||
INLINE void entity_set_angular_velocity(struct entity *ent, f32 velocity) { ent->angular_velocity = clamp_f32(velocity, -SIM_MAX_ANGULAR_VELOCITY, SIM_MAX_ANGULAR_VELOCITY); }
|
||||
void entity_apply_linear_impulse(struct entity *ent, struct v2 impulse, struct v2 world_point);
|
||||
void entity_apply_linear_impulse_to_center(struct entity *ent, struct v2 impulse);
|
||||
void entity_apply_force_to_center(struct entity *ent, struct v2 force);
|
||||
|
||||
135
src/game.h
135
src/game.h
@ -1,135 +0,0 @@
|
||||
#ifndef GAME_H
|
||||
#define GAME_H
|
||||
|
||||
#include "host.h"
|
||||
|
||||
struct world;
|
||||
struct mixer_startup_receipt;
|
||||
struct sprite_startup_receipt;
|
||||
struct sound_startup_receipt;
|
||||
struct phys_startup_receipt;
|
||||
struct host_startup_receipt;
|
||||
|
||||
/* Absolute layers */
|
||||
#define GAME_LAYER_FLOOR_DECALS -300
|
||||
#define GAME_LAYER_BULLETS -200
|
||||
#define GAME_LAYER_TRACERS -100
|
||||
#define GAME_LAYER_SHOULDERS 0
|
||||
|
||||
/* Relative layers */
|
||||
#define GAME_LAYER_RELATIVE_DEFAULT 0
|
||||
#define GAME_LAYER_RELATIVE_WEAPON 1
|
||||
|
||||
struct game_startup_receipt { i32 _; };
|
||||
struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr,
|
||||
struct sprite_startup_receipt *sheet_sr,
|
||||
struct sound_startup_receipt *sound_sr,
|
||||
struct phys_startup_receipt *phys_sr,
|
||||
struct host_startup_receipt *host_sr);
|
||||
|
||||
|
||||
/* ========================== *
|
||||
* Game cmd
|
||||
* ========================== */
|
||||
|
||||
enum game_cmd_state {
|
||||
GAME_CMD_STATE_STOP = -1,
|
||||
GAME_CMD_STATE_NO_CHANGE = 0,
|
||||
GAME_CMD_STATE_START = 1
|
||||
};
|
||||
|
||||
enum game_cmd_kind {
|
||||
GAME_CMD_KIND_NONE,
|
||||
|
||||
GAME_CMD_KIND_PLAYER_MOVE,
|
||||
GAME_CMD_KIND_PLAYER_FIRE,
|
||||
|
||||
GAME_CMD_KIND_CLIENT_CONNECT,
|
||||
GAME_CMD_KIND_CLIENT_DISCONNECT,
|
||||
|
||||
/* Testing */
|
||||
GAME_CMD_KIND_CLEAR_ALL,
|
||||
GAME_CMD_KIND_SPAWN_TEST,
|
||||
GAME_CMD_KIND_PAUSE,
|
||||
GAME_CMD_KIND_STEP,
|
||||
GAME_CMD_KIND_DRAG_OBJECT,
|
||||
GAME_CMD_KIND_CURSOR_MOVE,
|
||||
|
||||
GAME_CMD_KIND_COUNT
|
||||
};
|
||||
|
||||
struct game_cmd {
|
||||
enum game_cmd_kind kind;
|
||||
enum game_cmd_state state;
|
||||
struct host_channel_id channel_id;
|
||||
|
||||
/* GAME_CMD_KIND_PLAYER_MOVE */
|
||||
struct v2 move_dir;
|
||||
struct v2 aim_dir;
|
||||
|
||||
/* GAME_CMD_KIND_CURSOR_MOVE */
|
||||
struct v2 cursor_pos;
|
||||
|
||||
/* GAME_CMD_KIND_PLAYER_DISCONNECT */
|
||||
struct string disconnect_reason;
|
||||
|
||||
#if RTC
|
||||
u32 collider_gjk_steps;
|
||||
#endif
|
||||
|
||||
struct game_cmd *next;
|
||||
};
|
||||
|
||||
struct game_cmd_list {
|
||||
struct game_cmd *first;
|
||||
struct game_cmd *last;
|
||||
};
|
||||
|
||||
struct string game_string_from_cmds(struct arena *arena, struct game_cmd_list cmds);
|
||||
void game_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_cmd_list *cmds_out);
|
||||
|
||||
/* ========================== *
|
||||
* Game event
|
||||
* ========================== */
|
||||
|
||||
enum game_event_kind {
|
||||
GAME_EVENT_KIND_NONE,
|
||||
|
||||
GAME_EVENT_KIND_CONNECT,
|
||||
GAME_EVENT_KIND_DISCONNECT,
|
||||
GAME_EVENT_KIND_SNAPSHOT_FULL,
|
||||
|
||||
//GAME_EVENT_KIND_ENTITY_UPDATE,
|
||||
//GAME_EVENT_KIND_ENTITY_CREATE,
|
||||
//GAME_EVENT_KIND_ENTITY_DESTROY
|
||||
};
|
||||
|
||||
struct game_event {
|
||||
enum game_event_kind kind;
|
||||
struct host_channel_id channel_id;
|
||||
|
||||
struct string snapshot_data;
|
||||
struct string disconnect_reason;
|
||||
|
||||
//struct entity_handle entity;
|
||||
//struct string update_data;
|
||||
|
||||
struct game_event *next;
|
||||
};
|
||||
|
||||
struct game_event_list {
|
||||
struct game_event *first;
|
||||
struct game_event *last;
|
||||
};
|
||||
|
||||
struct string game_string_from_events(struct arena *arena, struct game_event_list events);
|
||||
void game_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_event_list *events_out);
|
||||
|
||||
/* ========================== *
|
||||
* Snapshot
|
||||
* ========================== */
|
||||
|
||||
struct string game_string_from_tick(struct arena *arena, struct world *tick);
|
||||
void game_tick_from_string(struct string str, struct world *tick_out);
|
||||
|
||||
#endif
|
||||
20
src/phys.c
20
src/phys.c
@ -19,7 +19,7 @@ GLOBAL struct {
|
||||
struct phys_startup_receipt phys_startup(void)
|
||||
{
|
||||
/* Initialize constants */
|
||||
const f32 substep_dt = (1.f / ((f32)GAME_FPS * (f32)GAME_PHYSICS_SUBSTEPS));
|
||||
const f32 substep_dt = (1.f / ((f32)SIM_FPS * (f32)SIM_PHYSICS_SUBSTEPS));
|
||||
|
||||
const f32 contact_frequency = (1.f / substep_dt) / 8.f;
|
||||
const f32 contact_damping_ratio = 10;
|
||||
@ -354,7 +354,7 @@ void phys_prepare_contacts(struct phys_ctx *ctx, u64 phys_iteration)
|
||||
contact->inv_tangent_mass = k > 0.0f ? 1.0f / k : 0.0f;
|
||||
}
|
||||
|
||||
#if !GAME_PHYSICS_ENABLE_WARM_STARTING
|
||||
#if !SIM_PHYSICS_ENABLE_WARM_STARTING
|
||||
contact->normal_impulse = 0;
|
||||
contact->tangent_impulse = 0;
|
||||
#endif
|
||||
@ -646,7 +646,7 @@ void phys_prepare_motor_joints(struct phys_ctx *ctx)
|
||||
|
||||
joint->angular_mass = 1.f / (inv_i0 + inv_i1);
|
||||
|
||||
#if !GAME_PHYSICS_ENABLE_WARM_STARTING
|
||||
#if !SIM_PHYSICS_ENABLE_WARM_STARTING
|
||||
joint->linear_impulse = V2(0, 0);
|
||||
joint->angular_impulse = 0;
|
||||
#endif
|
||||
@ -874,7 +874,7 @@ void phys_prepare_mouse_joints(struct phys_ctx *ctx)
|
||||
linear_mass_xf.by.y = inv_m + inv_i * vcp.x * vcp.x;
|
||||
joint->linear_mass_xf = xform_invert(linear_mass_xf);
|
||||
|
||||
#if !GAME_PHYSICS_ENABLE_WARM_STARTING
|
||||
#if !SIM_PHYSICS_ENABLE_WARM_STARTING
|
||||
joint->linear_impulse = V2(0, 0);
|
||||
joint->angular_impulse = 0;
|
||||
#endif
|
||||
@ -1150,7 +1150,7 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_phys_iteration)
|
||||
/* TOI */
|
||||
f32 step_dt = remaining_dt;
|
||||
{
|
||||
#if GAME_PHYSICS_ENABLE_TOI
|
||||
#if SIM_PHYSICS_ENABLE_TOI
|
||||
const f32 min_toi = 0.000001f;
|
||||
const f32 tolerance = 0.0001f;
|
||||
const u32 max_iterations = 16;
|
||||
@ -1175,19 +1175,19 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_phys_iteration)
|
||||
ctx->pre_solve_callback(collision_data);
|
||||
}
|
||||
|
||||
f32 substep_dt = step_dt / GAME_PHYSICS_SUBSTEPS;
|
||||
for (u32 i = 0; i < GAME_PHYSICS_SUBSTEPS; ++i) {
|
||||
f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS;
|
||||
for (u32 i = 0; i < SIM_PHYSICS_SUBSTEPS; ++i) {
|
||||
__profscope(substep);
|
||||
|
||||
/* Warm start */
|
||||
#if GAME_PHYSICS_ENABLE_WARM_STARTING
|
||||
#if SIM_PHYSICS_ENABLE_WARM_STARTING
|
||||
phys_warm_start_contacts(ctx);
|
||||
phys_warm_start_motor_joints(ctx);
|
||||
phys_warm_start_mouse_joints(ctx);
|
||||
#endif
|
||||
|
||||
/* Solve */
|
||||
#if GAME_PHYSICS_ENABLE_COLLISION
|
||||
#if SIM_PHYSICS_ENABLE_COLLISION
|
||||
phys_solve_contacts(ctx, substep_dt, true);
|
||||
#endif
|
||||
phys_solve_motor_joints(ctx, substep_dt);
|
||||
@ -1197,7 +1197,7 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_phys_iteration)
|
||||
phys_integrate_velocities(ctx, substep_dt);
|
||||
|
||||
/* Relaxation solve */
|
||||
#if GAME_PHYSICS_ENABLE_COLLISION && GAME_PHYSICS_ENABLE_RELAXATION
|
||||
#if SIM_PHYSICS_ENABLE_COLLISION && SIM_PHYSICS_ENABLE_RELAXATION
|
||||
phys_solve_contacts(ctx, substep_dt, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include "game.h"
|
||||
#include "sim.h"
|
||||
#include "sys.h"
|
||||
#include "util.h"
|
||||
#include "world.h"
|
||||
@ -19,8 +19,8 @@
|
||||
#include "host.h"
|
||||
|
||||
GLOBAL struct {
|
||||
struct atomic_i32 game_thread_shutdown;
|
||||
struct sys_thread game_thread;
|
||||
struct atomic_i32 sim_thread_shutdown;
|
||||
struct sys_thread sim_thread;
|
||||
|
||||
u64 last_phys_iteration;
|
||||
|
||||
@ -47,17 +47,17 @@ GLOBAL struct {
|
||||
|
||||
/* Tick */
|
||||
struct world tick;
|
||||
} G = ZI, DEBUG_ALIAS(G, G_game);
|
||||
} G = ZI, DEBUG_ALIAS(G, G_sim);
|
||||
|
||||
/* ========================== *
|
||||
* Startup
|
||||
* ========================== */
|
||||
|
||||
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(game_shutdown);
|
||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg);
|
||||
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sim_shutdown);
|
||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg);
|
||||
INTERNAL void reset_world(void);
|
||||
|
||||
struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr,
|
||||
struct sim_startup_receipt sim_startup(struct mixer_startup_receipt *mixer_sr,
|
||||
struct sprite_startup_receipt *sheet_sr,
|
||||
struct sound_startup_receipt *sound_sr,
|
||||
struct phys_startup_receipt *phys_sr,
|
||||
@ -77,17 +77,17 @@ struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr,
|
||||
/* Initialize empty world */
|
||||
reset_world();
|
||||
|
||||
G.game_thread = sys_thread_alloc(&game_thread_entry_point, NULL, LIT("[P2] Game thread"));
|
||||
app_register_exit_callback(&game_shutdown);
|
||||
G.sim_thread = sys_thread_alloc(&sim_thread_entry_point, NULL, LIT("[P2] Sim thread"));
|
||||
app_register_exit_callback(&sim_shutdown);
|
||||
|
||||
return (struct game_startup_receipt) { 0 };
|
||||
return (struct sim_startup_receipt) { 0 };
|
||||
}
|
||||
|
||||
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(game_shutdown)
|
||||
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sim_shutdown)
|
||||
{
|
||||
__prof;
|
||||
atomic_i32_eval_exchange(&G.game_thread_shutdown, true);
|
||||
sys_thread_wait_release(&G.game_thread);
|
||||
atomic_i32_eval_exchange(&G.sim_thread_shutdown, true);
|
||||
sys_thread_wait_release(&G.sim_thread);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
@ -116,7 +116,7 @@ INTERNAL void reset_world(void)
|
||||
|
||||
/* Re-create world */
|
||||
world_alloc(&G.tick);
|
||||
G.tick.timescale = GAME_TIMESCALE;
|
||||
G.tick.timescale = SIM_TIMESCALE;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
@ -174,7 +174,7 @@ INTERNAL void spawn_test_entities(void)
|
||||
//e->sprite_span_name = LIT("idle.unarmed");
|
||||
//e->sprite_span_name = LIT("idle.one_handed");
|
||||
e->sprite_span_name = LIT("idle.two_handed");
|
||||
e->layer = GAME_LAYER_SHOULDERS;
|
||||
e->layer = SIM_LAYER_SHOULDERS;
|
||||
|
||||
struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size);
|
||||
//xf.bx.y = -1.f;
|
||||
@ -207,7 +207,7 @@ INTERNAL void spawn_test_entities(void)
|
||||
|
||||
e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase"));
|
||||
e->sprite_collider_slice = LIT("shape");
|
||||
e->layer = GAME_LAYER_SHOULDERS;
|
||||
e->layer = SIM_LAYER_SHOULDERS;
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_PHYSICAL_DYNAMIC);
|
||||
e->mass_unscaled = 10;
|
||||
@ -230,7 +230,7 @@ INTERNAL void spawn_test_entities(void)
|
||||
|
||||
e->sprite = sprite_tag_from_path(LIT("res/graphics/box.ase"));
|
||||
e->sprite_collider_slice = LIT("shape");
|
||||
e->layer = GAME_LAYER_SHOULDERS;
|
||||
e->layer = SIM_LAYER_SHOULDERS;
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_PHYSICAL_DYNAMIC);
|
||||
e->mass_unscaled = 100;
|
||||
@ -253,7 +253,7 @@ INTERNAL void spawn_test_entities(void)
|
||||
|
||||
e->sprite = sprite_tag_from_path(LIT("res/graphics/bullet.ase"));
|
||||
e->sprite_collider_slice = LIT("shape");
|
||||
e->layer = GAME_LAYER_SHOULDERS;
|
||||
e->layer = SIM_LAYER_SHOULDERS;
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_PHYSICAL_DYNAMIC);
|
||||
e->mass_unscaled = 0.5;
|
||||
@ -269,7 +269,7 @@ INTERNAL void spawn_test_entities(void)
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_ATTACHED);
|
||||
e->attach_slice = LIT("attach.wep");
|
||||
e->layer = GAME_LAYER_RELATIVE_WEAPON;
|
||||
e->layer = SIM_LAYER_RELATIVE_WEAPON;
|
||||
|
||||
entity_enable_prop(e, ENTITY_PROP_WEAPON);
|
||||
//e->trigger_delay = 1.0f / 10.0f;
|
||||
@ -406,7 +406,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array)
|
||||
struct entity *decal = entity_alloc(root);
|
||||
decal->sprite = sprite_tag_from_path(LIT("res/graphics/blood.ase"));
|
||||
decal->sprite_tint = RGBA_32_F(1, 1, 1, 0.25f);
|
||||
decal->layer = GAME_LAYER_FLOOR_DECALS;
|
||||
decal->layer = SIM_LAYER_FLOOR_DECALS;
|
||||
entity_set_xform(decal, xf);
|
||||
|
||||
f32 perp_range = 0.5;
|
||||
@ -433,7 +433,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array)
|
||||
* Update
|
||||
* ========================== */
|
||||
|
||||
INTERNAL void game_update(void)
|
||||
INTERNAL void sim_update(void)
|
||||
{
|
||||
__prof;
|
||||
|
||||
@ -456,7 +456,7 @@ INTERNAL void game_update(void)
|
||||
|
||||
++G.tick.tick_id;
|
||||
|
||||
G.tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, (1.0 / GAME_FPS) * G.tick.timescale));
|
||||
G.tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, (1.0 / SIM_FPS) * G.tick.timescale));
|
||||
G.tick.time_ns += G.tick.dt_ns;
|
||||
|
||||
f64 dt = SECONDS_FROM_NS(G.tick.dt_ns);
|
||||
@ -525,48 +525,48 @@ INTERNAL void game_update(void)
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Process host events into game cmds
|
||||
* Process host events into sim cmds
|
||||
* ========================== */
|
||||
|
||||
|
||||
struct game_cmd_list game_cmds = ZI;
|
||||
struct sim_cmd_list sim_cmds = ZI;
|
||||
{
|
||||
struct host_event_array host_events = host_pop_events(scratch.arena, G.host);
|
||||
game_cmds_from_host_events(scratch.arena, host_events, &game_cmds);
|
||||
sim_cmds_from_host_events(scratch.arena, host_events, &sim_cmds);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Process game cmds
|
||||
* Process sim cmds
|
||||
* ========================== */
|
||||
|
||||
for (struct game_cmd *cmd = game_cmds.first; cmd; cmd = cmd->next) {
|
||||
enum game_cmd_kind kind = cmd->kind;
|
||||
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;
|
||||
|
||||
struct client *client = client_from_channel_id(G.client_store, channel_id);
|
||||
if (client->valid || host_channel_id_is_nil(channel_id)) {
|
||||
switch (kind) {
|
||||
/* Cursor */
|
||||
case GAME_CMD_KIND_CURSOR_MOVE:
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
G.user_cursor = cmd->cursor_pos;
|
||||
} break;
|
||||
|
||||
/* Clear level */
|
||||
case GAME_CMD_KIND_CLEAR_ALL:
|
||||
case SIM_CMD_KIND_CLEAR_ALL:
|
||||
{
|
||||
G.should_reset_level = true;
|
||||
} break;
|
||||
|
||||
/* Spawn test */
|
||||
case GAME_CMD_KIND_SPAWN_TEST:
|
||||
case SIM_CMD_KIND_SPAWN_TEST:
|
||||
{
|
||||
logf_info("Spawning (test)");
|
||||
spawn_test_entities();
|
||||
} break;
|
||||
|
||||
/* Disconnect client */
|
||||
case GAME_CMD_KIND_CLIENT_DISCONNECT:
|
||||
case SIM_CMD_KIND_CLIENT_DISCONNECT:
|
||||
{
|
||||
if (client->valid) {
|
||||
struct entity *client_ent = entity_from_handle(entity_store, client->ent);
|
||||
@ -581,7 +581,7 @@ INTERNAL void game_update(void)
|
||||
|
||||
default: break;
|
||||
};
|
||||
} else if (kind == GAME_CMD_KIND_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id) && !client->valid) {
|
||||
} else if (kind == SIM_CMD_KIND_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id) && !client->valid) {
|
||||
/* Connect client */
|
||||
client = client_alloc(G.client_store, channel_id);
|
||||
struct entity *client_ent = entity_alloc(root);
|
||||
@ -724,21 +724,21 @@ INTERNAL void game_update(void)
|
||||
struct v2 focus = ent->control.focus;
|
||||
b32 firing = entity_has_prop(ent, ENTITY_PROP_TRIGGERING_EQUIPPED);
|
||||
|
||||
for (struct game_cmd *cmd = game_cmds.first; cmd; cmd = cmd->next) {
|
||||
b32 start = cmd->state == GAME_CMD_STATE_START;
|
||||
b32 stop = cmd->state == GAME_CMD_STATE_STOP;
|
||||
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
|
||||
b32 start = cmd->state == SIM_CMD_STATE_START;
|
||||
b32 stop = cmd->state == SIM_CMD_STATE_STOP;
|
||||
|
||||
/* TODO: Combine movement from multiple inputs? E.G. a sudden
|
||||
* start and immediate stop cmd should still move the player a
|
||||
* tad. */
|
||||
switch (cmd->kind) {
|
||||
case GAME_CMD_KIND_PLAYER_MOVE:
|
||||
case SIM_CMD_KIND_PLAYER_MOVE:
|
||||
{
|
||||
move = cmd->move_dir;
|
||||
focus = cmd->aim_dir;
|
||||
} break;
|
||||
|
||||
case GAME_CMD_KIND_PLAYER_FIRE:
|
||||
case SIM_CMD_KIND_PLAYER_FIRE:
|
||||
{
|
||||
if (start) {
|
||||
firing = true;
|
||||
@ -871,7 +871,7 @@ INTERNAL void game_update(void)
|
||||
bullet->bullet_knockback = 10;
|
||||
bullet->mass_unscaled = 0.04f;
|
||||
bullet->inertia_unscaled = 0.00001f;
|
||||
bullet->layer = GAME_LAYER_BULLETS;
|
||||
bullet->layer = SIM_LAYER_BULLETS;
|
||||
|
||||
#if 1
|
||||
/* Point collider */
|
||||
@ -890,7 +890,7 @@ INTERNAL void game_update(void)
|
||||
{
|
||||
struct entity *tracer = entity_alloc(root);
|
||||
tracer->tracer_fade_duration = 0.025f;
|
||||
tracer->layer = GAME_LAYER_TRACERS;
|
||||
tracer->layer = SIM_LAYER_TRACERS;
|
||||
entity_enable_prop(tracer, ENTITY_PROP_TRACER);
|
||||
|
||||
bullet->bullet_tracer = tracer->handle;
|
||||
@ -947,7 +947,7 @@ INTERNAL void game_update(void)
|
||||
* Create forces from control focus (aim)
|
||||
* ========================== */
|
||||
|
||||
#if GAME_PLAYER_AIM
|
||||
#if SIM_PLAYER_AIM
|
||||
for (u64 entity_index = 0; entity_index < entity_store->num_reserved; ++entity_index) {
|
||||
struct entity *ent = &entity_store->entities[entity_index];
|
||||
if (!entity_is_valid_and_active(ent)) continue;
|
||||
@ -1082,11 +1082,11 @@ INTERNAL void game_update(void)
|
||||
|
||||
/* Mouse drag */
|
||||
ctx.dbg_cursor_pos = G.user_cursor;
|
||||
for (struct game_cmd *cmd = game_cmds.first; cmd; cmd = cmd->next) {
|
||||
if (cmd->kind == GAME_CMD_KIND_DRAG_OBJECT) {
|
||||
if (cmd->state == GAME_CMD_STATE_START) {
|
||||
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
|
||||
if (cmd->kind == SIM_CMD_KIND_DRAG_OBJECT) {
|
||||
if (cmd->state == SIM_CMD_STATE_START) {
|
||||
ctx.dbg_start_dragging = true;
|
||||
} else if (cmd->state == GAME_CMD_STATE_STOP) {
|
||||
} else if (cmd->state == SIM_CMD_STATE_STOP) {
|
||||
ctx.dbg_stop_dragging = true;
|
||||
}
|
||||
}
|
||||
@ -1279,7 +1279,7 @@ INTERNAL void game_update(void)
|
||||
* Update sound emitters
|
||||
* ========================== */
|
||||
|
||||
/* TODO: Sound entities should be created by game thread, but played by the
|
||||
/* TODO: Sound entities should be created by sim thread, but played by the
|
||||
* user thread. This is so sounds play at the correct time on the user
|
||||
* thread regardless of interp delay. */
|
||||
|
||||
@ -1318,14 +1318,14 @@ INTERNAL void game_update(void)
|
||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
/* TODO: Not like this */
|
||||
struct game_event snapshot_event = ZI;
|
||||
snapshot_event.kind = GAME_EVENT_KIND_SNAPSHOT_FULL;
|
||||
snapshot_event.snapshot_data = game_string_from_tick(temp.arena, &G.tick);
|
||||
struct sim_event snapshot_event = ZI;
|
||||
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT_FULL;
|
||||
snapshot_event.snapshot_data = sim_string_from_tick(temp.arena, &G.tick);
|
||||
|
||||
struct game_event_list l = ZI;
|
||||
struct sim_event_list l = ZI;
|
||||
l.first = &snapshot_event;
|
||||
l.last = &snapshot_event;
|
||||
struct string msg = game_string_from_events(temp.arena, l);
|
||||
struct string msg = sim_string_from_events(temp.arena, l);
|
||||
|
||||
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, msg, 0);
|
||||
|
||||
@ -1333,7 +1333,7 @@ INTERNAL void game_update(void)
|
||||
}
|
||||
|
||||
host_update(G.host);
|
||||
__profframe("Game");
|
||||
__profframe("Sim");
|
||||
|
||||
/* ========================== *
|
||||
* End frame cache scopes
|
||||
@ -1345,15 +1345,15 @@ INTERNAL void game_update(void)
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Game cmd
|
||||
* Sim cmd
|
||||
* ========================== */
|
||||
|
||||
struct string game_string_from_cmds(struct arena *arena, struct game_cmd_list cmds)
|
||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
|
||||
for (struct game_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
||||
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||
u64 start = bw_pos(&bw);
|
||||
|
||||
@ -1365,13 +1365,13 @@ struct string game_string_from_cmds(struct arena *arena, struct game_cmd_list cm
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case GAME_CMD_KIND_PLAYER_MOVE:
|
||||
case SIM_CMD_KIND_PLAYER_MOVE:
|
||||
{
|
||||
bw_write_v2(&bw, cmd->move_dir);
|
||||
bw_write_v2(&bw, cmd->aim_dir);
|
||||
} break;
|
||||
|
||||
case GAME_CMD_KIND_CURSOR_MOVE:
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
bw_write_v2(&bw, cmd->cursor_pos);
|
||||
} break;
|
||||
@ -1386,7 +1386,7 @@ struct string game_string_from_cmds(struct arena *arena, struct game_cmd_list cm
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void game_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_cmd_list *cmds_out)
|
||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
|
||||
{
|
||||
__prof;
|
||||
for (u64 i = 0; i < host_events.count; ++i) {
|
||||
@ -1395,8 +1395,8 @@ void game_cmds_from_host_events(struct arena *arena, struct host_event_array hos
|
||||
switch (host_event_kind) {
|
||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||
{
|
||||
struct game_cmd *cmd = arena_push_zero(arena, struct game_cmd);
|
||||
cmd->kind = GAME_CMD_KIND_CLIENT_CONNECT;
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
cmd->kind = SIM_CMD_KIND_CLIENT_CONNECT;
|
||||
cmd->channel_id = host_event.channel_id;
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
@ -1408,8 +1408,8 @@ void game_cmds_from_host_events(struct arena *arena, struct host_event_array hos
|
||||
|
||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||
{
|
||||
struct game_cmd *cmd = arena_push_zero(arena, struct game_cmd);
|
||||
cmd->kind = GAME_CMD_KIND_CLIENT_DISCONNECT;
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
cmd->kind = SIM_CMD_KIND_CLIENT_DISCONNECT;
|
||||
cmd->disconnect_reason = LIT("Connection lost");
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
@ -1423,7 +1423,7 @@ void game_cmds_from_host_events(struct arena *arena, struct host_event_array hos
|
||||
{
|
||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
||||
while (br_bytes_left(&br) > 0) {
|
||||
struct game_cmd *cmd = arena_push_zero(arena, struct game_cmd);
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
u64 cmd_size = br_read_u64(&br);
|
||||
u64 cmd_pos_end = br_pos(&br) + cmd_size;
|
||||
cmd->kind = br_read_i8(&br);
|
||||
@ -1433,13 +1433,13 @@ void game_cmds_from_host_events(struct arena *arena, struct host_event_array hos
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case GAME_CMD_KIND_PLAYER_MOVE:
|
||||
case SIM_CMD_KIND_PLAYER_MOVE:
|
||||
{
|
||||
cmd->move_dir = br_read_v2(&br);
|
||||
cmd->aim_dir = br_read_v2(&br);
|
||||
} break;
|
||||
|
||||
case GAME_CMD_KIND_CURSOR_MOVE:
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
cmd->cursor_pos = br_read_v2(&br);
|
||||
} break;
|
||||
@ -1465,20 +1465,20 @@ void game_cmds_from_host_events(struct arena *arena, struct host_event_array hos
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Game event
|
||||
* Sim event
|
||||
* ========================== */
|
||||
|
||||
struct string game_string_from_events(struct arena *arena, struct game_event_list events)
|
||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
for (struct game_event *event = events.first; event; event = event->next) {
|
||||
for (struct sim_event *event = events.first; event; event = event->next) {
|
||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||
u64 start = bw_pos(&bw);
|
||||
bw_write_i8(&bw, event->kind);
|
||||
|
||||
switch (event->kind) {
|
||||
case GAME_EVENT_KIND_SNAPSHOT_FULL:
|
||||
case SIM_EVENT_KIND_SNAPSHOT_FULL:
|
||||
{
|
||||
bw_write_string(&bw, event->snapshot_data);
|
||||
} break;
|
||||
@ -1492,24 +1492,24 @@ struct string game_string_from_events(struct arena *arena, struct game_event_lis
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void game_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_event_list *events_out)
|
||||
void sim_events_from_host_events(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 game_event *game_event = arena_push_zero(arena, struct game_event);
|
||||
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;
|
||||
game_event->channel_id = host_event.channel_id;
|
||||
sim_event->channel_id = host_event.channel_id;
|
||||
switch (host_event_kind) {
|
||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||
{
|
||||
game_event->kind = GAME_EVENT_KIND_CONNECT;
|
||||
sim_event->kind = SIM_EVENT_KIND_CONNECT;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||
{
|
||||
game_event->kind = GAME_EVENT_KIND_DISCONNECT;
|
||||
game_event->disconnect_reason = LIT("Connection lost");
|
||||
sim_event->kind = SIM_EVENT_KIND_DISCONNECT;
|
||||
sim_event->disconnect_reason = LIT("Connection lost");
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_MSG:
|
||||
@ -1519,11 +1519,11 @@ void game_events_from_host_events(struct arena *arena, struct host_event_array h
|
||||
u64 event_size = br_read_u64(&br);
|
||||
u64 event_pos_end = br_pos(&br) + event_size;
|
||||
|
||||
game_event->kind = br_read_i8(&br);
|
||||
switch (game_event->kind) {
|
||||
case GAME_EVENT_KIND_SNAPSHOT_FULL:
|
||||
sim_event->kind = br_read_i8(&br);
|
||||
switch (sim_event->kind) {
|
||||
case SIM_EVENT_KIND_SNAPSHOT_FULL:
|
||||
{
|
||||
game_event->snapshot_data = br_read_string(arena, &br);
|
||||
sim_event->snapshot_data = br_read_string(arena, &br);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
@ -1538,11 +1538,11 @@ void game_events_from_host_events(struct arena *arena, struct host_event_array h
|
||||
}
|
||||
|
||||
if (events_out->last) {
|
||||
events_out->last->next = game_event;
|
||||
events_out->last->next = sim_event;
|
||||
} else {
|
||||
events_out->first = game_event;
|
||||
events_out->first = sim_event;
|
||||
}
|
||||
events_out->last = game_event;
|
||||
events_out->last = sim_event;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1550,7 +1550,7 @@ void game_events_from_host_events(struct arena *arena, struct host_event_array h
|
||||
* Snapshot
|
||||
* ========================== */
|
||||
|
||||
struct string game_string_from_tick(struct arena *arena, struct world *tick)
|
||||
struct string sim_string_from_tick(struct arena *arena, struct world *tick)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
@ -1574,7 +1574,7 @@ struct string game_string_from_tick(struct arena *arena, struct world *tick)
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void game_tick_from_string(struct string str, struct world *tick_out)
|
||||
void sim_tick_from_string(struct string str, struct world *tick_out)
|
||||
{
|
||||
__prof;
|
||||
struct byte_reader br = br_from_buffer(str);
|
||||
@ -1606,19 +1606,19 @@ void game_tick_from_string(struct string str, struct world *tick_out)
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Game thread
|
||||
* Sim thread
|
||||
* ========================== */
|
||||
|
||||
|
||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg)
|
||||
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg)
|
||||
{
|
||||
(UNUSED)arg;
|
||||
i64 last_frame_ns = 0;
|
||||
i64 target_dt_ns = NS_FROM_SECONDS(GAME_FPS > (0) ? (1.0 / GAME_FPS) : 0);
|
||||
while (!atomic_i32_eval(&G.game_thread_shutdown)) {
|
||||
__profscope(game_update_w_sleep);
|
||||
i64 target_dt_ns = NS_FROM_SECONDS(SIM_FPS > (0) ? (1.0 / SIM_FPS) : 0);
|
||||
while (!atomic_i32_eval(&G.sim_thread_shutdown)) {
|
||||
__profscope(sim_update_w_sleep);
|
||||
sleep_frame(last_frame_ns, target_dt_ns);
|
||||
last_frame_ns = sys_time_ns();
|
||||
game_update();
|
||||
sim_update();
|
||||
}
|
||||
}
|
||||
135
src/sim.h
Normal file
135
src/sim.h
Normal file
@ -0,0 +1,135 @@
|
||||
#ifndef SIM_H
|
||||
#define SIM_H
|
||||
|
||||
#include "host.h"
|
||||
|
||||
struct world;
|
||||
struct mixer_startup_receipt;
|
||||
struct sprite_startup_receipt;
|
||||
struct sound_startup_receipt;
|
||||
struct phys_startup_receipt;
|
||||
struct host_startup_receipt;
|
||||
|
||||
/* Absolute layers */
|
||||
#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
|
||||
|
||||
struct sim_startup_receipt { i32 _; };
|
||||
struct sim_startup_receipt sim_startup(struct mixer_startup_receipt *mixer_sr,
|
||||
struct sprite_startup_receipt *sheet_sr,
|
||||
struct sound_startup_receipt *sound_sr,
|
||||
struct phys_startup_receipt *phys_sr,
|
||||
struct host_startup_receipt *host_sr);
|
||||
|
||||
|
||||
/* ========================== *
|
||||
* Sim cmd
|
||||
* ========================== */
|
||||
|
||||
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_PLAYER_MOVE,
|
||||
SIM_CMD_KIND_PLAYER_FIRE,
|
||||
|
||||
SIM_CMD_KIND_CLIENT_CONNECT,
|
||||
SIM_CMD_KIND_CLIENT_DISCONNECT,
|
||||
|
||||
/* Testing */
|
||||
SIM_CMD_KIND_CLEAR_ALL,
|
||||
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_COUNT
|
||||
};
|
||||
|
||||
struct sim_cmd {
|
||||
enum sim_cmd_kind kind;
|
||||
enum sim_cmd_state state;
|
||||
struct host_channel_id channel_id;
|
||||
|
||||
/* SIM_CMD_KIND_PLAYER_MOVE */
|
||||
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;
|
||||
|
||||
#if RTC
|
||||
u32 collider_gjk_steps;
|
||||
#endif
|
||||
|
||||
struct sim_cmd *next;
|
||||
};
|
||||
|
||||
struct sim_cmd_list {
|
||||
struct sim_cmd *first;
|
||||
struct sim_cmd *last;
|
||||
};
|
||||
|
||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds);
|
||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
|
||||
|
||||
/* ========================== *
|
||||
* Sim event
|
||||
* ========================== */
|
||||
|
||||
enum sim_event_kind {
|
||||
SIM_EVENT_KIND_NONE,
|
||||
|
||||
SIM_EVENT_KIND_CONNECT,
|
||||
SIM_EVENT_KIND_DISCONNECT,
|
||||
SIM_EVENT_KIND_SNAPSHOT_FULL,
|
||||
|
||||
//SIM_EVENT_KIND_ENTITY_UPDATE,
|
||||
//SIM_EVENT_KIND_ENTITY_CREATE,
|
||||
//SIM_EVENT_KIND_ENTITY_DESTROY
|
||||
};
|
||||
|
||||
struct sim_event {
|
||||
enum sim_event_kind kind;
|
||||
struct host_channel_id channel_id;
|
||||
|
||||
struct string snapshot_data;
|
||||
struct string disconnect_reason;
|
||||
|
||||
//struct entity_handle entity;
|
||||
//struct string update_data;
|
||||
|
||||
struct sim_event *next;
|
||||
};
|
||||
|
||||
struct sim_event_list {
|
||||
struct sim_event *first;
|
||||
struct sim_event *last;
|
||||
};
|
||||
|
||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events);
|
||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
|
||||
|
||||
/* ========================== *
|
||||
* Snapshot
|
||||
* ========================== */
|
||||
|
||||
struct string sim_string_from_tick(struct arena *arena, struct world *tick);
|
||||
void sim_tick_from_string(struct string str, struct world *tick_out);
|
||||
|
||||
#endif
|
||||
92
src/user.c
92
src/user.c
@ -6,7 +6,7 @@
|
||||
#include "draw.h"
|
||||
#include "intrinsics.h"
|
||||
#include "app.h"
|
||||
#include "game.h"
|
||||
#include "sim.h"
|
||||
#include "asset_cache.h"
|
||||
#include "string.h"
|
||||
#include "scratch.h"
|
||||
@ -148,7 +148,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
||||
struct font_startup_receipt *font_sr,
|
||||
struct sprite_startup_receipt *sprite_sr,
|
||||
struct draw_startup_receipt *draw_sr,
|
||||
struct game_startup_receipt *game_sr,
|
||||
struct sim_startup_receipt *sim_sr,
|
||||
struct asset_cache_startup_receipt *asset_cache_sr,
|
||||
struct mixer_startup_receipt *mixer_sr,
|
||||
struct host_startup_receipt *host_sr,
|
||||
@ -159,7 +159,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
||||
(UNUSED)font_sr;
|
||||
(UNUSED)sprite_sr;
|
||||
(UNUSED)draw_sr;
|
||||
(UNUSED)game_sr;
|
||||
(UNUSED)sim_sr;
|
||||
(UNUSED)asset_cache_sr;
|
||||
(UNUSED)mixer_sr;
|
||||
(UNUSED)host_sr;
|
||||
@ -227,7 +227,7 @@ INTERNAL SYS_WINDOW_EVENT_CALLBACK_FUNC_DEF(window_event_callback, event)
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Game -> user communication
|
||||
* Sim -> user communication
|
||||
* ========================== */
|
||||
|
||||
#if 0
|
||||
@ -293,12 +293,12 @@ INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns)
|
||||
|
||||
struct world *from_tick;
|
||||
struct world *to_tick;
|
||||
if (newest_tick && game_get_latest_tick_continuity_gen() == newest_tick->continuity_gen) {
|
||||
/* Pull new tick from game thread if necessary */
|
||||
if (!newest_tick || game_get_latest_tick_id() > newest_tick->tick_id) {
|
||||
if (newest_tick && sim_get_latest_tick_continuity_gen() == newest_tick->continuity_gen) {
|
||||
/* Pull new tick from sim thread if necessary */
|
||||
if (!newest_tick || sim_get_latest_tick_id() > newest_tick->tick_id) {
|
||||
struct blend_tick *latest_bt = blend_tick_alloc();
|
||||
newest_tick = &latest_bt->world;
|
||||
game_get_latest_tick(newest_tick);
|
||||
sim_get_latest_tick(newest_tick);
|
||||
}
|
||||
|
||||
/* Find oldest tick */
|
||||
@ -365,7 +365,7 @@ INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns)
|
||||
/* Allocate new blend tick */
|
||||
struct blend_tick *bt = blend_tick_alloc();
|
||||
struct world *tick = &bt->world;
|
||||
game_get_latest_tick(tick);
|
||||
sim_get_latest_tick(tick);
|
||||
|
||||
from_tick = tick;
|
||||
to_tick = tick;
|
||||
@ -472,9 +472,9 @@ INTERNAL SORT_COMPARE_FUNC_DEF(entity_draw_order_cmp, arg_a, arg_b, udata)
|
||||
|
||||
|
||||
|
||||
INTERNAL void queue_game_cmd(struct arena *arena, struct game_cmd_list *list, struct game_cmd src)
|
||||
INTERNAL void queue_sim_cmd(struct arena *arena, struct sim_cmd_list *list, struct sim_cmd src)
|
||||
{
|
||||
struct game_cmd *cmd = arena_push(arena, struct game_cmd);
|
||||
struct sim_cmd *cmd = arena_push(arena, struct sim_cmd);
|
||||
*cmd = src;
|
||||
if (list->last) {
|
||||
list->last->next = cmd;
|
||||
@ -519,19 +519,19 @@ INTERNAL void user_update(void)
|
||||
|
||||
struct entity_store *store = G.world.entity_store;
|
||||
struct sprite_scope *sprite_frame_scope = sprite_scope_begin();
|
||||
struct game_cmd_list cmd_list = ZI;
|
||||
struct sim_cmd_list cmd_list = ZI;
|
||||
|
||||
#if 0
|
||||
/* ========================== *
|
||||
* Interpolate between game ticks
|
||||
* Interpolate between sim ticks
|
||||
* ========================== */
|
||||
|
||||
{
|
||||
__profscope(interpolate_ticks);
|
||||
|
||||
#if USER_INTERP_ENABLED
|
||||
/* TODO: Use actual fps of game thread (will differ from GAME_FPS if game thread is lagging) to hide lag with slow-motion? */
|
||||
i64 blend_time_offset_ns = NS_FROM_SECONDS((1.0 / GAME_FPS) * USER_INTERP_OFFSET_TICK_RATIO);
|
||||
/* TODO: Use actual fps of sim thread (will differ from SIM_FPS if sim thread is lagging) to hide lag with slow-motion? */
|
||||
i64 blend_time_offset_ns = NS_FROM_SECONDS((1.0 / SIM_FPS) * USER_INTERP_OFFSET_TICK_RATIO);
|
||||
i64 blend_time_ns = G.time_ns > blend_time_offset_ns ? G.time_ns - blend_time_offset_ns : 0;
|
||||
|
||||
/* Pull ticks */
|
||||
@ -573,7 +573,7 @@ INTERNAL void user_update(void)
|
||||
e->local_xform = xform_lerp(e0->local_xform, e1->local_xform, tick_blend);
|
||||
|
||||
if (e->is_top) {
|
||||
/* TODO: Cache parent & child xforms in game thread */
|
||||
/* TODO: Cache parent & child xforms in sim thread */
|
||||
struct xform e0_xf = entity_get_xform(e0);
|
||||
struct xform e1_xf = entity_get_xform(e1);
|
||||
entity_set_xform(e, xform_lerp(e0_xf, e1_xf, tick_blend));
|
||||
@ -610,17 +610,17 @@ INTERNAL void user_update(void)
|
||||
#endif
|
||||
|
||||
/* ========================== *
|
||||
* Process host events into game events
|
||||
* Process host events into sim events
|
||||
* ========================== */
|
||||
|
||||
struct game_event_list game_events = ZI;
|
||||
struct sim_event_list sim_events = ZI;
|
||||
{
|
||||
struct host_event_array host_events = host_pop_events(scratch.arena, G.host);
|
||||
game_events_from_host_events(scratch.arena, host_events, &game_events);
|
||||
sim_events_from_host_events(scratch.arena, host_events, &sim_events);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Process game events
|
||||
* Process sim events
|
||||
* ========================== */
|
||||
|
||||
{
|
||||
@ -632,24 +632,24 @@ INTERNAL void user_update(void)
|
||||
last_try_connect = now;
|
||||
}
|
||||
|
||||
for (struct game_event *event = game_events.first; event; event = event->next) {
|
||||
enum game_event_kind kind = event->kind;
|
||||
for (struct sim_event *event = sim_events.first; event; event = event->next) {
|
||||
enum sim_event_kind kind = event->kind;
|
||||
|
||||
switch (kind) {
|
||||
case GAME_EVENT_KIND_CONNECT:
|
||||
case SIM_EVENT_KIND_CONNECT:
|
||||
{
|
||||
last_try_connect = F64_INFINITY;
|
||||
} break;
|
||||
|
||||
case GAME_EVENT_KIND_DISCONNECT:
|
||||
case SIM_EVENT_KIND_DISCONNECT:
|
||||
{
|
||||
last_try_connect = 0;
|
||||
} break;
|
||||
|
||||
case GAME_EVENT_KIND_SNAPSHOT_FULL:
|
||||
case SIM_EVENT_KIND_SNAPSHOT_FULL:
|
||||
{
|
||||
struct string snapshot_data = event->snapshot_data;
|
||||
game_tick_from_string(snapshot_data, &G.world);
|
||||
sim_tick_from_string(snapshot_data, &G.world);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
@ -759,8 +759,8 @@ INTERNAL void user_update(void)
|
||||
{
|
||||
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_CLEAR];
|
||||
if (state.num_presses) {
|
||||
queue_game_cmd(scratch.arena, &cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_CLEAR_ALL
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_CLEAR_ALL
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -769,8 +769,8 @@ INTERNAL void user_update(void)
|
||||
{
|
||||
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_PAUSE];
|
||||
if (state.num_presses) {
|
||||
queue_game_cmd(scratch.arena, &cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_PAUSE
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_PAUSE
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -779,8 +779,8 @@ 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_game_cmd(scratch.arena, &cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_STEP
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_STEP
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -789,8 +789,8 @@ INTERNAL void user_update(void)
|
||||
{
|
||||
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_SPAWN];
|
||||
if (state.num_presses) {
|
||||
queue_game_cmd(scratch.arena, &cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_SPAWN_TEST
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_SPAWN_TEST
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1554,15 +1554,15 @@ INTERNAL void user_update(void)
|
||||
struct v2 input_aim_dir = v2_sub(G.world_cursor, entity_get_xform(active_player).og);
|
||||
|
||||
/* Queue cursor move cmd */
|
||||
queue_game_cmd(scratch.arena, &cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_CURSOR_MOVE,
|
||||
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 */
|
||||
if (!G.debug_camera) {
|
||||
queue_game_cmd(scratch.arena, &cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_PLAYER_MOVE,
|
||||
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
|
||||
.kind = SIM_CMD_KIND_PLAYER_MOVE,
|
||||
.move_dir = input_move_dir,
|
||||
.aim_dir = input_aim_dir
|
||||
});
|
||||
@ -1571,18 +1571,18 @@ INTERNAL void user_update(void)
|
||||
/* 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_game_cmd(scratch.arena, &cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_PLAYER_FIRE,
|
||||
.state = fire_presses > 0 ? GAME_CMD_STATE_START : GAME_CMD_STATE_STOP
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
/* 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_game_cmd(scratch.arena, &cmd_list, (struct game_cmd) {
|
||||
.kind = GAME_CMD_KIND_DRAG_OBJECT,
|
||||
.state = drag_presses > 0 ? GAME_CMD_STATE_START : GAME_CMD_STATE_STOP
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
@ -1689,11 +1689,11 @@ INTERNAL void user_update(void)
|
||||
|
||||
}
|
||||
|
||||
/* Publish game cmds */
|
||||
/* Publish sim cmds */
|
||||
{
|
||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
struct string cmds_str = game_string_from_cmds(temp.arena, cmd_list);
|
||||
struct string cmds_str = sim_string_from_cmds(temp.arena, cmd_list);
|
||||
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, cmds_str, 0);
|
||||
|
||||
arena_temp_end(temp);
|
||||
|
||||
@ -7,7 +7,7 @@ struct renderer_startup_receipt;
|
||||
struct font_startup_receipt;
|
||||
struct sprite_startup_receipt;
|
||||
struct draw_startup_receipt;
|
||||
struct game_startup_receipt;
|
||||
struct sim_startup_receipt;
|
||||
struct asset_cache_startup_receipt;
|
||||
struct mixer_startup_receipt;
|
||||
struct host_startup_receipt;
|
||||
@ -54,7 +54,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
||||
struct font_startup_receipt *font_sr,
|
||||
struct sprite_startup_receipt *sprite_sr,
|
||||
struct draw_startup_receipt *draw_sr,
|
||||
struct game_startup_receipt *game_sr,
|
||||
struct sim_startup_receipt *sim_sr,
|
||||
struct asset_cache_startup_receipt *asset_cache_sr,
|
||||
struct mixer_startup_receipt *mixer_sr,
|
||||
struct host_startup_receipt *host_sr,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user