Fix player being duplicated on reload, fix bad pointer to old memory in world and player pointer in gamestate on deserialization

main
Cameron Murphy Reikes 7 months ago
parent 3bdd29438d
commit 218ef02089

Binary file not shown.

150
main.c

@ -909,6 +909,20 @@ AABB entity_aabb(Entity *e)
return entity_aabb_at(e, at);
}
Entity *player(GameState *gs) {
ENTITIES_ITER(gs->entities) {
if(it->is_player) return it;
}
return 0;
}
Entity *world(GameState *gs) {
ENTITIES_ITER(gs->entities) {
if(it->is_world) return it;
}
return 0;
}
typedef struct LoadedImage
{
struct LoadedImage *next;
@ -2294,15 +2308,12 @@ void cleanup_gamestate(GameState *gs) {
// this can be called more than once, it cleanly handles all states of the gamestate
void initialize_gamestate(GameState *gs, u64 roomid) {
if(!gs->arena) gs->arena = ArenaAlloc();
if(!gs->world_entity) {
gs->world_entity = new_entity(gs);
gs->world_entity->is_world = true;
if(!world(gs)) {
Entity *world = new_entity(gs);
world->is_world = true;
}
gs->current_roomid = roomid;
rnd_gamerand_seed(&gs->random, RANDOM_SEED);
#ifdef DEVTOOLS
gs->edit.enabled = true;
#endif
}
void reset_level()
@ -2315,6 +2326,7 @@ void reset_level()
enum
{
V0,
V1,
VMax,
} Version;
@ -2353,8 +2365,9 @@ void ser_entity(SerState *ser, Entity *e)
ser_float(ser, &e->damage);
ser_bool(ser, &e->is_world);
ser_bool(ser, &e->is_npc);
ser_bool(ser, &e->is_player);
ser_bool(ser, &e->being_hovered);
ser_bool(ser, &e->perceptions_dirty);
@ -2482,15 +2495,7 @@ void ser_GameState(SerState *ser, GameState *gs)
if (!ser->cur_error.failed)
{
ARR_ITER(Entity, gs->entities)
{
if (it->is_world)
{
gs->world_entity = it;
}
}
if (gs->world_entity == 0)
if (world(gs) == 0)
{
ser->cur_error = (SerError){.failed = true, .why = S8Lit("No world entity found in deserialized entities")};
}
@ -3100,7 +3105,7 @@ void do_serialization_tests()
GameState gs = {0};
initialize_gamestate_from_threedee_level(&gs, &level_threedee);
gs.player->pos = V2(50.0f, 0.0);
player(&gs)->pos = V2(50.0f, 0.0);
String8 error = {0};
String8 saved = save_to_string(scratch.arena, scratch.arena, &error, &gs);
@ -3111,7 +3116,7 @@ void do_serialization_tests()
initialize_gamestate_from_threedee_level(&gs, &level_threedee);
gs = load_from_string(persistent_arena, scratch.arena, saved, &error);
assert(gs.player->pos.x == 50.0f);
assert(player(&gs)->pos.x == 50.0f);
assert(error.size == 0);
Log("Default save data size is %lld bytes\n", saved.size);
@ -4632,7 +4637,7 @@ Vec2 move_and_slide(MoveSlideParams p)
// add world boxes
for (CollisionCylinder *cur = get_cur_room(&gs, &level_threedee)->collision_list; cur; cur = cur->next)
{
BUFF_APPEND(&to_check, ((CollisionObj){cur->bounds, gs.world_entity}));
BUFF_APPEND(&to_check, ((CollisionObj){cur->bounds, world(&gs)}));
}
// add entity boxes
@ -5663,10 +5668,10 @@ void frame(void)
cam_target_pos.x = gs.edit.camera_panning.x;
cam_target_pos.z = gs.edit.camera_panning.y;
}
else if (gs.player)
else if (player(&gs))
{
cam_target_pos.x = gs.player->pos.x;
cam_target_pos.z = gs.player->pos.y;
cam_target_pos.x = player(&gs)->pos.x;
cam_target_pos.z = player(&gs)->pos.y;
}
// dbgline(V2(0,0), V2(500, 500));
const float vertical_to_horizontal_ratio = CAM_VERTICAL_TO_HORIZONTAL_RATIO;
@ -5812,10 +5817,11 @@ void frame(void)
assert(it->is_npc);
Transform draw_with = entity_transform(it);
// draw_thing((DrawnThing){.mesh = &mesh_tombstone, .t = draw_with, .outline = gete(gs.player->interacting_with) == it});
{
Armature *to_use = &player_armature;
// if9!
if (it->killed)
{
to_use->go_to_animation = S8Lit("Die Backwards");
@ -5830,7 +5836,7 @@ void frame(void)
to_use->go_to_animation = S8Lit("Idle");
}
draw_thing((DrawnThing){.armature = to_use, .t = draw_with, .outline = gs.player && gete(gs.player->interacting_with) == it});
draw_thing((DrawnThing){.armature = to_use, .t = draw_with, .outline = player(&gs) && gete(player(&gs)->interacting_with) == it});
if (gete(it->aiming_shotgun_at))
{
@ -6128,8 +6134,8 @@ void frame(void)
// dialog bubble rendering
const float text_scale = speech_bubble.text_scale;
float dist = 0.0f;
if (gs.player)
dist = LenV2(SubV2(it->pos, gs.player->pos));
if (player(&gs))
dist = LenV2(SubV2(it->pos, player(&gs)->pos));
float bubble_factor = 1.0f - clamp01(dist / 6.0f);
Vec3 bubble_pos = AddV3(plane_point(it->pos), V3(0, 1.7f, 0)); // 1.7 meters is about 5'8", average person height
Vec2 head_pos = threedee_to_screenspace(bubble_pos);
@ -6249,13 +6255,13 @@ void frame(void)
gs.tick += 1;
if (!gs.edit.enabled && gs.player == 0)
if (!gs.edit.enabled && player(&gs) == 0)
{
gs.player = new_entity(&gs);
gs.player->is_player = true;
gs.player->is_npc = true;
gs.player->current_roomid = gs.edit.player_spawn_roomid;
gs.player->pos = gs.edit.player_spawn_position;
Entity *player = new_entity(&gs);
player->is_player = true;
player->is_npc = true;
player->current_roomid = gs.edit.player_spawn_roomid;
player->pos = gs.edit.player_spawn_position;
}
// process gs.entities process entities
@ -6383,7 +6389,7 @@ void frame(void)
it->words_said_on_page += 1;
it->characters_of_word_animated = 0.0f;
float dist = LenV2(SubV2(it->pos, gs.player->pos));
float dist = LenV2(SubV2(it->pos, player(&gs)->pos));
float volume = Lerp(-0.6f, clamp01(dist / 70.0f), -1.0f);
AudioSample *possible_grunts[] = {
&sound_grunt_0,
@ -6431,7 +6437,7 @@ void frame(void)
// A* code
if (false)
{
Entity *targeting = gs.player;
Entity *targeting = player(&gs);
/*
G cost: distance from the current node to the start node
@ -6843,7 +6849,7 @@ void frame(void)
}
// @Place(process player)
if (gs.player)
if (player(&gs))
PROFILE_SCOPE("process player")
{
// do dialog
@ -6851,7 +6857,7 @@ void frame(void)
{
// find closest to talk to
{
AABB dialog_rect = aabb_centered(gs.player->pos, V2(DIALOG_INTERACT_SIZE, DIALOG_INTERACT_SIZE));
AABB dialog_rect = aabb_centered(player(&gs)->pos, V2(DIALOG_INTERACT_SIZE, DIALOG_INTERACT_SIZE));
dbgrect(dialog_rect);
Overlapping possible_dialogs = get_overlapping(dialog_rect);
float closest_interact_with_dist = INFINITY;
@ -6873,7 +6879,7 @@ void frame(void)
if (entity_interactible)
{
float dist = LenV2(SubV2((*it)->pos, gs.player->pos));
float dist = LenV2(SubV2((*it)->pos, player(&gs)->pos));
if (dist < closest_interact_with_dist)
{
closest_interact_with_dist = dist;
@ -6884,7 +6890,7 @@ void frame(void)
}
interacting_with = closest_interact_with;
gs.player->interacting_with = frome(interacting_with);
player(&gs)->interacting_with = frome(interacting_with);
}
if (pressed.interact)
@ -6894,7 +6900,7 @@ void frame(void)
if (closest_interact_with->is_npc)
{
// begin dialog with closest npc
gs.player->talking_to = frome(closest_interact_with);
player(&gs)->talking_to = frome(closest_interact_with);
begin_text_input(S8Lit(""));
}
else
@ -6905,55 +6911,55 @@ void frame(void)
}
float speed = 0.0f;
if (!gs.player->killed)
if (!player(&gs)->killed)
speed = PLAYER_SPEED;
// velocity processing for player player movement
{
gs.player->last_moved = NormV2(movement);
player(&gs)->last_moved = NormV2(movement);
Vec2 target_vel = MulV2F(movement, pixels_per_meter * speed);
float player_speed = LenV2(gs.player->vel);
float player_speed = LenV2(player(&gs)->vel);
float target_speed = LenV2(target_vel);
bool quick_turn = (player_speed < target_speed / 2) || DotV2(gs.player->vel, target_vel) < -0.707f;
gs.player->quick_turning_timer -= dt;
bool quick_turn = (player_speed < target_speed / 2) || DotV2(player(&gs)->vel, target_vel) < -0.707f;
player(&gs)->quick_turning_timer -= dt;
if (quick_turn)
{
gs.player->quick_turning_timer = 0.125f;
player(&gs)->quick_turning_timer = 0.125f;
}
if (quick_turn)
{
gs.player->vel = target_vel;
player(&gs)->vel = target_vel;
}
else
{ // framerate-independent smoothly transition towards target (functions as friction when target is 0)
gs.player->vel = SubV2(gs.player->vel, target_vel);
gs.player->vel = MulV2F(gs.player->vel, powf(1e-8f, dt));
gs.player->vel = AddV2(gs.player->vel, target_vel);
player(&gs)->vel = SubV2(player(&gs)->vel, target_vel);
player(&gs)->vel = MulV2F(player(&gs)->vel, powf(1e-8f, dt));
player(&gs)->vel = AddV2(player(&gs)->vel, target_vel);
}
// printf("%f%s\n", LenV2(gs.player->vel), gs.player->quick_turning_timer > 0 ? " QUICK TURN" : "");
// printf("%f%s\n", LenV2(player(&gs)->vel), player(&gs)->quick_turning_timer > 0 ? " QUICK TURN" : "");
gs.player->pos = move_and_slide((MoveSlideParams){gs.player, gs.player->pos, MulV2F(gs.player->vel, dt)});
player(&gs)->pos = move_and_slide((MoveSlideParams){player(&gs), player(&gs)->pos, MulV2F(player(&gs)->vel, dt)});
bool should_append = false;
// make it so no snap when new points added
if (gs.player->position_history.cur_index > 0)
if (player(&gs)->position_history.cur_index > 0)
{
gs.player->position_history.data[gs.player->position_history.cur_index - 1] = gs.player->pos;
player(&gs)->position_history.data[player(&gs)->position_history.cur_index - 1] = player(&gs)->pos;
}
if (gs.player->position_history.cur_index > 2)
if (player(&gs)->position_history.cur_index > 2)
{
should_append = LenV2(SubV2(gs.player->position_history.data[gs.player->position_history.cur_index - 2], gs.player->pos)) > TILE_SIZE;
should_append = LenV2(SubV2(player(&gs)->position_history.data[player(&gs)->position_history.cur_index - 2], player(&gs)->pos)) > TILE_SIZE;
}
else
{
should_append = true;
}
if (should_append)
BUFF_QUEUE_APPEND(&gs.player->position_history, gs.player->pos);
BUFF_QUEUE_APPEND(&player(&gs)->position_history, player(&gs)->pos);
}
// health
if (gs.player->damage >= 1.0)
if (player(&gs)->damage >= 1.0)
{
reset_level();
}
@ -6984,24 +6990,24 @@ void frame(void)
if (0)
PROFILE_SCOPE("render player") // draw character draw player render character
{
if (gs.player->position_history.cur_index > 0)
if (player(&gs)->position_history.cur_index > 0)
{
float trail_len = get_total_trail_len(BUFF_MAKEREF(&gs.player->position_history));
float trail_len = get_total_trail_len(BUFF_MAKEREF(&player(&gs)->position_history));
if (trail_len > 0.0f) // fmodf returns nan
{
float along = fmodf((float)elapsed_time * 100.0f, 200.0f);
Vec2 at = get_point_along_trail(BUFF_MAKEREF(&gs.player->position_history), along);
Vec2 at = get_point_along_trail(BUFF_MAKEREF(&player(&gs)->position_history), along);
dbgbigsquare(at);
dbgbigsquare(get_point_along_trail(BUFF_MAKEREF(&gs.player->position_history), 50.0f));
dbgbigsquare(get_point_along_trail(BUFF_MAKEREF(&player(&gs)->position_history), 50.0f));
}
BUFF_ITER_I(Vec2, &gs.player->position_history, i)
BUFF_ITER_I(Vec2, &player(&gs)->position_history, i)
{
if (i == gs.player->position_history.cur_index - 1)
if (i == player(&gs)->position_history.cur_index - 1)
{
}
else
{
dbgline(*it, gs.player->position_history.data[i + 1]);
dbgline(*it, player(&gs)->position_history.data[i + 1]);
}
}
}
@ -7013,7 +7019,7 @@ void frame(void)
if (!mobile_controls)
{
float size = 100.0f;
Vec2 midpoint = MulV2F(AddV2(interacting_with->pos, gs.player->pos), 0.5f);
Vec2 midpoint = MulV2F(AddV2(interacting_with->pos, player(&gs)->pos), 0.5f);
draw_quad((DrawParams){quad_centered(AddV2(midpoint, V2(0.0, 5.0f + sinf((float)elapsed_time * 3.0f) * 5.0f)), V2(size, size)), IMG(image_e_icon), blendalpha(WHITE, clamp01(1.0f - learned_e)), .layer = LAYER_UI_FG});
}
@ -7022,13 +7028,13 @@ void frame(void)
}
// hurt vignette
if (gs.player->damage > 0.0)
if (player(&gs)->damage > 0.0)
{
draw_quad((DrawParams){
(Quad){.ul = V2(0.0f, screen_size().Y), .ur = screen_size(), .lr = V2(screen_size().X, 0.0f)},
image_hurt_vignette,
full_region(image_hurt_vignette),
(Color){1.0f, 1.0f, 1.0f, gs.player->damage},
(Color){1.0f, 1.0f, 1.0f, player(&gs)->damage},
.layer = LAYER_SCREENSPACE_EFFECTS,
});
}
@ -7064,7 +7070,7 @@ void frame(void)
}
// killed screen
if (gs.player)
if (player(&gs))
{
static float visible = 0.0f;
float target = 0.0f;
@ -7074,7 +7080,7 @@ void frame(void)
if (it->undismissed_action)
anybody_unread = true;
}
if (gs.player->killed && (!anybody_unread || gs.finished_reading_dying_dialog))
if (player(&gs)->killed && (!anybody_unread || gs.finished_reading_dying_dialog))
{
gs.finished_reading_dying_dialog = true;
target = 1.0f;
@ -7089,7 +7095,7 @@ void frame(void)
if (imbutton(aabb_centered(V2(screen_size().x / 2.0f, screen_size().y * 0.25f), MulV2F(V2(170.0f, 60.0f), visible)), 1.5f * visible, S8Lit("Continue")))
{
gs.player->killed = false;
player(&gs)->killed = false;
// transition_to_room(&gs, &level_threedee, S8Lit("StartingRoom"));
reset_level();
}
@ -7127,7 +7133,7 @@ void frame(void)
}
#ifdef DEVTOOLS
if(gs.edit.enabled && pressed.mouse_up) {
if(pressed.mouse_up) {
String8 error = {0};
Log("Saving gamestate...\n");
String8 saved = save_to_string(frame_arena, frame_arena, &error, &gs);
@ -7234,7 +7240,7 @@ void frame(void)
profiling ? "yes" : "no",
num_timestep_loops,
flycam ? "yes" : "no",
v2varg((gs.player ? gs.player->pos : V2(0, 0))));
v2varg((player(&gs) ? player(&gs)->pos : V2(0, 0))));
AABB bounds = draw_text((TextParams){true, stats, pos, BLACK, 1.0f});
pos.Y -= bounds.upper_left.Y - screen_size().Y;
bounds = draw_text((TextParams){true, stats, pos, BLACK, 1.0f});

@ -425,8 +425,6 @@ typedef struct GameState {
// these must point entities in its own array.
u64 current_roomid;
Entity *player;
Entity *world_entity;
Entity entities[MAX_ENTITIES];
rnd_gamerand_t random;
} GameState;

Loading…
Cancel
Save