Fixes and helix fixign

main
Cameron Murphy Reikes 2 years ago
parent 9519189cd8
commit 0ce9ecad9d

2
.gitignore vendored

@ -1,3 +1,5 @@
compile_commands.json
.cache/
enc_temp_folder/ enc_temp_folder/
*.spall # profiling *.spall # profiling
*.bin # world files *.bin # world files

Binary file not shown.

@ -81,11 +81,13 @@ static uint64_t box_unlock_number(enum BoxType box)
void unlock_box(Player *player, enum BoxType box) void unlock_box(Player *player, enum BoxType box)
{ {
assert(box < MAX_BOX_TYPES);
player->box_unlocks |= box_unlock_number(box); player->box_unlocks |= box_unlock_number(box);
} }
bool box_unlocked(Player *player, enum BoxType box) bool box_unlocked(Player *player, enum BoxType box)
{ {
assert(box < MAX_BOX_TYPES);
return (player->box_unlocks & box_unlock_number(box)) > 0; return (player->box_unlocks & box_unlock_number(box)) > 0;
} }
@ -533,8 +535,11 @@ static void on_damage(cpArbiter *arb, cpSpace *space, cpDataPointer userData)
// cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, b, NULL); // cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, b, NULL);
// cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, a, NULL); // cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, a, NULL);
} }
// must be called with zero initialized game state, because copies the server side computing!
void initialize(GameState *gs, void *entity_arena, size_t entity_arena_size) void initialize(GameState *gs, void *entity_arena, size_t entity_arena_size)
{ {
bool is_server_side = gs->server_side_computing;
*gs = (GameState){0}; *gs = (GameState){0};
memset(entity_arena, 0, entity_arena_size); // SUPER critical. Random vals in the entity data causes big problem memset(entity_arena, 0, entity_arena_size); // SUPER critical. Random vals in the entity data causes big problem
gs->entities = (Entity *)entity_arena; gs->entities = (Entity *)entity_arena;
@ -543,6 +548,7 @@ void initialize(GameState *gs, void *entity_arena, size_t entity_arena_size)
cpSpaceSetUserData(gs->space, (cpDataPointer)gs); // needed in the handler cpSpaceSetUserData(gs->space, (cpDataPointer)gs); // needed in the handler
cpCollisionHandler *handler = cpSpaceAddCollisionHandler(gs->space, 0, 0); // @Robust limit collision type to just blocks that can be damaged cpCollisionHandler *handler = cpSpaceAddCollisionHandler(gs->space, 0, 0); // @Robust limit collision type to just blocks that can be damaged
handler->postSolveFunc = on_damage; handler->postSolveFunc = on_damage;
gs->server_side_computing = is_server_side;
} }
void destroy(GameState *gs) void destroy(GameState *gs)
{ {
@ -792,6 +798,7 @@ enum GameVersion
VReallyRemovedTimeFromDiskSave, // apparently last one didn't work VReallyRemovedTimeFromDiskSave, // apparently last one didn't work
VRemovedInsideOfMe, VRemovedInsideOfMe,
VSwitchedToUnlocks, VSwitchedToUnlocks,
VAddedPlatonic,
VMax, // this minus one will be the version used VMax, // this minus one will be the version used
}; };
@ -979,6 +986,9 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e)
SER_VAR(&e->box_type); SER_VAR(&e->box_type);
SER_VAR(&e->always_visible); SER_VAR(&e->always_visible);
if (ser->version >= VAddedPlatonic)
SER_VAR(&e->is_platonic);
if (ser->version <= VSwitchedToUnlocks) if (ser->version <= VSwitchedToUnlocks)
{ {
bool throwaway; bool throwaway;
@ -992,6 +1002,12 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e)
SER_VAR(&e->wanted_thrust); SER_VAR(&e->wanted_thrust);
SER_VAR(&e->energy_used); SER_VAR(&e->energy_used);
SER_VAR(&e->sun_amount); SER_VAR(&e->sun_amount);
if (ser->version >= VAddedPlatonic)
{
SER_VAR(&e->scanner_head_rotate);
SER_VAR(&e->platonic_nearest_direction);
SER_VAR(&e->platonic_detection_strength);
}
if (ser->version >= VRemovedInsideOfMe && ser->save_or_load_from_disk) if (ser->version >= VRemovedInsideOfMe && ser->save_or_load_from_disk)
{ {
@ -1077,9 +1093,6 @@ SerMaybeFailure ser_server_to_client(SerState *ser, ServerToClient *s)
SER_VAR(&cur_next_entity); SER_VAR(&cur_next_entity);
SER_ASSERT(cur_next_entity <= ser->max_entity_index); SER_ASSERT(cur_next_entity <= ser->max_entity_index);
if (!ser->save_or_load_from_disk)
SER_MAYBE_RETURN(ser_entityid(ser, &gs->cur_spacestation));
SER_VAR(&s->your_player); SER_VAR(&s->your_player);
if (ser->version >= VReallyRemovedTimeFromDiskSave && ser->save_or_load_from_disk) if (ser->version >= VReallyRemovedTimeFromDiskSave && ser->save_or_load_from_disk)
{ {
@ -1122,7 +1135,7 @@ SerMaybeFailure ser_server_to_client(SerState *ser, ServerToClient *s)
// are loaded in the parent body is loaded in and can be referenced. // are loaded in the parent body is loaded in and can be referenced.
BOXES_ITER(gs, cur, e) BOXES_ITER(gs, cur, e)
{ {
bool this_box_in_range = (ser->for_player == NULL || (ser->for_player != NULL && V2distsqr(entity_pos(ser->for_player), entity_pos(cur)) < VISION_RADIUS * VISION_RADIUS)); bool this_box_in_range = (ser->save_or_load_from_disk || ser->for_player == NULL || (ser->for_player != NULL && V2distsqr(entity_pos(ser->for_player), entity_pos(cur)) < VISION_RADIUS * VISION_RADIUS));
if (cur->always_visible) if (cur->always_visible)
this_box_in_range = true; this_box_in_range = true;
if (this_box_in_range) if (this_box_in_range)
@ -1534,7 +1547,7 @@ V2 box_vel(Entity *box)
return cp_to_v2(cpBodyGetVelocityAtWorldPoint(grid->body, v2_to_cp(entity_pos(box)))); return cp_to_v2(cpBodyGetVelocityAtWorldPoint(grid->body, v2_to_cp(entity_pos(box))));
} }
EntityID create_spacestation(GameState *gs) EntityID create_initial_world(GameState *gs)
{ {
#define BOX_AT_TYPE(grid, pos, type) \ #define BOX_AT_TYPE(grid, pos, type) \
{ \ { \
@ -1542,21 +1555,18 @@ EntityID create_spacestation(GameState *gs)
box_create(gs, box, grid, pos); \ box_create(gs, box, grid, pos); \
box->box_type = type; \ box->box_type = type; \
box->indestructible = indestructible; \ box->indestructible = indestructible; \
box->always_visible = true; \
box->no_save_to_disk = true; \
} }
#define BOX_AT(grid, pos) BOX_AT_TYPE(grid, pos, BoxHullpiece) #define BOX_AT(grid, pos) BOX_AT_TYPE(grid, pos, BoxHullpiece)
bool indestructible = false; bool indestructible = false;
Entity *grid = new_entity(gs); Entity *grid = new_entity(gs);
grid_create(gs, grid); grid_create(gs, grid);
grid->no_save_to_disk = true; entity_set_pos(grid, (V2){-16.0f, 0.0f});
entity_set_pos(grid, (V2){-80.0f, 0.0f});
entity_ensure_in_orbit(grid); entity_ensure_in_orbit(grid);
Entity *explosion_box = new_entity(gs); Entity *explosion_box = new_entity(gs);
box_create(gs, explosion_box, grid, (V2){0}); box_create(gs, explosion_box, grid, (V2){0});
explosion_box->no_save_to_disk = true; explosion_box->box_type = BoxExplosive;
explosion_box->always_visible = true; explosion_box->is_platonic = true;
BOX_AT_TYPE(grid, ((V2){BOX_SIZE, 0}), BoxExplosive); BOX_AT_TYPE(grid, ((V2){BOX_SIZE, 0}), BoxExplosive);
BOX_AT_TYPE(grid, ((V2){BOX_SIZE * 2, 0}), BoxHullpiece); BOX_AT_TYPE(grid, ((V2){BOX_SIZE * 2, 0}), BoxHullpiece);
BOX_AT_TYPE(grid, ((V2){BOX_SIZE * 3, 0}), BoxHullpiece); BOX_AT_TYPE(grid, ((V2){BOX_SIZE * 3, 0}), BoxHullpiece);
@ -1826,11 +1836,6 @@ void process(GameState *gs, float dt)
p->damage = clamp01(p->damage); p->damage = clamp01(p->damage);
} }
if (get_entity(gs, gs->cur_spacestation) == NULL)
{
gs->cur_spacestation = create_spacestation(gs);
}
// process entities // process entities
for (size_t i = 0; i < gs->cur_next_entity; i++) for (size_t i = 0; i < gs->cur_next_entity; i++)
{ {
@ -1869,12 +1874,18 @@ void process(GameState *gs, float dt)
if (e->is_box) if (e->is_box)
{ {
if (e->is_platonic)
{
e->damage = 0.0f;
gs->platonic_positions[(int)e->box_type] = entity_pos(e);
}
if (e->box_type == BoxExplosive && e->damage >= EXPLOSION_DAMAGE_THRESHOLD) if (e->box_type == BoxExplosive && e->damage >= EXPLOSION_DAMAGE_THRESHOLD)
{ {
Entity *explosion = new_entity(gs); Entity *explosion = new_entity(gs);
explosion->is_explosion = true; explosion->is_explosion = true;
explosion->explosion_pos = entity_pos(e); explosion->explosion_pos = entity_pos(e);
explosion->explosion_vel = grid_vel(box_grid(e)); explosion->explosion_vel = grid_vel(box_grid(e));
if (!e->is_platonic)
grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e); grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e);
} }
if (e->damage >= 1.0f) if (e->damage >= 1.0f)
@ -1884,9 +1895,10 @@ void process(GameState *gs, float dt)
} }
if (e->is_grid) if (e->is_grid)
{ {
Entity *grid = e;
// calculate how much energy solar panels provide // calculate how much energy solar panels provide
float energy_to_add = 0.0f; float energy_to_add = 0.0f;
BOXES_ITER(gs, cur, e) BOXES_ITER(gs, cur, grid)
{ {
if (cur->box_type == BoxSolarPanel) if (cur->box_type == BoxSolarPanel)
{ {
@ -1896,7 +1908,7 @@ void process(GameState *gs, float dt)
} }
// apply all of the energy to all connected batteries // apply all of the energy to all connected batteries
BOXES_ITER(gs, cur, e) BOXES_ITER(gs, cur, grid)
{ {
if (energy_to_add <= 0.0f) if (energy_to_add <= 0.0f)
break; break;
@ -1913,33 +1925,78 @@ void process(GameState *gs, float dt)
float non_battery_energy_left_over = energy_to_add; float non_battery_energy_left_over = energy_to_add;
// use the energy, stored in the batteries, in various boxes // use the energy, stored in the batteries, in various boxes
BOXES_ITER(gs, cur, e) BOXES_ITER(gs, cur_box, grid)
{ {
if (cur->box_type == BoxThruster) if (cur_box->box_type == BoxThruster)
{ {
float energy_to_consume = cur->wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt; float energy_to_consume = cur_box->wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt;
if (energy_to_consume > 0.0f) if (energy_to_consume > 0.0f)
{ {
cur->thrust = 0.0f; cur_box->thrust = 0.0f;
float energy_unconsumed = batteries_use_energy(gs, e, &non_battery_energy_left_over, energy_to_consume); float energy_unconsumed = batteries_use_energy(gs, grid, &non_battery_energy_left_over, energy_to_consume);
cur->thrust = (1.0f - energy_unconsumed / energy_to_consume) * cur->wanted_thrust; cur_box->thrust = (1.0f - energy_unconsumed / energy_to_consume) * cur_box->wanted_thrust;
if (cur->thrust >= 0.0f) if (cur_box->thrust >= 0.0f)
cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(entity_pos(cur))); cpBodyApplyForceAtWorldPoint(grid->body, v2_to_cp(thruster_force(cur_box)), v2_to_cp(entity_pos(cur_box)));
} }
} }
if (cur->box_type == BoxMedbay) if (cur_box->box_type == BoxMedbay)
{ {
Entity *potential_meatbag_to_heal = get_entity(gs, cur->player_who_is_inside_of_me); Entity *potential_meatbag_to_heal = get_entity(gs, cur_box->player_who_is_inside_of_me);
if (potential_meatbag_to_heal != NULL) if (potential_meatbag_to_heal != NULL)
{ {
float wanted_energy_use = fminf(potential_meatbag_to_heal->damage, PLAYER_ENERGY_RECHARGE_PER_SECOND * dt); float wanted_energy_use = fminf(potential_meatbag_to_heal->damage, PLAYER_ENERGY_RECHARGE_PER_SECOND * dt);
if (wanted_energy_use > 0.0f) if (wanted_energy_use > 0.0f)
{ {
float energy_unconsumed = batteries_use_energy(gs, e, &non_battery_energy_left_over, wanted_energy_use); float energy_unconsumed = batteries_use_energy(gs, grid, &non_battery_energy_left_over, wanted_energy_use);
potential_meatbag_to_heal->damage -= (1.0f - energy_unconsumed / wanted_energy_use) * wanted_energy_use; potential_meatbag_to_heal->damage -= (1.0f - energy_unconsumed / wanted_energy_use) * wanted_energy_use;
} }
} }
} }
if (cur_box->box_type == BoxScanner)
{
// set the nearest platonic solid!
if (gs->server_side_computing)
{
float energy_unconsumed = batteries_use_energy(gs, grid, &non_battery_energy_left_over, SCANNER_ENERGY_USE * dt);
if (energy_unconsumed >= SCANNER_ENERGY_USE * dt)
{
cur_box->platonic_detection_strength = 0.0f;
cur_box->platonic_nearest_direction = (V2){0};
}
else
{
V2 from_pos = entity_pos(cur_box);
V2 nearest = {0};
float nearest_dist = INFINITY;
for (int i = 0; i < MAX_BOX_TYPES; i++)
{
V2 cur_pos = gs->platonic_positions[i];
if (V2length(cur_pos) > 0.0f) // zero is uninitialized, the platonic solid doesn't exist (probably) @Robust do better
{
float length_to_cur = V2dist(from_pos, cur_pos);
if (length_to_cur < nearest_dist)
{
nearest_dist = length_to_cur;
nearest = cur_pos;
}
}
}
if (nearest_dist < INFINITY)
{
cur_box->platonic_nearest_direction = V2normalize(V2sub(nearest, from_pos));
cur_box->platonic_detection_strength = fmaxf(0.1f, 1.0f - fminf(1.0f, nearest_dist / 100.0f));
}
else
{
cur_box->platonic_nearest_direction = (V2){0};
cur_box->platonic_detection_strength = 0.0f;
}
}
}
cur_box->scanner_head_rotate_speed = lerp(cur_box->scanner_head_rotate_speed, cur_box->platonic_detection_strength > 0.0f ? 3.0f : 0.0f, dt * 3.0f);
cur_box->scanner_head_rotate += cur_box->scanner_head_rotate_speed * dt;
cur_box->scanner_head_rotate = fmodf(cur_box->scanner_head_rotate, 2.0f * PI);
}
} }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

@ -1629,14 +1629,28 @@ static void frame(void)
if (b->box_type == BoxScanner) if (b->box_type == BoxScanner)
{ {
sgp_set_image(0, image_scanner_head); sgp_set_image(0, image_scanner_head);
sgp_rotate_at((float)gs.time * 3.0f, entity_pos(b).x, entity_pos(b).y); sgp_rotate_at(b->scanner_head_rotate, entity_pos(b).x, entity_pos(b).y);
pipeline_scope(goodpixel_pipeline) pipeline_scope(goodpixel_pipeline)
draw_texture_centered(entity_pos(b), BOX_SIZE); draw_texture_centered(entity_pos(b), BOX_SIZE);
set_color(WHITE);
} }
sgp_set_color(0.5f, 0.1f, 0.1f, b->damage); sgp_set_color(0.5f, 0.1f, 0.1f, b->damage);
draw_color_rect_centered(entity_pos(b), BOX_SIZE); draw_color_rect_centered(entity_pos(b), BOX_SIZE);
} }
// outside of the transform scope
if (b->box_type == BoxScanner)
{
if (b->platonic_detection_strength > 0.0f)
{
set_color(colhexcode(0xf2d75c));
V2 to = V2add(entity_pos(b), V2scale(b->platonic_nearest_direction, b->platonic_detection_strength));
dbg_rect(to);
dbg_rect(entity_pos(b));
sgp_draw_line(entity_pos(b).x, entity_pos(b).y, to.x, to.y);
}
}
} }
} }

@ -1,3 +1,6 @@
main.c
gamestate.c
server.c
-Ithirdparty -Ithirdparty
-Ithirdparty/minilzo -Ithirdparty/minilzo
-Ithirdparty/enet/include -Ithirdparty/enet/include

@ -76,8 +76,11 @@ void server(void *info_raw)
size_t entities_size = (sizeof(Entity) * MAX_ENTITIES); size_t entities_size = (sizeof(Entity) * MAX_ENTITIES);
Entity *entity_data = malloc(entities_size); Entity *entity_data = malloc(entities_size);
initialize(&gs, entity_data, entities_size); initialize(&gs, entity_data, entities_size);
gs.server_side_computing = true;
Log("Allocated %zu bytes for entities\n", entities_size); Log("Allocated %zu bytes for entities\n", entities_size);
create_initial_world(&gs);
// inputs // inputs
Queue player_input_queues[MAX_PLAYERS] = {0}; Queue player_input_queues[MAX_PLAYERS] = {0};
size_t input_queue_data_size = QUEUE_SIZE_FOR_ELEMENTS(sizeof(InputFrame), INPUT_QUEUE_MAX); size_t input_queue_data_size = QUEUE_SIZE_FOR_ELEMENTS(sizeof(InputFrame), INPUT_QUEUE_MAX);

@ -8,12 +8,17 @@ SetWorkingDir, %A_ScriptDir%
^Esc::return ^Esc::return
^b:: ^b::
WinKill, "Flight Not Hosting" WinKill, Flight Hosting
Sleep, 20 Sleep, 20
WinActivate flight.rdbg
Sleep 20
Send, {Shift down}{F5}{Shift up}
Send, {F5}
WinActivate, flightbuild WinActivate, flightbuild
If WinActive("flightbuild") If WinActive("flightbuild")
{ {
Send, cd C:\Users\Cameron\Documents\flight{Enter} build_debug.bat && flight_debug.exe{Enter} Send, {Enter}
Send, msbuild{Enter}
} }
return return

@ -2,6 +2,7 @@
#include "ipsettings.h" #include "ipsettings.h"
#define MAX_BOX_TYPES 64
#define MAX_PLAYERS 16 #define MAX_PLAYERS 16
#define MAX_ENTITIES 1024 * 25 #define MAX_ENTITIES 1024 * 25
#define BOX_SIZE 0.25f #define BOX_SIZE 0.25f
@ -10,6 +11,7 @@
#define PLAYER_JETPACK_FORCE 1.5f #define PLAYER_JETPACK_FORCE 1.5f
// #define PLAYER_JETPACK_FORCE 20.0f // #define PLAYER_JETPACK_FORCE 20.0f
#define PLAYER_JETPACK_SPICE_PER_SECOND 0.1f #define PLAYER_JETPACK_SPICE_PER_SECOND 0.1f
#define SCANNER_ENERGY_USE 0.05f
#define MAX_HAND_REACH 1.0f #define MAX_HAND_REACH 1.0f
#define GOLD_COLLECT_RADIUS 0.3f #define GOLD_COLLECT_RADIUS 0.3f
#define BUILD_BOX_SNAP_DIST_TO_SHIP 0.2f #define BUILD_BOX_SNAP_DIST_TO_SHIP 0.2f
@ -229,7 +231,10 @@ typedef struct Entity
// boxes // boxes
bool is_box; bool is_box;
bool is_platonic; // can't be destroyed, unaffected by physical forces
bool always_visible; // always serialized to the player bool always_visible; // always serialized to the player
enum BoxType box_type; enum BoxType box_type;
EntityID next_box; EntityID next_box;
EntityID prev_box; // doubly linked so can remove in middle of chain EntityID prev_box; // doubly linked so can remove in middle of chain
@ -240,6 +245,12 @@ typedef struct Entity
float energy_used; // battery, between 0 battery capacity. You have to look through code to figure out what that is! haha sucker! float energy_used; // battery, between 0 battery capacity. You have to look through code to figure out what that is! haha sucker!
float sun_amount; // solar panel, between 0 and 1 float sun_amount; // solar panel, between 0 and 1
EntityID player_who_is_inside_of_me; EntityID player_who_is_inside_of_me;
// only updated when it's a scanner
float scanner_head_rotate_speed; // not serialized, cosmetic
float scanner_head_rotate;
V2 platonic_nearest_direction; // normalized
float platonic_detection_strength; // from zero to one
} Entity; } Entity;
typedef struct Player typedef struct Player
@ -262,7 +273,9 @@ typedef struct GameState
Player players[MAX_PLAYERS]; Player players[MAX_PLAYERS];
EntityID cur_spacestation; V2 platonic_positions[MAX_BOX_TYPES]; // don't want to search over every entity to get the nearest platonic box!
bool server_side_computing; // some things only the server should know and calculate, like platonic locations
// Entity arena // Entity arena
// ent:ity pointers can't move around because of how the physics engine handles user data. // ent:ity pointers can't move around because of how the physics engine handles user data.
@ -333,7 +346,7 @@ void create_player(Player *player);
bool box_unlocked(Player *player, enum BoxType box); bool box_unlocked(Player *player, enum BoxType box);
// gamestate // gamestate
EntityID create_spacestation(GameState *gs); EntityID create_initial_world(GameState *gs);
void initialize(struct GameState *gs, void *entity_arena, size_t entity_arena_size); void initialize(struct GameState *gs, void *entity_arena, size_t entity_arena_size);
void destroy(struct GameState *gs); void destroy(struct GameState *gs);
void process_fixed_timestep(GameState *gs); void process_fixed_timestep(GameState *gs);

Binary file not shown.
Loading…
Cancel
Save