re-add networked debug drag
This commit is contained in:
parent
eee5945954
commit
6fa3517d7a
@ -501,6 +501,11 @@ struct sim_ent_handle {
|
||||
u64 gen;
|
||||
};
|
||||
|
||||
struct sim_client_handle {
|
||||
u32 idx;
|
||||
u32 gen;
|
||||
};
|
||||
|
||||
struct space_entry_handle {
|
||||
u64 idx;
|
||||
u64 gen;
|
||||
|
||||
@ -681,7 +681,7 @@ void host_update(struct host *host)
|
||||
{
|
||||
/* A foreign host is trying to connect to us */
|
||||
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? */
|
||||
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 */
|
||||
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);
|
||||
queued_event->event.kind = HOST_EVENT_KIND_CHANNEL_OPENED;
|
||||
queued_event->event.channel_id = channel->id;
|
||||
@ -706,7 +706,7 @@ void host_update(struct host *host)
|
||||
{
|
||||
/* A foreign host disconnected from us */
|
||||
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);
|
||||
queued_event->event.kind = HOST_EVENT_KIND_CHANNEL_CLOSED;
|
||||
queued_event->event.channel_id = channel->id;
|
||||
|
||||
79
src/phys.c
79
src/phys.c
@ -9,7 +9,6 @@ GLOBAL struct {
|
||||
struct math_spring_result contact_softness;
|
||||
struct math_spring_result mouse_joint_linear_softness;
|
||||
struct math_spring_result mouse_joint_angular_softness;
|
||||
f32 mouse_joint_max_force;
|
||||
} 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_angular_frequency = 0.5f;
|
||||
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_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
|
||||
* ========================== */
|
||||
|
||||
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;
|
||||
res.e0 = def.e0;
|
||||
@ -771,72 +769,16 @@ void phys_solve_motor_joints(struct phys_ctx *ctx, f32 dt)
|
||||
* 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 sim_ent_store *store = ctx->store;
|
||||
struct v2 cursor = ctx->dbg_cursor_pos;
|
||||
b32 start_dragging = ctx->dbg_start_dragging;
|
||||
b32 stop_dragging = ctx->dbg_stop_dragging;
|
||||
struct sim_ent *root = sim_ent_from_handle(store, store->root);
|
||||
|
||||
struct sim_ent *joint_ent = sim_ent_find_first_match_one(store, SIM_ENT_PROP_MOUSE_JOINT);
|
||||
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();
|
||||
}
|
||||
}
|
||||
struct phys_mouse_joint res = ZI;
|
||||
res.target = def.target;
|
||||
res.point_local_start = def.point_local_start;
|
||||
res.point_local_end = def.point_local_end;
|
||||
res.linear_softness = G.mouse_joint_linear_softness;
|
||||
res.angular_softness = G.mouse_joint_angular_softness;
|
||||
res.max_force = def.max_force;
|
||||
return res;
|
||||
}
|
||||
|
||||
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);
|
||||
phys_create_mouse_joints(ctx);
|
||||
|
||||
phys_prepare_contacts(ctx, phys_iteration);
|
||||
phys_prepare_motor_joints(ctx);
|
||||
|
||||
14
src/phys.h
14
src/phys.h
@ -41,9 +41,6 @@ struct phys_ctx {
|
||||
void *post_solve_callback_udata;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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_warm_start_motor_joints(struct phys_ctx *ctx);
|
||||
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
|
||||
* ========================== */
|
||||
|
||||
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 sim_ent_handle target;
|
||||
struct v2 point_local_start;
|
||||
@ -178,7 +182,7 @@ struct phys_mouse_joint {
|
||||
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_warm_start_mouse_joints(struct phys_ctx *ctx);
|
||||
void phys_solve_mouse_joints(struct phys_ctx *ctx, f32 dt);
|
||||
|
||||
@ -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
|
||||
* ========================== */
|
||||
|
||||
/* TODO: Use deterministic prng rather than embedded data */
|
||||
|
||||
u32 rng_noise_u32(u32 seed)
|
||||
{
|
||||
return (u32)G.noise[seed % G.noise_count];
|
||||
|
||||
365
src/sim.c
365
src/sim.c
@ -546,107 +546,144 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
|
||||
* Process host events into sim cmds
|
||||
* ========================== */
|
||||
|
||||
|
||||
struct sim_cmd_list sim_cmds = ZI;
|
||||
struct sim_cmd_list *client_cmds;
|
||||
{
|
||||
struct sim_cmd_list sim_cmds = ZI;
|
||||
struct host_event_array host_events = host_pop_events(scratch.arena, ctx->host);
|
||||
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
|
||||
* ========================== */
|
||||
|
||||
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);
|
||||
/* Process client cmds */
|
||||
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 sim_ent *player_ent = sim_ent_from_handle(ctx->tick.ent_store, client->control_ent);
|
||||
b32 start = cmd->state == SIM_CMD_STATE_START;
|
||||
b32 stop = cmd->state == SIM_CMD_STATE_STOP;
|
||||
switch (kind) {
|
||||
/* TODO: Combine movement from multiple inputs? E.ctx-> a sudden
|
||||
* start and immediate stop cmd should still move the player a
|
||||
* tad. */
|
||||
case SIM_CMD_KIND_PLAYER_MOVE:
|
||||
{
|
||||
if (player_ent->valid) {
|
||||
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 stop = cmd->state == SIM_CMD_STATE_STOP;
|
||||
switch (kind) {
|
||||
/* TODO: Combine movement from multiple inputs? E.ctx-> a sudden
|
||||
* start and immediate stop cmd should still move the player a
|
||||
* tad. */
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
{
|
||||
struct v2 move = cmd->move_dir;
|
||||
struct v2 focus = cmd->aim_dir;
|
||||
if (v2_len_sq(move) > 1) {
|
||||
/* Cap movement vector magnitude at 1 */
|
||||
move = v2_norm(move);
|
||||
}
|
||||
player_ent->control.move = move;
|
||||
player_ent->control.focus = focus;
|
||||
}
|
||||
} break;
|
||||
control->move = move;
|
||||
control->focus = focus;
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_PLAYER_FIRE:
|
||||
{
|
||||
if (player_ent->valid) {
|
||||
b32 firing = sim_ent_has_prop(player_ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
|
||||
case SIM_CMD_KIND_PLAYER_FIRE:
|
||||
{
|
||||
/* TODO: Allow sub-tick firing (start & stop on same tick should still fire for one tick */
|
||||
b32 firing = control->firing;
|
||||
if (start) {
|
||||
firing = true;
|
||||
} else if (stop) {
|
||||
}
|
||||
if (stop) {
|
||||
firing = false;
|
||||
}
|
||||
if (firing) {
|
||||
sim_ent_enable_prop(player_ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
|
||||
} else {
|
||||
sim_ent_disable_prop(player_ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
|
||||
control->firing = firing;
|
||||
} break;
|
||||
|
||||
/* Cursor */
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
client->cursor_pos = cmd->cursor_pos;
|
||||
} 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;
|
||||
} break;
|
||||
|
||||
/* Cursor */
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
client->cursor_pos = cmd->cursor_pos;
|
||||
} break;
|
||||
/* Clear level */
|
||||
case SIM_CMD_KIND_CLEAR_ALL:
|
||||
{
|
||||
ctx->should_reset_level = true;
|
||||
} break;
|
||||
|
||||
/* Clear level */
|
||||
case SIM_CMD_KIND_CLEAR_ALL:
|
||||
{
|
||||
ctx->should_reset_level = true;
|
||||
} break;
|
||||
/* Spawn test */
|
||||
case SIM_CMD_KIND_SPAWN_TEST:
|
||||
{
|
||||
logf_info("Spawning (test)");
|
||||
spawn_test_entities(ctx);
|
||||
} break;
|
||||
|
||||
/* Spawn test */
|
||||
case SIM_CMD_KIND_SPAWN_TEST:
|
||||
{
|
||||
logf_info("Spawning (test)");
|
||||
spawn_test_entities(ctx);
|
||||
} break;
|
||||
|
||||
/* Disconnect client */
|
||||
case SIM_CMD_KIND_SIM_CLIENT_DISCONNECT:
|
||||
{
|
||||
if (player_ent->valid) {
|
||||
sim_ent_enable_prop(player_ent, SIM_ENT_PROP_RELEASE_NEXT_TICK);
|
||||
/* Disconnect client */
|
||||
case SIM_CMD_KIND_SIM_CLIENT_DISCONNECT:
|
||||
{
|
||||
host_queue_disconnect(ctx->host, channel_id);
|
||||
}
|
||||
sim_client_release(client);
|
||||
} break;
|
||||
sim_client_release(client);
|
||||
} 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;
|
||||
default: break;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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) {
|
||||
@ -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_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
|
||||
/* Process cmds */
|
||||
struct v2 move = ent->control.move;
|
||||
struct v2 focus = ent->control.focus;
|
||||
b32 firing = sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
|
||||
|
||||
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;
|
||||
struct sim_client *client = sim_client_from_handle(ctx->tick.client_store, ent->controlling_client);
|
||||
if (client->valid) {
|
||||
ent->control = client->control;
|
||||
/* TODO: Move this */
|
||||
if (ent->control.firing) {
|
||||
sim_ent_enable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
|
||||
} else {
|
||||
sim_ent_disable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
} else {
|
||||
sim_ent_disable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ========================== *
|
||||
* 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) {
|
||||
struct sim_ent *ent = &ent_store->entities[ent_index];
|
||||
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.max_force = ent->control_force;
|
||||
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_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
|
||||
@ -1025,7 +1015,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
|
||||
def.e1 = ent->handle;
|
||||
def.max_force = 0;
|
||||
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 */
|
||||
@ -1091,7 +1081,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
|
||||
#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) {
|
||||
@ -1112,12 +1102,80 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
|
||||
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_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* 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
|
||||
* ========================== */
|
||||
@ -1134,20 +1192,6 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt)
|
||||
phys.debug_lookup = &phys->collision_debug_lookup;
|
||||
#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 */
|
||||
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);
|
||||
}
|
||||
|
||||
#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
|
||||
* ========================== */
|
||||
|
||||
@ -1,12 +1,9 @@
|
||||
#ifndef SIM_CLIENT_H
|
||||
#define SIM_CLIENT_H
|
||||
|
||||
struct sim_client_channel_lookup_bucket;
|
||||
#include "sim_ent.h"
|
||||
|
||||
struct sim_client_handle {
|
||||
u32 idx;
|
||||
u32 gen;
|
||||
};
|
||||
struct sim_client_channel_lookup_bucket;
|
||||
|
||||
struct sim_client {
|
||||
b32 valid;
|
||||
@ -22,6 +19,12 @@ struct sim_client {
|
||||
struct v2 cursor_pos;
|
||||
struct sim_ent_handle camera_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 {
|
||||
|
||||
@ -381,8 +381,8 @@ void sim_ent_unlink_from_parent(struct sim_ent *ent)
|
||||
} else {
|
||||
parent->last = prev->handle;
|
||||
}
|
||||
ent->prev = sim_ent_handle_nil();
|
||||
ent->next = sim_ent_handle_nil();
|
||||
ent->prev = sim_ent_nil()->handle;
|
||||
ent->next = sim_ent_nil()->handle;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
#include "sprite.h"
|
||||
#include "mixer.h"
|
||||
#include "phys.h"
|
||||
#include "sim_client.h"
|
||||
|
||||
enum sim_ent_prop {
|
||||
SIM_ENT_PROP_NONE,
|
||||
@ -81,6 +80,12 @@ struct sim_ent_lookup {
|
||||
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 {
|
||||
/* ====================================================================== */
|
||||
/* Metadata */
|
||||
@ -168,10 +173,7 @@ struct sim_ent {
|
||||
|
||||
f32 control_torque; /* How much torque is applied when turning towards desired focus */
|
||||
|
||||
struct {
|
||||
struct v2 move; /* Movement direction vector (speed of 0 -> 1) */
|
||||
struct v2 focus; /* Focus direction vector (where should the entity look) */
|
||||
} control;
|
||||
struct sim_control control;
|
||||
|
||||
struct sim_ent_handle move_joint;
|
||||
struct sim_ent_handle aim_joint;
|
||||
@ -314,11 +316,6 @@ struct sim_ent_prop_array {
|
||||
* 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)
|
||||
{
|
||||
return a.gen == b.gen && a.idx == b.idx;
|
||||
|
||||
@ -24,7 +24,7 @@ struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds
|
||||
#endif
|
||||
|
||||
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->aim_dir);
|
||||
@ -93,7 +93,7 @@ void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case SIM_CMD_KIND_PLAYER_MOVE:
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
{
|
||||
cmd->move_dir = br_read_v2(&br);
|
||||
cmd->aim_dir = br_read_v2(&br);
|
||||
|
||||
@ -19,7 +19,7 @@ enum sim_cmd_state {
|
||||
enum sim_cmd_kind {
|
||||
SIM_CMD_KIND_NONE,
|
||||
|
||||
SIM_CMD_KIND_PLAYER_MOVE,
|
||||
SIM_CMD_KIND_PLAYER_CONTROL,
|
||||
SIM_CMD_KIND_PLAYER_FIRE,
|
||||
|
||||
SIM_CMD_KIND_SIM_CLIENT_CONNECT,
|
||||
@ -41,7 +41,7 @@ struct sim_cmd {
|
||||
enum sim_cmd_state state;
|
||||
struct host_channel_id channel_id;
|
||||
|
||||
/* SIM_CMD_KIND_PLAYER_MOVE */
|
||||
/* SIM_CMD_KIND_PLAYER_CONTROL */
|
||||
struct v2 move_dir;
|
||||
struct v2 aim_dir;
|
||||
|
||||
|
||||
@ -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);
|
||||
break;
|
||||
} else if (ai_res->ai_family == AF_INET6) {
|
||||
/* TODO: Enable ipv6 */
|
||||
#if 0
|
||||
struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_res->ai_addr;
|
||||
res.valid = true;
|
||||
|
||||
109
src/user.c
109
src/user.c
@ -740,15 +740,7 @@ INTERNAL void user_update(void)
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* 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);
|
||||
|
||||
/* ========================== *
|
||||
* Debug commands
|
||||
* Update user state from binds
|
||||
* ========================== */
|
||||
|
||||
/* 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) {
|
||||
G.debug_draw = !G.debug_draw;
|
||||
}
|
||||
@ -809,6 +761,14 @@ INTERNAL void user_update(void)
|
||||
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
|
||||
* ========================== */
|
||||
@ -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 */
|
||||
if (!G.debug_camera) {
|
||||
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,
|
||||
.aim_dir = input_aim_dir
|
||||
});
|
||||
@ -1601,6 +1561,53 @@ INTERNAL void user_update(void)
|
||||
#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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user