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 ASSERT_DO_POPUP_AND_CRASH
// #define SERVER_ADDRESS "207.246.80.160" // #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_RENDERING
#define DEBUG_WORLD #define DEBUG_WORLD
#define UNLOCK_ALL #define UNLOCK_ALL
@ -24,7 +26,7 @@
#define DEBUG_TOOLS #define DEBUG_TOOLS
#define CHIPMUNK_INTEGRITY_CHECK #define CHIPMUNK_INTEGRITY_CHECK
// #define FAT_THRUSTERS // #define FAT_THRUSTERS
#define NO_GRAVITY // #define NO_GRAVITY
// #define NO_SUNS // #define NO_SUNS
#else #else

Binary file not shown.

@ -336,6 +336,18 @@ static void rect_query(cpSpace *space, BoxCentered box)
cpShapeFree(tmp_shape); 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) LauncherTarget missile_launcher_target(GameState *gs, Entity *launcher)
{ {
double to_face = 0.0; double to_face = 0.0;
@ -538,9 +550,12 @@ enum
{ {
DEFAULT = 1 << 0, DEFAULT = 1 << 0,
BOXES = 1 << 1, BOXES = 1 << 1,
MERGE_BOXES = 1 << 2,
}; };
static const cpShapeFilter FILTER_ONLY_BOXES = {CP_NO_GROUP, BOXES, BOXES}; 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_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}; static const cpShapeFilter FILTER_DEFAULT = {CP_NO_GROUP, DEFAULT, CP_ALL_CATEGORIES};
#define PLAYER_FILTER FILTER_DEFAULT #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 // 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 // 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; new_box->is_box = true;
flight_assert(gs->space != NULL); 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); create_rectangle_shape(gs, new_box, grid, pos, (cpVect){halfbox, halfbox}, 1.0);
new_box->box_type = type;
switch (type)
{
case BoxMerge:
cpShapeSetFilter(new_box->shape, FILTER_MERGE_BOX);
break;
default:
cpShapeSetFilter(new_box->shape, FILTER_BOXES); cpShapeSetFilter(new_box->shape, FILTER_BOXES);
break;
}
box_add_to_boxes(gs, grid, new_box); 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); cpShapeSetUserData(cur->shape, NULL);
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; 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->cursor += sizeof(size_to_write);
SER_ASSERT(ser->cursor < ser->max_size); 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++) for (int b = 0; b < data_len; b++)
{ {
ser->bytes[ser->cursor] = data[b]; ser->bytes[ser->cursor] = data[b];
ser->cursor += 1; ser->cursor += 1;
SER_ASSERT(ser->cursor < ser->max_size); SER_ASSERT(ser->cursor < ser->max_size);
} }
*/
} }
else else
{ {
@ -1177,12 +1209,10 @@ SerMaybeFailure ser_data(SerState *ser, char *data, size_t data_len, const char
} }
SER_ASSERT(got_size == expected_size); SER_ASSERT(got_size == expected_size);
} }
for (int b = 0; b < data_len; b++) size_t new_cursor = ser->cursor + data_len;
{ SER_ASSERT(new_cursor <= ser->max_size);
data[b] = ser->bytes[ser->cursor]; memcpy(data, ser->bytes + ser->cursor, data_len);
ser->cursor += 1; ser->cursor = new_cursor;
SER_ASSERT(ser->cursor <= ser->max_size);
}
} }
return ser_ok; 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 // 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! // 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 *)) 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)) if (filter_func != NULL && !filter_func(e))
continue; continue;
double dist = cpvlength((cpvsub(res->pointA, res->pointB))); double dist_sqr = cpvlengthsq((cpvsub(res->pointA, res->pointB)));
// double dist = -points->points[0].distance; // 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; closest_to_point_in_radius_result = shape;
} }
} }
if (closest_to_point_in_radius_result != NULL) if (closest_to_point_in_radius_result != NULL)
{ {
return cp_shape_entity(closest_to_point_in_radius_result); return cp_shape_entity(closest_to_point_in_radius_result);
} }
return NULL; 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) \ #define BOX_AT_TYPE(grid, pos, type) \
{ \ { \
Entity *box = new_entity(gs); \ Entity *box = new_entity(gs); \
box_create(gs, box, grid, pos); \ box_create(gs, box, grid, pos, type); \
box->box_type = type; \
box->compass_rotation = rot; \ box->compass_rotation = rot; \
box->indestructible = indestructible; \ box->indestructible = indestructible; \
} }
@ -2225,8 +2244,7 @@ void create_bomb_station(GameState *gs, cpVect pos, enum BoxType platonic_type)
grid_create(gs, grid); grid_create(gs, grid);
entity_set_pos(grid, pos); entity_set_pos(grid, pos);
Entity *platonic_box = new_entity(gs); Entity *platonic_box = new_entity(gs);
box_create(gs, platonic_box, grid, (cpVect){0}); box_create(gs, platonic_box, grid, (cpVect){0}, platonic_type);
platonic_box->box_type = platonic_type;
platonic_box->is_platonic = true; platonic_box->is_platonic = true;
BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE, 0}), BoxExplosive); BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE, 0}), BoxExplosive);
BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE * 2, 0}), BoxHullpiece); 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); grid_create(gs, grid);
entity_set_pos(grid, pos); entity_set_pos(grid, pos);
Entity *platonic_box = new_entity(gs); Entity *platonic_box = new_entity(gs);
box_create(gs, platonic_box, grid, (cpVect){0}); box_create(gs, platonic_box, grid, (cpVect){0}, platonic_type);
platonic_box->box_type = platonic_type;
platonic_box->is_platonic = true; platonic_box->is_platonic = true;
BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE * 2, 0}), BoxHullpiece); BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE * 2, 0}), BoxHullpiece);
BOX_AT_TYPE(grid, ((cpVect){BOX_SIZE * 3, 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); created_box_position = grid_world_to_local(target_grid, world_build);
} }
Entity *new_box = new_entity(gs); 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; new_box->owning_squad = player->squad;
grid_correct_for_holes(gs, target_grid); // no holey ship for you! 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; new_box->compass_rotation = player->input.build_rotation;
if (new_box->box_type == BoxScanner) if (new_box->box_type == BoxScanner)
new_box->blueprints_learned = player->box_unlocks; new_box->blueprints_learned = player->box_unlocks;
@ -2715,10 +2731,11 @@ void process(struct GameState *gs, double dt)
if (!e->exists) if (!e->exists)
continue; 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))); #ifdef INTENSIVE_PROFILING
if (e->body != NULL && dist_from_center > (INSTANT_DEATH_DISTANCE_FROM_CENTER * INSTANT_DEATH_DISTANCE_FROM_CENTER)) PROFILE_SCOPE("instant death")
#endif
{ {
bool platonic_found = false; bool platonic_found = false;
if (e->is_grid) 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!) 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)))); sqdist = cpvlengthsq(cpvsub((entity_pos(e)), (entity_pos(i.sun))));
if (sqdist < (i.sun->sun_radius * i.sun->sun_radius)) 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) if (e->body != NULL)
{ {
#ifdef INTENSIVE_PROFILING
PROFILE_SCOPE("Body processing") PROFILE_SCOPE("Body processing")
#endif
{ {
cpVect accel = sun_gravity_accel_for_entity(e, i.sun); cpVect accel = sun_gravity_accel_for_entity(e, i.sun);
cpVect new_vel = entity_vel(gs, e); cpVect new_vel = entity_vel(gs, e);
@ -2849,7 +2870,9 @@ void process(struct GameState *gs, double dt)
if (e->is_box) if (e->is_box)
{ {
// PROFILE_SCOPE("Box processing") #ifdef INTENSIVE_PROFILING
PROFILE_SCOPE("Box processing")
#endif
{ {
if (e->is_platonic) if (e->is_platonic)
{ {
@ -2869,17 +2892,35 @@ void process(struct GameState *gs, double dt)
} }
if (e->box_type == BoxMerge) if (e->box_type == BoxMerge)
{ {
#ifdef INTENSIVE_PROFILING
PROFILE_SCOPE("Merge box")
#endif
{
Entity *from_merge = e; Entity *from_merge = e;
flight_assert(from_merge != NULL); flight_assert(from_merge != NULL);
grid_to_exclude = box_grid(from_merge); 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); // 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) if (other_merge == NULL && from_merge->wants_disconnect)
from_merge->wants_disconnect = false; from_merge->wants_disconnect = false;
if (!from_merge->wants_disconnect && other_merge != NULL && !other_merge->wants_disconnect) 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)); flight_assert(box_grid(from_merge) != box_grid(other_merge));
Entity *from_grid = box_grid(from_merge); Entity *from_grid = box_grid(from_merge);
@ -2921,7 +2962,7 @@ void process(struct GameState *gs, double dt)
enum CompassRotation new_rotation = facing_vector_to_compass(from_grid, other_grid, box_facing_vector(cur)); enum CompassRotation new_rotation = facing_vector_to_compass(from_grid, other_grid, box_facing_vector(cur));
cur->compass_rotation = new_rotation; cur->compass_rotation = new_rotation;
cpVect new_cur_pos = grid_snapped_box_pos(from_grid, cpvadd(snap_movement_vect, world)); 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 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)); flight_assert(box_grid(cur) == box_grid(from_merge));
cur = next; cur = next;
} }
@ -2929,6 +2970,8 @@ void process(struct GameState *gs, double dt)
} }
} }
} }
}
}
if (e->damage >= 1.0) if (e->damage >= 1.0)
{ {
grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e); grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e);

@ -84,7 +84,9 @@ void init_profiling_mythread(uint32_t id);
void end_profiling(); void end_profiling();
void end_profiling_mythread(); 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 #else // PROFILING

@ -97,32 +97,6 @@ void server(void *info_raw)
} }
#define BOX_AT(grid, pos) BOX_AT_TYPE(grid, pos, BoxHullpiece) #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) if (enet_initialize() != 0)
{ {

@ -503,7 +503,7 @@ LauncherTarget missile_launcher_target(GameState *gs, Entity *launcher);
// grid // grid
void grid_create(struct GameState *gs, Entity *e); 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); Entity *box_grid(Entity *box);
cpVect grid_com(Entity *grid); cpVect grid_com(Entity *grid);
cpVect grid_vel(Entity *grid); cpVect grid_vel(Entity *grid);

Loading…
Cancel
Save