/* * This file is part of OpenTTD. * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . */ /** @file game_core.cpp Implementation of Game. */ #include "../stdafx.h" #include "../core/backup_type.hpp" #include "../company_base.h" #include "../company_func.h" #include "../network/network.h" #include "../window_func.h" #include "../framerate_type.h" #include "game.hpp" #include "game_scanner.hpp" #include "game_config.hpp" #include "game_instance.hpp" #include "game_info.hpp" #include "../safeguards.h" /* static */ uint Game::frame_counter = 0; /* static */ GameInfo *Game::info = nullptr; /* static */ GameInstance *Game::instance = nullptr; /* static */ GameScannerInfo *Game::scanner_info = nullptr; /* static */ GameScannerLibrary *Game::scanner_library = nullptr; /* static */ void Game::GameLoop() { if (_networking && !_network_server) { PerformanceMeasurer::SetInactive(PFE_GAMESCRIPT); return; } if (Game::instance == nullptr) { PerformanceMeasurer::SetInactive(PFE_GAMESCRIPT); return; } PerformanceMeasurer framerate(PFE_GAMESCRIPT); Game::frame_counter++; Backup cur_company(_current_company, FILE_LINE); cur_company.Change(OWNER_DEITY); Game::instance->GameLoop(); cur_company.Restore(); /* Occasionally collect garbage */ if ((Game::frame_counter & 255) == 0) { Game::instance->CollectGarbage(); } } /* static */ void Game::Initialize() { if (Game::instance != nullptr) Game::Uninitialize(true); Game::frame_counter = 0; if (Game::scanner_info == nullptr) { TarScanner::DoScan(TarScanner::GAME); Game::scanner_info = new GameScannerInfo(); Game::scanner_info->Initialize(); Game::scanner_library = new GameScannerLibrary(); Game::scanner_library->Initialize(); } } /* static */ void Game::StartNew() { if (Game::instance != nullptr) return; /* Clients shouldn't start GameScripts */ if (_networking && !_network_server) return; GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME); GameInfo *info = config->GetInfo(); if (info == nullptr) return; config->AnchorUnchangeableSettings(); Backup cur_company(_current_company, FILE_LINE); cur_company.Change(OWNER_DEITY); Game::info = info; Game::instance = new GameInstance(); Game::instance->Initialize(info); cur_company.Restore(); InvalidateWindowData(WC_AI_DEBUG, 0, -1); } /* static */ void Game::Uninitialize(bool keepConfig) { Backup cur_company(_current_company, FILE_LINE); delete Game::instance; Game::instance = nullptr; Game::info = nullptr; cur_company.Restore(); if (keepConfig) { /* Do not bother re-scanning game script files, just reset config */ ResetConfig(); } else { /* Do not bother re-scanning game script, just delete config */ if (_settings_game.game_config != nullptr) { delete _settings_game.game_config; _settings_game.game_config = nullptr; } if (_settings_newgame.game_config != nullptr) { delete _settings_newgame.game_config; _settings_newgame.game_config = nullptr; } } } /* static */ void Game::Pause() { if (Game::instance != nullptr) Game::instance->Pause(); } /* static */ void Game::Unpause() { if (Game::instance != nullptr) Game::instance->Unpause(); } /* static */ bool Game::IsPaused() { return Game::instance != nullptr? Game::instance->IsPaused() : false; } /* static */ void Game::NewEvent(ScriptEvent *event) { /* AddRef() and Release() need to be called at least once, so do it here */ event->AddRef(); /* Clients should ignore events */ if (_networking && !_network_server) { event->Release(); return; } /* Check if Game instance is alive */ if (Game::instance == nullptr) { event->Release(); return; } /* Queue the event */ Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); Game::instance->InsertEvent(event); cur_company.Restore(); event->Release(); } /* static */ void Game::ResetConfig() { /* Check for both newgame as current game if we can reload the GameInfo inside * the GameConfig. If not, remove the Game from the list. */ if (_settings_game.game_config != nullptr && _settings_game.game_config->HasScript()) { if (!_settings_game.game_config->ResetInfo(true)) { DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_game.game_config->GetName()); _settings_game.game_config->Change(nullptr); if (Game::instance != nullptr) { delete Game::instance; Game::instance = nullptr; Game::info = nullptr; } } else if (Game::instance != nullptr) { Game::info = _settings_game.game_config->GetInfo(); } } if (_settings_newgame.game_config != nullptr && _settings_newgame.game_config->HasScript()) { if (!_settings_newgame.game_config->ResetInfo(false)) { DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_newgame.game_config->GetName()); _settings_newgame.game_config->Change(nullptr); } } } /* static */ void Game::Rescan() { TarScanner::DoScan(TarScanner::GAME); Game::scanner_info->RescanDir(); Game::scanner_library->RescanDir(); ResetConfig(); InvalidateWindowData(WC_AI_LIST, 0, 1); SetWindowClassesDirty(WC_AI_DEBUG); InvalidateWindowClassesData(WC_AI_SETTINGS); } /* static */ void Game::Save() { if (Game::instance != nullptr && (!_networking || _network_server)) { Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); Game::instance->Save(); cur_company.Restore(); } else { GameInstance::SaveEmpty(); } } /* static */ void Game::Load(int version) { if (Game::instance != nullptr && (!_networking || _network_server)) { Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); Game::instance->Load(version); cur_company.Restore(); } else { /* Read, but ignore, the load data */ GameInstance::LoadEmpty(); } } /* static */ std::string Game::GetConsoleList(bool newest_only) { return Game::scanner_info->GetConsoleList(newest_only); } /* static */ std::string Game::GetConsoleLibraryList() { return Game::scanner_library->GetConsoleList(true); } /* static */ const ScriptInfoList *Game::GetInfoList() { return Game::scanner_info->GetInfoList(); } /* static */ const ScriptInfoList *Game::GetUniqueInfoList() { return Game::scanner_info->GetUniqueInfoList(); } /* static */ GameInfo *Game::FindInfo(const char *name, int version, bool force_exact_match) { return Game::scanner_info->FindInfo(name, version, force_exact_match); } /* static */ GameLibrary *Game::FindLibrary(const char *library, int version) { return Game::scanner_library->FindLibrary(library, version); } /** * Check whether we have an Game (library) with the exact characteristics as ci. * @param ci the characteristics to search on (shortname and md5sum) * @param md5sum whether to check the MD5 checksum * @return true iff we have an Game (library) matching. */ /* static */ bool Game::HasGame(const ContentInfo *ci, bool md5sum) { return Game::scanner_info->HasScript(ci, md5sum); } /* static */ bool Game::HasGameLibrary(const ContentInfo *ci, bool md5sum) { return Game::scanner_library->HasScript(ci, md5sum); } /* static */ GameScannerInfo *Game::GetScannerInfo() { return Game::scanner_info; } /* static */ GameScannerLibrary *Game::GetScannerLibrary() { return Game::scanner_library; }