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

main
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