diff options
-rw-r--r-- | src/clear_cmd.cpp | 1 | ||||
-rw-r--r-- | src/console_cmds.cpp | 2 | ||||
-rw-r--r-- | src/genworld.cpp | 80 | ||||
-rw-r--r-- | src/genworld.h | 5 | ||||
-rw-r--r-- | src/genworld_gui.cpp | 26 | ||||
-rw-r--r-- | src/gfx.cpp | 20 | ||||
-rw-r--r-- | src/landscape.cpp | 6 | ||||
-rw-r--r-- | src/network/network_content_gui.cpp | 3 | ||||
-rw-r--r-- | src/newgrf_config.cpp | 33 | ||||
-rw-r--r-- | src/newgrf_gui.cpp | 2 | ||||
-rw-r--r-- | src/openttd.cpp | 40 | ||||
-rw-r--r-- | src/openttd.h | 2 | ||||
-rw-r--r-- | src/progress.cpp | 21 | ||||
-rw-r--r-- | src/progress.h | 18 | ||||
-rw-r--r-- | src/thread.h | 5 | ||||
-rw-r--r-- | src/tree_cmd.cpp | 1 | ||||
-rw-r--r-- | src/video/dedicated_v.cpp | 14 | ||||
-rw-r--r-- | src/video/video_driver.cpp | 19 | ||||
-rw-r--r-- | src/video/video_driver.hpp | 2 |
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. */ |