re-add networked debug drag

This commit is contained in:
jacob 2025-02-09 11:13:36 -06:00
parent eee5945954
commit 6fa3517d7a
13 changed files with 298 additions and 325 deletions

View File

@ -501,6 +501,11 @@ struct sim_ent_handle {
u64 gen; u64 gen;
}; };
struct sim_client_handle {
u32 idx;
u32 gen;
};
struct space_entry_handle { struct space_entry_handle {
u64 idx; u64 idx;
u64 gen; u64 gen;

View File

@ -681,7 +681,7 @@ void host_update(struct host *host)
{ {
/* A foreign host is trying to connect to us */ /* A foreign host is trying to connect to us */
if (!channel->valid) { if (!channel->valid) {
logf_info("Received conection attempt from %F", FMT_STR(sock_string_from_address(scratch.arena, address))); logf_info("Host received conection attempt from %F", FMT_STR(sock_string_from_address(scratch.arena, address)));
/* TODO: Verify that some per-host uuid isn't present in a rolling window to prevent reconnects right after a disconnect? */ /* TODO: Verify that some per-host uuid isn't present in a rolling window to prevent reconnects right after a disconnect? */
channel = host_channel_alloc(host, address); channel = host_channel_alloc(host, address);
} }
@ -694,7 +694,7 @@ void host_update(struct host *host)
{ {
/* We successfully connected to a foreign host and they are ready to receive messages */ /* We successfully connected to a foreign host and they are ready to receive messages */
if (channel->valid && !channel->connected) { if (channel->valid && !channel->connected) {
logf_info("Received connection from %F", FMT_STR(sock_string_from_address(scratch.arena, address))); logf_info("Host received connection from %F", FMT_STR(sock_string_from_address(scratch.arena, address)));
struct host_queued_event *queued_event = host_queued_event_alloc_and_append(host); struct host_queued_event *queued_event = host_queued_event_alloc_and_append(host);
queued_event->event.kind = HOST_EVENT_KIND_CHANNEL_OPENED; queued_event->event.kind = HOST_EVENT_KIND_CHANNEL_OPENED;
queued_event->event.channel_id = channel->id; queued_event->event.channel_id = channel->id;
@ -706,7 +706,7 @@ void host_update(struct host *host)
{ {
/* A foreign host disconnected from us */ /* A foreign host disconnected from us */
if (channel->valid) { if (channel->valid) {
logf_info("Received disconnection from %F", FMT_STR(sock_string_from_address(scratch.arena, address))); logf_info("Host received disconnection from %F", FMT_STR(sock_string_from_address(scratch.arena, address)));
struct host_queued_event *queued_event = host_queued_event_alloc_and_append(host); struct host_queued_event *queued_event = host_queued_event_alloc_and_append(host);
queued_event->event.kind = HOST_EVENT_KIND_CHANNEL_CLOSED; queued_event->event.kind = HOST_EVENT_KIND_CHANNEL_CLOSED;
queued_event->event.channel_id = channel->id; queued_event->event.channel_id = channel->id;

View File

@ -9,7 +9,6 @@ GLOBAL struct {
struct math_spring_result contact_softness; struct math_spring_result contact_softness;
struct math_spring_result mouse_joint_linear_softness; struct math_spring_result mouse_joint_linear_softness;
struct math_spring_result mouse_joint_angular_softness; struct math_spring_result mouse_joint_angular_softness;
f32 mouse_joint_max_force;
} G = ZI, DEBUG_ALIAS(G, G_phys); } G = ZI, DEBUG_ALIAS(G, G_phys);
/* ========================== * /* ========================== *
@ -29,7 +28,6 @@ struct phys_startup_receipt phys_startup(void)
const f32 mouse_joint_linear_damping_ratio = 0.7f; const f32 mouse_joint_linear_damping_ratio = 0.7f;
const f32 mouse_joint_angular_frequency = 0.5f; const f32 mouse_joint_angular_frequency = 0.5f;
const f32 mouse_joint_angular_damping_ratio = 0.1f; const f32 mouse_joint_angular_damping_ratio = 0.1f;
G.mouse_joint_max_force = 1000;
G.mouse_joint_linear_softness = math_spring(mouse_joint_linear_frequency, mouse_joint_linear_damping_ratio, substep_dt); G.mouse_joint_linear_softness = math_spring(mouse_joint_linear_frequency, mouse_joint_linear_damping_ratio, substep_dt);
G.mouse_joint_angular_softness = math_spring(mouse_joint_angular_frequency, mouse_joint_angular_damping_ratio, substep_dt); G.mouse_joint_angular_softness = math_spring(mouse_joint_angular_frequency, mouse_joint_angular_damping_ratio, substep_dt);
@ -583,7 +581,7 @@ void phys_solve_contacts(struct phys_ctx *ctx, f32 dt, b32 apply_bias)
* Motor joint * Motor joint
* ========================== */ * ========================== */
struct phys_motor_joint motor_joint_from_def(struct phys_motor_joint_def def) struct phys_motor_joint phys_motor_joint_from_def(struct phys_motor_joint_def def)
{ {
struct phys_motor_joint res = ZI; struct phys_motor_joint res = ZI;
res.e0 = def.e0; res.e0 = def.e0;
@ -771,72 +769,16 @@ void phys_solve_motor_joints(struct phys_ctx *ctx, f32 dt)
* Mouse joint * Mouse joint
* ========================== */ * ========================== */
void phys_create_mouse_joints(struct phys_ctx *ctx) struct phys_mouse_joint phys_mouse_joint_from_def(struct phys_mouse_joint_def def)
{ {
__prof; struct phys_mouse_joint res = ZI;
struct sim_ent_store *store = ctx->store; res.target = def.target;
struct v2 cursor = ctx->dbg_cursor_pos; res.point_local_start = def.point_local_start;
b32 start_dragging = ctx->dbg_start_dragging; res.point_local_end = def.point_local_end;
b32 stop_dragging = ctx->dbg_stop_dragging; res.linear_softness = G.mouse_joint_linear_softness;
struct sim_ent *root = sim_ent_from_handle(store, store->root); res.angular_softness = G.mouse_joint_angular_softness;
res.max_force = def.max_force;
struct sim_ent *joint_ent = sim_ent_find_first_match_one(store, SIM_ENT_PROP_MOUSE_JOINT); return res;
struct sim_ent *target_ent = sim_ent_from_handle(store, joint_ent->mouse_joint_data.target);
if (start_dragging) {
struct xform mouse_xf = xform_from_pos(cursor);
struct collider_shape mouse_shape = ZI;
mouse_shape.points[0] = V2(0, 0);
mouse_shape.count = 1;
for (u64 sim_ent_index = 0; sim_ent_index < store->num_reserved; ++sim_ent_index) {
struct sim_ent *ent = &store->entities[sim_ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
struct collider_shape ent_collider = ent->local_collider;
if (ent_collider.count > 0) {
struct xform ent_xf = sim_ent_get_xform(ent);
/* TODO: Can just use boolean GJK */
struct collider_collision_points_result res = collider_collision_points(&ent_collider, &mouse_shape, ent_xf, mouse_xf);
if (res.num_points > 0) {
target_ent = ent;
break;
}
}
}
} else if (stop_dragging) {
target_ent = sim_ent_nil();
}
if (sim_ent_is_valid_and_active(target_ent)) {
if (!sim_ent_is_valid_and_active(joint_ent)) {
joint_ent = sim_ent_alloc(root);
joint_ent->mass_unscaled = F32_INFINITY;
joint_ent->inertia_unscaled = F32_INFINITY;
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT);
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE);
}
struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data;
struct xform xf = sim_ent_get_xform(target_ent);
f32 mass = target_ent->mass_unscaled * math_fabs(xform_get_determinant(xf));
if (!sim_ent_handle_eq(joint->target, target_ent->handle)) {
joint->point_local_start = xform_invert_mul_v2(xf, cursor);
joint->target = target_ent->handle;
}
joint->point_local_end = xform_invert_mul_v2(xf, cursor);
joint->linear_softness = G.mouse_joint_linear_softness;
joint->angular_softness = G.mouse_joint_angular_softness;
joint->max_force = G.mouse_joint_max_force * mass;
} else {
if (sim_ent_is_valid_and_active(joint_ent)) {
joint_ent->mouse_joint_data.target = sim_ent_handle_nil();
}
}
} }
void phys_prepare_mouse_joints(struct phys_ctx *ctx) void phys_prepare_mouse_joints(struct phys_ctx *ctx)
@ -1164,7 +1106,6 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_phys_iteration)
} }
struct phys_collision_data_array collision_data = phys_create_and_update_contacts(scratch.arena, ctx, timestep - remaining_dt, phys_iteration); struct phys_collision_data_array collision_data = phys_create_and_update_contacts(scratch.arena, ctx, timestep - remaining_dt, phys_iteration);
phys_create_mouse_joints(ctx);
phys_prepare_contacts(ctx, phys_iteration); phys_prepare_contacts(ctx, phys_iteration);
phys_prepare_motor_joints(ctx); phys_prepare_motor_joints(ctx);

View File

@ -41,9 +41,6 @@ struct phys_ctx {
void *post_solve_callback_udata; void *post_solve_callback_udata;
struct sim_ent_lookup *debug_lookup; struct sim_ent_lookup *debug_lookup;
struct v2 dbg_cursor_pos;
b32 dbg_start_dragging;
b32 dbg_stop_dragging;
}; };
@ -152,7 +149,7 @@ struct phys_motor_joint {
f32 angular_mass; f32 angular_mass;
}; };
struct phys_motor_joint motor_joint_from_def(struct phys_motor_joint_def def); struct phys_motor_joint phys_motor_joint_from_def(struct phys_motor_joint_def def);
void phys_prepare_motor_joints(struct phys_ctx *ctx); void phys_prepare_motor_joints(struct phys_ctx *ctx);
void phys_warm_start_motor_joints(struct phys_ctx *ctx); void phys_warm_start_motor_joints(struct phys_ctx *ctx);
void phys_solve_motor_joints(struct phys_ctx *ctx, f32 dt); void phys_solve_motor_joints(struct phys_ctx *ctx, f32 dt);
@ -161,6 +158,13 @@ void phys_solve_motor_joints(struct phys_ctx *ctx, f32 dt);
* Mouse joint * Mouse joint
* ========================== */ * ========================== */
struct phys_mouse_joint_def {
struct sim_ent_handle target;
struct v2 point_local_start;
struct v2 point_local_end;
f32 max_force;
};
struct phys_mouse_joint { struct phys_mouse_joint {
struct sim_ent_handle target; struct sim_ent_handle target;
struct v2 point_local_start; struct v2 point_local_start;
@ -178,7 +182,7 @@ struct phys_mouse_joint {
struct xform linear_mass_xf; struct xform linear_mass_xf;
}; };
void phys_create_mouse_joints(struct phys_ctx *ctx); struct phys_mouse_joint phys_mouse_joint_from_def(struct phys_mouse_joint_def def);
void phys_prepare_mouse_joints(struct phys_ctx *ctx); void phys_prepare_mouse_joints(struct phys_ctx *ctx);
void phys_warm_start_mouse_joints(struct phys_ctx *ctx); void phys_warm_start_mouse_joints(struct phys_ctx *ctx);
void phys_solve_mouse_joints(struct phys_ctx *ctx, f32 dt); void phys_solve_mouse_joints(struct phys_ctx *ctx, f32 dt);

View File

@ -88,6 +88,8 @@ f64 rng_rand_f64(f64 range_start, f64 range_end)
* NOTE: Noise pattern repeats after period depending on how much noise data exists in noise.dat * 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(u32 seed) u32 rng_noise_u32(u32 seed)
{ {
return (u32)G.noise[seed % G.noise_count]; return (u32)G.noise[seed % G.noise_count];

293
src/sim.c
View File

@ -546,59 +546,99 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
* Process host events into sim cmds * Process host events into sim cmds
* ========================== */ * ========================== */
struct sim_cmd_list *client_cmds;
struct sim_cmd_list sim_cmds = ZI;
{ {
struct sim_cmd_list sim_cmds = ZI;
struct host_event_array host_events = host_pop_events(scratch.arena, ctx->host); struct host_event_array host_events = host_pop_events(scratch.arena, ctx->host);
sim_cmds_from_host_events(scratch.arena, host_events, &sim_cmds); sim_cmds_from_host_events(scratch.arena, host_events, &sim_cmds);
/* Create connecting clients */
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 sim_client *client = sim_client_from_channel_id(ctx->tick.client_store, channel_id);
if (!client->valid && kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id)) {
client = sim_client_alloc(ctx->tick.client_store, channel_id);
/* TODO: Create player ent not here */
/* FIXME: Player ent never released upon disconnect */
struct sim_ent *player_ent = spawn_test_player(ctx);
sim_ent_enable_prop(player_ent, SIM_ENT_PROP_CONTROLLED);
struct sim_ent *camera_ent = spawn_test_player_camera(ctx, player_ent);
client->control_ent = player_ent->handle;
client->camera_ent = camera_ent->handle;
player_ent->controlling_client = client->handle;
}
}
/* Split cmds by client */
client_cmds = arena_push_array_zero(scratch.arena, struct sim_cmd_list, ctx->tick.client_store->num_reserved);
{
struct sim_cmd *cmd = sim_cmds.first;
while (cmd) {
struct sim_cmd *next = cmd->next;
struct host_channel_id channel_id = cmd->channel_id;
struct sim_client *client = sim_client_from_channel_id(ctx->tick.client_store, channel_id);
if (client->valid) {
struct sim_cmd_list *cmd_list = &client_cmds[client->handle.idx];
if (cmd_list->last) {
cmd_list->last->next = cmd;
} else {
cmd_list->first = cmd;
}
cmd_list->last = cmd;
cmd->next = NULL;
}
cmd = next;
}
}
} }
/* ========================== * /* ========================== *
* Process sim cmds * Process sim cmds
* ========================== */ * ========================== */
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) { /* Process client cmds */
enum sim_cmd_kind kind = cmd->kind; for (u64 i = 0; i < ctx->tick.client_store->num_reserved; ++i) {
struct host_channel_id channel_id = cmd->channel_id; struct sim_client *client = &ctx->tick.client_store->clients[i];
struct sim_client *client = sim_client_from_channel_id(ctx->tick.client_store, channel_id);
if (client->valid) { if (client->valid) {
struct sim_ent *player_ent = sim_ent_from_handle(ctx->tick.ent_store, client->control_ent); struct host_channel_id channel_id = client->channel_id;
struct sim_cmd_list cmds = client_cmds[client->handle.idx];
struct sim_control *control = &client->control;
client->dbg_drag_start = false;
client->dbg_drag_stop = false;
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
enum sim_cmd_kind kind = cmd->kind;
b32 start = cmd->state == SIM_CMD_STATE_START; b32 start = cmd->state == SIM_CMD_STATE_START;
b32 stop = cmd->state == SIM_CMD_STATE_STOP; b32 stop = cmd->state == SIM_CMD_STATE_STOP;
switch (kind) { switch (kind) {
/* TODO: Combine movement from multiple inputs? E.ctx-> a sudden /* TODO: Combine movement from multiple inputs? E.ctx-> a sudden
* start and immediate stop cmd should still move the player a * start and immediate stop cmd should still move the player a
* tad. */ * tad. */
case SIM_CMD_KIND_PLAYER_MOVE: case SIM_CMD_KIND_PLAYER_CONTROL:
{ {
if (player_ent->valid) {
struct v2 move = cmd->move_dir; struct v2 move = cmd->move_dir;
struct v2 focus = cmd->aim_dir; struct v2 focus = cmd->aim_dir;
if (v2_len_sq(move) > 1) { if (v2_len_sq(move) > 1) {
/* Cap movement vector magnitude at 1 */ /* Cap movement vector magnitude at 1 */
move = v2_norm(move); move = v2_norm(move);
} }
player_ent->control.move = move; control->move = move;
player_ent->control.focus = focus; control->focus = focus;
}
} break; } break;
case SIM_CMD_KIND_PLAYER_FIRE: case SIM_CMD_KIND_PLAYER_FIRE:
{ {
if (player_ent->valid) { /* TODO: Allow sub-tick firing (start & stop on same tick should still fire for one tick */
b32 firing = sim_ent_has_prop(player_ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); b32 firing = control->firing;
if (start) { if (start) {
firing = true; firing = true;
} else if (stop) { }
if (stop) {
firing = false; firing = false;
} }
if (firing) { control->firing = firing;
sim_ent_enable_prop(player_ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
} else {
sim_ent_disable_prop(player_ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
}
}
} break; } break;
/* Cursor */ /* Cursor */
@ -607,6 +647,15 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
client->cursor_pos = cmd->cursor_pos; client->cursor_pos = cmd->cursor_pos;
} break; } break;
case SIM_CMD_KIND_DRAG_OBJECT:
{
if (cmd->state == SIM_CMD_STATE_START) {
client->dbg_drag_start = true;
} else if (cmd->state == SIM_CMD_STATE_STOP) {
client->dbg_drag_stop = true;
}
} break;
/* Clear level */ /* Clear level */
case SIM_CMD_KIND_CLEAR_ALL: case SIM_CMD_KIND_CLEAR_ALL:
{ {
@ -623,30 +672,18 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
/* Disconnect client */ /* Disconnect client */
case SIM_CMD_KIND_SIM_CLIENT_DISCONNECT: case SIM_CMD_KIND_SIM_CLIENT_DISCONNECT:
{ {
if (player_ent->valid) {
sim_ent_enable_prop(player_ent, SIM_ENT_PROP_RELEASE_NEXT_TICK);
host_queue_disconnect(ctx->host, channel_id); host_queue_disconnect(ctx->host, channel_id);
}
sim_client_release(client); sim_client_release(client);
} break; } break;
default: break; default: break;
}; };
} else if (kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id) && !client->valid) { }
/* Connect client */
client = sim_client_alloc(ctx->tick.client_store, channel_id);
struct sim_ent *player_ent = spawn_test_player(ctx);
sim_ent_enable_prop(player_ent, SIM_ENT_PROP_CONTROLLED);
struct sim_ent *camera_ent = spawn_test_player_camera(ctx, player_ent);
client->control_ent = player_ent->handle;
client->camera_ent = camera_ent->handle;;
player_ent->controlling_client = client->handle;
} }
} }
#if 0
/* ========================== * /* ========================== *
* Update entity movement from control * Update entity control from client control
* ========================== */ * ========================== */
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) { for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
@ -654,52 +691,18 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
if (!sim_ent_is_valid_and_active(ent)) continue; if (!sim_ent_is_valid_and_active(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) { if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
/* Process cmds */ struct sim_client *client = sim_client_from_handle(ctx->tick.client_store, ent->controlling_client);
struct v2 move = ent->control.move; if (client->valid) {
struct v2 focus = ent->control.focus; ent->control = client->control;
b32 firing = sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); /* TODO: Move this */
if (ent->control.firing) {
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
/* TODO: Combine movement from multiple inputs? E.ctx-> a sudden
* start and immediate stop cmd should still move the player a
* tad. */
switch (cmd->kind) {
case SIM_CMD_KIND_PLAYER_MOVE:
{
move = cmd->move_dir;
focus = cmd->aim_dir;
} break;
case SIM_CMD_KIND_PLAYER_FIRE:
{
if (start) {
firing = true;
} else if (stop) {
firing = false;
}
} break;
default: break;
}
}
/* Movement */
if (v2_len_sq(move) > 1) {
/* Cap movement vector magnitude at 1 */
move = v2_norm(move);
}
ent->control.move = move;
ent->control.focus = focus;
/* Firing */
if (firing) {
sim_ent_enable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); sim_ent_enable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
} else { } else {
sim_ent_disable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); sim_ent_disable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
} }
} }
} }
#endif }
/* ========================== * /* ========================== *
* Update entities from sprite * Update entities from sprite
@ -952,21 +955,9 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
} }
/* ========================== * /* ========================== *
* Create forces from control move * Create motor joints from control move
* ========================== */ * ========================== */
#if 0
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
struct sim_ent *ent = &ent_store->entities[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_PLAYER_CONTROLLED)) {
struct v2 move = ent->control.move;
struct v2 force = v2_mul(move, ent->control_force);
sim_ent_apply_force_to_center(ent, force);
}
}
#else
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) { for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
struct sim_ent *ent = &ent_store->entities[ent_index]; struct sim_ent *ent = &ent_store->entities[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue; if (!sim_ent_is_valid_and_active(ent)) continue;
@ -987,17 +978,16 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
def.correction_rate = 0; def.correction_rate = 0;
def.max_force = ent->control_force; def.max_force = ent->control_force;
def.max_torque = 0; def.max_torque = 0;
joint_ent->motor_joint_data = motor_joint_from_def(def); joint_ent->motor_joint_data = phys_motor_joint_from_def(def);
} }
sim_ent_set_xform(joint_ent, XFORM_IDENT); /* Reset joint ent position */ sim_ent_set_xform(joint_ent, XFORM_IDENT); /* Reset joint ent position */
sim_ent_set_linear_velocity(joint_ent, v2_mul(v2_clamp_len(ent->control.move, 1), ent->control_force_max_speed)); sim_ent_set_linear_velocity(joint_ent, v2_mul(v2_clamp_len(ent->control.move, 1), ent->control_force_max_speed));
} }
} }
#endif
/* ========================== * /* ========================== *
* Create forces from control focus (aim) * Create motor joints from control focus (aim)
* ========================== */ * ========================== */
#if SIM_PLAYER_AIM #if SIM_PLAYER_AIM
@ -1025,7 +1015,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
def.e1 = ent->handle; def.e1 = ent->handle;
def.max_force = 0; def.max_force = 0;
def.max_torque = ent->control_torque; def.max_torque = ent->control_torque;
joint_ent->motor_joint_data = motor_joint_from_def(def); joint_ent->motor_joint_data = phys_motor_joint_from_def(def);
} }
/* Set correction rate dynamically since motor velocity is only set for one frame */ /* Set correction rate dynamically since motor velocity is only set for one frame */
@ -1091,7 +1081,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
#endif #endif
/* ========================== * /* ========================== *
* Create ground friction force (gravity) * Create motor joints from ground friction (gravity)
* ========================== */ * ========================== */
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) { for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
@ -1112,12 +1102,80 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
joint_ent = sim_ent_alloc(root); joint_ent = sim_ent_alloc(root);
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT);
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE);
joint_ent->motor_joint_data = motor_joint_from_def(def); joint_ent->motor_joint_data = phys_motor_joint_from_def(def);
ent->ground_friction_joint = joint_ent->handle; ent->ground_friction_joint = joint_ent->handle;
} }
} }
} }
/* ========================== *
* Create mouse joints from client debug drag
* ========================== */
for (u64 i = 0; i < ctx->tick.client_store->num_reserved; ++i) {
struct sim_client *client = &ctx->tick.client_store->clients[i];
if (client->valid) {
struct v2 cursor = client->cursor_pos;
b32 start_dragging = client->dbg_drag_start;
b32 stop_dragging = client->dbg_drag_stop;
struct sim_ent *joint_ent = sim_ent_from_handle(ent_store, client->dbg_drag_joint_ent);
struct sim_ent *target_ent = sim_ent_from_handle(ent_store, joint_ent->mouse_joint_data.target);
if (start_dragging) {
struct xform mouse_xf = xform_from_pos(cursor);
struct collider_shape mouse_shape = ZI;
mouse_shape.points[0] = V2(0, 0);
mouse_shape.count = 1;
for (u64 sim_ent_index = 0; sim_ent_index < ent_store->num_reserved; ++sim_ent_index) {
struct sim_ent *ent = &ent_store->entities[sim_ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
struct collider_shape ent_collider = ent->local_collider;
if (ent_collider.count > 0) {
struct xform ent_xf = sim_ent_get_xform(ent);
/* TODO: Can just use boolean GJK */
struct collider_collision_points_result res = collider_collision_points(&ent_collider, &mouse_shape, ent_xf, mouse_xf);
if (res.num_points > 0) {
target_ent = ent;
break;
}
}
}
}
if (stop_dragging) {
target_ent = sim_ent_nil();
}
if (sim_ent_is_valid_and_active(target_ent)) {
if (!sim_ent_is_valid_and_active(joint_ent)) {
/* FIXME: Joint ent never released */
joint_ent = sim_ent_alloc(root);
joint_ent->mass_unscaled = F32_INFINITY;
joint_ent->inertia_unscaled = F32_INFINITY;
client->dbg_drag_joint_ent = joint_ent->handle;
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT);
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE);
}
struct xform xf = sim_ent_get_xform(target_ent);
f32 mass = target_ent->mass_unscaled * math_fabs(xform_get_determinant(xf));
struct phys_mouse_joint_def def = ZI;
def.target = target_ent->handle;
if (!sim_ent_handle_eq(joint_ent->mouse_joint_data.target, target_ent->handle)) {
def.point_local_start = xform_invert_mul_v2(xf, cursor);
}
def.point_local_end = xform_invert_mul_v2(xf, cursor);
def.max_force = mass * 1000;
joint_ent->mouse_joint_data = phys_mouse_joint_from_def(def);
} else if (sim_ent_is_valid_and_active(joint_ent)) {
joint_ent->mouse_joint_data.target = target_ent->handle;
}
}
}
/* ========================== * /* ========================== *
* Physics * Physics
* ========================== */ * ========================== */
@ -1134,20 +1192,6 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
phys.debug_lookup = &phys->collision_debug_lookup; phys.debug_lookup = &phys->collision_debug_lookup;
#endif #endif
#if 0
/* Mouse drag */
phys.dbg_cursor_pos = ctx->user_cursor;
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) {
phys.dbg_start_dragging = true;
} else if (cmd->state == SIM_CMD_STATE_STOP) {
phys.dbg_stop_dragging = true;
}
}
}
#endif
/* Step */ /* Step */
ctx->last_phys_iteration = phys_step(&phys, dt, ctx->last_phys_iteration); ctx->last_phys_iteration = phys_step(&phys, dt, ctx->last_phys_iteration);
} }
@ -1331,37 +1375,6 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
arena_temp_end(temp); arena_temp_end(temp);
} }
#if 0
/* ========================== *
* Update sound emitters
* ========================== */
/* 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. */
for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) {
struct sim_ent *ent = &ent_store->entities[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TEST_SOUND_EMITTER)) {
struct mixer_desc desc = ent->sound_desc;
desc.speed = ctx->tick.timescale;
desc.pos = sim_ent_get_xform(ent).og;
struct sound *sound = sound_load_async(ent->sound_name, 0);
b32 played = ent->sound_handle.gen != 0;
if (sound) {
if (!played) {
ent->sound_handle = mixer_play_ex(sound, desc);
} else {
mixer_track_set(ent->sound_handle, desc);
}
}
}
}
#endif
/* ========================== * /* ========================== *
* Release entities * Release entities
* ========================== */ * ========================== */

