| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613 |
- /*
- ** 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. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: GameClient.cpp ////////////////////////////////////////////////////
- // Implementation of GameClient singleton
- // Author: Michael S. Booth, March 2001
- ///////////////////////////////////////////////////////////////////////////////
- // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "GameClient/GameClient.h"
- // USER INCLUDES //////////////////////////////////////////////////////////////
- #include "Common/ActionManager.h"
- #include "Common/GameEngine.h"
- #include "Common/GameState.h"
- #include "Common/GlobalData.h"
- #include "Common/PerfTimer.h"
- #include "Common/Player.h"
- #include "Common/PlayerList.h"
- #include "Common/ThingFactory.h"
- #include "Common/ThingTemplate.h"
- #include "Common/Xfer.h"
- #include "Common/GameLOD.h"
- #include "GameClient/Anim2D.h"
- #include "GameClient/CampaignManager.h"
- #include "GameClient/ChallengeGenerals.h"
- #include "GameClient/CommandXlat.h"
- #include "GameClient/ControlBar.h"
- #include "GameClient/Diplomacy.h"
- #include "GameClient/Display.h"
- #include "GameClient/DisplayStringManager.h"
- #include "GameClient/Drawable.h"
- #include "GameClient/DrawGroupInfo.h"
- #include "GameClient/Eva.h"
- #include "GameClient/GameWindowManager.h"
- #include "GameClient/GlobalLanguage.h"
- #include "GameClient/GraphDraw.h"
- #include "GameClient/GUICommandTranslator.h"
- #include "GameClient/HeaderTemplate.h"
- #include "GameClient/HintSpy.h"
- #include "GameClient/HotKey.h"
- #include "GameClient/IMEManager.h"
- #include "GameClient/InGameUI.h"
- #include "GameClient/Keyboard.h"
- #include "GameClient/LanguageFilter.h"
- #include "GameClient/LookAtXlat.h"
- #include "GameClient/MetaEvent.h"
- #include "GameClient/Mouse.h"
- #include "GameClient/ParticleSys.h"
- #include "GameClient/PlaceEventTranslator.h"
- #include "GameClient/RayEffect.h"
- #include "GameClient/SelectionXlat.h"
- #include "GameClient/Shell.h"
- #include "GameClient/Snow.h"
- #include "GameClient/TerrainVisual.h"
- #include "GameClient/View.h"
- #include "GameClient/VideoPlayer.h"
- #include "GameClient/WindowXlat.h"
- #include "GameLogic/FPUControl.h"
- #include "GameLogic/GameLogic.h"
- #include "GameLogic/GhostObject.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/ScriptEngine.h" // For TheScriptEngine - jkmcd
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- #define DRAWABLE_HASH_SIZE 8192
- /// The GameClient singleton instance
- GameClient *TheGameClient = NULL;
- //-------------------------------------------------------------------------------------------------
- GameClient::GameClient()
- {
- // zero our translator list
- for( Int i = 0; i < MAX_CLIENT_TRANSLATORS; i++ )
- m_translators[ i ] = TRANSLATOR_ID_INVALID;
- m_numTranslators = 0;
- m_commandTranslator = NULL;
-
- // Added By Sadullah Nader
- // Initializations missing and needed
- m_drawableTOC.clear();
- //
- m_textBearingDrawableList.clear();
- m_frame = 0;
- m_drawableList = NULL;
-
- m_nextDrawableID = (DrawableID)1;
- TheDrawGroupInfo = new DrawGroupInfo;
- }
- //std::vector<std::string> preloadTextureNamesGlobalHack;
- //std::vector<std::string> preloadTextureNamesGlobalHack2;
- //-------------------------------------------------------------------------------------------------
- GameClient::~GameClient()
- {
- #ifdef PERF_TIMERS
- delete TheGraphDraw;
- TheGraphDraw = NULL;
- #endif
- if (TheDrawGroupInfo)
- {
- delete TheDrawGroupInfo;
- TheDrawGroupInfo = NULL;
- }
- // clear any drawable TOC we might have
- m_drawableTOC.clear();
- //DEBUG_LOG(("Preloaded texture files ------------------------------------------\n"));
- //for (Int oog=0; oog<preloadTextureNamesGlobalHack2.size(); ++oog)
- //{
- // DEBUG_LOG(("%s\n", preloadTextureNamesGlobalHack2[oog]));
- //}
- //DEBUG_LOG(("------------------------------------------------------------------\n"));
- //for (oog=0; oog<preloadTextureNamesGlobalHack.size(); ++oog)
- //{
- // DEBUG_LOG(("%s\n", preloadTextureNamesGlobalHack[oog]));
- //}
- //DEBUG_LOG(("End Texture files ------------------------------------------------\n"));
- if(TheCampaignManager)
- delete TheCampaignManager;
- TheCampaignManager = NULL;
- // destroy all Drawables
- Drawable *draw, *nextDraw;
- for( draw = m_drawableList; draw; draw = nextDraw )
- {
- nextDraw = draw->getNextDrawable();
- destroyDrawable( draw );
- }
- m_drawableList = NULL;
- // delete the ray effects
- delete TheRayEffects;
- TheRayEffects = NULL;
- // delete the hot key manager
- delete TheHotKeyManager;
- TheHotKeyManager = NULL;
- // destroy the in-game user interface
- delete TheInGameUI;
- TheInGameUI = NULL;
- delete TheChallengeGenerals;
- TheChallengeGenerals = NULL;
- // delete the shell
- delete TheShell;
- TheShell = NULL;
- delete TheIMEManager;
- TheIMEManager = NULL;
- // delete window manager
- delete TheWindowManager;
- TheWindowManager = NULL;
- // delete the font library
- TheFontLibrary->reset();
- delete TheFontLibrary;
- TheFontLibrary = NULL;
- delete TheMouse;
- TheMouse = NULL;
- ///@todo : TheTerrainVisual used to be the first thing destroyed.
- //I had to put in here so that drawables free their track marks before
- //the terrain visual deletes the track laying system. MW
- // destroy the terrain visual representation
- delete TheTerrainVisual;
- TheTerrainVisual = NULL;
- // destroy the display
- delete TheDisplay;
- TheDisplay = NULL;
- delete TheHeaderTemplateManager;
- TheHeaderTemplateManager = NULL;
-
- delete TheLanguageFilter;
- TheLanguageFilter = NULL;
- delete TheVideoPlayer;
- TheVideoPlayer = NULL;
- // destroy all translators
- for( Int i = 0; i < m_numTranslators; i++ )
- TheMessageStream->removeTranslator( m_translators[ i ] );
- m_numTranslators = 0;
- m_commandTranslator = NULL;
- delete TheAnim2DCollection;
- TheAnim2DCollection = NULL;
- delete TheMappedImageCollection;
- TheMappedImageCollection = NULL;
-
- delete TheKeyboard;
- TheKeyboard = NULL;
- delete TheDisplayStringManager;
- TheDisplayStringManager = NULL;
- delete TheEva;
- TheEva = NULL;
- delete TheSnowManager;
- TheSnowManager = NULL;
- } // end ~GameClient
- //-------------------------------------------------------------------------------------------------
- /** Initialize resources for the game client */
- //-------------------------------------------------------------------------------------------------
- void GameClient::init( void )
- {
- setFrameRate(MSEC_PER_LOGICFRAME_REAL); // from GameCommon.h... tell W3D what our expected framerate is
- INI ini;
- // Load the DrawGroupInfo here, before the Display Manager is loaded.
- ini.load("Data\\INI\\DrawGroupInfo.ini", INI_LOAD_OVERWRITE, NULL);
-
- // Override the ini values with localized versions:
- if (TheGlobalLanguageData && TheGlobalLanguageData->m_drawGroupInfoFont.name.isNotEmpty())
- {
- TheDrawGroupInfo->m_fontName = TheGlobalLanguageData->m_drawGroupInfoFont.name;
- TheDrawGroupInfo->m_fontSize = TheGlobalLanguageData->m_drawGroupInfoFont.size;
- TheDrawGroupInfo->m_fontIsBold = TheGlobalLanguageData->m_drawGroupInfoFont.bold;
- }
- // create the display string factory
- TheDisplayStringManager = createDisplayStringManager();
- if( TheDisplayStringManager ) {
- TheDisplayStringManager->init();
- TheDisplayStringManager->setName("TheDisplayStringManager");
- }
-
- // create the keyboard
- TheKeyboard = createKeyboard();
- TheKeyboard->init();
- TheKeyboard->setName("TheKeyboard");
- // allocate and load image collection for the GUI and just load the 256x256 ones for now
- TheMappedImageCollection = MSGNEW("GameClientSubsystem") ImageCollection;
- TheMappedImageCollection->load( 512 );
- // now that we have all the images loaded ... load any animation definitions from those images
- TheAnim2DCollection = MSGNEW("GameClientSubsystem") Anim2DCollection;
- TheAnim2DCollection->init();
- TheAnim2DCollection->setName("TheAnim2DCollection");
- // register message translators
- if( TheMessageStream )
- {
- //
- // NOTE: Make sure m_translators[] is large enough to accomodate all the translators you
- // are loading here. See MAX_CLIENT_TRANSLATORS
- //
- // since we only allocate one of each, don't bother pooling 'em
- m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") WindowTranslator, 10 );
- m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") MetaEventTranslator, 20 );
- m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") HotKeyTranslator, 25 );
- m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") PlaceEventTranslator, 30 );
- m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") GUICommandTranslator, 40 );
- m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") SelectionTranslator, 50 );
- m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") LookAtTranslator, 60 );
- m_translators[ m_numTranslators ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") CommandTranslator, 70 );
- // we keep a pointer to the command translator because it's useful
- m_commandTranslator = (CommandTranslator *)TheMessageStream->findTranslator( m_translators[ m_numTranslators++ ] );
- m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") HintSpyTranslator, 100 );
- //
- // the client message translator should probably remain as the last reaction of the
- // client before the messages are given to the network for processing. This
- // lets all systems in the client give events that can be processed by the
- // client message translator
- //
- m_translators[ m_numTranslators++ ] = TheMessageStream->attachTranslator( MSGNEW("GameClientSubsystem") GameClientMessageDispatcher, 999999999 );
- }
- // create the font library
- TheFontLibrary = createFontLibrary();
- if( TheFontLibrary )
- TheFontLibrary->init();
- // create the mouse
- TheMouse = createMouse();
- TheMouse->parseIni();
- TheMouse->initCursorResources();
- TheMouse->setName("TheMouse");
- // instantiate the display
- TheDisplay = createGameDisplay();
- if( TheDisplay ) {
- TheDisplay->init();
- TheDisplay->setName("TheDisplay");
- }
-
- TheHeaderTemplateManager = MSGNEW("GameClientSubsystem") HeaderTemplateManager;
- if(TheHeaderTemplateManager){
- TheHeaderTemplateManager->init();
- }
- // create the window manager
- TheWindowManager = createWindowManager();
- if( TheWindowManager )
- {
- TheWindowManager->init();
- TheWindowManager->setName("TheWindowManager");
- // TheWindowManager->initTestGUI();
- } // end if
- // create the IME manager
- TheIMEManager = CreateIMEManagerInterface();
- if ( TheIMEManager )
- {
- TheIMEManager->init();
- TheIMEManager->setName("TheIMEManager");
- }
- // create the shell
- TheShell = MSGNEW("GameClientSubsystem") Shell;
- if( TheShell ) {
- TheShell->init();
- TheShell->setName("TheShell");
- }
- // instantiate the in-game user interface
- TheInGameUI = createInGameUI();
- if( TheInGameUI ) {
- TheInGameUI->init();
- TheInGameUI->setName("TheInGameUI");
- }
- TheChallengeGenerals = createChallengeGenerals();
- if( TheChallengeGenerals ) {
- TheChallengeGenerals->init();
- }
- TheHotKeyManager = MSGNEW("GameClientSubsystem") HotKeyManager;
- if( TheHotKeyManager ) {
- TheHotKeyManager->init();
- TheHotKeyManager->setName("TheHotKeyManager");
- }
- // instantiate the terrain visual display
- TheTerrainVisual = createTerrainVisual();
- if( TheTerrainVisual ) {
- TheTerrainVisual->init();
- TheTerrainVisual->setName("TheTerrainVisual");
- }
- // allocate the ray effects manager
- TheRayEffects = MSGNEW("GameClientSubsystem") RayEffectSystem;
- if( TheRayEffects ) {
- TheRayEffects->init();
- TheRayEffects->setName("TheRayEffects");
- }
- TheMouse->init(); //finish initializing the mouse.
- // set the limits of the mouse now that we've created the display and such
- if( TheMouse )
- {
- TheMouse->setPosition( 0, 0 );
- TheMouse->setMouseLimits();
- TheMouse->setName("TheMouse");
- } // end if
- // create the video player
- TheVideoPlayer = createVideoPlayer();
- if ( TheVideoPlayer )
- {
- TheVideoPlayer->init();
- TheVideoPlayer->setName("TheVideoPlayer");
- }
- // create the language filter.
- TheLanguageFilter = createLanguageFilter();
- if (TheLanguageFilter)
- {
- TheLanguageFilter->init();
- TheLanguageFilter->setName("TheLanguageFilter");
- }
- TheCampaignManager = MSGNEW("GameClientSubsystem") CampaignManager;
- TheCampaignManager->init();
- TheEva = MSGNEW("GameClientSubsystem") Eva;
- TheEva->init();
- TheEva->setName("TheEva");
- TheDisplayStringManager->postProcessLoad();
- TheSnowManager = createSnowManager();
- if (TheSnowManager)
- {
- TheSnowManager->init();
- TheSnowManager->setName("TheSnowManager");
- }
- #ifdef PERF_TIMERS
- TheGraphDraw = new GraphDraw;
- #endif
- } // end init
- //-------------------------------------------------------------------------------------------------
- /** Reset the game client for a new game */
- void GameClient::reset( void )
- {
- Drawable *draw, *nextDraw;
- // m_drawableHash.clear();
- // m_drawableHash.resize(DRAWABLE_HASH_SIZE);
- m_drawableVector.clear();
- m_drawableVector.resize(DRAWABLE_HASH_SIZE, NULL);
- // need to reset the in game UI to clear drawables before they are destroyed
- TheInGameUI->reset();
- // destroy all Drawables
- for( draw = m_drawableList; draw; draw = nextDraw )
- {
- nextDraw = draw->getNextDrawable();
- destroyDrawable( draw );
- }
- m_drawableList = NULL;
- TheDisplay->reset();
- TheTerrainVisual->reset();
- TheRayEffects->reset();
- TheVideoPlayer->reset();
- TheEva->reset();
- if (TheSnowManager)
- TheSnowManager->reset();
- // clear any drawable TOC we might have
- m_drawableTOC.clear();
- } // end reset
- /** -----------------------------------------------------------------------------------------------
- * Return a new unique object id.
- */
- DrawableID GameClient::allocDrawableID( void )
- {
- /// @todo Find unused value in current set
- DrawableID ret = m_nextDrawableID;
- m_nextDrawableID = (DrawableID)((UnsignedInt)m_nextDrawableID + 1);
- return ret;
- }
- /** -----------------------------------------------------------------------------------------------
- * Given a drawable, register it with the GameClient and give it a unique ID.
- */
- void GameClient::registerDrawable( Drawable *draw )
- {
- // assign this drawable a unique ID, this will add it to the fast lookup table too
- draw->setID( allocDrawableID() );
- // add the drawable to the master list
- draw->prependToList( &m_drawableList );
- } // end registerDrawable
- /** -----------------------------------------------------------------------------------------------
- * Redraw all views, update the GUI, play sound effects, etc.
- */
- DECLARE_PERF_TIMER(GameClient_update)
- DECLARE_PERF_TIMER(GameClient_draw)
- void GameClient::update( void )
- {
- USE_PERF_TIMER(GameClient_update)
- // create the FRAME_TICK message
- GameMessage *frameMsg = TheMessageStream->appendMessage( GameMessage::MSG_FRAME_TICK );
- frameMsg->appendTimestampArgument( getFrame() );
- static Bool playSizzle = FALSE;
- // We need to show the movie first.
- if(TheGlobalData->m_playIntro && !TheDisplay->isMoviePlaying())
- {
- if(TheGameLODManager && TheGameLODManager->didMemPass())
- TheDisplay->playLogoMovie("EALogoMovie", 5000, 3000);
- else
- TheDisplay->playLogoMovie("EALogoMovie640", 5000, 3000);
- TheWritableGlobalData->m_playIntro = FALSE;
- TheWritableGlobalData->m_afterIntro = TRUE;
- playSizzle = TRUE;
- }
- //Initial Game Codition. We must show the movie first and then we can display the shell
- if(TheGlobalData->m_afterIntro && !TheDisplay->isMoviePlaying())
- {
- if( playSizzle && TheGlobalData->m_playSizzle )
- {
- TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
- if(TheGameLODManager && TheGameLODManager->didMemPass())
- TheDisplay->playMovie("Sizzle");
- else
- TheDisplay->playMovie("Sizzle640");
- playSizzle = FALSE;
- }
- else
- {
- TheWritableGlobalData->m_breakTheMovie = TRUE;
- TheWritableGlobalData->m_allowExitOutOfMovies = TRUE;
- if(TheGameLODManager && !TheGameLODManager->didMemPass())
- {
- TheWritableGlobalData->m_breakTheMovie = FALSE;
- WindowLayout *legal = TheWindowManager->winCreateLayout("Menus/LegalPage.wnd");
- if(legal)
- {
- legal->hide(FALSE);
- legal->bringForward();
- Int beginTime = timeGetTime();
- while(beginTime + 4000 > timeGetTime() )
- {
- TheWindowManager->update();
- // redraw all views, update the GUI
- TheDisplay->draw();
- Sleep(100);
- }
- setFPMode();
- legal->destroyWindows();
- legal->deleteInstance();
- }
- TheWritableGlobalData->m_breakTheMovie = TRUE;
-
- }
- TheShell->showShellMap(TRUE);
- TheShell->showShell();
- TheWritableGlobalData->m_afterIntro = FALSE;
- }
- }
- //Update snow particles.
- if (TheSnowManager)
- TheSnowManager->UPDATE();
- // update animation 2d collection
- TheAnim2DCollection->UPDATE();
- // update the keyboard
- if( TheKeyboard )
- {
- TheKeyboard->UPDATE();
- TheKeyboard->createStreamMessages();
- } // end if
- // Update the Eva stuff
- TheEva->UPDATE();
- // update the mouse
- if( TheMouse )
- {
- TheMouse->UPDATE();
- TheMouse->createStreamMessages();
- } // end if
-
- if (TheInGameUI->isCameraTrackingDrawable())
- {
- Drawable *draw = TheInGameUI->getFirstSelectedDrawable();
- if ( draw )
- {
- const Coord3D *pos = draw->getPosition();
- TheTacticalView->lookAt( pos );
- }
- else
- TheInGameUI->setCameraTrackingDrawable( FALSE );
- }
- if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro)
- {
- // redraw all views, update the GUI
- {
- TheDisplay->DRAW();
- }
- {
- TheDisplay->UPDATE();
- }
- return;
- }
- // update the window system itself
- {
- TheWindowManager->UPDATE();
- }
- // update the video player
- {
- TheVideoPlayer->UPDATE();
- }
- Bool freezeTime = TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished();
- freezeTime = freezeTime || TheScriptEngine->isTimeFrozenDebug();
- freezeTime = freezeTime || TheScriptEngine->isTimeFrozenScript();
- freezeTime = freezeTime || TheGameLogic->isGamePaused();
- Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
- // hack to let client spin fast in network games but still do effects at the same pace. -MDC
- static UnsignedInt lastFrame = ~0;
- freezeTime = freezeTime || (lastFrame == m_frame);
- lastFrame = m_frame;
- if (!freezeTime)
- {
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData->m_shroudOn)
- #else
- if (true)
- #endif
- {
- //localPlayerIndex=TheGhostObjectManager->getLocalPlayerIndex(); //always use the first local player set since normally can't change. Doesn't work with debug "CTRL_SHIFT_SPACE"
- #ifdef DEBUG_FOG_MEMORY
- //Find indices of all active players
- Int numPlayers=ThePlayerList->getPlayerCount();
- Int numNonLocalPlayers=0;
- Int nonLocalPlayerIndices[MAX_PLAYER_COUNT];
- for (Int i=0; i<numPlayers; i++)
- { Player *player=ThePlayerList->getNthPlayer(i);
- //if (player->getPlayerType == PLAYER_HUMAN)
- if (player->getPlayerIndex() != localPlayerIndex)
- nonLocalPlayerIndices[numNonLocalPlayers++]=player->getPlayerIndex();
- }
- //update ghostObjects which don't have drawables or objects.
- TheGhostObjectManager->updateOrphanedObjects(nonLocalPlayerIndices,numNonLocalPlayers);
- #else
- TheGhostObjectManager->updateOrphanedObjects(NULL,0);
- #endif
- }
- // call the update for all client drawables
- Drawable* draw = firstDrawable();
- while (draw)
- { // update() could free the Drawable, so go ahead and grab 'next'
- Drawable* next = draw->getNextDrawable();
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData->m_shroudOn)
- #else
- if (true)
- #endif
- { //immobile objects need to take snapshots whenever they become fogged
- //so need to refresh their status. We can't rely on external calls
- //to getShroudStatus() because they are only made for visible on-screen
- //objects.
- Object *object=draw->getObject();
- if (object)
- {
- #ifdef DEBUG_FOG_MEMORY
- Int *playerIndex=nonLocalPlayerIndices;
- for (i=0; i<numNonLocalPlayers; i++, playerIndex++)
- object->getShroudedStatus(*playerIndex);
- #endif
- ObjectShroudStatus ss=object->getShroudedStatus(localPlayerIndex);
- if (ss >= OBJECTSHROUD_FOGGED && draw->getShroudClearFrame()!=0) {
- UnsignedInt limit = 2*LOGICFRAMES_PER_SECOND;
- if (object->isEffectivelyDead()) {
- // extend the time, so we can see the dead plane blow up & crash.
- limit += 3*LOGICFRAMES_PER_SECOND;
- }
- if (TheGameLogic->getFrame() < limit + draw->getShroudClearFrame()) {
- // It's been less than 2 seconds since we could see them clear, so keep showing them.
- ss = OBJECTSHROUD_CLEAR;
- }
- }
- draw->setFullyObscuredByShroud(ss >= OBJECTSHROUD_FOGGED);
- }
- }
- draw->updateDrawable();
- draw = next;
- }
- }
- #if defined(_INTERNAL) || defined(_DEBUG)
- // need to draw the first frame, then don't draw again until TheGlobalData->m_noDraw
- if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0)
- {
- return;
- }
- #endif
- // update all particle systems
- if( !freezeTime )
- {
- // update particle systems
- TheParticleSystemManager->setLocalPlayerIndex(localPlayerIndex);
- // TheParticleSystemManager->update();
- } // end if
- // update the terrain visuals
- {
- TheTerrainVisual->UPDATE();
- }
- // update display
- {
- TheDisplay->UPDATE();
- }
- {
- USE_PERF_TIMER(GameClient_draw)
-
- // redraw all views, update the GUI
- //if(TheGameLogic->getFrame() >= 2)
-
- TheDisplay->DRAW();
- }
- {
- // let display string factory handle its update
- TheDisplayStringManager->update();
- }
- {
- // update the shell
- TheShell->UPDATE();
- }
- {
- // update the in game UI
- TheInGameUI->UPDATE();
- }
- } // end update
- /** -----------------------------------------------------------------------------------------------
- * Call the given callback function for each object contained within the given region.
- */
- void GameClient::iterateDrawablesInRegion( Region3D *region, GameClientFuncPtr userFunc, void *userData )
- {
- Drawable *draw, *nextDrawable;
- for( draw = m_drawableList; draw; draw=nextDrawable )
- {
- nextDrawable = draw->getNextDrawable();
- Coord3D pos = *draw->getPosition();
- if( region == NULL ||
- (pos.x >= region->lo.x && pos.x <= region->hi.x &&
- pos.y >= region->lo.y && pos.y <= region->hi.y &&
- pos.z >= region->lo.z && pos.z <= region->hi.z) )
- {
- (*userFunc)( draw, userData );
- }
- }
- }
- /**Helper function to update fake GLA structures to become visible to certain players.
- We should only call this during critical moments, such as changing teams, changing to
- observer, etc.*/
- void GameClient::updateFakeDrawables(void)
- {
- for( Drawable *draw = getDrawableList(); draw; draw = draw->getNextDrawable() )
- {
- const Object *object=draw->getObject();
- if( object && object->isKindOf( KINDOF_FS_FAKE ) )
- {
- Relationship rel=ThePlayerList->getLocalPlayer()->getRelationship(object->getTeam());
- if (rel == ALLIES || rel == NEUTRAL)
- draw->setTerrainDecal(TERRAIN_DECAL_SHADOW_TEXTURE);
- else
- draw->setTerrainDecal(TERRAIN_DECAL_NONE);
- }
- }
- }
- /** -----------------------------------------------------------------------------------------------
- * Destroy the drawable immediately.
- */
- void GameClient::destroyDrawable( Drawable *draw )
- {
- // remove any notion of the Drawable in the in-game user interface
- TheInGameUI->disregardDrawable( draw );
- // remove from the master list
- draw->removeFromList(&m_drawableList);
- //
- // because drawables and objects are tightly coupled, not only MUST we maintain
- // our links in all instances, but it is NECESSARY for the client to actually
- // modify data in the logic, that is the pointer in an object to *this* drawable
- //
- Object *obj = draw->getObject();
- if( obj )
- {
- DEBUG_ASSERTCRASH( obj->getDrawable() == draw, ("Object/Drawable pointer mismatch!\n") );
- obj->friend_bindToDrawable( NULL );
- } // end if
- // remove the drawable from our hash of drawables
- removeDrawableFromLookupTable( draw );
- // free storage
- draw->deleteInstance();
- }
- // ------------------------------------------------------------------------------------------------
- /** Add drawable to lookup table for fast id searching */
- // ------------------------------------------------------------------------------------------------
- void GameClient::addDrawableToLookupTable(Drawable *draw )
- {
- // sanity
- if( draw == NULL )
- return;
- // add to lookup
- // m_drawableHash[ draw->getID() ] = draw;
- DrawableID newID = draw->getID();
- while( newID >= m_drawableVector.size() ) // Fail case is hella rare, so faster to double up on size() call
- m_drawableVector.resize(m_drawableVector.size() * 2, NULL);
- m_drawableVector[ newID ] = draw;
- } // end addDrawableToLookupTable
- // ------------------------------------------------------------------------------------------------
- /** Remove drawable from lookup table of fast id searching */
- // ------------------------------------------------------------------------------------------------
- void GameClient::removeDrawableFromLookupTable( Drawable *draw )
- {
- // sanity
- if( draw == NULL )
- return;
- // remove from table
- // m_drawableHash.erase( draw->getID() );
- m_drawableVector[ draw->getID() ] = NULL;
- } // end removeDrawableFromLookupTable
- //-------------------------------------------------------------------------------------------------
- /** Load a map into the game interface */
- Bool GameClient::loadMap( AsciiString mapName )
- {
- // sanity
- if( mapName.isEmpty() )
- return false;
- assert( 0 ); // who calls this?
- return TRUE;
- } // end loadMap
- //-------------------------------------------------------------------------------------------------
- /** Unload a map from the game interface */
- void GameClient::unloadMap( AsciiString mapName )
- {
- assert( 0 ); // who calls this?
- } // end unloadMap
- //-------------------------------------------------------------------------------------------------
- void GameClient::setTimeOfDay( TimeOfDay tod )
- {
- Drawable *draw = firstDrawable();
- while( draw )
- {
- draw->setTimeOfDay( tod );
- draw = draw->getNextDrawable();
- }
- }
- //-------------------------------------------------------------------------------------------------
- void GameClient::assignSelectedDrawablesToGroup( Int group )
- {
- /*
- Drawable *draw = firstDrawable();
- while( draw )
- {
-
- if( draw->isSelected() && draw->getObject()->isLocallyControlled())
- {
- draw->setDrawableGroup( group );
- }
- else if( draw->getDrawableGroup() == group )
- {
- draw->setDrawableGroup( 0 );
- }
- draw = draw->getNextDrawable();
- }
- */
- }
- //-------------------------------------------------------------------------------------------------
- void GameClient::selectDrawablesInGroup( Int group )
- {
- /*
- Drawable *draw = firstDrawable();
- // create a message that will assign a group ID to all the selected drawables, this
- // way when we do things with this current selected group of units, we only have
- // to refer to the group ID and not each individual object ID
- GameMessage *teamMsg = TheMessageStream->appendMessage( GameMessage::MSG_CREATE_SELECTED_GROUP );
- //We are creating a new group from scratch.
- teamMsg->appendBooleanArgument( true );
- while( draw )
- {
- int counter = 0;
-
- const Object *object = draw->getObject();
- if( object && draw->getDrawableGroup() == group && object->isLocallyControlled() && !object->isContained() )
- {
- //Only select the object if it is locally controlled and not contained by anything.
- TheInGameUI->selectDrawable(draw);
- teamMsg->appendObjectIDArgument( draw->getObject()->getID() );
- }
- else
- {
- TheInGameUI->deselectDrawable(draw);
- }
- draw = draw->getNextDrawable();
- counter++;
- }
- */
- }
- // ------------------------------------------------------------------------------------------------
- void GameClient::addTextBearingDrawable( Drawable *tbd )
- {
- if ( tbd != NULL )
- m_textBearingDrawableList.push_back( tbd );
- }
- // ------------------------------------------------------------------------------------------------
- void GameClient::flushTextBearingDrawables( void )
- {
- /////////////////////////////
- // WALK THIS LIST AND CALL EACH DRAWABLES TEXTY STUFF
- /////////////////////////////
- for( TextBearingDrawableListIterator it = m_textBearingDrawableList.begin(); it != m_textBearingDrawableList.end(); ++it )
- (*it)->drawUIText();
- m_textBearingDrawableList.clear();
- }
- // ------------------------------------------------------------------------------------------------
- GameMessage::Type GameClient::evaluateContextCommand( Drawable *draw,
- const Coord3D *pos,
- CommandTranslator::CommandEvaluateType cmdType )
- {
- if( m_commandTranslator )
- return m_commandTranslator->evaluateContextCommand( draw, pos, cmdType );
- else
- return GameMessage::MSG_INVALID;
- } // end evaluateContextCommand
- //-------------------------------------------------------------------------------------------------
- /** Get the ray effect data for a drawable */
- void GameClient::getRayEffectData( Drawable *draw, RayEffectData *effectData )
- {
- TheRayEffects->getRayEffectData( draw, effectData );
- } // end getRayEffectData
- //-------------------------------------------------------------------------------------------------
- /** remove the drawble from the ray effects sytem if present */
- void GameClient::removeFromRayEffects( Drawable *draw )
- {
- TheRayEffects->deleteRayEffect( draw );
- } // end removeFromRayEffects
- /** frees all shadow resources used by this module - used by Options screen.*/
- void GameClient::releaseShadows(void)
- {
- Drawable *draw;
- for( draw = firstDrawable(); draw; draw = draw->getNextDrawable() )
- draw->releaseShadows();
- }
- /** create shadow resources if not already present. Used by Options screen.*/
- void GameClient::allocateShadows(void)
- {
- Drawable *draw;
- for( draw = firstDrawable(); draw; draw = draw->getNextDrawable() )
- draw->allocateShadows();
- }
- //-------------------------------------------------------------------------------------------------
- /** Preload assets for the currently loaded map. Those assets include all the damage states
- * for every building loaded, as well as any faction units/structures we can build and
- * all their damage states */
- //-------------------------------------------------------------------------------------------------
- void GameClient::preloadAssets( TimeOfDay timeOfDay )
- {
- MEMORYSTATUS before, after;
- GlobalMemoryStatus(&before);
- // first, for every drawable in the map load the assets for all states we care about
- Drawable *draw;
- for( draw = firstDrawable(); draw; draw = draw->getNextDrawable() )
- draw->preloadAssets( timeOfDay );
- //
- // now create a temporary drawble for each of the faction things we can create, preload
- // their assets, and dump the drawable
- //
- AsciiString side;
- const ThingTemplate *tTemplate;
- for( tTemplate = TheThingFactory->firstTemplate();
- tTemplate;
- tTemplate = tTemplate->friend_getNextTemplate() )
- {
-
- // if this isn't one of the objects that can be preloaded ignore it
- if( tTemplate->isKindOf( KINDOF_PRELOAD ) == FALSE && !TheGlobalData->m_preloadEverything )
- continue;
- // create the drawable and do the preloading
- draw = TheThingFactory->newDrawable( tTemplate );
- if( draw )
- {
- // preload the assets
- draw->preloadAssets( timeOfDay );
- // destroy the drawable
- TheGameClient->destroyDrawable( draw );
- } // end if
- } // end for
- GlobalMemoryStatus(&after);
- DEBUG_LOG(("Preloading memory dwAvailPageFile %d --> %d : %d\n",
- before.dwAvailPageFile, after.dwAvailPageFile, before.dwAvailPageFile - after.dwAvailPageFile));
- DEBUG_LOG(("Preloading memory dwAvailPhys %d --> %d : %d\n",
- before.dwAvailPhys, after.dwAvailPhys, before.dwAvailPhys - after.dwAvailPhys));
- DEBUG_LOG(("Preloading memory dwAvailVirtual %d --> %d : %d\n",
- before.dwAvailVirtual, after.dwAvailVirtual, before.dwAvailVirtual - after.dwAvailVirtual));
- /*
- DEBUG_LOG(("Preloading memory dwLength %d --> %d : %d\n",
- before.dwLength, after.dwLength, before.dwLength - after.dwLength));
- DEBUG_LOG(("Preloading memory dwMemoryLoad %d --> %d : %d\n",
- before.dwMemoryLoad, after.dwMemoryLoad, before.dwMemoryLoad - after.dwMemoryLoad));
- DEBUG_LOG(("Preloading memory dwTotalPageFile %d --> %d : %d\n",
- before.dwTotalPageFile, after.dwTotalPageFile, before.dwTotalPageFile - after.dwTotalPageFile));
- DEBUG_LOG(("Preloading memory dwTotalPhys %d --> %d : %d\n",
- before.dwTotalPhys , after.dwTotalPhys, before.dwTotalPhys - after.dwTotalPhys));
- DEBUG_LOG(("Preloading memory dwTotalVirtual %d --> %d : %d\n",
- before.dwTotalVirtual , after.dwTotalVirtual, before.dwTotalVirtual - after.dwTotalVirtual));
- */
- GlobalMemoryStatus(&before);
- extern std::vector<AsciiString> debrisModelNamesGlobalHack;
- for (Int i=0; i<debrisModelNamesGlobalHack.size(); ++i)
- {
- TheDisplay->preloadModelAssets(debrisModelNamesGlobalHack[i]);
- }
- GlobalMemoryStatus(&after);
- debrisModelNamesGlobalHack.clear();
- DEBUG_LOG(("Preloading memory dwAvailPageFile %d --> %d : %d\n",
- before.dwAvailPageFile, after.dwAvailPageFile, before.dwAvailPageFile - after.dwAvailPageFile));
- DEBUG_LOG(("Preloading memory dwAvailPhys %d --> %d : %d\n",
- before.dwAvailPhys, after.dwAvailPhys, before.dwAvailPhys - after.dwAvailPhys));
- DEBUG_LOG(("Preloading memory dwAvailVirtual %d --> %d : %d\n",
- before.dwAvailVirtual, after.dwAvailVirtual, before.dwAvailVirtual - after.dwAvailVirtual));
- TheControlBar->preloadAssets( timeOfDay );
- GlobalMemoryStatus(&before);
- TheParticleSystemManager->preloadAssets( timeOfDay );
- GlobalMemoryStatus(&after);
- DEBUG_LOG(("Preloading memory dwAvailPageFile %d --> %d : %d\n",
- before.dwAvailPageFile, after.dwAvailPageFile, before.dwAvailPageFile - after.dwAvailPageFile));
- DEBUG_LOG(("Preloading memory dwAvailPhys %d --> %d : %d\n",
- before.dwAvailPhys, after.dwAvailPhys, before.dwAvailPhys - after.dwAvailPhys));
- DEBUG_LOG(("Preloading memory dwAvailVirtual %d --> %d : %d\n",
- before.dwAvailVirtual, after.dwAvailVirtual, before.dwAvailVirtual - after.dwAvailVirtual));
- char *textureNames[] = {
- "ptspruce01.tga",
- "exrktflame.tga",
- "cvlimo3_d2.tga",
- "exfthrowerstream.tga",
- "uvrockbug_d1.tga",
- "arcbackgroundc.tga",
- "grade3.tga",
- "framebasec.tga",
- "gradec.tga",
- "frametopc.tga",
- "arcbackgrounda.tga",
- "arcglow2.tga",
- "framebasea.tga",
- "gradea.tga",
- "frametopa.tga",
- "sauserinterface256_002.tga",
- "sauserinterface256_001.tga",
- "unitbackgrounda.tga",
- "sauserinterface256_004.tga",
- "sagentank.tga",
- "sauserinterface256_005.tga",
- "sagenair.tga",
- "sauserinterface256_003.tga",
- "sagenspec.tga",
- "snuserinterface256_003.tga",
- "snuserinterface256_002.tga",
- "unitbackgroundc.tga",
- "snuserinterface256_004.tga",
- "sngenredarm.tga",
- "snuserinterface256_001.tga",
- "sngenspewea.tga",
- "sngensecpol.tga",
- "ciburn.tga",
- "ptmaple02.tga",
- "scuserinterface256_005.tga",
- "scuserinterface256_002.tga",
- "sauserinterface256_006.tga",
- "pmcrates.tga",
- ""
- };
- GlobalMemoryStatus(&before);
- for (i=0; *textureNames[i]; ++i)
- TheDisplay->preloadTextureAssets(textureNames[i]);
- GlobalMemoryStatus(&after);
- DEBUG_LOG(("Preloading memory dwAvailPageFile %d --> %d : %d\n",
- before.dwAvailPageFile, after.dwAvailPageFile, before.dwAvailPageFile - after.dwAvailPageFile));
- DEBUG_LOG(("Preloading memory dwAvailPhys %d --> %d : %d\n",
- before.dwAvailPhys, after.dwAvailPhys, before.dwAvailPhys - after.dwAvailPhys));
- DEBUG_LOG(("Preloading memory dwAvailVirtual %d --> %d : %d\n",
- before.dwAvailVirtual, after.dwAvailVirtual, before.dwAvailVirtual - after.dwAvailVirtual));
- // preloadTextureNamesGlobalHack2 = preloadTextureNamesGlobalHack;
- // preloadTextureNamesGlobalHack.clear();
- } // end preloadAssets
- // ------------------------------------------------------------------------------------------------
- /** Given a string name, find the drawable TOC entry (if any) associated with it */
- // ------------------------------------------------------------------------------------------------
- GameClient::DrawableTOCEntry *GameClient::findTOCEntryByName( AsciiString name )
- {
- for( DrawableTOCListIterator it = m_drawableTOC.begin(); it != m_drawableTOC.end(); ++it )
- if( (*it).name == name )
- return &(*it);
- return NULL;
- } // end findTOCEntryByname
- // ------------------------------------------------------------------------------------------------
- /** Given a drawable TOC identifier, find the drawable TOC if any */
- // ------------------------------------------------------------------------------------------------
- GameClient::DrawableTOCEntry *GameClient::findTOCEntryById( UnsignedShort id )
- {
- for( DrawableTOCListIterator it = m_drawableTOC.begin(); it != m_drawableTOC.end(); ++it )
- if( (*it).id == id )
- return &(*it);
- return NULL;
- } // end findTOCEntryById
- // ------------------------------------------------------------------------------------------------
- /** Add an drawable TOC entry */
- // ------------------------------------------------------------------------------------------------
- void GameClient::addTOCEntry( AsciiString name, UnsignedShort id )
- {
- DrawableTOCEntry tocEntry;
- tocEntry.name = name;
- tocEntry.id = id;
- m_drawableTOC.push_back( tocEntry );
- } // end addTOCEntry
- // ------------------------------------------------------------------------------------------------
- static Bool shouldSaveDrawable(const Drawable* draw)
- {
- if (draw->testDrawableStatus(DRAWABLE_STATUS_NO_SAVE))
- {
- if (draw->getObject() == NULL)
- {
- return false;
- }
- else
- {
- DEBUG_CRASH(("You should not ever set DRAWABLE_STATUS_NO_SAVE for a Drawable with an object. (%s)\n",draw->getTemplate()->getName().str()));
- }
- }
- return true;
- }
- // ------------------------------------------------------------------------------------------------
- /** Xfer drawable table of contents */
- // ------------------------------------------------------------------------------------------------
- void GameClient::xferDrawableTOC( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 1;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // clear our current table of contents
- m_drawableTOC.clear();
- // xfer the table
- UnsignedInt tocCount = 0;
- if( xfer->getXferMode() == XFER_SAVE )
- {
- AsciiString templateName;
- // generate a new TOC based on the drawables that are in the map
- for( Drawable *draw = getDrawableList(); draw; draw = draw->getNextDrawable() )
- {
- if (!shouldSaveDrawable(draw))
- continue;
- // get the name we're working with
- templateName = draw->getTemplate()->getName();
- // if is this drawable name already in the TOC, skip it
- if( findTOCEntryByName( templateName ) != NULL )
- continue;
-
- // add this entry to the TOC
- addTOCEntry( draw->getTemplate()->getName(), ++tocCount );
- } // end for obj
- // xfer entries in the TOC
- xfer->xferUnsignedInt( &tocCount );
- // xfer each TOC entry
- DrawableTOCListIterator it;
- DrawableTOCEntry *tocEntry;
- for( it = m_drawableTOC.begin(); it != m_drawableTOC.end(); ++it )
- {
- // get this toc entry
- tocEntry = &(*it);
- // xfer the name
- xfer->xferAsciiString( &tocEntry->name );
- // xfer the paired id
- xfer->xferUnsignedShort( &tocEntry->id );
- } // end for
- } // end if
- else
- {
- AsciiString templateName;
- UnsignedShort id;
- // how many entries are we going to read
- xfer->xferUnsignedInt( &tocCount );
- // read all the entries
- for( UnsignedInt i = 0; i < tocCount; ++i )
- {
- // read the name
- xfer->xferAsciiString( &templateName );
- // read the id
- xfer->xferUnsignedShort( &id );
-
- // add this to the TOC
- addTOCEntry( templateName, id );
-
- } // end for i
- } // end else
- } // end xferDrawableTOC
- // ------------------------------------------------------------------------------------------------
- /** Xfer method for Game Client
- * Version History:
- * 1: Initial
- * 2: Adding mission briefing history
- * 3: Added block markers around drawable data, no version checking is done and therefore
- * this version breaks compatibility with previous versions. (CBD)
- */
- // ------------------------------------------------------------------------------------------------
- void GameClient::xfer( Xfer *xfer )
- {
- // version
- XferVersion currentVersion = 3;
- XferVersion version = currentVersion;
- xfer->xferVersion( &version, currentVersion );
- // client frame number
- xfer->xferUnsignedInt( &m_frame );
- //
- // note that we do not do the id counter here, we did it in the game state block because
- // it's important to do that part very early in the load process
- //
- // !!!DON'T DO THIS!!! ----> xfer->xferDrawableID( &m_nextDrawableID ); <---- !!!DON'T DO THIS!!!
- //
- // xfer a table of contents that contain thing template and indentifier pairs. this
- // table of contents is good for this save file only as unique numbers are only
- // generated and stored for the actual things that are on this map
- //
- xferDrawableTOC( xfer );
- // drawable count
- Drawable *draw;
- UnsignedShort drawableCount = 0;
- for( draw = getDrawableList(); draw; draw = draw->getNextDrawable() )
- {
- if (xfer->getXferMode() == XFER_SAVE && !shouldSaveDrawable(draw))
- continue;
- drawableCount++;
- }
- xfer->xferUnsignedShort( &drawableCount );
- // drawable data
- DrawableTOCEntry *tocEntry;
- ObjectID objectID;
- if( xfer->getXferMode() == XFER_SAVE )
- {
-
- // iterate all drawables
- for( draw = getDrawableList(); draw; draw = draw->getNextDrawable() )
- {
- if (!shouldSaveDrawable(draw))
- continue;
- // get TOC entry for this drawable
- tocEntry = findTOCEntryByName( draw->getTemplate()->getName() );
- if( tocEntry == NULL )
- {
- DEBUG_CRASH(( "GameClient::xfer - Drawable TOC entry not found for '%s'\n", draw->getTemplate()->getName().str() ));
- throw SC_INVALID_DATA;
- } // end if
- // xfer toc id entry
- xfer->xferUnsignedShort( &tocEntry->id );
- // begin data block
- xfer->beginBlock();
- // write the object ID this drawable is attached to
- objectID = draw->getObject() ? draw->getObject()->getID() : INVALID_ID;
- xfer->xferObjectID( &objectID );
- // write snapshot data
- xfer->xferSnapshot( draw );
- // end data block
- xfer->endBlock();
- } // end for, draw
- } // end if, save
- else
- {
- UnsignedShort tocID;
- const ThingTemplate *thingTemplate;
- Int dataSize;
- // read all entries
- for( UnsignedShort i = 0; i < drawableCount; ++i )
- {
- // read toc id entry
- xfer->xferUnsignedShort( &tocID );
- // find TOC entry with this identifier
- tocEntry = findTOCEntryById( tocID );
- if( tocEntry == NULL )
- {
- DEBUG_CRASH(( "GameClient::xfer - No TOC entry match for id '%d'\n", tocID ));
- throw SC_INVALID_DATA;
- } // end if
- // read data block size
- dataSize = xfer->beginBlock();
- // find matching thing template
- thingTemplate = TheThingFactory->findTemplate( tocEntry->name );
- if( thingTemplate == NULL )
- {
- DEBUG_CRASH(( "GameClient::xfer - Unrecognized thing template '%s', skipping. ENGINEERS - Are you *sure* it's OK to be ignoring this object from the save file??? Think hard about it!\n",
- tocEntry->name.str() ));
- xfer->skip( dataSize );
- continue;
- } // end if
- // read the object ID this drawable is attached to (if any)
- xfer->xferObjectID( &objectID );
- //
- // if we have an attached object ID, we won't create a new drawable, we'll use the
- // one that has been created and attached to the object already
- //
- if( objectID != INVALID_ID )
- {
- Object *object = TheGameLogic->findObjectByID( objectID );
- // sanity
- if( object == NULL )
- {
- DEBUG_CRASH(( "GameClient::xfer - Cannot find object '%d' that is supposed to be attached to this drawable '%s'\n",
- objectID, thingTemplate->getName().str() ));
- throw SC_INVALID_DATA;
- } // end if
- // get the drawable from the object
- draw = object->getDrawable();
- if( draw == NULL )
- {
- DEBUG_CRASH(( "GameClient::xfer - There is no drawable attached to the object '%s' (%d) and there should be\n",
- object->getTemplate()->getName().str(), object->getID() ));
- throw SC_INVALID_DATA;
- } // end if
- // srj sez: some objects (eg, diguised bombtrucks) may have an "abnormal" drawable. so check.
- //
- // note carefully: we do NOT want to use isEquivalentTo() here, because different object reskins
- // SHOULD count as different templates for our purposes here (which are purely visual). however, we
- // do need to compare getFinalOverride, because draw->getTemplate() is always gonna return the final
- // override, while TheThingFactory->findTemplate does not.
- //
- const ThingTemplate* drawTemplate = draw->getTemplate();
- if (drawTemplate->getFinalOverride() != thingTemplate->getFinalOverride())
- {
- TheGameClient->destroyDrawable( draw );
- draw = TheThingFactory->newDrawable( thingTemplate );
- TheGameLogic->bindObjectAndDrawable(object, draw);
- }
- } // end if
- else
- {
- //
- // there was no object attached to this drawable when we saved, we need to create a
- // whole brand new drawable now
- //
- draw = TheThingFactory->newDrawable( thingTemplate );
-
- // sanity
- if( draw == NULL )
- {
- DEBUG_CRASH(( "GameClient::xfer - Unable to create drawable for '%s'\n",
- thingTemplate->getName().str() ));
- throw SC_INVALID_DATA;
- } // end if
- } // end else
- // xfer the drawable data
- xfer->xferSnapshot( draw );
- // end block (not necessary since this is a no-op but symettrically nice)
- xfer->endBlock();
- } // end for, i
- } // end else, load
-
- // xfer the in-game mission briefing history list
- if (version >= 2)
- {
- if( xfer->getXferMode() == XFER_SAVE )
- {
- BriefingList *bList = GetBriefingTextList();
- Int numEntries = bList->size();
- xfer->xferInt(&numEntries);
- DEBUG_LOG(("Saving %d briefing lines\n", numEntries));
- for (BriefingList::const_iterator bIt = bList->begin(); bIt != bList->end(); ++bIt)
- {
- AsciiString tempStr = *bIt;
- DEBUG_LOG(("'%s'\n", tempStr.str()));
- xfer->xferAsciiString(&tempStr);
- }
- }
- else // XFER_LOAD
- {
- Int numEntries = 0;
- xfer->xferInt(&numEntries);
- DEBUG_LOG(("Loading %d briefing lines\n", numEntries));
- UpdateDiplomacyBriefingText(AsciiString::TheEmptyString, TRUE); // clear out briefing list first
- while (numEntries-- > 0)
- {
- AsciiString tempStr;
- xfer->xferAsciiString(&tempStr);
- DEBUG_LOG(("'%s'\n", tempStr.str()));
- UpdateDiplomacyBriefingText(tempStr, FALSE);
- }
- }
- }
- } // end xfer
- // ------------------------------------------------------------------------------------------------
- /** Load post process */
- // ------------------------------------------------------------------------------------------------
- void GameClient::loadPostProcess( void )
- {
- //
- // due to the fact that during the load process we have called newDrawable for drawables
- // without objects, and then overwrote their ids with data from the save file, our allocater
- // id may be far higher than it needs to be. We'll pull it back down as low as we can
- //
- Drawable *draw;
- for( draw = getDrawableList(); draw; draw = draw->getNextDrawable() )
- if( draw->getID() >= m_nextDrawableID )
- m_nextDrawableID = (DrawableID)((UnsignedInt)draw->getID() + 1);
- } // end loadPostProcess
- // ------------------------------------------------------------------------------------------------
- /** CRC */
- // ------------------------------------------------------------------------------------------------
- void GameClient::crc( Xfer *xfer )
- {
- } // end crc
|