Merge fixes and perf improvements. Raycast

main
Cameron Murphy Reikes 2 years ago
parent e74453e838
commit 89a7cab44c

@ -14,7 +14,9 @@
#define ASSERT_DO_POPUP_AND_CRASH
// #define SERVER_ADDRESS "207.246.80.160"
#define PROFILING
// #define PROFILING
// Intensive profiling means profiling a lot of little tiny stuff. Not always enabled because tanks performance
#define INTENSIVE_PROFILING
// #define DEBUG_RENDERING
#define DEBUG_WORLD
#define UNLOCK_ALL
@ -24,7 +26,7 @@
#define DEBUG_TOOLS
#define CHIPMUNK_INTEGRITY_CHECK
// #define FAT_THRUSTERS
#define NO_GRAVITY
// #define NO_GRAVITY
// #define NO_SUNS
#else

Binary file not shown.

@ -336,6 +336,18 @@ static void rect_query(cpSpace *space, BoxCentered box)
cpShapeFree(tmp_shape);
}
static THREADLOCAL cpShape *found_merge_shape = NULL;
static void raycast_query_callback(cpShape *shape, cpVect point, cpVect normal, cpFloat alpha, void *data)
{
Entity *grid_to_exclude = (Entity *)data;
flight_assert(grid_to_exclude != NULL);
if (cp_shape_entity(shape)->is_box && cp_shape_entity(shape)->box_type == BoxMerge && box_grid(cp_shape_entity(shape)) != grid_to_exclude)
{
found_merge_shape = shape;
}
}
LauncherTarget missile_launcher_target(GameState *gs, Entity *launcher)
{
double to_face = 0.0;
@ -538,9 +550,12 @@ enum
{
DEFAULT = 1 << 0,
BOXES = 1 << 1,
MERGE_BOXES = 1 << 2,
};
static const cpShapeFilter FILTER_ONLY_BOXES = {CP_NO_GROUP, BOXES, BOXES};
static const cpShapeFilter FILTER_BOXES = {CP_NO_GROUP, DEFAULT | BOXES, CP_ALL_CATEGORIES};
static const cpShapeFilter FILTER_MERGE_BOX = {CP_NO_GROUP, DEFAULT | BOXES | MERGE_BOXES, CP_ALL_CATEGORIES};
static const cpShapeFilter FILTER_ONLY_MERGE_BOX = {CP_NO_GROUP, MERGE_BOXES, CP_ALL_CATEGORIES};
static const cpShapeFilter FILTER_DEFAULT = {CP_NO_GROUP, DEFAULT, CP_ALL_CATEGORIES};
#define PLAYER_FILTER FILTER_DEFAULT
@ -638,7 +653,8 @@ void box_add_to_boxes(GameState *gs, Entity *grid, Entity *box_to_add)
// box must be passed as a parameter as the box added to chipmunk uses this pointer in its
// user data. pos is in local coordinates. Adds the box to the grid's chain of boxes
void box_create(GameState *gs, Entity *new_box, Entity *grid, cpVect pos)
// Must pass in a type so it knows what filter to give the collision shape
void box_create(GameState *gs, Entity *new_box, Entity *grid, cpVect pos, enum BoxType type)
{
new_box->is_box = true;
flight_assert(gs->space != NULL);
@ -648,7 +664,16 @@ void box_create(GameState *gs, Entity *new_box, Entity *grid, cpVect pos)
create_rectangle_shape(gs, new_box, grid, pos, (cpVect){halfbox, halfbox}, 1.0);
cpShapeSetFilter(new_box->shape, FILTER_BOXES);
new_box->box_type = type;
switch (type)
{
case BoxMerge:
cpShapeSetFilter(new_box->shape, FILTER_MERGE_BOX);
break;
default:
cpShapeSetFilter(new_box->shape, FILTER_BOXES);
break;
}
box_add_to_boxes(gs, grid, new_box);
}
@ -834,7 +859,7 @@ static void grid_correct_for_holes(GameState *gs, struct Entity *grid)
cpShapeSetUserData(cur->shape, NULL);
cur->shape = NULL;
box_create(gs, cur, new_grid, new_shape_position); // destroys next/prev fields on cur
box_create(gs, cur, new_grid, new_shape_position, cur->box_type); // destroys next/prev fields on cur
cur = next;
}
@ -1123,12 +1148,19 @@ SerMaybeFailure ser_data(SerState *ser, char *data, size_t data_len, const char
ser->cursor += sizeof(size_to_write);
SER_ASSERT(ser->cursor < ser->max_size);
}
size_t new_cursor = ser->cursor + data_len;
SER_ASSERT(new_cursor < ser->max_size);
memcpy(ser->bytes + ser->cursor, data, data_len);
ser->cursor = new_cursor;
/*
for (int b = 0; b < data_len; b++)
{
ser->bytes[ser->cursor] = data[b];
ser->cursor += 1;
SER_ASSERT(ser->cursor < ser->max_size);
}
*/
}
else
{
@ -1177,12 +1209,10 @@ SerMaybeFailure ser_data(SerState *ser, char *data, size_t data_len, const char
}
SER_ASSERT(got_size == expected_size);
}
for (int b = 0; b < data_len; b++)
{
data[b] = ser->bytes[ser->cursor];
ser->cursor += 1;
SER_ASSERT(ser->cursor <= ser->max_size);
}
size_t new_cursor = ser->cursor + data_len;
SER_ASSERT(new_cursor <= ser->max_size);
memcpy(data, ser->bytes + ser->cursor, data_len);
ser->cursor = new_cursor;
}
return ser_ok;
}
@ -1912,14 +1942,6 @@ bool client_to_server_deserialize(GameState *gs, struct ClientToServer *msg, uns
}
}
static THREADLOCAL Entity *grid_to_exclude = NULL;
static bool merge_filter(Entity *potential_merge)
{
flight_assert(grid_to_exclude != NULL);
flight_assert(grid_to_exclude->is_grid);
return potential_merge->is_box && potential_merge->box_type == BoxMerge && box_grid(potential_merge) != grid_to_exclude;
}
// filter func null means everything is ok, if it's not null and returns false, that means
// exclude it from the selection. This returns the closest box entity!
Entity *closest_box_to_point_in_radius(struct GameState *gs, cpVect point, double radius, bool (*filter_func)(Entity *))
@ -1938,20 +1960,18 @@ Entity *closest_box_to_point_in_radius(struct GameState *gs, cpVect point, doubl
if (filter_func != NULL && !filter_func(e))
continue;
double dist = cpvlength((cpvsub(res->pointA, res->pointB)));
double dist_sqr = cpvlengthsq((cpvsub(res->pointA, res->pointB)));
// double dist = -points->points[0].distance;
if (dist > closest_to_point_in_radius_result_largest_dist)
if (dist_sqr > closest_to_point_in_radius_result_largest_dist)
{
closest_to_point_in_radius_result_largest_dist = dist;
closest_to_point_in_radius_result_largest_dist = dist_sqr;
closest_to_point_in_radius_result = shape;
}
}
if (closest_to_point_in_radius_result != NULL)
{
return cp_shape_entity(closest_to_point_in_radius_result);
}
return NULL;
}
@ -2213,8 +2233,7 @@ void create_bomb_station(GameState *gs, cpVect pos, enum BoxType platonic_type)
#define BOX_AT_TYPE(grid, pos, type) \
{ \
Entity *box = new_entity(gs); \
box_create(gs, box, grid, pos); \
box->box_type = type; \
box_create(gs, box, grid, pos, type); \
box->compass_rotation = rot; \
box->indestructible = indestructible; \
}
@ -2225,8 +2244,7 @@ void create_bomb_station(GameState *gs, cpVect pos, enum BoxType platonic_type)
grid_create(gs, grid);
entity_set_pos(grid, pos);
Entity *platonic_box = new_entity(gs);
box_create(gs, platonic_box, grid, (cpVect){0});
platonic_box->box_type = platonic_type;
box_create(gs, platonic_box, grid, (cpVect){0}, platonic_type);
platonic_box->is_platonic = true;
BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE, 0}), BoxExplosive);
BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE * 2, 0}), BoxHullpiece);
@ -2264,8 +2282,7 @@ void create_hard_shell_station(GameState *gs, cpVect pos, enum BoxType platonic_
grid_create(gs, grid);
entity_set_pos(grid, pos);
Entity *platonic_box = new_entity(gs);
box_create(gs, platonic_box, grid, (cpVect){0});
platonic_box->box_type = platonic_type;
box_create(gs, platonic_box, grid, (cpVect){0}, platonic_type);
platonic_box->is_platonic = true;
BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE * 2, 0}), BoxHullpiece);
BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE * 3, 0}), BoxHullpiece);
@ -2684,10 +2701,9 @@ void process(struct GameState *gs, double dt)
created_box_position = grid_world_to_local(target_grid, world_build);
}
Entity *new_box = new_entity(gs);
box_create(gs, new_box, target_grid, created_box_position);
box_create(gs, new_box, target_grid, created_box_position, player->input.build_type);
new_box->owning_squad = player->squad;
grid_correct_for_holes(gs, target_grid); // no holey ship for you!
new_box->box_type = player->input.build_type;
new_box->compass_rotation = player->input.build_rotation;
if (new_box->box_type == BoxScanner)
new_box->blueprints_learned = player->box_unlocks;
@ -2715,10 +2731,11 @@ void process(struct GameState *gs, double dt)
if (!e->exists)
continue;
// PROFILE_SCOPE("instant death")
if (e->body != NULL && cpvlengthsq((entity_pos(e))) > (INSTANT_DEATH_DISTANCE_FROM_CENTER * INSTANT_DEATH_DISTANCE_FROM_CENTER))
{
cpFloat dist_from_center = cpvlengthsq((entity_pos(e)));
if (e->body != NULL && dist_from_center > (INSTANT_DEATH_DISTANCE_FROM_CENTER * INSTANT_DEATH_DISTANCE_FROM_CENTER))
#ifdef INTENSIVE_PROFILING
PROFILE_SCOPE("instant death")
#endif
{
bool platonic_found = false;
if (e->is_grid)
@ -2759,7 +2776,9 @@ void process(struct GameState *gs, double dt)
if (!e->is_grid) // grids aren't damaged (this edge case sucks!)
{
// PROFILE_SCOPE("Grid processing")
#ifdef INTENSIVE_PROFILING
PROFILE_SCOPE("Grid processing")
#endif
{
sqdist = cpvlengthsq(cpvsub((entity_pos(e)), (entity_pos(i.sun))));
if (sqdist < (i.sun->sun_radius * i.sun->sun_radius))
@ -2771,7 +2790,9 @@ void process(struct GameState *gs, double dt)
if (e->body != NULL)
{
#ifdef INTENSIVE_PROFILING
PROFILE_SCOPE("Body processing")
#endif
{
cpVect accel = sun_gravity_accel_for_entity(e, i.sun);
cpVect new_vel = entity_vel(gs, e);
@ -2849,7 +2870,9 @@ void process(struct GameState *gs, double dt)
if (e->is_box)
{
// PROFILE_SCOPE("Box processing")
#ifdef INTENSIVE_PROFILING
PROFILE_SCOPE("Box processing")
#endif
{
if (e->is_platonic)
{
@ -2869,63 +2892,83 @@ void process(struct GameState *gs, double dt)
}
if (e->box_type == BoxMerge)
{
Entity *from_merge = e;
flight_assert(from_merge != NULL);
grid_to_exclude = box_grid(from_merge);
Entity *other_merge = closest_box_to_point_in_radius(gs, entity_pos(from_merge), MERGE_MAX_DIST, merge_filter);
if (other_merge == NULL && from_merge->wants_disconnect)
from_merge->wants_disconnect = false;
if (!from_merge->wants_disconnect && other_merge != NULL && !other_merge->wants_disconnect)
#ifdef INTENSIVE_PROFILING
PROFILE_SCOPE("Merge box")
#endif
{
flight_assert(box_grid(from_merge) != box_grid(other_merge));
Entity *from_merge = e;
flight_assert(from_merge != NULL);
Entity *grid_to_exclude = box_grid(from_merge);
// Entity *other_merge = closest_box_to_point_in_radius(gs, entity_pos(from_merge), MERGE_MAX_DIST, merge_filter);
cpVect along = box_facing_vector(from_merge);
cpVect from = cpvadd(entity_pos(from_merge), cpvmult(along, BOX_SIZE / 2.0 + 0.03));
cpVect to = cpvadd(from, cpvmult(along, MERGE_MAX_DIST));
found_merge_shape = NULL;
cpSpaceSegmentQuery(gs->space, from, to, 0.0, FILTER_ONLY_MERGE_BOX, raycast_query_callback, (void *)grid_to_exclude);
cpShape *other_merge_shape = found_merge_shape;
Entity *other_merge = NULL;
if (other_merge_shape != NULL)
other_merge = cp_shape_entity(other_merge_shape);
if (other_merge == NULL && from_merge->wants_disconnect)
from_merge->wants_disconnect = false;
if (!from_merge->wants_disconnect && other_merge != NULL && !other_merge->wants_disconnect)
{
#ifdef INTENSIVE_PROFILING
PROFILE_SCOPE("Do actual merge")
#endif
{
flight_assert(box_grid(from_merge) != box_grid(other_merge));
Entity *from_grid = box_grid(from_merge);
Entity *other_grid = box_grid(other_merge);
Entity *from_grid = box_grid(from_merge);
Entity *other_grid = box_grid(other_merge);
// the merges are near eachother, but are they facing eachother...
bool from_facing_other = cpvdot(box_facing_vector(from_merge), cpvnormalize(cpvsub(entity_pos(other_merge), entity_pos(from_merge)))) > 0.8;
bool other_facing_from = cpvdot(box_facing_vector(other_merge), cpvnormalize(cpvsub(entity_pos(from_merge), entity_pos(other_merge)))) > 0.8;
// the merges are near eachother, but are they facing eachother...
bool from_facing_other = cpvdot(box_facing_vector(from_merge), cpvnormalize(cpvsub(entity_pos(other_merge), entity_pos(from_merge)))) > 0.8;
bool other_facing_from = cpvdot(box_facing_vector(other_merge), cpvnormalize(cpvsub(entity_pos(from_merge), entity_pos(other_merge)))) > 0.8;
// using this stuff to detect if when the other grid's boxes are snapped, they'll be snapped
// to be next to the from merge box
cpVect actual_new_pos = grid_snapped_box_pos(from_grid, entity_pos(other_merge));
cpVect needed_new_pos = cpvadd(entity_pos(from_merge), cpvmult(box_facing_vector(from_merge), BOX_SIZE));
if (from_facing_other && other_facing_from && cpvnear(needed_new_pos, actual_new_pos, 0.01))
{
// do the merge
cpVect facing_vector_needed = cpvmult(box_facing_vector(from_merge), -1.0);
cpVect current_facing_vector = box_facing_vector(other_merge);
double angle_diff = cpvanglediff(current_facing_vector, facing_vector_needed);
if (angle_diff == FLT_MIN)
angle_diff = 0.0;
flight_assert(!isnan(angle_diff));
// using this stuff to detect if when the other grid's boxes are snapped, they'll be snapped
// to be next to the from merge box
cpVect actual_new_pos = grid_snapped_box_pos(from_grid, entity_pos(other_merge));
cpVect needed_new_pos = cpvadd(entity_pos(from_merge), cpvmult(box_facing_vector(from_merge), BOX_SIZE));
if (from_facing_other && other_facing_from && cpvnear(needed_new_pos, actual_new_pos, 0.01))
{
// do the merge
cpVect facing_vector_needed = cpvmult(box_facing_vector(from_merge), -1.0);
cpVect current_facing_vector = box_facing_vector(other_merge);
double angle_diff = cpvanglediff(current_facing_vector, facing_vector_needed);
if (angle_diff == FLT_MIN)
angle_diff = 0.0;
flight_assert(!isnan(angle_diff));
cpBodySetAngle(other_grid->body, cpBodyGetAngle(other_grid->body) + angle_diff);
cpBodySetAngle(other_grid->body, cpBodyGetAngle(other_grid->body) + angle_diff);
cpVect moved_because_angle_change = cpvsub(needed_new_pos, entity_pos(other_merge));
cpBodySetPosition(other_grid->body, (cpvadd(entity_pos(other_grid), moved_because_angle_change)));
cpVect moved_because_angle_change = cpvsub(needed_new_pos, entity_pos(other_merge));
cpBodySetPosition(other_grid->body, (cpvadd(entity_pos(other_grid), moved_because_angle_change)));
// cpVect snap_movement_vect = cpvsub(actual_new_pos, entity_pos(other_merge));
cpVect snap_movement_vect = (cpVect){0};
// cpVect snap_movement_vect = cpvsub(actual_new_pos, entity_pos(other_merge));
cpVect snap_movement_vect = (cpVect){0};
Entity *cur = get_entity(gs, other_grid->boxes);
Entity *cur = get_entity(gs, other_grid->boxes);
other_grid->boxes = (EntityID){0};
while (cur != NULL)
{
Entity *next = get_entity(gs, cur->next_box);
cpVect world = entity_pos(cur);
enum CompassRotation new_rotation = facing_vector_to_compass(from_grid, other_grid, box_facing_vector(cur));
cur->compass_rotation = new_rotation;
cpVect new_cur_pos = grid_snapped_box_pos(from_grid, cpvadd(snap_movement_vect, world));
box_create(gs, cur, from_grid, grid_world_to_local(from_grid, new_cur_pos)); // destroys next/prev fields on cur
flight_assert(box_grid(cur) == box_grid(from_merge));
cur = next;
other_grid->boxes = (EntityID){0};
while (cur != NULL)
{
Entity *next = get_entity(gs, cur->next_box);
cpVect world = entity_pos(cur);
enum CompassRotation new_rotation = facing_vector_to_compass(from_grid, other_grid, box_facing_vector(cur));
cur->compass_rotation = new_rotation;
cpVect new_cur_pos = grid_snapped_box_pos(from_grid, cpvadd(snap_movement_vect, world));
box_create(gs, cur, from_grid, grid_world_to_local(from_grid, new_cur_pos), cur->box_type); // destroys next/prev fields on cur
flight_assert(box_grid(cur) == box_grid(from_merge));
cur = next;
}
entity_destroy(gs, other_grid);
}
}
entity_destroy(gs, other_grid);
}
}
}

@ -84,7 +84,9 @@ void init_profiling_mythread(uint32_t id);
void end_profiling();
void end_profiling_mythread();
#define PROFILE_SCOPE(name) DeferLoop(SpallTraceBeginLenTidPid(&spall_ctx, &spall_buffer, name, sizeof(name) - 1, my_thread_id, 0, get_time_in_micros()), SpallTraceEndTidPid(&spall_ctx, &spall_buffer, my_thread_id, 0, get_time_in_micros()))
#define STRINGIZE(x) STRINGIZE2(x)
#define STRINGIZE2(x) #x
#define PROFILE_SCOPE(name) DeferLoop(SpallTraceBeginLenTidPid(&spall_ctx, &spall_buffer, "L" STRINGIZE(__LINE__) " " name , sizeof("L" STRINGIZE(__LINE__) " " name) - 1, my_thread_id, 0, get_time_in_micros()), SpallTraceEndTidPid(&spall_ctx, &spall_buffer, my_thread_id, 0, get_time_in_micros()))
#else // PROFILING

@ -97,32 +97,6 @@ void server(void *info_raw)
}
#define BOX_AT(grid, pos) BOX_AT_TYPE(grid, pos, BoxHullpiece)
// one box policy
if (false)
{
Entity *grid = new_entity(&gs);
grid_create(&gs, grid);
entity_set_pos(grid, (cpVect){-BOX_SIZE * 2, 0.0});
Entity *box = new_entity(&gs);
box_create(&gs, box, grid, (cpVect){0});
}
// rotation test
if (false)
{
Entity *grid = new_entity(&gs);
grid_create(&gs, grid);
entity_set_pos(grid, (cpVect){-BOX_SIZE * 2, 0.0});
entity_set_rotation(grid, PI / 1.7);
cpBodySetVelocity(grid->body, cpv(-0.1, 0.0));
cpBodySetAngularVelocity(grid->body, 1.0);
BOX_AT(grid, ((cpVect){0}));
BOX_AT(grid, ((cpVect){BOX_SIZE, 0}));
BOX_AT(grid, ((cpVect){2.0 * BOX_SIZE, 0}));
BOX_AT(grid, ((cpVect){2.0 * BOX_SIZE, BOX_SIZE}));
BOX_AT(grid, ((cpVect){0.0 * BOX_SIZE, -BOX_SIZE}));
}
if (enet_initialize() != 0)
{

@ -503,7 +503,7 @@ LauncherTarget missile_launcher_target(GameState *gs, Entity *launcher);
// grid
void grid_create(struct GameState *gs, Entity *e);
void box_create(struct GameState *gs, Entity *new_box, Entity *grid, cpVect pos);
void box_create(struct GameState *gs, Entity *new_box, Entity *grid, cpVect pos, enum BoxType type);
Entity *box_grid(Entity *box);
cpVect grid_com(Entity *grid);
cpVect grid_vel(Entity *grid);

Loading…
Cancel
Save