View File

@ -1,12 +1,9 @@
#ifndef SIM_CLIENT_H #ifndef SIM_CLIENT_H
#define SIM_CLIENT_H #define SIM_CLIENT_H
struct sim_client_channel_lookup_bucket; #include "sim_ent.h"
struct sim_client_handle { struct sim_client_channel_lookup_bucket;
u32 idx;
u32 gen;
};
struct sim_client { struct sim_client {
b32 valid; b32 valid;
@ -22,6 +19,12 @@ struct sim_client {
struct v2 cursor_pos; struct v2 cursor_pos;
struct sim_ent_handle camera_ent; struct sim_ent_handle camera_ent;
struct sim_ent_handle control_ent; struct sim_ent_handle control_ent;
struct sim_control control;
b32 dbg_drag_start;
b32 dbg_drag_stop;
struct sim_ent_handle dbg_drag_joint_ent;
}; };
struct sim_client_store { struct sim_client_store {

View File

@ -381,8 +381,8 @@ void sim_ent_unlink_from_parent(struct sim_ent *ent)
} else { } else {
parent->last = prev->handle; parent->last = prev->handle;
} }
ent->prev = sim_ent_handle_nil(); ent->prev = sim_ent_nil()->handle;
ent->next = sim_ent_handle_nil(); ent->next = sim_ent_nil()->handle;
} }
/* ========================== * /* ========================== *

View File

@ -4,7 +4,6 @@
#include "sprite.h" #include "sprite.h"
#include "mixer.h" #include "mixer.h"
#include "phys.h" #include "phys.h"
#include "sim_client.h"
enum sim_ent_prop { enum sim_ent_prop {
SIM_ENT_PROP_NONE, SIM_ENT_PROP_NONE,
@ -81,6 +80,12 @@ struct sim_ent_lookup {
struct sim_ent_lookup_entry *first_free_entry; struct sim_ent_lookup_entry *first_free_entry;
}; };
struct sim_control {
struct v2 move; /* Movement direction vector (speed of 0 -> 1) */
struct v2 focus; /* Focus direction vector (where should the entity look) */
b32 firing;
};
struct sim_ent { struct sim_ent {
/* ====================================================================== */ /* ====================================================================== */
/* Metadata */ /* Metadata */
@ -168,10 +173,7 @@ struct sim_ent {
f32 control_torque; /* How much torque is applied when turning towards desired focus */ f32 control_torque; /* How much torque is applied when turning towards desired focus */
struct { struct sim_control control;
struct v2 move; /* Movement direction vector (speed of 0 -> 1) */
struct v2 focus; /* Focus direction vector (where should the entity look) */
} control;
struct sim_ent_handle move_joint; struct sim_ent_handle move_joint;
struct sim_ent_handle aim_joint; struct sim_ent_handle aim_joint;
@ -314,11 +316,6 @@ struct sim_ent_prop_array {
* Handle helpers * Handle helpers
* ========================== */ * ========================== */
INLINE struct sim_ent_handle sim_ent_handle_nil(void)
{
return (struct sim_ent_handle) { 0 };
}
INLINE b32 sim_ent_handle_eq(struct sim_ent_handle a, struct sim_ent_handle b) INLINE b32 sim_ent_handle_eq(struct sim_ent_handle a, struct sim_ent_handle b)
{ {
return a.gen == b.gen && a.idx == b.idx; return a.gen == b.gen && a.idx == b.idx;

View File

@ -24,7 +24,7 @@ struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds
#endif #endif
switch (cmd->kind) { switch (cmd->kind) {
case SIM_CMD_KIND_PLAYER_MOVE: case SIM_CMD_KIND_PLAYER_CONTROL:
{ {
bw_write_v2(&bw, cmd->move_dir); bw_write_v2(&bw, cmd->move_dir);
bw_write_v2(&bw, cmd->aim_dir); bw_write_v2(&bw, cmd->aim_dir);
@ -93,7 +93,7 @@ void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host
#endif #endif
switch (cmd->kind) { switch (cmd->kind) {
case SIM_CMD_KIND_PLAYER_MOVE: case SIM_CMD_KIND_PLAYER_CONTROL:
{ {
cmd->move_dir = br_read_v2(&br); cmd->move_dir = br_read_v2(&br);
cmd->aim_dir = br_read_v2(&br); cmd->aim_dir = br_read_v2(&br);

View File

@ -19,7 +19,7 @@ enum sim_cmd_state {
enum sim_cmd_kind { enum sim_cmd_kind {
SIM_CMD_KIND_NONE, SIM_CMD_KIND_NONE,
SIM_CMD_KIND_PLAYER_MOVE, SIM_CMD_KIND_PLAYER_CONTROL,
SIM_CMD_KIND_PLAYER_FIRE, SIM_CMD_KIND_PLAYER_FIRE,
SIM_CMD_KIND_SIM_CLIENT_CONNECT, SIM_CMD_KIND_SIM_CLIENT_CONNECT,
@ -41,7 +41,7 @@ struct sim_cmd {
enum sim_cmd_state state; enum sim_cmd_state state;
struct host_channel_id channel_id; struct host_channel_id channel_id;
/* SIM_CMD_KIND_PLAYER_MOVE */ /* SIM_CMD_KIND_PLAYER_CONTROL */
struct v2 move_dir; struct v2 move_dir;
struct v2 aim_dir; struct v2 aim_dir;

View File

@ -86,6 +86,7 @@ INTERNAL struct sock_address sock_address_from_ip_port_cstr(char *ip_cstr, char
MEMCPY(res.ipnb, (void *)&sockaddr->sin_addr, 4); MEMCPY(res.ipnb, (void *)&sockaddr->sin_addr, 4);
break; break;
} else if (ai_res->ai_family == AF_INET6) { } else if (ai_res->ai_family == AF_INET6) {
/* TODO: Enable ipv6 */
#if 0 #if 0
struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_res->ai_addr; struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_res->ai_addr;
res.valid = true; res.valid = true;

View File

@ -740,15 +740,7 @@ INTERNAL void user_update(void)
} }
/* ========================== * /* ========================== *
* Find local entities * Update user state from binds
* ========================== */
struct sim_client *local_client = sim_client_from_handle(G.world.client_store, G.world.local_client);
struct sim_ent *local_player = sim_ent_from_handle(G.world.ent_store, local_client->control_ent);
struct sim_ent *local_camera = sim_ent_from_handle(G.world.ent_store, local_client->camera_ent);
/* ========================== *
* Debug commands
* ========================== */ * ========================== */
/* Test fullscreen */ /* Test fullscreen */
@ -761,46 +753,6 @@ INTERNAL void user_update(void)
} }
} }
/* Test clear world */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_CLEAR];
if (state.num_presses) {
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
.kind = SIM_CMD_KIND_CLEAR_ALL
});
}
}
/* Test pause */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_PAUSE];
if (state.num_presses) {
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
.kind = SIM_CMD_KIND_PAUSE
});
}
}
/* Test step */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_STEP];
for (u32 i = 0; i < state.num_presses_and_repeats; ++i) {
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
.kind = SIM_CMD_KIND_STEP
});
}
}
/* Test spawn */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_SPAWN];
if (state.num_presses) {
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
.kind = SIM_CMD_KIND_SPAWN_TEST
});
}
}
if (G.bind_states[USER_BIND_KIND_DEBUG_DRAW].num_presses > 0) { if (G.bind_states[USER_BIND_KIND_DEBUG_DRAW].num_presses > 0) {
G.debug_draw = !G.debug_draw; G.debug_draw = !G.debug_draw;
} }
@ -809,6 +761,14 @@ INTERNAL void user_update(void)
G.debug_camera = !G.debug_camera; G.debug_camera = !G.debug_camera;
} }
/* ========================== *
* Find local entities
* ========================== */
struct sim_client *local_client = sim_client_from_handle(G.world.client_store, G.world.local_client);
struct sim_ent *local_player = sim_ent_from_handle(G.world.ent_store, local_client->control_ent);
struct sim_ent *local_camera = sim_ent_from_handle(G.world.ent_store, local_client->camera_ent);
/* ========================== * /* ========================== *
* Apply shake * Apply shake
* ========================== */ * ========================== */
@ -1508,7 +1468,7 @@ INTERNAL void user_update(void)
} }
/* ========================== * /* ========================== *
* Construct player control cmd * Queue player control cmd
* ========================== */ * ========================== */
{ {
@ -1565,7 +1525,7 @@ INTERNAL void user_update(void)
/* Queue player input cmd */ /* Queue player input cmd */
if (!G.debug_camera) { if (!G.debug_camera) {
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) { queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
.kind = SIM_CMD_KIND_PLAYER_MOVE, .kind = SIM_CMD_KIND_PLAYER_CONTROL,
.move_dir = input_move_dir, .move_dir = input_move_dir,
.aim_dir = input_aim_dir .aim_dir = input_aim_dir
}); });
@ -1601,6 +1561,53 @@ INTERNAL void user_update(void)
#endif #endif
} }
/* ========================== *
* Queue debug cmds
* ========================== */
{
/* Test clear world */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_CLEAR];
if (state.num_presses) {
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
.kind = SIM_CMD_KIND_CLEAR_ALL
});
}
}
/* Test pause */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_PAUSE];
if (state.num_presses) {
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
.kind = SIM_CMD_KIND_PAUSE
});
}
}
/* Test step */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_STEP];
for (u32 i = 0; i < state.num_presses_and_repeats; ++i) {
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
.kind = SIM_CMD_KIND_STEP
});
}
}
/* Test spawn */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_SPAWN];
if (state.num_presses) {
queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) {
.kind = SIM_CMD_KIND_SPAWN_TEST
});
}
}
}
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */