| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program 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, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // GameEngine.cpp /////////////////////////////////////////////////////////////////////////////////
- // Implementation of the Game Engine singleton
- // Author: Michael S. Booth, April 2001
- #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine
- #include "Common/ActionManager.h"
- #include "Common/AudioAffect.h"
- #include "Common/BuildAssistant.h"
- #include "Common/CRCDebug.h"
- #include "Common/Radar.h"
- #include "Common/PlayerTemplate.h"
- #include "Common/Team.h"
- #include "Common/PlayerList.h"
- #include "Common/GameAudio.h"
- #include "Common/GameEngine.h"
- #include "Common/INI.h"
- #include "Common/INIException.h"
- #include "Common/MessageStream.h"
- #include "Common/ThingFactory.h"
- #include "Common/File.h"
- #include "Common/FileSystem.h"
- #include "Common/ArchiveFileSystem.h"
- #include "Common/LocalFileSystem.h"
- #include "Common/CDManager.h"
- #include "Common/GlobalData.h"
- #include "Common/PerfTimer.h"
- #include "Common/RandomValue.h"
- #include "Common/NameKeyGenerator.h"
- #include "Common/ModuleFactory.h"
- #include "Common/Debug.h"
- #include "Common/GameState.h"
- #include "Common/GameStateMap.h"
- #include "Common/Science.h"
- #include "Common/FunctionLexicon.h"
- #include "Common/CommandLine.h"
- #include "Common/DamageFX.h"
- #include "Common/MultiplayerSettings.h"
- #include "Common/Recorder.h"
- #include "Common/SpecialPower.h"
- #include "Common/TerrainTypes.h"
- #include "Common/Upgrade.h"
- #include "Common/UserPreferences.h"
- #include "Common/Xfer.h"
- #include "Common/XferCRC.h"
- #include "Common/GameLOD.h"
- #include "Common/Registry.h"
- #include "Common/GameCommon.h" // FOR THE ALLOW_DEBUG_CHEATS_IN_RELEASE #define
- #include "GameLogic/Armor.h"
- #include "GameLogic/AI.h"
- #include "GameLogic/CaveSystem.h"
- #include "GameLogic/CrateSystem.h"
- #include "GameLogic/Damage.h"
- #include "GameLogic/VictoryConditions.h"
- #include "GameLogic/ObjectCreationList.h"
- #include "GameLogic/Weapon.h"
- #include "GameLogic/GameLogic.h"
- #include "GameLogic/Locomotor.h"
- #include "GameLogic/RankInfo.h"
- #include "GameLogic/ScriptEngine.h"
- #include "GameLogic/SidesList.h"
- #include "GameClient/Display.h"
- #include "GameClient/FXList.h"
- #include "GameClient/GameClient.h"
- #include "GameClient/Keyboard.h"
- #include "GameClient/Shell.h"
- #include "GameClient/GameText.h"
- #include "GameClient/ParticleSys.h"
- #include "GameClient/Water.h"
- #include "GameClient/TerrainRoads.h"
- #include "GameClient/MetaEvent.h"
- #include "GameClient/MapUtil.h"
- #include "GameClient/GameWindowManager.h"
- #include "GameClient/GlobalLanguage.h"
- #include "GameClient/Drawable.h"
- #include "GameClient/GUICallbacks.h"
- #include "GameNetwork/NetworkInterface.h"
- #include "GameNetwork/WOLBrowser/WebBrowser.h"
- #include "GameNetwork/LANAPI.h"
- #include "GameNetwork/GameSpy/GameResultsThread.h"
- #include "Common/Version.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- //-------------------------------------------------------------------------------------------------
- #ifdef DEBUG_CRC
- class DeepCRCSanityCheck : public SubsystemInterface
- {
- public:
- DeepCRCSanityCheck() {}
- virtual ~DeepCRCSanityCheck() {}
- virtual void init(void) {}
- virtual void reset(void);
- virtual void update(void) {}
- protected:
- };
- DeepCRCSanityCheck *TheDeepCRCSanityCheck = NULL;
- void DeepCRCSanityCheck::reset(void)
- {
- static Int timesThrough = 0;
- static UnsignedInt lastCRC = 0;
- AsciiString fname;
- fname.format("%sCRCAfter%dMaps.dat", TheGlobalData->getPath_UserData().str(), timesThrough);
- UnsignedInt thisCRC = TheGameLogic->getCRC( CRC_RECALC, fname );
- DEBUG_LOG(("DeepCRCSanityCheck: CRC is %X\n", thisCRC));
- DEBUG_ASSERTCRASH(timesThrough == 0 || thisCRC == lastCRC,
- ("CRC after reset did not match beginning CRC!\nNetwork games won't work after this.\nOld: 0x%8.8X, New: 0x%8.8X",
- lastCRC, thisCRC));
- lastCRC = thisCRC;
- timesThrough++;
- }
- #endif // DEBUG_CRC
- //-------------------------------------------------------------------------------------------------
- /// The GameEngine singleton instance
- GameEngine *TheGameEngine = NULL;
- //-------------------------------------------------------------------------------------------------
- SubsystemInterfaceList* TheSubsystemList = NULL;
- //-------------------------------------------------------------------------------------------------
- template<class SUBSYSTEM>
- void initSubsystem(SUBSYSTEM*& sysref, AsciiString name, SUBSYSTEM* sys, Xfer *pXfer, const char* path1 = NULL,
- const char* path2 = NULL, const char* dirpath = NULL)
- {
- sysref = sys;
- TheSubsystemList->initSubsystem(sys, path1, path2, dirpath, pXfer, name);
- }
- //-------------------------------------------------------------------------------------------------
- extern HINSTANCE ApplicationHInstance; ///< our application instance
- extern CComModule _Module;
- //-------------------------------------------------------------------------------------------------
- static void updateTGAtoDDS();
- Int GameEngine::getFramesPerSecondLimit( void )
- {
- return m_maxFPS;
- }
- //-------------------------------------------------------------------------------------------------
- GameEngine::GameEngine( void )
- {
- // Set the time slice size to 1 ms.
- timeBeginPeriod(1);
- // initialize to non garbage values
- m_maxFPS = 0;
- m_quitting = FALSE;
- m_isActive = FALSE;
- _Module.Init(NULL, ApplicationHInstance);
- }
- //-------------------------------------------------------------------------------------------------
- GameEngine::~GameEngine()
- {
- //extern std::vector<std::string> preloadTextureNamesGlobalHack;
- //preloadTextureNamesGlobalHack.clear();
- delete TheMapCache;
- TheMapCache = NULL;
- // delete TheShell;
- // TheShell = NULL;
- TheGameResultsQueue->endThreads();
- TheSubsystemList->shutdownAll();
- delete TheSubsystemList;
- TheSubsystemList = NULL;
- delete TheNetwork;
- TheNetwork = NULL;
- delete TheCommandList;
- TheCommandList = NULL;
- delete TheNameKeyGenerator;
- TheNameKeyGenerator = NULL;
- delete TheFileSystem;
- TheFileSystem = NULL;
- if (TheGameLODManager)
- delete TheGameLODManager;
- Drawable::killStaticImages();
- _Module.Term();
- #ifdef PERF_TIMERS
- PerfGather::termPerfDump();
- #endif
- // Restore the previous time slice for Windows.
- timeEndPeriod(1);
- }
- void GameEngine::setFramesPerSecondLimit( Int fps )
- {
- DEBUG_LOG(("GameEngine::setFramesPerSecondLimit() - setting max fps to %d (TheGlobalData->m_useFpsLimit == %d)\n", fps, TheGlobalData->m_useFpsLimit));
- m_maxFPS = fps;
- }
- /** -----------------------------------------------------------------------------------------------
- * Initialize the game engine by initializing the GameLogic and GameClient.
- */
- void GameEngine::init( void ) {} /// @todo: I changed this to take argc & argv so we can parse those after the GDF is loaded. We need to rethink this immediately as it is a nasty hack
- void GameEngine::init( int argc, char *argv[] )
- {
- try {
- //create an INI object to use for loading stuff
- INI ini;
- #ifdef DEBUG_LOGGING
- if (TheVersion)
- {
- DEBUG_LOG(("================================================================================\n"));
- #if defined _DEBUG
- const char *buildType = "Debug";
- #elif defined _INTERNAL
- const char *buildType = "Internal";
- #else
- const char *buildType = "Release";
- #endif
- DEBUG_LOG(("Generals version %s (%s)\n", TheVersion->getAsciiVersion().str(), buildType));
- DEBUG_LOG(("Build date: %s\n", TheVersion->getAsciiBuildTime().str()));
- DEBUG_LOG(("Build location: %s\n", TheVersion->getAsciiBuildLocation().str()));
- DEBUG_LOG(("Built by: %s\n", TheVersion->getAsciiBuildUser().str()));
- DEBUG_LOG(("================================================================================\n"));
- }
- #endif
- #if defined(PERF_TIMERS) || defined(DUMP_PERF_STATS)
- DEBUG_LOG(("Calculating CPU frequency for performance timers.\n"));
- InitPrecisionTimer();
- #endif
- #ifdef PERF_TIMERS
- PerfGather::initPerfDump("AAAPerfStats", PerfGather::PERF_NETTIME);
- #endif
- #ifdef DUMP_PERF_STATS////////////////////////////////////////////////////////////
- __int64 startTime64;//////////////////////////////////////////////////////////////
- __int64 endTime64,freq64;///////////////////////////////////////////////////////////
- GetPrecisionTimerTicksPerSec(&freq64);///////////////////////////////////////////////
- GetPrecisionTimer(&startTime64);////////////////////////////////////////////////////
- char Buf[256];//////////////////////////////////////////////////////////////////////
- #endif//////////////////////////////////////////////////////////////////////////////
-
- m_maxFPS = DEFAULT_MAX_FPS;
- TheSubsystemList = MSGNEW("GameEngineSubsystem") SubsystemInterfaceList;
-
- TheSubsystemList->addSubsystem(this);
- // initialize the random number system
- InitRandom();
- // Create the low-level file system interface
- TheFileSystem = createFileSystem();
- //Kris: Patch 1.01 - November 17, 2003
- //I was unable to resolve the RTPatch method of deleting a shipped file. English, Chinese, and Korean
- //SKU's shipped with two INIZH.big files. One properly in the Run directory and the other in Run\INI\Data.
- //We need to toast the latter in order for the game to patch properly.
- DeleteFile( "Data\\INI\\INIZH.big" );
- // not part of the subsystem list, because it should normally never be reset!
- TheNameKeyGenerator = MSGNEW("GameEngineSubsystem") NameKeyGenerator;
- TheNameKeyGenerator->init();
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheNameKeyGenerator = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- // not part of the subsystem list, because it should normally never be reset!
- TheCommandList = MSGNEW("GameEngineSubsystem") CommandList;
- TheCommandList->init();
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheCommandList = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- XferCRC xferCRC;
- xferCRC.open("lightCRC");
- initSubsystem(TheLocalFileSystem, "TheLocalFileSystem", createLocalFileSystem(), NULL);
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheLocalFileSystem = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- initSubsystem(TheArchiveFileSystem, "TheArchiveFileSystem", createArchiveFileSystem(), NULL); // this MUST come after TheLocalFileSystem creation
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheArchiveFileSystem = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- initSubsystem(TheWritableGlobalData, "TheWritableGlobalData", MSGNEW("GameEngineSubsystem") GlobalData(), &xferCRC, "Data\\INI\\Default\\GameData.ini", "Data\\INI\\GameData.ini");
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheWritableGlobalData = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- #if defined(_DEBUG) || defined(_INTERNAL)
- // If we're in Debug or Internal, load the Debug info as well.
- ini.load( AsciiString( "Data\\INI\\GameDataDebug.ini" ), INI_LOAD_OVERWRITE, NULL );
- #endif
-
- // special-case: parse command-line parameters after loading global data
- parseCommandLine(argc, argv);
- // doesn't require resets so just create a single instance here.
- TheGameLODManager = MSGNEW("GameEngineSubsystem") GameLODManager;
- TheGameLODManager->init();
-
- // after parsing the command line, we may want to perform dds stuff. Do that here.
- if (TheGlobalData->m_shouldUpdateTGAToDDS) {
- // update any out of date targas here.
- updateTGAtoDDS();
- }
- // read the water settings from INI (must do prior to initing GameClient, apparently)
- ini.load( AsciiString( "Data\\INI\\Default\\Water.ini" ), INI_LOAD_OVERWRITE, &xferCRC );
- ini.load( AsciiString( "Data\\INI\\Water.ini" ), INI_LOAD_OVERWRITE, &xferCRC );
- ini.load( AsciiString( "Data\\INI\\Default\\Weather.ini" ), INI_LOAD_OVERWRITE, &xferCRC );
- ini.load( AsciiString( "Data\\INI\\Weather.ini" ), INI_LOAD_OVERWRITE, &xferCRC );
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After water INI's = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- #ifdef DEBUG_CRC
- initSubsystem(TheDeepCRCSanityCheck, "TheDeepCRCSanityCheck", MSGNEW("GameEngineSubystem") DeepCRCSanityCheck, NULL, NULL, NULL, NULL);
- #endif // DEBUG_CRC
- initSubsystem(TheGameText, "TheGameText", CreateGameTextInterface(), NULL);
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheGameText = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- initSubsystem(TheScienceStore,"TheScienceStore", MSGNEW("GameEngineSubsystem") ScienceStore(), &xferCRC, "Data\\INI\\Default\\Science.ini", "Data\\INI\\Science.ini");
- initSubsystem(TheMultiplayerSettings,"TheMultiplayerSettings", MSGNEW("GameEngineSubsystem") MultiplayerSettings(), &xferCRC, "Data\\INI\\Default\\Multiplayer.ini", "Data\\INI\\Multiplayer.ini");
- initSubsystem(TheTerrainTypes,"TheTerrainTypes", MSGNEW("GameEngineSubsystem") TerrainTypeCollection(), &xferCRC, "Data\\INI\\Default\\Terrain.ini", "Data\\INI\\Terrain.ini");
- initSubsystem(TheTerrainRoads,"TheTerrainRoads", MSGNEW("GameEngineSubsystem") TerrainRoadCollection(), &xferCRC, "Data\\INI\\Default\\Roads.ini", "Data\\INI\\Roads.ini");
- initSubsystem(TheGlobalLanguageData,"TheGlobalLanguageData",MSGNEW("GameEngineSubsystem") GlobalLanguage, NULL); // must be before the game text
- initSubsystem(TheCDManager,"TheCDManager", CreateCDManager(), NULL);
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheCDManager = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- initSubsystem(TheAudio,"TheAudio", createAudioManager(), NULL);
- if (!TheAudio->isMusicAlreadyLoaded())
- setQuitting(TRUE);
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheAudio = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- initSubsystem(TheFunctionLexicon,"TheFunctionLexicon", createFunctionLexicon(), NULL);
- initSubsystem(TheModuleFactory,"TheModuleFactory", createModuleFactory(), NULL);
- initSubsystem(TheMessageStream,"TheMessageStream", createMessageStream(), NULL);
- initSubsystem(TheSidesList,"TheSidesList", MSGNEW("GameEngineSubsystem") SidesList(), NULL);
- initSubsystem(TheCaveSystem,"TheCaveSystem", MSGNEW("GameEngineSubsystem") CaveSystem(), NULL);
- initSubsystem(TheRankInfoStore,"TheRankInfoStore", MSGNEW("GameEngineSubsystem") RankInfoStore(), &xferCRC, NULL, "Data\\INI\\Rank.ini");
- initSubsystem(ThePlayerTemplateStore,"ThePlayerTemplateStore", MSGNEW("GameEngineSubsystem") PlayerTemplateStore(), &xferCRC, "Data\\INI\\Default\\PlayerTemplate.ini", "Data\\INI\\PlayerTemplate.ini");
- initSubsystem(TheParticleSystemManager,"TheParticleSystemManager", createParticleSystemManager(), NULL);
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheParticleSystemManager = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
-
-
- initSubsystem(TheFXListStore,"TheFXListStore", MSGNEW("GameEngineSubsystem") FXListStore(), &xferCRC, "Data\\INI\\Default\\FXList.ini", "Data\\INI\\FXList.ini");
- initSubsystem(TheWeaponStore,"TheWeaponStore", MSGNEW("GameEngineSubsystem") WeaponStore(), &xferCRC, NULL, "Data\\INI\\Weapon.ini");
- initSubsystem(TheObjectCreationListStore,"TheObjectCreationListStore", MSGNEW("GameEngineSubsystem") ObjectCreationListStore(), &xferCRC, "Data\\INI\\Default\\ObjectCreationList.ini", "Data\\INI\\ObjectCreationList.ini");
- initSubsystem(TheLocomotorStore,"TheLocomotorStore", MSGNEW("GameEngineSubsystem") LocomotorStore(), &xferCRC, NULL, "Data\\INI\\Locomotor.ini");
- initSubsystem(TheSpecialPowerStore,"TheSpecialPowerStore", MSGNEW("GameEngineSubsystem") SpecialPowerStore(), &xferCRC, "Data\\INI\\Default\\SpecialPower.ini", "Data\\INI\\SpecialPower.ini");
- initSubsystem(TheDamageFXStore,"TheDamageFXStore", MSGNEW("GameEngineSubsystem") DamageFXStore(), &xferCRC, NULL, "Data\\INI\\DamageFX.ini");
- initSubsystem(TheArmorStore,"TheArmorStore", MSGNEW("GameEngineSubsystem") ArmorStore(), &xferCRC, NULL, "Data\\INI\\Armor.ini");
- initSubsystem(TheBuildAssistant,"TheBuildAssistant", MSGNEW("GameEngineSubsystem") BuildAssistant, NULL);
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheBuildAssistant = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- initSubsystem(TheThingFactory,"TheThingFactory", createThingFactory(), &xferCRC, "Data\\INI\\Default\\Object.ini", NULL, "Data\\INI\\Object");
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheThingFactory = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
-
-
- initSubsystem(TheUpgradeCenter,"TheUpgradeCenter", MSGNEW("GameEngineSubsystem") UpgradeCenter, &xferCRC, "Data\\INI\\Default\\Upgrade.ini", "Data\\INI\\Upgrade.ini");
- initSubsystem(TheGameClient,"TheGameClient", createGameClient(), NULL);
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheGameClient = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
-
- initSubsystem(TheAI,"TheAI", MSGNEW("GameEngineSubsystem") AI(), &xferCRC, "Data\\INI\\Default\\AIData.ini", "Data\\INI\\AIData.ini");
- initSubsystem(TheGameLogic,"TheGameLogic", createGameLogic(), NULL);
- initSubsystem(TheTeamFactory,"TheTeamFactory", MSGNEW("GameEngineSubsystem") TeamFactory(), NULL);
- initSubsystem(TheCrateSystem,"TheCrateSystem", MSGNEW("GameEngineSubsystem") CrateSystem(), &xferCRC, "Data\\INI\\Default\\Crate.ini", "Data\\INI\\Crate.ini");
- initSubsystem(ThePlayerList,"ThePlayerList", MSGNEW("GameEngineSubsystem") PlayerList(), NULL);
- initSubsystem(TheRecorder,"TheRecorder", createRecorder(), NULL);
- initSubsystem(TheRadar,"TheRadar", createRadar(), NULL);
- initSubsystem(TheVictoryConditions,"TheVictoryConditions", createVictoryConditions(), NULL);
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheVictoryConditions = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- AsciiString fname;
- fname.format("Data\\%s\\CommandMap.ini", GetRegistryLanguage().str());
- initSubsystem(TheMetaMap,"TheMetaMap", MSGNEW("GameEngineSubsystem") MetaMap(), NULL, fname.str(), "Data\\INI\\CommandMap.ini");
- #if defined(_DEBUG) || defined(_INTERNAL)
- ini.load("Data\\INI\\CommandMapDebug.ini", INI_LOAD_MULTIFILE, NULL);
- #endif
- #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)
- ini.load("Data\\INI\\CommandMapDemo.ini", INI_LOAD_MULTIFILE, NULL);
- #endif
- initSubsystem(TheActionManager,"TheActionManager", MSGNEW("GameEngineSubsystem") ActionManager(), NULL);
- //initSubsystem((CComObject<WebBrowser> *)TheWebBrowser,"(CComObject<WebBrowser> *)TheWebBrowser", (CComObject<WebBrowser> *)createWebBrowser(), NULL);
- initSubsystem(TheGameStateMap,"TheGameStateMap", MSGNEW("GameEngineSubsystem") GameStateMap, NULL, NULL, NULL );
- initSubsystem(TheGameState,"TheGameState", MSGNEW("GameEngineSubsystem") GameState, NULL, NULL, NULL );
- // Create the interface for sending game results
- initSubsystem(TheGameResultsQueue,"TheGameResultsQueue", GameResultsInterface::createNewGameResultsInterface(), NULL, NULL, NULL, NULL);
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheGameResultsQueue = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- xferCRC.close();
- TheWritableGlobalData->m_iniCRC = xferCRC.getCRC();
- DEBUG_LOG(("INI CRC is 0x%8.8X\n", TheGlobalData->m_iniCRC));
- TheSubsystemList->postProcessLoadAll();
- setFramesPerSecondLimit(TheGlobalData->m_framesPerSecondLimit);
- TheAudio->setOn(TheGlobalData->m_audioOn && TheGlobalData->m_musicOn, AudioAffect_Music);
- TheAudio->setOn(TheGlobalData->m_audioOn && TheGlobalData->m_soundsOn, AudioAffect_Sound);
- TheAudio->setOn(TheGlobalData->m_audioOn && TheGlobalData->m_sounds3DOn, AudioAffect_Sound3D);
- TheAudio->setOn(TheGlobalData->m_audioOn && TheGlobalData->m_speechOn, AudioAffect_Speech);
-
- // We're not in a network game yet, so set the network singleton to NULL.
- TheNetwork = NULL;
- //Create a default ini file for options if it doesn't already exist.
- //OptionPreferences prefs( TRUE );
- // If we turn m_quitting to FALSE here, then we throw away any requests to quit that
- // took place during loading. :-\ - jkmcd
- // If this really needs to take place, please make sure that pressing cancel on the audio
- // load music dialog will still cause the game to quit.
- // m_quitting = FALSE;
- // for fingerprinting, we need to ensure the presence of these files
- #if !defined(_INTERNAL) && !defined(_DEBUG)
- AsciiString dirName;
- dirName = TheArchiveFileSystem->getArchiveFilenameForFile("generalsbzh.sec");
- if (dirName.compareNoCase("genseczh.big") != 0)
- {
- DEBUG_LOG(("generalsbzh.sec was not found in genseczh.big - it was in '%s'\n", dirName.str()));
- m_quitting = TRUE;
- }
-
- dirName = TheArchiveFileSystem->getArchiveFilenameForFile("generalsazh.sec");
- const char *noPath = dirName.reverseFind('\\');
- if (noPath) {
- dirName = noPath + 1;
- }
- if (dirName.compareNoCase("musiczh.big") != 0)
- {
- DEBUG_LOG(("generalsazh.sec was not found in musiczh.big - it was in '%s'\n", dirName.str()));
- m_quitting = TRUE;
- }
- #endif
- // initialize the MapCache
- TheMapCache = MSGNEW("GameEngineSubsystem") MapCache;
- TheMapCache->updateCache();
- #ifdef DUMP_PERF_STATS///////////////////////////////////////////////////////////////////////////
- GetPrecisionTimer(&endTime64);//////////////////////////////////////////////////////////////////
- sprintf(Buf,"----------------------------------------------------------------------------After TheMapCache->updateCache = %f seconds \n",((double)(endTime64-startTime64)/(double)(freq64)));
- startTime64 = endTime64;//Reset the clock ////////////////////////////////////////////////////////
- DEBUG_LOG(("%s", Buf));////////////////////////////////////////////////////////////////////////////
- #endif/////////////////////////////////////////////////////////////////////////////////////////////
- if (TheGlobalData->m_buildMapCache)
- {
- // just quit, since the map cache has already updated
- //populateMapListbox(NULL, true, true);
- m_quitting = TRUE;
- }
-
- // load the initial shell screen
- //TheShell->push( AsciiString("Menus/MainMenu.wnd") );
-
- // This allows us to run a map/reply from the command line
- if (TheGlobalData->m_initialFile.isEmpty() == FALSE)
- {
- AsciiString fname = TheGlobalData->m_initialFile;
- fname.toLower();
- if (fname.endsWithNoCase(".map"))
- {
- TheWritableGlobalData->m_shellMapOn = FALSE;
- TheWritableGlobalData->m_playIntro = FALSE;
- TheWritableGlobalData->m_pendingFile = TheGlobalData->m_initialFile;
- // shutdown the top, but do not pop it off the stack
- // TheShell->hideShell();
- // send a message to the logic for a new game
- GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_NEW_GAME );
- msg->appendIntegerArgument(GAME_SINGLE_PLAYER);
- msg->appendIntegerArgument(DIFFICULTY_NORMAL);
- msg->appendIntegerArgument(0);
- InitRandom(0);
- }
- else if (fname.endsWithNoCase(".rep"))
- {
- TheRecorder->playbackFile(fname);
- }
- }
- //
- if (TheMapCache && TheGlobalData->m_shellMapOn)
- {
- AsciiString lowerName = TheGlobalData->m_shellMapName;
- lowerName.toLower();
- MapCache::const_iterator it = TheMapCache->find(lowerName);
- if (it == TheMapCache->end())
- {
- TheWritableGlobalData->m_shellMapOn = FALSE;
- }
- }
- if(!TheGlobalData->m_playIntro)
- TheWritableGlobalData->m_afterIntro = TRUE;
- //initDisabledMasks();
-
- }
- catch (ErrorCode ec)
- {
- if (ec == ERROR_INVALID_D3D)
- {
- RELEASE_CRASHLOCALIZED("ERROR:D3DFailurePrompt", "ERROR:D3DFailureMessage");
- }
- }
- catch (INIException e)
- {
- if (e.mFailureMessage)
- RELEASE_CRASH((e.mFailureMessage));
- else
- RELEASE_CRASH(("Uncaught Exception during initialization."));
- }
- catch (...)
- {
- RELEASE_CRASH(("Uncaught Exception during initialization."));
- }
- if(!TheGlobalData->m_playIntro)
- TheWritableGlobalData->m_afterIntro = TRUE;
- initKindOfMasks();
- initDisabledMasks();
- initDamageTypeFlags();
- TheSubsystemList->resetAll();
- HideControlBar();
- } // end init
- /** -----------------------------------------------------------------------------------------------
- * Reset all necessary parts of the game engine to be ready to accept new game data
- */
- void GameEngine::reset( void )
- {
- WindowLayout *background = TheWindowManager->winCreateLayout("Menus/BlankWindow.wnd");
- DEBUG_ASSERTCRASH(background,("We Couldn't Load Menus/BlankWindow.wnd"));
- background->hide(FALSE);
- background->bringForward();
- background->getFirstWindow()->winClearStatus(WIN_STATUS_IMAGE);
- Bool deleteNetwork = false;
- if (TheGameLogic->isInMultiplayerGame())
- deleteNetwork = true;
- TheSubsystemList->resetAll();
- if (deleteNetwork)
- {
- DEBUG_ASSERTCRASH(TheNetwork, ("Deleting NULL TheNetwork!"));
- if (TheNetwork)
- delete TheNetwork;
- TheNetwork = NULL;
- }
- if(background)
- {
- background->destroyWindows();
- background->deleteInstance();
- background = NULL;
- }
- }
- /// -----------------------------------------------------------------------------------------------
- DECLARE_PERF_TIMER(GameEngine_update)
- /** -----------------------------------------------------------------------------------------------
- * Update the game engine by updating the GameClient and GameLogic singletons.
- * @todo Allow the client to run as fast as possible, but limit the execution
- * of TheNetwork and TheGameLogic to a fixed framerate.
- */
- void GameEngine::update( void )
- {
- USE_PERF_TIMER(GameEngine_update)
- {
- {
-
- // VERIFY CRC needs to be in this code block. Please to not pull TheGameLogic->update() inside this block.
- VERIFY_CRC
- TheRadar->UPDATE();
- /// @todo Move audio init, update, etc, into GameClient update
-
- TheAudio->UPDATE();
- TheGameClient->UPDATE();
- TheMessageStream->propagateMessages();
- if (TheNetwork != NULL)
- {
- TheNetwork->UPDATE();
- }
-
- TheCDManager->UPDATE();
- }
- if ((TheNetwork == NULL && !TheGameLogic->isGamePaused()) || (TheNetwork && TheNetwork->isFrameDataReady()))
- {
- TheGameLogic->UPDATE();
- }
- } // end perfGather
- }
- // Horrible reference, but we really, really need to know if we are windowed.
- extern bool DX8Wrapper_IsWindowed;
- extern HWND ApplicationHWnd;
- /** -----------------------------------------------------------------------------------------------
- * The "main loop" of the game engine. It will not return until the game exits.
- */
- void GameEngine::execute( void )
- {
-
- DWORD prevTime = timeGetTime();
- #if defined(_DEBUG) || defined(_INTERNAL)
- DWORD startTime = timeGetTime() / 1000;
- #endif
- // pretty basic for now
- while( !m_quitting )
- {
- //if (TheGlobalData->m_vTune)
- {
- #ifdef PERF_TIMERS
- PerfGather::resetAll();
- #endif
- }
- {
- #if defined(_DEBUG) || defined(_INTERNAL)
- {
- // enter only if in benchmark mode
- if (TheGlobalData->m_benchmarkTimer > 0)
- {
- DWORD currentTime = timeGetTime() / 1000;
- if (TheGlobalData->m_benchmarkTimer < currentTime - startTime)
- {
- if (TheGameLogic->isInGame())
- {
- if (TheRecorder->getMode() == RECORDERMODETYPE_RECORD)
- {
- TheRecorder->stopRecording();
- }
- TheGameLogic->clearGameData();
- }
- TheGameEngine->setQuitting(TRUE);
- }
- }
- }
- #endif
-
- {
- try
- {
- // compute a frame
- update();
- }
- catch (INIException e)
- {
- // Release CRASH doesn't return, so don't worry about executing additional code.
- if (e.mFailureMessage)
- RELEASE_CRASH((e.mFailureMessage));
- else
- RELEASE_CRASH(("Uncaught Exception in GameEngine::update"));
- }
- catch (...)
- {
- // try to save info off
- try
- {
- if (TheRecorder && TheRecorder->getMode() == RECORDERMODETYPE_RECORD && TheRecorder->isMultiplayer())
- TheRecorder->cleanUpReplayFile();
- }
- catch (...)
- {
- }
- RELEASE_CRASH(("Uncaught Exception in GameEngine::update"));
- } // catch
- } // perf
- {
- if (TheTacticalView->getTimeMultiplier()<=1 && !TheScriptEngine->isTimeFast())
- {
- // I'm disabling this in internal because many people need alt-tab capability. If you happen to be
- // doing performance tuning, please just change this on your local system. -MDC
- #if defined(_DEBUG) || defined(_INTERNAL)
- ::Sleep(1); // give everyone else a tiny time slice.
- #endif
- #if defined(_ALLOW_DEBUG_CHEATS_IN_RELEASE)
- if ( ! TheGlobalData->m_TiVOFastMode )
- #else //always allow this cheatkey if we're in a replaygame.
- if ( ! (TheGlobalData->m_TiVOFastMode && TheGameLogic->isInReplayGame()))
- #endif
- {
- // limit the framerate
- DWORD now = timeGetTime();
- DWORD limit = (1000.0f/m_maxFPS)-1;
- while (TheGlobalData->m_useFpsLimit && (now - prevTime) < limit)
- {
- ::Sleep(0);
- now = timeGetTime();
- }
- //Int slept = now - prevTime;
- //DEBUG_LOG(("delayed %d\n",slept));
- prevTime = now;
- }
-
- }
- }
- } // perfgather for execute_loop
- #ifdef PERF_TIMERS
- if (!m_quitting && TheGameLogic->isInGame() && !TheGameLogic->isInShellGame() && !TheGameLogic->isGamePaused())
- {
- PerfGather::dumpAll(TheGameLogic->getFrame());
- PerfGather::displayGraph(TheGameLogic->getFrame());
- PerfGather::resetAll();
- }
- #endif
- }
- }
- /** -----------------------------------------------------------------------------------------------
- * Factory for the message stream
- */
- MessageStream *GameEngine::createMessageStream( void )
- {
- // if you change this update the tools that use the engine systems
- // like GUIEdit, it creates a message stream to run in "test" mode
- return MSGNEW("GameEngineSubsystem") MessageStream;
- }
- //-------------------------------------------------------------------------------------------------
- FileSystem *GameEngine::createFileSystem( void )
- {
- return MSGNEW("GameEngineSubsystem") FileSystem;
- }
- //-------------------------------------------------------------------------------------------------
- Bool GameEngine::isMultiplayerSession( void )
- {
- return TheRecorder->isMultiplayer();
- }
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- //-------------------------------------------------------------------------------------------------
- #define CONVERT_EXEC1 "..\\Build\\nvdxt -list buildDDS.txt -dxt5 -full -outdir Art\\Textures > buildDDS.out"
- void updateTGAtoDDS()
- {
- // Here's the scoop. We're going to traverse through all of the files in the Art\Textures folder
- // and determine if there are any .tga files that are newer than associated .dds files. If there
- // are, then we will re-run the compression tool on them.
-
- File *fp = TheLocalFileSystem->openFile("buildDDS.txt", File::WRITE | File::CREATE | File::TRUNCATE | File::TEXT);
- if (!fp) {
- return;
- }
- FilenameList files;
- TheLocalFileSystem->getFileListInDirectory("Art\\Textures\\", "", "*.tga", files, TRUE);
- FilenameList::iterator it;
- for (it = files.begin(); it != files.end(); ++it) {
- AsciiString filenameTGA = *it;
- AsciiString filenameDDS = *it;
- FileInfo infoTGA;
- TheLocalFileSystem->getFileInfo(filenameTGA, &infoTGA);
- // skip the water textures, since they need to be NOT compressed
- filenameTGA.toLower();
- if (strstr(filenameTGA.str(), "caust"))
- {
- continue;
- }
- // and the recolored stuff.
- if (strstr(filenameTGA.str(), "zhca"))
- {
- continue;
- }
- // replace tga with dds
- filenameDDS.removeLastChar(); // a
- filenameDDS.removeLastChar(); // g
- filenameDDS.removeLastChar(); // t
- filenameDDS.concat("dds");
- Bool needsToBeUpdated = FALSE;
- FileInfo infoDDS;
- if (TheFileSystem->doesFileExist(filenameDDS.str())) {
- TheFileSystem->getFileInfo(filenameDDS, &infoDDS);
- if (infoTGA.timestampHigh > infoDDS.timestampHigh ||
- (infoTGA.timestampHigh == infoDDS.timestampHigh &&
- infoTGA.timestampLow > infoDDS.timestampLow)) {
- needsToBeUpdated = TRUE;
- }
- } else {
- needsToBeUpdated = TRUE;
- }
- if (!needsToBeUpdated) {
- continue;
- }
- filenameTGA.concat("\n");
- fp->write(filenameTGA.str(), filenameTGA.getLength());
- }
- fp->close();
- system(CONVERT_EXEC1);
- }
- //-------------------------------------------------------------------------------------------------
- // System things
- // If we're using the Wide character version of MessageBox, then there's no additional
- // processing necessary. Please note that this is a sleazy way to get this information,
- // but pending a better one, this'll have to do.
- extern const Bool TheSystemIsUnicode = (((void*) (::MessageBox)) == ((void*) (::MessageBoxW)));
|