Skip to content

Commit 41c99ec

Browse files
authored
Fix notorious crash when switching worlds (#3336)
Previously, the WorldMap::change() method would create a unique pointer that replaces the which would clobber the Currenton state of the worldmap by pushing a new screen. However, this screws up the Currenton instance making it null at some point due to how it's freed. This changes how the WorldMap initializes. WorldMap::change() instead simply changes it's state in-place. May fix some other occasional issues that occured with the WorldMap. Fixes #3280. Fixes #3130.
1 parent c546093 commit 41c99ec

File tree

4 files changed

+51
-20
lines changed

4 files changed

+51
-20
lines changed

src/worldmap/worldmap.cpp

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,41 @@ namespace worldmap {
4848

4949
WorldMap::WorldMap(const std::string& filename, Savegame& savegame,
5050
const std::string& force_sector, const std::string& force_spawnpoint) :
51-
m_sector(),
51+
m_sector(nullptr),
5252
m_sectors(),
53-
m_force_spawnpoint(force_spawnpoint),
54-
m_savegame(savegame),
55-
m_tileset(),
53+
m_force_spawnpoint(),
54+
m_savegame(nullptr),
55+
m_tileset(nullptr),
5656
m_name(),
57-
m_map_filename(physfsutil::realpath(filename)),
58-
m_levels_path(FileSystem::dirname(m_map_filename)),
59-
m_next_worldmap(),
57+
m_map_filename(),
58+
m_levels_path(),
59+
m_has_next_worldmap(false),
6060
m_passive_message(),
6161
m_passive_message_timer(),
6262
m_allow_item_pocket(true),
6363
m_enter_level(false),
6464
m_in_level(false),
65-
m_in_world_select(false)
65+
m_in_world_select(false),
66+
m_next_filename(),
67+
m_next_force_sector(),
68+
m_next_force_spawnpoint()
6669
{
70+
load(filename, savegame, force_sector, force_spawnpoint);
71+
}
72+
73+
void
74+
WorldMap::load(const std::string& filename, Savegame& savegame,
75+
const std::string& force_sector, const std::string& force_spawnpoint)
76+
{
77+
m_map_filename = physfsutil::realpath(filename);
78+
m_levels_path = FileSystem::dirname(m_map_filename);
79+
/* We are reloading, so save now. */
80+
if (m_has_next_worldmap)
81+
m_savegame->get_player_status().last_worldmap = m_map_filename;
82+
m_savegame = &savegame;
83+
m_force_spawnpoint = force_spawnpoint;
84+
m_sector = nullptr;
85+
m_sectors.clear();
6786
SoundManager::current()->preload("sounds/warp.wav");
6887

6988
/** Parse worldmap */
@@ -95,10 +114,13 @@ WorldMap::WorldMap(const std::string& filename, Savegame& savegame,
95114

96115
/** Force the initial sector, if provided */
97116
if (!force_sector.empty())
117+
{
98118
set_sector(force_sector, "", false);
119+
}
120+
if (m_has_next_worldmap)
121+
setup();
99122
}
100123

101-
102124
void
103125
WorldMap::setup()
104126
{
@@ -142,11 +164,10 @@ WorldMap::update(float dt_sec, const Controller& controller)
142164
if (m_in_level) return;
143165
if (MenuManager::instance().is_active()) return;
144166

145-
if (m_next_worldmap) // A worldmap is scheduled to be changed to.
167+
if (m_has_next_worldmap) // A worldmap is scheduled to be changed to.
146168
{
147-
m_savegame.get_player_status().last_worldmap = m_next_worldmap->m_map_filename;
148-
ScreenManager::current()->pop_screen();
149-
ScreenManager::current()->push_screen(std::move(m_next_worldmap));
169+
load(m_next_filename, *m_savegame, m_next_force_sector, m_next_force_spawnpoint);
170+
m_has_next_worldmap = false;
150171
return;
151172
}
152173

@@ -258,7 +279,10 @@ WorldMap::change(const std::string& filename, const std::string& force_sector,
258279
const std::string& force_spawnpoint)
259280
{
260281
// Schedule worldmap to be changed to next frame.
261-
m_next_worldmap = std::make_unique<WorldMap>(filename, m_savegame, force_sector, force_spawnpoint);
282+
m_next_filename = filename;
283+
m_next_force_sector = force_sector;
284+
m_next_force_spawnpoint = force_spawnpoint;
285+
m_has_next_worldmap = true;
262286
}
263287

264288

src/worldmap/worldmap.hpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class WorldMap final : public Screen,
8181
inline void set_initial_spawnpoint(const std::string& spawnpoint) { m_force_spawnpoint = spawnpoint; }
8282

8383
inline const std::string& get_title() const { return m_name; }
84-
inline Savegame& get_savegame() const { return m_savegame; }
84+
inline Savegame& get_savegame() const { return *m_savegame; }
8585
inline const std::string& get_levels_path() const { return m_levels_path; }
8686

8787
WorldMapSector* get_sector(const std::string& name) const;
@@ -97,6 +97,9 @@ class WorldMap final : public Screen,
9797
bool is_item_pocket_allowed() const { return m_allow_item_pocket; }
9898

9999
private:
100+
void load(const std::string& filename, Savegame& savegame,
101+
const std::string& force_sector = "", const std::string& force_spawnpoint = "");
102+
100103
void process_input(const Controller& controller);
101104

102105
void on_escape_press();
@@ -107,15 +110,15 @@ class WorldMap final : public Screen,
107110

108111
std::string m_force_spawnpoint;
109112

110-
Savegame& m_savegame;
113+
Savegame* m_savegame;
111114
TileSet* m_tileset;
112115

113116
std::string m_name;
114117
std::string m_map_filename;
115118
std::string m_levels_path;
116119

117-
/* A worldmap, scheduled to change to next frame. */
118-
std::unique_ptr<WorldMap> m_next_worldmap;
120+
/* If true, the worldmap will reload on the next update */
121+
bool m_has_next_worldmap;
119122

120123
/** Passive map message variables */
121124
std::string m_passive_message;
@@ -125,6 +128,10 @@ class WorldMap final : public Screen,
125128
bool m_enter_level;
126129
bool m_in_level;
127130
bool m_in_world_select;
131+
132+
std::string m_next_filename;
133+
std::string m_next_force_sector;
134+
std::string m_next_force_spawnpoint;
128135

129136
private:
130137
WorldMap(const WorldMap&) = delete;

src/worldmap/worldmap_sector.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ WorldMapSector::update(float dt_sec)
355355
level_->get_pos().y + 8 - m_camera->get_offset().y);
356356
std::string levelfile = m_parent.m_levels_path + level_->get_level_filename();
357357

358-
auto game_session = std::make_unique<GameSession>(levelfile, m_parent.m_savegame, &level_->get_statistics());
358+
auto game_session = std::make_unique<GameSession>(levelfile, m_parent.get_savegame(), &level_->get_statistics());
359359
game_session->restart_level();
360360

361361
// update state and savegame

src/worldmap/worldmap_state.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ WorldMapState::save_state() const
317317
log_warning << "Failed to save worldmap state: " << err.what() << std::endl;
318318
}
319319

320-
m_worldmap.m_savegame.save();
320+
m_worldmap.get_savegame().save();
321321
}
322322

323323
} // namespace worldmap

0 commit comments

Comments
 (0)