summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPatric Stout <truebrain@openttd.org>2021-03-09 14:53:51 +0100
committerPatric Stout <github@truebrain.nl>2021-03-10 13:41:18 +0100
commit970fedd78cef3f5ef7a26fcaf4fd9db0f6abbe4b (patch)
treeb894a4b222a74f9d8e80832e36bd21d9a16f4f9e /src
parent098d5b22395e123e4990b73a2ad7bf703adf068b (diff)
downloadopenttd-970fedd78cef3f5ef7a26fcaf4fd9db0f6abbe4b.tar.xz
Add: make modal windows update more smooth
Basically, modal windows had their own thread-locking for what drawing was possible. This is a bit nonsense now we have a game-thread. And it makes much more sense to do things like NewGRFScan and GenerateWorld in the game-thread, and not in a thread next to the game-thread. This commit changes that: it removes the threads for NewGRFScan and GenerateWorld, and just runs the code in the game-thread. On regular intervals it allows the draw-thread to do a tick, which gives a much smoother look and feel. It does slow down NewGRFScan and GenerateWorld ever so slightly as it spends more time on drawing. But the slowdown is not measureable on my machines (with 700+ NewGRFs / 4kx4k map and a Debug build). Running without a game-thread means NewGRFScan and GenerateWorld are now blocking.
Diffstat (limited to 'src')
-rw-r--r--src/clear_cmd.cpp1
-rw-r--r--src/console_cmds.cpp2
-rw-r--r--src/genworld.cpp80
-rw-r--r--src/genworld.h5
-rw-r--r--src/genworld_gui.cpp26
-rw-r--r--src/gfx.cpp20
-rw-r--r--src/landscape.cpp6
-rw-r--r--src/network/network_content_gui.cpp3
-rw-r--r--src/newgrf_config.cpp33
-rw-r--r--src/newgrf_gui.cpp2
-rw-r--r--src/openttd.cpp40
-rw-r--r--src/openttd.h2
-rw-r--r--src/progress.cpp21
-rw-r--r--src/progress.h18
-rw-r--r--src/thread.h5
-rw-r--r--src/tree_cmd.cpp1
-rw-r--r--src/video/dedicated_v.cpp14
-rw-r--r--src/video/video_driver.cpp19
-rw-r--r--src/video/video_driver.hpp2
19 files changed, 90 insertions, 210 deletions
diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp
index 6d3167e5a..403631312 100644
--- a/src/clear_cmd.cpp
+++ b/src/clear_cmd.cpp
@@ -338,6 +338,7 @@ void GenerateClearTile()
TileIndex tile_new;
SetClearGroundDensity(tile, CLEAR_ROCKS, 3);
+ MarkTileDirtyByTile(tile);
do {
if (--j == 0) goto get_out;
tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2));
diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp
index 8a7a5e399..18c4263f5 100644
--- a/src/console_cmds.cpp
+++ b/src/console_cmds.cpp
@@ -1340,7 +1340,7 @@ DEF_CONSOLE_CMD(ConRescanNewGRF)
return true;
}
- ScanNewGRFFiles(nullptr);
+ RequestNewGRFScan();
return true;
}
diff --git a/src/genworld.cpp b/src/genworld.cpp
index c76fe309d..03fa08819 100644
--- a/src/genworld.cpp
+++ b/src/genworld.cpp
@@ -59,18 +59,10 @@ GenWorldInfo _gw;
/** Whether we are generating the map or not. */
bool _generating_world;
-/**
- * Tells if the world generation is done in a thread or not.
- * @return the 'threaded' status
- */
-bool IsGenerateWorldThreaded()
-{
- return _gw.threaded && !_gw.quit_thread;
-}
+class AbortGenerateWorldSignal { };
/**
- * Clean up the 'mess' of generation. That is, show windows again, reset
- * thread variables, and delete the progress window.
+ * Generation is done; show windows again and delete the progress window.
*/
static void CleanupGeneration()
{
@@ -78,11 +70,10 @@ static void CleanupGeneration()
SetMouseCursorBusy(false);
/* Show all vital windows again, because we have hidden them */
- if (_gw.threaded && _game_mode != GM_MENU) ShowVitalWindows();
+ if (_game_mode != GM_MENU) ShowVitalWindows();
SetModalProgress(false);
_gw.proc = nullptr;
_gw.abortp = nullptr;
- _gw.threaded = false;
DeleteWindowByClass(WC_MODAL_PROGRESS);
ShowFirstError();
@@ -97,10 +88,8 @@ static void _GenerateWorld()
/* Make sure everything is done via OWNER_NONE. */
Backup<CompanyID> _cur_company(_current_company, OWNER_NONE, FILE_LINE);
- std::unique_lock<std::mutex> lock(_modal_progress_work_mutex, std::defer_lock);
try {
_generating_world = true;
- lock.lock();
if (_network_dedicated) DEBUG(net, 1, "Generating map, please wait...");
/* Set the Random() seed to generation_seed so we produce the same map with the same seed */
if (_settings_game.game_creation.generation_seed == GENERATE_NEW_SEED) _settings_game.game_creation.generation_seed = _settings_newgame.game_creation.generation_seed = InteractiveRandom();
@@ -136,14 +125,7 @@ static void _GenerateWorld()
/* Only generate towns, tree and industries in newgame mode. */
if (_game_mode != GM_EDITOR) {
if (!GenerateTowns(_settings_game.economy.town_layout)) {
- _cur_company.Restore();
HandleGeneratingWorldAbortion();
- BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP);
- if (_network_dedicated) {
- /* Exit the game to prevent a return to main menu. */
- DEBUG(net, 0, "Generating map failed, aborting");
- _exit_game = true;
- }
return;
}
GenerateIndustries();
@@ -200,7 +182,6 @@ static void _GenerateWorld()
IncreaseGeneratingWorldProgress(GWP_GAME_START);
CleanupGeneration();
- lock.unlock();
ShowNewGRFError();
@@ -212,11 +193,19 @@ static void _GenerateWorld()
seprintf(name, lastof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date);
SaveOrLoad(name, SLO_SAVE, DFT_GAME_FILE, AUTOSAVE_DIR, false);
}
- } catch (...) {
+ } catch (AbortGenerateWorldSignal&) {
+ CleanupGeneration();
+
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP, true);
if (_cur_company.IsValid()) _cur_company.Restore();
- _generating_world = false;
- throw;
+
+ if (_network_dedicated) {
+ /* Exit the game to prevent a return to main menu. */
+ DEBUG(net, 0, "Generating map failed, aborting");
+ _exit_game = true;
+ } else {
+ SwitchToMode(_switch_mode);
+ }
}
}
@@ -241,23 +230,6 @@ void GenerateWorldSetAbortCallback(GWAbortProc *proc)
}
/**
- * This will wait for the thread to finish up his work. It will not continue
- * till the work is done.
- */
-void WaitTillGeneratedWorld()
-{
- if (!_gw.thread.joinable()) return;
-
- _modal_progress_work_mutex.unlock();
- _modal_progress_paint_mutex.unlock();
- _gw.quit_thread = true;
- _gw.thread.join();
- _gw.threaded = false;
- _modal_progress_work_mutex.lock();
- _modal_progress_paint_mutex.lock();
-}
-
-/**
* Initializes the abortion process
*/
void AbortGeneratingWorld()
@@ -284,11 +256,7 @@ void HandleGeneratingWorldAbortion()
if (_gw.abortp != nullptr) _gw.abortp();
- CleanupGeneration();
-
- if (_gw.thread.joinable() && _gw.thread.get_id() == std::this_thread::get_id()) throw OTTDThreadExitSignal();
-
- SwitchToMode(_switch_mode);
+ throw AbortGenerateWorldSignal();
}
/**
@@ -308,8 +276,6 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti
_gw.abort = false;
_gw.abortp = nullptr;
_gw.lc = _local_company;
- _gw.quit_thread = false;
- _gw.threaded = true;
/* This disables some commands and stuff */
SetLocalCompany(COMPANY_SPECTATOR);
@@ -328,28 +294,16 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti
SetupColoursAndInitialWindow();
SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
- if (_gw.thread.joinable()) _gw.thread.join();
-
- if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !StartNewThread(&_gw.thread, "ottd:genworld", &_GenerateWorld)) {
- DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode");
- _gw.threaded = false;
- _modal_progress_work_mutex.unlock();
- _GenerateWorld();
- _modal_progress_work_mutex.lock();
- return;
- }
-
UnshowCriticalError();
- /* Remove any open window */
DeleteAllNonVitalWindows();
- /* Hide vital windows, because we don't allow to use them */
HideVitalWindows();
- /* Don't show the dialog if we don't have a thread */
ShowGenerateWorldProgress();
/* Centre the view on the map */
if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) {
ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / 2), true);
}
+
+ _GenerateWorld();
}
diff --git a/src/genworld.h b/src/genworld.h
index 801479712..e780ed169 100644
--- a/src/genworld.h
+++ b/src/genworld.h
@@ -52,15 +52,12 @@ typedef void GWAbortProc(); ///< Called when genworld is aborted
/** Properties of current genworld process */
struct GenWorldInfo {
bool abort; ///< Whether to abort the thread ASAP
- bool quit_thread; ///< Do we want to quit the active thread
- bool threaded; ///< Whether we run _GenerateWorld threaded
GenWorldMode mode; ///< What mode are we making a world in
CompanyID lc; ///< The local_company before generating
uint size_x; ///< X-size of the map
uint size_y; ///< Y-size of the map
GWDoneProc *proc; ///< Proc that is called when done (can be nullptr)
GWAbortProc *abortp; ///< Proc that is called when aborting (can be nullptr)
- std::thread thread; ///< The thread we are in (joinable if a thread was created)
};
/** Current stage of world generation process */
@@ -81,10 +78,8 @@ enum GenWorldProgress {
};
/* genworld.cpp */
-bool IsGenerateWorldThreaded();
void GenerateWorldSetCallback(GWDoneProc *proc);
void GenerateWorldSetAbortCallback(GWAbortProc *proc);
-void WaitTillGeneratedWorld();
void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_settings = true);
void AbortGeneratingWorld();
bool IsGeneratingWorldAborted();
diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp
index bf4d327a7..f26d43ac3 100644
--- a/src/genworld_gui.cpp
+++ b/src/genworld_gui.cpp
@@ -29,6 +29,7 @@
#include "error.h"
#include "newgrf_townname.h"
#include "townname_type.h"
+#include "video/video_driver.hpp"
#include "widgets/genworld_widget.h"
@@ -1312,10 +1313,10 @@ static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uin
static_assert(lengthof(percent_table) == GWP_CLASS_COUNT + 1);
assert(cls < GWP_CLASS_COUNT);
- /* Do not run this function if we aren't in a thread */
- if (!IsGenerateWorldThreaded() && !_network_dedicated) return;
-
- if (IsGeneratingWorldAborted()) HandleGeneratingWorldAbortion();
+ if (IsGeneratingWorldAborted()) {
+ HandleGeneratingWorldAbortion();
+ return;
+ }
if (total == 0) {
assert(_gws.cls == _generation_class_table[cls]);
@@ -1328,10 +1329,6 @@ static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uin
_gws.percent = percent_table[cls];
}
- /* Don't update the screen too often. So update it once in every once in a while... */
- if (!_network_dedicated && std::chrono::steady_clock::now() < _gws.next_update) return;
- _gws.next_update = std::chrono::steady_clock::now() + std::chrono::milliseconds(MODAL_PROGRESS_REDRAW_TIMEOUT);
-
/* Percentage is about the number of completed tasks, so 'current - 1' */
_gws.percent = percent_table[cls] + (percent_table[cls + 1] - percent_table[cls]) * (_gws.current == 0 ? 0 : _gws.current - 1) / _gws.total;
@@ -1350,21 +1347,12 @@ static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uin
DEBUG(net, 1, "Map generation percentage complete: %d", _gws.percent);
last_percent = _gws.percent;
- /* Don't continue as dedicated never has a thread running */
return;
}
SetWindowDirty(WC_MODAL_PROGRESS, 0);
- MarkWholeScreenDirty();
-
- /* Release the rights to the map generator, and acquire the rights to the
- * paint thread. The 'other' thread already has the paint thread rights so
- * this ensures us that we are waiting until the paint thread is done
- * before we reacquire the mapgen rights */
- _modal_progress_work_mutex.unlock();
- _modal_progress_paint_mutex.lock();
- _modal_progress_work_mutex.lock();
- _modal_progress_paint_mutex.unlock();
+
+ VideoDriver::GetInstance()->GameLoopPause();
}
/**
diff --git a/src/gfx.cpp b/src/gfx.cpp
index 3189b8d96..6bcee66b1 100644
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -1470,26 +1470,6 @@ void DrawDirtyBlocks()
int x;
int y;
- if (HasModalProgress()) {
- /* We are generating the world, so release our rights to the map and
- * painting while we are waiting a bit. */
- _modal_progress_paint_mutex.unlock();
- _modal_progress_work_mutex.unlock();
-
- /* Wait a while and hope the modal gives us a bit of time to draw the GUI. */
- if (!IsFirstModalProgressLoop()) CSleep(MODAL_PROGRESS_REDRAW_TIMEOUT);
-
- /* Modal progress thread may need blitter access while we are waiting for it. */
- _modal_progress_paint_mutex.lock();
- _modal_progress_work_mutex.lock();
-
- /* When we ended with the modal progress, do not draw the blocks.
- * Simply let the next run do so, otherwise we would be loading
- * the new state (and possibly change the blitter) when we hold
- * the drawing lock, which we must not do. */
- if (_switch_mode != SM_NONE && !HasModalProgress()) return;
- }
-
y = 0;
do {
x = 0;
diff --git a/src/landscape.cpp b/src/landscape.cpp
index 80ba516ac..ab6ba59f0 100644
--- a/src/landscape.cpp
+++ b/src/landscape.cpp
@@ -1062,6 +1062,7 @@ static bool MakeLake(TileIndex tile, void *user_data)
TileIndex t2 = tile + TileOffsByDiagDir(d);
if (IsWaterTile(t2)) {
MakeRiver(tile, Random());
+ MarkTileDirtyByTile(tile);
/* Remove desert directly around the river tile. */
TileIndex t = tile;
CircularTileSearch(&t, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
@@ -1135,6 +1136,7 @@ static void River_FoundEndNode(AyStar *aystar, OpenListNode *current)
TileIndex tile = path->node.tile;
if (!IsWaterTile(tile)) {
MakeRiver(tile, Random());
+ MarkTileDirtyByTile(tile);
/* Remove desert directly around the river tile. */
CircularTileSearch(&tile, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
}
@@ -1247,6 +1249,7 @@ static bool FlowRiver(TileIndex spring, TileIndex begin)
DistanceManhattan(spring, lakeCenter) > _settings_game.game_creation.min_river_length) {
end = lakeCenter;
MakeRiver(lakeCenter, Random());
+ MarkTileDirtyByTile(lakeCenter);
/* Remove desert directly around the river tile. */
CircularTileSearch(&lakeCenter, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
lakeCenter = end;
@@ -1368,8 +1371,11 @@ void GenerateLandscape(byte mode)
/* Do not call IncreaseGeneratingWorldProgress() before FixSlopes(),
* it allows screen redraw. Drawing of broken slopes crashes the game */
FixSlopes();
+ MarkWholeScreenDirty();
IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
+
ConvertGroundTilesIntoWaterTiles();
+ MarkWholeScreenDirty();
IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp
index 13e162b07..466279125 100644
--- a/src/network/network_content_gui.cpp
+++ b/src/network/network_content_gui.cpp
@@ -15,6 +15,7 @@
#include "../ai/ai.hpp"
#include "../game/game.hpp"
#include "../base_media_base.h"
+#include "../openttd.h"
#include "../sortlist_type.h"
#include "../stringfilter_type.h"
#include "../querystring_gui.h"
@@ -236,7 +237,7 @@ public:
break;
case CONTENT_TYPE_NEWGRF:
- ScanNewGRFFiles(nullptr);
+ RequestNewGRFScan();
break;
case CONTENT_TYPE_SCENARIO:
diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp
index e56f878bd..911d266df 100644
--- a/src/newgrf_config.cpp
+++ b/src/newgrf_config.cpp
@@ -635,20 +635,12 @@ bool GRFFileScanner::AddFile(const std::string &filename, size_t basepath_length
}
this->num_scanned++;
- if (std::chrono::steady_clock::now() >= this->next_update) {
- this->next_update = std::chrono::steady_clock::now() + std::chrono::milliseconds(MODAL_PROGRESS_REDRAW_TIMEOUT);
- _modal_progress_work_mutex.unlock();
- _modal_progress_paint_mutex.lock();
-
- const char *name = nullptr;
- if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name);
- if (name == nullptr) name = c->filename;
- UpdateNewGRFScanStatus(this->num_scanned, name);
-
- _modal_progress_work_mutex.lock();
- _modal_progress_paint_mutex.unlock();
- }
+ const char *name = nullptr;
+ if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name);
+ if (name == nullptr) name = c->filename;
+ UpdateNewGRFScanStatus(this->num_scanned, name);
+ VideoDriver::GetInstance()->GameLoopPause();
if (!added) {
/* File couldn't be opened, or is either not a NewGRF or is a
@@ -676,8 +668,6 @@ static bool GRFSorter(GRFConfig * const &c1, GRFConfig * const &c2)
*/
void DoScanNewGRFFiles(NewGRFScanCallback *callback)
{
- std::unique_lock<std::mutex> lock_work(_modal_progress_work_mutex);
-
ClearGRFConfigList(&_all_grfs);
TarScanner::DoScan(TarScanner::NEWGRF);
@@ -709,9 +699,6 @@ void DoScanNewGRFFiles(NewGRFScanCallback *callback)
NetworkAfterNewGRFScan();
}
- lock_work.unlock();
- std::lock_guard<std::mutex> lock_paint(_modal_progress_paint_mutex);
-
/* Yes... these are the NewGRF windows */
InvalidateWindowClassesData(WC_SAVELOAD, 0, true);
InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE, GOID_NEWGRF_RESCANNED, true);
@@ -733,15 +720,7 @@ void ScanNewGRFFiles(NewGRFScanCallback *callback)
/* Only then can we really start, especially by marking the whole screen dirty. Get those other windows hidden!. */
MarkWholeScreenDirty();
- if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !StartNewThread(nullptr, "ottd:newgrf-scan", &DoScanNewGRFFiles, (NewGRFScanCallback *)callback)) { // Without the seemingly superfluous cast, strange compiler errors ensue.
- _modal_progress_work_mutex.unlock();
- _modal_progress_paint_mutex.unlock();
- DoScanNewGRFFiles(callback);
- _modal_progress_paint_mutex.lock();
- _modal_progress_work_mutex.lock();
- } else {
- UpdateNewGRFScanStatus(0, nullptr);
- }
+ DoScanNewGRFFiles(callback);
}
/**
diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp
index 9e340654c..4e63eafbe 100644
--- a/src/newgrf_gui.cpp
+++ b/src/newgrf_gui.cpp
@@ -1127,7 +1127,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
case WID_NS_RESCAN_FILES:
case WID_NS_RESCAN_FILES2:
- ScanNewGRFFiles(this);
+ RequestNewGRFScan(this);
break;
}
}
diff --git a/src/openttd.cpp b/src/openttd.cpp
index 3397e4f0e..2d37c8e3a 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -91,6 +91,8 @@ extern void ShowOSErrorBox(const char *buf, bool system);
extern std::string _config_file;
bool _save_config = false;
+bool _request_newgrf_scan = false;
+NewGRFScanCallback *_request_newgrf_scan_callback = nullptr;
/**
* Error handling for fatal user errors.
@@ -345,7 +347,6 @@ static void LoadIntroGame(bool load_newgrfs = true)
/* Load the default opening screen savegame */
if (SaveOrLoad("opntitle.dat", SLO_LOAD, DFT_GAME_FILE, BASESET_DIR) != SL_OK) {
GenerateWorld(GWM_EMPTY, 64, 64); // if failed loading, make empty world.
- WaitTillGeneratedWorld();
SetLocalCompany(COMPANY_SPECTATOR);
} else {
SetLocalCompany(COMPANY_FIRST);
@@ -559,9 +560,6 @@ int openttd_main(int argc, char *argv[])
extern bool _dedicated_forks;
_dedicated_forks = false;
- std::unique_lock<std::mutex> modal_work_lock(_modal_progress_work_mutex, std::defer_lock);
- std::unique_lock<std::mutex> modal_paint_lock(_modal_progress_paint_mutex, std::defer_lock);
-
_game_mode = GM_MENU;
_switch_mode = SM_MENU;
@@ -828,30 +826,17 @@ int openttd_main(int argc, char *argv[])
if (musicdriver.empty() && !_ini_musicdriver.empty()) musicdriver = _ini_musicdriver;
DriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC);
- /* Take our initial lock on whatever we might want to do! */
- try {
- modal_work_lock.lock();
- modal_paint_lock.lock();
- } catch (const std::system_error&) {
- /* If there is some error we assume that threads aren't usable on the system we run. */
- extern bool _use_threaded_modal_progress; // From progress.cpp
- _use_threaded_modal_progress = false;
- }
-
GenerateWorld(GWM_EMPTY, 64, 64); // Make the viewport initialization happy
- WaitTillGeneratedWorld();
-
LoadIntroGame(false);
CheckForMissingGlyphs();
/* ScanNewGRFFiles now has control over the scanner. */
- ScanNewGRFFiles(scanner.release());
+ RequestNewGRFScan(scanner.release());
VideoDriver::GetInstance()->MainLoop();
WaitTillSaved();
- WaitTillGeneratedWorld(); // Make sure any generate world threads have been joined.
/* only save config if we have to */
if (_save_config) {
@@ -1460,6 +1445,19 @@ static void DoAutosave()
}
}
+/**
+ * Request a new NewGRF scan. This will be executed on the next game-tick.
+ * This is mostly needed to ensure NewGRF scans (which are blocking) are
+ * done in the game-thread, and not in the draw-thread (which most often
+ * triggers this request).
+ * @param callback Optional callback to call when NewGRF scan is completed.
+ */
+void RequestNewGRFScan(NewGRFScanCallback *callback)
+{
+ _request_newgrf_scan = true;
+ _request_newgrf_scan_callback = callback;
+}
+
void GameLoop()
{
if (_game_mode == GM_BOOTSTRAP) {
@@ -1468,6 +1466,12 @@ void GameLoop()
return;
}
+ if (_request_newgrf_scan) {
+ ScanNewGRFFiles(_request_newgrf_scan_callback);
+ _request_newgrf_scan = false;
+ _request_newgrf_scan_callback = nullptr;
+ }
+
ProcessAsyncSaveFinish();
/* autosave game? */
diff --git a/src/openttd.h b/src/openttd.h
index 62651fe7f..38c7f8064 100644
--- a/src/openttd.h
+++ b/src/openttd.h
@@ -81,4 +81,6 @@ void HandleExitGameRequest();
void SwitchToMode(SwitchMode new_mode);
+void RequestNewGRFScan(struct NewGRFScanCallback *callback = nullptr);
+
#endif /* OPENTTD_H */
diff --git a/src/progress.cpp b/src/progress.cpp
index e45e5db07..6444d8a85 100644
--- a/src/progress.cpp
+++ b/src/progress.cpp
@@ -14,33 +14,12 @@
/** Are we in a modal progress or not? */
bool _in_modal_progress = false;
-bool _first_in_modal_loop = false;
-/** Threading usable for modal progress? */
-bool _use_threaded_modal_progress = true;
-/** Rights for the performing work. */
-std::mutex _modal_progress_work_mutex;
-/** Rights for the painting. */
-std::mutex _modal_progress_paint_mutex;
/**
* Set the modal progress state.
- * @note Makes IsFirstModalProgressLoop return true for the next call.
* @param state The new state; are we modal or not?
*/
void SetModalProgress(bool state)
{
_in_modal_progress = state;
- _first_in_modal_loop = true;
-}
-
-/**
- * Check whether this is the first modal progress loop.
- * @note Set by SetModalProgress, unset by calling this method.
- * @return True if this is the first loop.
- */
-bool IsFirstModalProgressLoop()
-{
- bool ret = _first_in_modal_loop;
- _first_in_modal_loop = false;
- return ret;
}
diff --git a/src/progress.h b/src/progress.h
index 59a61c678..765020635 100644
--- a/src/progress.h
+++ b/src/progress.h
@@ -10,10 +10,6 @@
#ifndef PROGRESS_H
#define PROGRESS_H
-#include <mutex>
-
-static const uint MODAL_PROGRESS_REDRAW_TIMEOUT = 200; ///< Timeout between redraws
-
/**
* Check if we are currently in a modal progress state.
* @return Are we in the modal state?
@@ -24,20 +20,6 @@ static inline bool HasModalProgress()
return _in_modal_progress;
}
-/**
- * Check if we can use a thread for modal progress.
- * @return Threading usable?
- */
-static inline bool UseThreadedModelProgress()
-{
- extern bool _use_threaded_modal_progress;
- return _use_threaded_modal_progress;
-}
-
-bool IsFirstModalProgressLoop();
void SetModalProgress(bool state);
-extern std::mutex _modal_progress_work_mutex;
-extern std::mutex _modal_progress_paint_mutex;
-
#endif /* PROGRESS_H */
diff --git a/src/thread.h b/src/thread.h
index f4a16d4e0..f45694930 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -14,10 +14,6 @@
#include <system_error>
#include <thread>
-/** Signal used for signalling we knowingly want to end the thread. */
-class OTTDThreadExitSignal { };
-
-
/**
* Sleep on the current thread for a defined time.
* @param milliseconds Time to sleep for in milliseconds.
@@ -54,7 +50,6 @@ inline bool StartNewThread(std::thread *thr, const char *name, TFn&& _Fx, TArgs&
try {
/* Call user function with the given arguments. */
F(A...);
- } catch (OTTDThreadExitSignal&) {
} catch (...) {
NOT_REACHED();
}
diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp
index e4ce1da14..c0865ffc6 100644
--- a/src/tree_cmd.cpp
+++ b/src/tree_cmd.cpp
@@ -164,6 +164,7 @@ static void PlaceTree(TileIndex tile, uint32 r)
if (tree != TREE_INVALID) {
PlantTreesOnTile(tile, tree, GB(r, 22, 2), std::min<byte>(GB(r, 16, 3), 6));
+ MarkTileDirtyByTile(tile);
/* Rerandomize ground, if neither snow nor shore */
TreeGround ground = GetTreeGround(tile);
diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp
index ea1c14cff..e905a9d2c 100644
--- a/src/video/dedicated_v.cpp
+++ b/src/video/dedicated_v.cpp
@@ -251,19 +251,16 @@ void VideoDriver_Dedicated::MainLoop()
/* If SwitchMode is SM_LOAD_GAME, it means that the user used the '-g' options */
if (_switch_mode != SM_LOAD_GAME) {
StartNewGameWithoutGUI(GENERATE_NEW_SEED);
- SwitchToMode(_switch_mode);
- _switch_mode = SM_NONE;
} else {
- _switch_mode = SM_NONE;
/* First we need to test if the savegame can be loaded, else we will end up playing the
* intro game... */
- if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_NORMAL, BASE_DIR)) {
+ if (SaveOrLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, BASE_DIR) == SL_ERROR) {
/* Loading failed, pop out.. */
DEBUG(net, 0, "Loading requested map failed, aborting");
- _networking = false;
+ return;
} else {
/* We can load this game, so go ahead */
- SwitchToMode(SM_LOAD_GAME);
+ _switch_mode = SM_LOAD_GAME;
}
}
@@ -271,11 +268,6 @@ void VideoDriver_Dedicated::MainLoop()
/* Done loading, start game! */
- if (!_networking) {
- DEBUG(net, 0, "Dedicated server could not be started, aborting");
- return;
- }
-
while (!_exit_game) {
if (!_dedicated_forks) DedicatedHandleKeyInput();
diff --git a/src/video/video_driver.cpp b/src/video/video_driver.cpp
index 1b7fc6a4b..bee67e1ea 100644
--- a/src/video/video_driver.cpp
+++ b/src/video/video_driver.cpp
@@ -56,6 +56,25 @@ void VideoDriver::GameThread()
}
}
+/**
+ * Pause the game-loop for a bit, releasing the game-state lock. This allows,
+ * if the draw-tick requested this, the drawing to happen.
+ */
+void VideoDriver::GameLoopPause()
+{
+ /* If we are not called from the game-thread, ignore this request. */
+ if (std::this_thread::get_id() != this->game_thread.get_id()) return;
+
+ this->game_state_mutex.unlock();
+
+ {
+ /* See GameThread() for more details on this lock. */
+ std::lock_guard<std::mutex> lock(this->game_thread_wait_mutex);
+ }
+
+ this->game_state_mutex.lock();
+}
+
/* static */ void VideoDriver::GameThreadThunk(VideoDriver *drv)
{
drv->GameThread();
diff --git a/src/video/video_driver.hpp b/src/video/video_driver.hpp
index 8c2b9d437..7a859565a 100644
--- a/src/video/video_driver.hpp
+++ b/src/video/video_driver.hpp
@@ -179,6 +179,8 @@ public:
this->change_blitter = new_blitter;
}
+ void GameLoopPause();
+
/**
* Get the currently active instance of the video driver.
*/