////////////////////////////////////////////////////////////////////// // // Game source code // // File: GameLoading.cpp // // History: // -December 11,2001: // Created by Alberto and Petar // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Game.h" #include "XNetwork.h" #include "XServer.h" #include "XClient.h" #include "UIHud.h" #include "XPlayer.h" #include "XVehicle.h" #include "XVehicleSystem.h" #include "PlayerSystem.h" #include "XServer.h" #include "WeaponSystemEx.h" #include "EntityClassRegistry.h" #include "ScriptObjectGame.h" #include "ScriptObjectInput.h" #include "ScriptObjectLanguage.h" #include "ScriptObjectStream.h" #include "ScriptObjectRenderer.h" #include "ScriptObjectAI.h" #include #include #include "UISystem.h" #include "ScriptObjectUI.h" #include "TagPoint.h" //#include "XPath.h" #include #include #if !defined(LINUX) # include # pragma comment(lib, "dbghelp.lib") #else # include #endif #if defined(LINUX) #include "ILog.h" #endif ////////////////////////////////////////////////////////////////////// #define CHUNK_ENTITY 0x01 #define CHUNK_PLAYER 0x02 #define CHUNK_AI 0x03 #define CHUNK_INGAME_SEQUENCE 0x04 #define CHUNK_HUD 0x05 //#define _INTERNET_SIMULATOR #define SAVEGAME_THUMBNAIL_SIZEX 128 #define SAVEGAME_THUMBNAIL_SIZEY 96 ////////////////////////////////////////////////////////////////////// // load level batch process bool CXGame::LoadLevelForEditor(const char *pszLevelDirectory, const char *pszMissionName) { if (pszMissionName) m_currentMission = pszMissionName; // start local server if(!StartupServer(false,"__editor__")) return false; ////////////////////////////////////////////////////////////////////////// // Init common stuff. ////////////////////////////////////////////////////////////////////////// //init the entity registry m_pServer->m_pISystem->LoadLevel( pszLevelDirectory,m_currentMission.c_str(),true ); // start local client and connect if(!StartupLocalClient()) return false; m_pClient->XConnect("localhost"); m_pSystem->GetIInput()->GetIKeyboard()->ClearKeyState(); return true; } #define TABLE_END (-1) // a value not used in enum ScriptVarType ////////////////////////////////////////////////////////////////////////// struct PropertyWriter : IScriptObjectDumpSink { IScriptObject *table; CStream &stm; IScriptSystem *m_pScriptSystem; PropertyWriter(IScriptObject *p, CStream &s, IScriptSystem *ss) : table(p), stm(s), m_pScriptSystem(ss) {}; void Element(const char *sName, int nIdx, ScriptVarType type, bool iskey) { switch(type) { case svtUserData: case svtFunction: TRACE("WARNING: userdata or function found in properties table (%s)", sName); case svtNull: break; case svtString: { const char *s = ""; _VERIFY(iskey ? table->GetValue(sName, s) : table->GetAt(nIdx, s)); stm.Write(s); }; break; case svtNumber: { float f = 0; _VERIFY(iskey ? table->GetValue(sName, f) : table->GetAt(nIdx, f)); stm.Write(f); }; break; case svtObject: { _SmartScriptObject t(m_pScriptSystem, true); _VERIFY(iskey ? table->GetValue(sName, t) : table->GetAt(nIdx, t)); t->Dump(&PropertyWriter(t, stm, m_pScriptSystem)); stm.Write((char)TABLE_END); break; }; }; }; ////////////////////////////////////////////////////////////////////////// void OnElementFound(const char *sName, ScriptVarType type) { stm.Write((char)type); stm.Write((char)true); stm.Write(sName); Element(sName, 0, type, true); }; void OnElementFound(int nIdx, ScriptVarType type) { stm.Write((char)type); stm.Write((char)false); stm.Write(nIdx); Element("", nIdx, type, false); }; }; ////////////////////////////////////////////////////////////////////////// void LoadProperties(IScriptObject *table, CStream &stm, IScriptSystem *ss, char *parent) { ASSERT(table); ASSERT(ss); // martin made me do it for(;;) { char what; stm.Read(what); if(what==TABLE_END) return; char iskey; stm.Read(iskey); int idx = 0; string key; iskey ? stm.Read(key) : stm.Read(idx); switch(what) { case svtNull: { iskey ? table->SetToNull(key.c_str()) : table->SetNullAt(idx); break; }; case svtString: { string s; stm.Read(s); iskey ? table->SetValue(key.c_str(), s.c_str()) : table->SetAt(idx, s.c_str()); break; }; case svtNumber: { float f = 0; stm.Read(f); iskey ? table->SetValue(key.c_str(), f) : table->SetAt(idx, f); break; }; case svtObject: { _SmartScriptObject t(ss); iskey ? table->SetValue(key.c_str(), *t) : table->SetAt(idx, *t); LoadProperties(t, stm, ss, (char *)key.c_str()); break; }; case svtUserData: case svtFunction: TRACE("WARNING: can't restore userdata or function in properties table (%s.%s)", parent, key.c_str()); }; }; }; ////////////////////////////////////////////////////////////////////////// class CCVarSerializeGameSave : public ICVarDumpSink { public: CCVarSerializeGameSave(CStream *pStm, bool bSave) { m_pStm=pStm; m_bSave=bSave; m_nCount=0; } void OnElementFound(ICVar *pCVar) { if (m_bSave) { m_pStm->Write(pCVar->GetName()); m_pStm->Write(pCVar->GetString()); } m_nCount++; } int GetCount() { return(m_nCount); } private: CStream *m_pStm; bool m_bSave; int m_nCount; }; // IMPORTANT: DONT FORGET TO UPDATE "SAVEVERSION" DEFINE IN GAME.H IF THE FORMAT CHANGES // ////////////////////////////////////////////////////////////////////////// void SaveName(string &s, string &prof) { if(!s[0]) s = "quicksave"; for(unsigned int i = 0; iLog("Skipping savegame in editor..."); return false; }; IEntitySystem *pEntitySystem=m_pSystem->GetIEntitySystem(); IEntity *pPlayerEnt=NULL; if (m_pClient) pPlayerEnt=pEntitySystem->GetEntity(m_pClient->GetPlayerId()); //ASSERT(pPlayerEnt); if (!pPlayerEnt) //CryError("Saving to checkpoint - Current player not set or invalid - data error - possible reasons: \n - the first respawn point might be inside a checkpoint \n - something else other than shapes is used to trigger game events \n the trigger used to trigger checkpoint is not trigger once \n solution: check out the map and fix"); CryError("A checkpoint has been triggered to save data when the player is not existing yet, generally right after respawning. \n This is a data error, and must be fixed by the designer working on this map. \n Possible data errors are: \n - the first respawn point might be inside a checkpoint \n - something else other than shapes is used to trigger game events; \n - the area trigger used to trigger checkpoint is not trigger once; \n how to proceed: get the designer working on this map to fix this"); CPlayer *pPlayer=NULL; if(pPlayerEnt->GetContainer()) pPlayerEnt->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**) &pPlayer); //ASSERT(pPlayer); if (!pPlayer) CryError("Cannot get player container"); if(pPlayer->m_stats.health<=0) { m_pLog->Log("Cannot save while player is dead"); return false; }; CScriptObjectStream scriptStream; scriptStream.Create(m_pScriptSystem); scriptStream.Attach(&stm); //m_p3DEngine->UnRegisterAllEntities(); stm.Reset(); // save header stm.Write(SAVEMAGIC); stm.Write((int)PATCH2_SAVEVERSION); // get lowercase versions of levelname and missionname char szLowerCaseStr[256] = {0}; strncpy(szLowerCaseStr, g_LevelName->GetString(), 255); strlwr(szLowerCaseStr); // save levelname stm.Write(szLowerCaseStr); strncpy(szLowerCaseStr, m_pServer->m_GameContext.strMission.c_str(), 255); strlwr(szLowerCaseStr); // save mission name stm.Write(szLowerCaseStr); // write current time and date SYSTEMTIME pSystemTime; GetLocalTime(&pSystemTime); // FIX: this should be moved to crysystem stm.Write((unsigned char)pSystemTime.wHour); // hour stm.Write((unsigned char)pSystemTime.wMinute);// minute stm.Write((unsigned char)pSystemTime.wSecond);// second stm.Write((unsigned char)pSystemTime.wDay); // day stm.Write((unsigned char)pSystemTime.wMonth); // month stm.Write((unsigned short)pSystemTime.wYear); // year // save savegame name stm.Write(sFilename); // save the number of entities, for the loading screen bar int nEnt=pEntitySystem->GetNumEntities(); stm.Write(nEnt); WRITE_COOKIE_NO(stm,0x22); // save current EAX preset int nPreset; CS_REVERB_PROPERTIES tProps; m_pSystem->GetISoundSystem()->GetCurrentEaxEnvironment(nPreset,tProps); stm.Write(nPreset); if (nPreset==-1) { stm.WriteBits((BYTE *)&tProps,sizeof(CS_REVERB_PROPERTIES)); } WRITE_COOKIE_NO(stm,0x12); // save saveable cvars CCVarSerializeGameSave tCount(&stm,false); m_pSystem->GetIConsole()->DumpCVars(&tCount,VF_SAVEGAME); int nCount=tCount.GetCount(); // get the number of cvars to save stm.Write(nCount); CCVarSerializeGameSave t(&stm,true); m_pSystem->GetIConsole()->DumpCVars(&t,VF_SAVEGAME); // save them ASSERT(t.GetCount()==nCount); //[petar] save autobalancing stuff IAISystem *pAISystem = m_pSystem->GetAISystem(); AIBalanceStats stats; pAISystem->GetAutoBalanceInterface()->GetAutobalanceStats(stats); stm.Write(stats.nAllowedDeaths); /* WRITE_COOKIE_NO(stm,0x11); // save played cutscenes nCount=m_lstPlayedCutScenes.size(); stm.Write(nCount); for (std::set::iterator it=m_lstPlayedCutScenes.begin();it!=m_lstPlayedCutScenes.end();it++) { string sName=*it; stm.Write(sName); } //it */ IEntityClassRegistry *pECR=GetClassRegistry(); IEntityItPtr pEntities=pEntitySystem->GetEntityIterator(); pEntities->MoveFirst(); IEntity *pEnt=NULL; WRITE_COOKIE_NO(stm,0x3c); // [kirill] savig IDs of all dynamicaly spawn BUT saved entities // so would be able to preserve IDs from being taken by other dynamic entities on loadind std::vector dynSaveableEntities; while((pEnt=pEntities->Next())!=NULL) { if (!pEnt->IsSaveEnabled()) continue; if (pEntitySystem->IsDynamicEntityId( pEnt->GetId() )) dynSaveableEntities.push_back( pEnt->GetId() ); } stm.Write((int)dynSaveableEntities.size()); for(int cntr=0; cntr<(int)(dynSaveableEntities.size()); ++cntr ) stm.Write((int)dynSaveableEntities[cntr]); WRITE_COOKIE_NO(stm,61); pEntities=pEntitySystem->GetEntityIterator(); while((pEnt=pEntities->Next())!=NULL) { if (!pEnt->IsSaveEnabled()) continue; EntityClass *pClass = pECR->GetByClass(pEnt->GetEntityClassName()); CPlayer *pPlayer = NULL; if(pEnt->GetContainer()) pEnt->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**) &pPlayer); if(pPlayer && pPlayer->m_stats.health<=0) continue; //[kirill] // fixme somtimes health of dead players somehow not 0 so let's make sure we don't save dead guy if(pPlayer && pEnt->GetPhysics() && pEnt->GetPhysics()->GetType()!=PE_LIVING) { m_pSystem->GetILog()->Log("\001 WARNING, dead player [%s] has health %d ", pEnt->GetName(), pPlayer->m_stats.health ); continue; } stm.Write((BYTE)CHUNK_ENTITY); pBitStream->WriteBitStream(stm,pClass->ClassId,eEntityClassId); if(pPlayer && pPlayer->IsMyPlayer()) stm.Write((EntityId)0); // don't save id for local player - generate it on spawn, to avoid ID's collision else stm.Write(pEnt->GetId()); // the position is saved later // with pEnt->Save( ////////////////////////////////////////////////////////////////////////// // [marco] the position must be saved before / must be done the same way to // be consistent with load level! // save relative position if bound Vec3d vPos = pEnt->GetPos(!pEnt->IsBound()); Vec3d vAng = pEnt->GetAngles(pEnt->IsBound()); if (!stm.Write(vPos)) CryError("Error while saving entity %s, id=%d",pEnt->GetName(),(int)pClass->ClassId); if (!stm.Write(vAng)) CryError("Error while saving entity %s, id=%d",pEnt->GetName(),(int)pClass->ClassId); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // rendering stuff stm.Write(pEnt->GetScale()); stm.Write(pEnt->GetRndFlags()); unsigned char uViewDistRatio=(int)(pEnt->GetViewDistRatioNormilized()*100.0f); unsigned char uLodRatio=(int)(pEnt->GetLodRatioNormilized()*100.0f); stm.Write(uViewDistRatio); stm.Write(uLodRatio); IMatInfo *pMat=pEnt->GetMaterial(); string sMat; if (pMat) sMat=pMat->GetName(); stm.Write(sMat); stm.Write(pEnt->IsHidden()); ////////////////////////////////////////////////////////////////////////// WRITE_COOKIE_NO(stm,76); stm.Write(pEnt->GetName()); if (m_pLog->GetVerbosityLevel()>5) m_pLog->Log("SAVED entity name %s classname %s classid=%d id=%d",pEnt->GetName(),pClass->strClassName.c_str(),(int)pClass->ClassId,pEnt->GetId()); IScriptObject *so = pEnt->GetScriptObject(); ASSERT(so); WRITE_COOKIE_NO(stm,77); stm.AlignWrite(); _SmartScriptObject props(m_pScriptSystem, true); if(so->GetValue("Properties", props)) props->Dump(&PropertyWriter(props, stm, m_pScriptSystem)); stm.Write((char)TABLE_END); _SmartScriptObject propsi(m_pScriptSystem, true); if(so->GetValue("PropertiesInstance", propsi)) propsi->Dump(&PropertyWriter(propsi, stm, m_pScriptSystem)); stm.Write((char)TABLE_END); _SmartScriptObject events(m_pScriptSystem, true); if(so->GetValue("Events", events)) events->Dump(&PropertyWriter(events, stm, m_pScriptSystem)); stm.Write((char)TABLE_END); WRITE_COOKIE_NO(stm,78); WRITE_COOKIE_NO(stm,45); if(pPlayer) stm.Write(pPlayer->m_stats.health); // int else stm.Write((int)0); // int WRITE_COOKIE_NO(stm,46); pEnt->Save(stm,scriptStream.GetScriptObject()); if(pPlayer) { pPlayer->SaveGame(stm); if (pEnt->GetAI()) stm.Write(pEnt->GetAI()->GetName()); } } stm.Write((BYTE)CHUNK_PLAYER); if(pPlayer->IsMyPlayer()) stm.Write((EntityId)0); // don't save id for local player - generate it on spawn, to avoid ID's collision else stm.Write(m_pClient->GetPlayerId()); stm.Write(pPlayer->m_bFirstPerson); IEntityCamera *pCam=pPlayerEnt->GetCamera(); ASSERT(pCam); if(pos && angles) { stm.Write(*pos); stm.Write(*angles); } else { //[PETAR] please do not touch anything that is not clear to you //the next lines serialize THE CAMERA POSITION, not the player entity position //the entity position is serialized in a normal entity chunk stm.Write(pCam->GetPos()); stm.Write(pCam->GetAngles()); }; // now loop through entities again to save their AI state // it has to be done here because all entities need to be spawned when AI state is recreated pEntities->MoveFirst(); while((pEnt=pEntities->Next())!=NULL) { CPlayer *pPlayer=NULL; CVehicle *pVehicle=NULL; IAIObject *pAIObject = pEnt->GetAI(); if(pEnt->GetContainer()) { pEnt->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**) &pPlayer); pEnt->GetContainer()->QueryContainerInterface(CIT_IVEHICLE,(void**) &pVehicle); } if (!pEnt->IsSaveEnabled()) continue; if (!pPlayer && !pVehicle && !pAIObject) continue; if (pPlayer) { if (!pPlayer->IsAlive()) continue; // if (pPlayer->IsMyPlayer()) // continue; stm.Write((BYTE)CHUNK_AI); // [kirill] // for local player ID will be different - it will be spawn if(pPlayer->IsMyPlayer()) stm.Write((int)0); else stm.Write((int)pEnt->GetId()); // for which player is this pPlayer->SaveAIState(stm, scriptStream); } if (pVehicle) { stm.Write((BYTE)CHUNK_AI); stm.Write((int)pEnt->GetId()); // for which player is this pVehicle->SaveAIState(stm, scriptStream); } if (!pPlayer && !pVehicle) { stm.Write((BYTE)CHUNK_AI); stm.Write((int)pEnt->GetId()); // for which player is this pAIObject->Save(stm); IScriptSystem *pScriptSystem = GetSystem()->GetIScriptSystem(); HSCRIPTFUNCTION saveOverallFunction=NULL; if( pEnt->GetScriptObject() && pEnt->GetScriptObject()->GetValue("OnSaveOverall", saveOverallFunction) ) { pScriptSystem->BeginCall(saveOverallFunction); pScriptSystem->PushFuncParam(pEnt->GetScriptObject()); pScriptSystem->PushFuncParam(scriptStream.GetScriptObject()); pScriptSystem->EndCall(); } } WRITE_COOKIE_NO(stm,13); } // serialize any playing cutscenes IMovieSystem *pMovies = m_pSystem->GetIMovieSystem(); ISequenceIt *pIt = pMovies->GetSequences(); IAnimSequence *pSeq = pIt->first(); while (pSeq) { if (pMovies->IsPlaying(pSeq)) { stm.Write((BYTE)CHUNK_INGAME_SEQUENCE); stm.Write(pSeq->GetName()); stm.Write(pMovies->GetPlayingTime(pSeq)); } pSeq = pIt->next(); } pIt->Release(); // save required hud/clientstuff data stm.Write((BYTE)CHUNK_HUD); if (m_pUIHud) { GetScriptSystem()->BeginCall("Hud", "OnSave"); GetScriptSystem()->PushFuncParam(m_pUIHud->GetScript()); GetScriptSystem()->PushFuncParam(scriptStream.GetScriptObject()); GetScriptSystem()->EndCall(); } _SmartScriptObject pClientStuff(m_pScriptSystem,true); if(m_pScriptSystem->GetGlobalValue("ClientStuff",pClientStuff)) { m_pScriptSystem->BeginCall("ClientStuff","OnSave"); m_pScriptSystem->PushFuncParam(pClientStuff); m_pScriptSystem->PushFuncParam(scriptStream.GetScriptObject()); m_pScriptSystem->EndCall(); } return true; }; ////////////////////////////////////////////////////////////////////////// void CXGame::Save(string sFileName, Vec3d *pos, Vec3d *angles,bool bFirstCheckpoint ) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); //// Saving in Multiplayer only possible on server. //if (!GetServer() && IsMultiplayer()) // return; // No saving in mp if(IsMultiplayer()) { m_pLog->Log("Cannot save multiplayer game"); return; } m_sLastSavedCheckpointFilename = ""; if (m_bIsLoadingLevelFromFile) { m_pLog->Log("\001 [ERROR!!!] CANNOT SAVE WHILE LOADING!!!"); return; } if(!m_pClient) { m_pLog->Log("Cannot save game with no map loaded"); return; }; // ? if(!m_pServer) { m_pLog->Log("Cannot save multiplayer game"); return; }; CDefaultStreamAllocator sa; CStream stm(3000, &sa); if (SaveToStream(stm, pos, angles,sFileName)) { m_strLastSaveGame = sFileName; assert(g_playerprofile); if (g_playerprofile->GetString() && strlen(g_playerprofile->GetString())) { string tmp( g_playerprofile->GetString() ); SaveName(sFileName, tmp); } else { string tmp( "default" ); SaveName(sFileName, tmp); } m_pLog->LogToConsole("Level saved in %d bytes(%s)", BITS2BYTES(stm.GetSize()), sFileName.c_str()); // replace / by \ because MakeSureDirectoryPathExists does not work with unix paths size_t pos = 1; for(;;) { pos = sFileName.find_first_of("/", pos); if (pos == string::npos) { break; } sFileName.replace(pos, 1, "\\", 1); pos+=1; } if (MakeSureDirectoryPathExists(sFileName.c_str())) { if(!m_pSystem->WriteCompressedFile((char *)sFileName.c_str(), stm.GetPtr(), stm.GetSize())) { m_pLog->Log("cannot write savegame to file %s", sFileName.c_str()); return; }; m_sLastSavedCheckpointFilename = sFileName; /* ////////////////////////////////////////////////////////////////////////// // Make screenshot of current location, and save it to the .dds file. ////////////////////////////////////////////////////////////////////////// if (!bFirstCheckpoint) m_fTimeToSaveThumbnail = 1.0f; // Save checkpoint thumbnail 1 second from now. else { m_fTimeToSaveThumbnail = 5.0f; // Save checkpoint thumbnail 5 seconds from now. } ////////////////////////////////////////////////////////////////////////// */ } }; } ////////////////////////////////////////////////////////////////////////// bool CXGame::LoadFromStream(CStream &stm, bool isdemo) { if(IsMultiplayer()) { assert(0); m_pLog->LogError("ERROR: LoadFromStream IsMultiplayer=true"); // severe problem - stream is different for MP return false; } m_bIsLoadingLevelFromFile = true; // [anton] make sure physical world has the most recent IsMultiplayer flag before loading m_pSystem->GetIPhysicalWorld()->GetPhysVars()->bMultiplayer = IsMultiplayer() ? 1:0; CScriptObjectStream scriptStream; scriptStream.Create(m_pScriptSystem); scriptStream.Attach(&stm); string sMagic; stm.Read(sMagic); if(strcmp(sMagic.c_str(), SAVEMAGIC)) { m_pLog->LogToConsole("ERROR: this is not a valid savegame file"); m_bIsLoadingLevelFromFile = false; return false; }; int nVersion; stm.Read(nVersion); stm.SetStreamVersion(nVersion); switch (nVersion) { case SAVEVERSION: return LoadFromStream_RELEASEVERSION(stm,isdemo,scriptStream); case PATCH1_SAVEVERSION: return LoadFromStream_PATCH_1(stm,isdemo,scriptStream); // add more here as more patches are released } if(nVersion!=PATCH1_SAVEVERSION && nVersion!=PATCH2_SAVEVERSION) { m_pLog->LogToConsole("ERROR: savegame file from different version of the game"); m_bIsLoadingLevelFromFile = false; return false; }; IBitStream *pBitStream=GetIBitStream(); IEntitySystem *pEntitySystem=m_pSystem->GetIEntitySystem(); IEntityClassRegistry *pECR=GetClassRegistry(); IEntity *pEnt=NULL; CEntityDesc ed; int localPlayerId=0; string sLevelName; string sMissionName; stm.Read(sLevelName); stm.Read(sMissionName); // read dummy save date and time unsigned char bDummy; unsigned short wDummy; stm.Read(bDummy); // hour stm.Read(bDummy); // minute stm.Read(bDummy); // second stm.Read(bDummy); // day stm.Read(bDummy); // month stm.Read(wDummy); // year // load savegame name string sFilename; stm.Read(sFilename); // load the number of entities, for loading screen bar int nEnt; stm.Read(nEnt); bool bS=IsServer(); bool bC=IsClient(); assert(!IsMultiplayer()); VERIFY_COOKIE_NO(stm,0x22); // Load EAX preset int nPreset; CS_REVERB_PROPERTIES tProps; m_pSystem->GetISoundSystem()->GetCurrentEaxEnvironment(nPreset,tProps); stm.Read(nPreset); if (nPreset==-1) { stm.ReadBits((BYTE *)&tProps,sizeof(CS_REVERB_PROPERTIES)); } VERIFY_COOKIE_NO(stm,0x12); // load saved cvars string varname,val; int nCount,i; stm.Read(nCount); IConsole *pCon=m_pSystem->GetIConsole(); for (i=0;iGetIConsole()->GetCVar(varname.c_str()); if (!pCVar) { m_pSystem->GetILog()->Log("\001 WARNING, CVar %s(%s) was saved but is not present",varname.c_str(),val.c_str()); } else pCVar->Set(val.c_str()); } else { m_pSystem->GetILog()->LogError("CXGame::LoadFromStream %d/%d critical error",i,nCount); stm.Debug(); m_bIsLoadingLevelFromFile = false; return false; } } //i if(m_pSystem->GetISoundSystem()) m_pSystem->GetISoundSystem()->Silence(); m_pSystem->GetISoundSystem()->Mute(true); bool bLoadBar = false; IConsole *pConsole = m_pSystem->GetIConsole(); assert(pConsole); if(stricmp(g_LevelName->GetString(),sLevelName.c_str()) != 0 || !m_pServer || (stricmp(m_pServer->m_GameContext.strMission.c_str(),sMissionName.c_str()) != 0)) { m_pLog->LogToConsole("Loading %s / %s", sLevelName.c_str(), sMissionName.c_str()); if (m_pServer) ShutdownServer(); if (isdemo) { //StartupClient(); m_pClient->DemoConnect(); LoadLevelCS( false,sLevelName.c_str(), sMissionName.c_str(), false); } else { GetISystem()->GetIInput()->EnableEventPosting(false); //m_pSystem->GetIInput()->GetIKeyboard()->ClearKeyState(); LoadLevelCS(false,sLevelName.c_str(), sMissionName.c_str(), false); //m_pClient->Connect("localhost"); //m_pSystem->GetIInput()->GetIKeyboard()->ClearKeyState(); GetISystem()->GetIInput()->EnableEventPosting(true); }; } else { bLoadBar = 1; string sLoadingScreenTexture = m_currentLevelFolder + "/loadscreen_" + m_currentLevel + ".dds"; pConsole->SetLoadingImage( sLoadingScreenTexture.c_str() ); pConsole->Clear(); pConsole->ResetProgressBar(nEnt + 3); pConsole->SetScrollMax(600); pConsole->ShowConsole(1); DeleteMessage("Switch"); // no switching during loading // local player has to exit all areas before starting to delete entities IEntity *pIMyPlayer = GetMyPlayer(); if( pIMyPlayer ) { IEntityContainer *pIContainer = pIMyPlayer->GetContainer(); if (pIContainer) { CPlayer *pPlayer = NULL; if (pIContainer->QueryContainerInterface(CIT_IPLAYER, (void**)&pPlayer)) m_XAreaMgr.ExitAllAreas( pPlayer->m_AreaUser ); } } m_pSystem->GetI3DEngine()->RestoreTerrainFromDisk(); m_pSystem->GetIMovieSystem()->Reset( false ); m_pLog->Log("REMOVING entities:"); IEntityItPtr pEntities=pEntitySystem->GetEntityIterator(); pEntities->MoveFirst(); IEntity *pEnt=NULL; while((pEnt=pEntities->Next())!=NULL) { EntityClass *pClass=pECR->GetByClass(pEnt->GetEntityClassName()); if (m_pWeaponSystemEx->IsProjectileClass(pClass->ClassId)) continue; #ifdef _DEBUG m_pLog->Log("REMOVING entity classname %s classid=%02d id=%3id ",pClass->strClassName.c_str(),(int)pClass->ClassId,pEnt->GetId()); #endif pEntitySystem->RemoveEntity(pEnt->GetId()); } pConsole->TickProgressBar(); // advance progress pEntitySystem->Update(); SoftReset(); m_pEntitySystem->Reset(); pConsole->TickProgressBar(); // advance progress } // PETAR lets delete all guys since they will be spawned anyway m_pSystem->GetAISystem()->Reset(); IAISystem *pAISystem = m_pSystem->GetAISystem(); // adaptive balancing if (pAISystem) { if (cv_game_Difficulty->GetIVal()) { float fAcc,fAgg,fHealth; if (pAISystem->GetAutoBalanceInterface()) { pAISystem->GetAutoBalanceInterface()->GetMultipliers(fAcc,fAgg,fHealth); cv_game_Aggression->Set(fAgg); cv_game_Accuracy->Set(fAcc); cv_game_Health->Set(fHealth); } } } //[petar] load autobalancing stuff int nAllowedDeaths; stm.Read(nAllowedDeaths); pAISystem->GetAutoBalanceInterface()->SetAllowedDeathCount(nAllowedDeaths); // apparently these 20 updates are needed to setup everything, // from hud to netwrok stream etc. do not remove it // or savegame won't load for (int i = 0; i<20; i++) Update(); if (bLoadBar) { pConsole->TickProgressBar(); // advance progress } VERIFY_COOKIE_NO(stm,0x3c); // loading reserver IDs for dynacally created saved entities int dynReservedIDsNumber=0; stm.Read(dynReservedIDsNumber); for( ; dynReservedIDsNumber>0; --dynReservedIDsNumber ) { int reservedId; stm.Read((int&)reservedId); pEntitySystem->MarkId( reservedId ); } // only load this in case of older save if(nVersionBeginCall("Hud", "OnLoadOld"); GetScriptSystem()->PushFuncParam(m_pUIHud->GetScript()); GetScriptSystem()->PushFuncParam(scriptStream.GetScriptObject()); GetScriptSystem()->EndCall(); } } VERIFY_COOKIE_NO(stm,61); while (!stm.EOS()) { BYTE cChunk=0; stm.Read(cChunk); switch(cChunk) { case CHUNK_ENTITY: { EntityId id; EntityClassId ClassID; pBitStream->ReadBitStream(stm,ClassID,eEntityClassId); EntityClass *pClass=pECR->GetByClassId(ClassID); ASSERT(pClass); ed.className=pClass->strClassName; ed.ClassId=pClass->ClassId; stm.Read(id); ed.id=id; // [kirill] if this entity was dynamicly created - ID was marked when dynReservedIDsNumber loaded, to prevent // from being taked by some other dynamically spawned non-saved entity. So now we load it and let's free the id if (pEntitySystem->IsDynamicEntityId( id )) pEntitySystem->ClearId(id); // position and angles are read later - // with pEnt->Load( ////////////////////////////////////////////////////////////////////////// //[marco] position and angles must be read before spawining the entity - must // be consistent with load level! Vec3d vPos,vAngles; if (!stm.Read(vPos)) CryError("Error while reading position for entity id=%d",id); if (!stm.Read(vAngles)) CryError("Error while reading position for entity id=%d",id); ed.pos=vPos; ed.angles=vAngles; ////////////////////////////////////////////////////////////////////////// // renderer stuff float fScale; stm.Read(fScale); int dwRendFlags; stm.Read(dwRendFlags); unsigned char uViewDistRatio; stm.Read(uViewDistRatio); unsigned char uLodRatio; stm.Read(uLodRatio); string MatName; stm.Read(MatName); bool bHidden=false; stm.Read(bHidden); ////////////////////////////////////////////////////////////////////////// VERIFY_COOKIE_NO(stm,76); string name; stm.Read(name); if (m_pLog->GetVerbosityLevel()>=5) m_pLog->Log("LOADED entity classname %s classid=%02d id=%3id ",pClass->strClassName.c_str(),(int)pClass->ClassId,id); ////////////////////////////////////////////////////////////////////////// VERIFY_COOKIE_NO(stm,77); stm.AlignRead(); _SmartScriptObject props(m_pScriptSystem); LoadProperties(props, stm, m_pScriptSystem, "_root"); _SmartScriptObject propsi(m_pScriptSystem); LoadProperties(propsi, stm, m_pScriptSystem, "_root"); _SmartScriptObject events(m_pScriptSystem); LoadProperties(events, stm, m_pScriptSystem, "_root"); VERIFY_COOKIE_NO(stm,78); //m_pScriptSystem->BeginCall("dump"); //m_pScriptSystem->PushFuncParam(props); //m_pScriptSystem->EndCall(); //ASSERT(!pEntitySystem->GetEntity(id)); // entity already exists in map //IEntity* dbgEnt=pEntitySystem->GetEntity(id); if (pEntitySystem->GetEntity(id)) { CryError("entity classname %s classid=%d id=%d ALREADY EXISTING IN THE MAP",pClass->strClassName.c_str(),(int)pClass->ClassId,id); } ed.pProperties=props; ed.pPropertiesInstance=propsi; ed.name = name; pEnt=pEntitySystem->SpawnEntity(ed); //ASSERT(pEnt); if (!pEnt) CryError("entity classname %s classid=%02d id=%3id CANNOT BE SPAWNED",pClass->strClassName.c_str(),(int)pClass->ClassId,id); if(id==0) // it's a local player localPlayerId = ed.id; ////////////////////////////////////////////////////////////////////////// // render flags pEnt->SetRndFlags(dwRendFlags); pEnt->SetScale(fScale); pEnt->SetViewDistRatio(uViewDistRatio); pEnt->SetLodRatio(uLodRatio); if (!MatName.empty()) { IMatInfo *pMtl = GetSystem()->GetI3DEngine()->FindMaterial(MatName.c_str()); if (pMtl) pEnt->SetMaterial(pMtl); } pEnt->Hide(bHidden); ////////////////////////////////////////////////////////////////////////// ///pEnt->SetName(name.c_str()); IScriptObject *so = pEnt->GetScriptObject(); ASSERT(so); //so->SetValue("Properties", props); //so->SetValue("PropertiesInstance", propsi); so->SetValue("Events", events); CPlayer *pPlayer=NULL; if(pEnt->GetContainer()) pEnt->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**) &pPlayer); VERIFY_COOKIE_NO(stm,45); int health = 0; stm.Read(health); VERIFY_COOKIE_NO(stm,46); if(pPlayer) { if(health<=0) { pEnt->GetCharInterface()->KillCharacter(0); #ifdef _DEBUG m_pLog->Log("DEAD entity classname %s classid=%02d id=%3id ",pClass->strClassName.c_str(),(int)pClass->ClassId,pEnt->GetId()); #endif //pEntitySystem->RemoveEntity(pEnt->GetId()); }; }; bool b = pEnt->Load(stm,scriptStream.GetScriptObject()); if (!b) CryError("entity classname %s classid=%02d id=%3id CANNOT BE LOADED",pClass->strClassName.c_str(),(int)pClass->ClassId,id); //ASSERT(b); // [anton] proper state serialization was absent BasicEntity.lua, // we'll have to at least make sure that activated rigid bodies that were initially not active // don't load velocity from active state IPhysicalEntity *pPhys = pEnt->GetPhysics(); pe_status_dynamics sd; if (nVersion<=PATCH1_SAVEVERSION && pPhys && pPhys->GetType()==PE_RIGID && pPhys->GetStatus(&sd) && sd.mass==0) { pe_action_set_velocity asv; asv.v.Set(0,0,0); asv.w.Set(0,0,0); pPhys->Action(&asv); } // update position if ended up under terrain and outdoors if(pPlayer) { if(id==0) { I3DEngine *pEngine = m_pSystem->GetI3DEngine(); if (pEngine && pAISystem) { Vec3d pos = pEnt->GetPos(); IVisArea *pArea; int nBuildingid; if (!pAISystem->CheckInside(pos,nBuildingid,pArea)) { float newz = pEngine->GetTerrainElevation(pos.x,pos.y); if (newz>pos.z) pos.z=newz+0.1f; pEnt->SetPos(pos); } } } //[kirill] the OnReset called from OnInit which is called when entity is spawned // if(health>0) // { // // call on reset for the spawned entity // m_pScriptSystem->BeginCall(pEnt->GetEntityClassName(),"OnReset"); // m_pScriptSystem->PushFuncParam(pEnt->GetScriptObject()); // m_pScriptSystem->EndCall(); // }; pPlayer->LoadGame(stm); if (pEnt->GetAI()) { char sName[255]; stm.Read(sName,255); pEnt->GetAI()->SetName(sName); } }; break; } case CHUNK_PLAYER: { EntityId wPlayerID = 0; bool b = stm.Read(wPlayerID); ASSERT(b); if(wPlayerID==0) // we write 0 for localplayer on save wPlayerID = localPlayerId; m_pClient->SetPlayerID(wPlayerID); pEnt=pEntitySystem->GetEntity(wPlayerID); // if( wPlayerID==0 ) // pEnt=m_pClient->m_pISystem->GetLocalPlayer(); if (!pEnt) CryError("player id=%3id NOT FOUND",wPlayerID); //ASSERT(pEnt); CPlayer *pPlayer=NULL; if(pEnt->GetContainer()) pEnt->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**) &pPlayer); ASSERT(pPlayer); stm.Read(pPlayer->m_bFirstPerson); SetViewMode(!pPlayer->m_bFirstPerson); // hack, but works /* [kirill] moved this to int CScriptObjectGame::TouchCheckPoint(IFunctionHandler *pH) needed to fix quickLoad restoreHealth problem // do we want to overwrite health with half of maximum if(p_restorehalfhealth->GetIVal()) { pPlayer->m_stats.health = 255; // [marco] danger! this should be set by // gamerules but it gets overwritten by the save checkpoint //m_pSystem->GetILog()->Log("player health=%d",pPlayer->m_stats.health); // [kirill] // this was requested by UBI. It's expected here that current health value is the maximum //Everytime Jack dies he should respawn with half of his hit points instead of full health. //Same mechanics for Val, she should get half her hit points everytime Jack respawns. pPlayer->m_stats.health/=2; } if (pPlayer->m_stats.health<128) pPlayer->m_stats.health = 128; */ IEntityCamera *pCam=pEnt->GetCamera(); ASSERT(pCam); Vec3d vPos; stm.Read(vPos); pCam->SetPos(vPos); //pEnt->SetPos(vPos); m_pLog->Log("PLAYER %d (%f %f %f) ", wPlayerID, vPos.x, vPos.y, vPos.z); Vec3d vAngles; stm.Read(vAngles); pCam->SetAngles(vAngles); //[kirill] //why do we do it here? entity angles are set when entity is loaded //pEnt->SetAngles(vAngles); m_pClient->m_PlayerProcessingCmd.SetDeltaAngles(vAngles); GetSystem()->SetViewCamera( pCam->GetCamera() ); GetSystem()->GetISoundSystem()->SetListener(pCam->GetCamera(),Vec3(0,0,0)); if(!isdemo) { CXServer::XSlotMap::iterator itor; ASSERT(m_pServer->GetSlotsMap().size()==1); itor = m_pServer->GetSlotsMap().begin(); CXServerSlot *pSSlot=itor->second; // serverslot associated with the player pSSlot->SetPlayerID(wPlayerID); pSSlot->SetGameState(CGS_INPROGRESS); // start game imediatly }; break; } case CHUNK_AI: { // find for which entity this chunk is int nID; stm.Read(nID); IEntity *pEntity = m_pEntitySystem->GetEntity(nID); if ( nID == 0 ) // it's local player pEntity = m_pClient->m_pISystem->GetLocalPlayer(); if (pEntity) { m_pLog->Log("Now loading AICHUNK for entity %s", pEntity->GetName()); CPlayer *pPlayer=0; CVehicle *pVehicle=0; if (pEntity->GetContainer()) { if (pEntity->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**)&pPlayer)) pPlayer->LoadAIState(stm, scriptStream); if (pEntity->GetContainer()->QueryContainerInterface(CIT_IVEHICLE,(void**)&pVehicle)) pVehicle->LoadAIState(stm, scriptStream); } else if( pEntity->GetAI() ) { pEntity->GetAI()->Load(stm); IScriptSystem *pScriptSystem = GetSystem()->GetIScriptSystem(); HSCRIPTFUNCTION loadOverallFunction=NULL; if( pEntity->GetScriptObject() && pEntity->GetScriptObject()->GetValue("OnLoadOverall", loadOverallFunction) ) { pScriptSystem->BeginCall(loadOverallFunction); pScriptSystem->PushFuncParam(pEntity->GetScriptObject()); pScriptSystem->PushFuncParam(scriptStream.GetScriptObject()); pScriptSystem->EndCall(); } } } VERIFY_COOKIE_NO(stm,13); } break; case CHUNK_INGAME_SEQUENCE: { #if !defined(LINUX) IMovieSystem *pMovies = m_pSystem->GetIMovieSystem(); char szName[1024]; stm.Read(szName,1024); float fTime; stm.Read(fTime); IAnimSequence *pSeq = pMovies->FindSequence(szName); pMovies->PlaySequence(pSeq,false); pMovies->SetPlayingTime(pSeq,fTime); #endif } break; case CHUNK_HUD: { // load hud/clientstuff viewlayers data if (m_pUIHud) { GetScriptSystem()->BeginCall("Hud", "OnLoad"); GetScriptSystem()->PushFuncParam(m_pUIHud->GetScript()); GetScriptSystem()->PushFuncParam(scriptStream.GetScriptObject()); GetScriptSystem()->EndCall(); } _SmartScriptObject pClientStuff(m_pScriptSystem,true); if(m_pScriptSystem->GetGlobalValue("ClientStuff",pClientStuff)) { m_pScriptSystem->BeginCall("ClientStuff","OnLoad"); m_pScriptSystem->PushFuncParam(pClientStuff); m_pScriptSystem->PushFuncParam(scriptStream.GetScriptObject()); m_pScriptSystem->EndCall(); } } break; default: ASSERT(0); }; if (bLoadBar) { pConsole->TickProgressBar(); // advance progress } } { // [Anton] - allow entities to restore pointer links between them during post load step // [kirill] restore all the bindings IEntityItPtr pEntities=pEntitySystem->GetEntityIterator(); pEntities->MoveFirst(); IEntity *pEnt=NULL; while((pEnt=pEntities->Next())!=NULL) pEnt->PostLoad(); } pEntitySystem->Update(); m_pSystem->GetIMovieSystem()->PlayOnLoadSequences(); // yes, we reset this twice, the first time to remove all entity-pointers and now to restore them m_pClient->Reset(); m_bIsLoadingLevelFromFile = false; m_pSystem->GetISoundSystem()->Mute(false); m_bMapLoadedFromCheckpoint=true; m_pEntitySystem->PauseTimers(false,true); // m_pLog->Log("HIDE CONSOLE"); m_pRenderer->ClearColorBuffer(Vec3(0,0,0)); m_pSystem->GetIConsole()->ResetProgressBar(0); m_pSystem->GetIConsole()->ShowConsole(false); m_pSystem->GetIConsole()->SetScrollMax(600/2); if (nPreset!=-1) m_pSystem->GetISoundSystem()->SetEaxListenerEnvironment(nPreset,NULL); else m_pSystem->GetISoundSystem()->SetEaxListenerEnvironment(nPreset,&tProps); GotoGame(1); m_nDEBUG_TIMING = 0; return true; }; ////////////////////////////////////////////////////////////////////////// bool CXGame::Load(string sFileName) { m_pSystem->VTuneResume(); assert(g_playerprofile); string tmp( g_playerprofile->GetString() ); SaveName(sFileName, tmp); CDefaultStreamAllocator sa; CStream stm(300, &sa); int bitslen=m_pSystem->GetCompressedFileSize((char *)sFileName.c_str()); if(bitslen==0) { return false; } IInput *pInput=GetSystem()->GetIInput(); if(pInput) pInput->SetMouseExclusive(false); stm.Resize(bitslen); int bitsread = m_pSystem->ReadCompressedFile((char *)sFileName.c_str(), stm.GetPtr(), stm.GetAllocatedSize()); if(!bitsread) { m_pLog->Log("No such savegame: %s", sFileName.c_str()); if(pInput) pInput->SetMouseExclusive(true); return false; }; stm.SetSize(bitsread); if (m_pUISystem) { m_pUISystem->StopAllVideo(); } ////////////////////////////////////////////////////////////////////////// // Lock resources before loading checkpoint. // Speed ups loading a lot. m_pSystem->GetI3DEngine()->LockCGFResources(); m_pSystem->GetIAnimationSystem()->LockResources(); m_pSystem->GetISoundSystem()->LockResources(); ////////////////////////////////////////////////////////////////////////// bool ok = LoadFromStream(stm, false); ////////////////////////////////////////////////////////////////////////// // Unlock resources after loading checkpoint. // Some uneeded resources that were locked before may get released here. m_pSystem->GetISoundSystem()->UnlockResources(); m_pSystem->GetIAnimationSystem()->UnlockResources(); m_pSystem->GetI3DEngine()->UnlockCGFResources(); ////////////////////////////////////////////////////////////////////////// if(ok) m_strLastSaveGame = sFileName; if(pInput) pInput->SetMouseExclusive(true); m_pSystem->VTunePause(); //pInput->GetIKeyboard()->ClearKeyState(); if (!IsMultiplayer()) { _SmartScriptObject pMissionScript(m_pScriptSystem); m_pScriptSystem->GetGlobalValue("Mission", pMissionScript); if (((IScriptObject *)pMissionScript) != 0) { HSCRIPTFUNCTION pfnOnCheckpointLoaded = 0; pMissionScript->GetValue("OnCheckpointLoaded", pfnOnCheckpointLoaded); if (pfnOnCheckpointLoaded) { m_pScriptSystem->BeginCall(pfnOnCheckpointLoaded); m_pScriptSystem->PushFuncParam((IScriptObject*)pMissionScript); m_pScriptSystem->EndCall(); m_pScriptSystem->ReleaseFunc(pfnOnCheckpointLoaded); } } } AllowQuicksave(true); return ok; } ////////////////////////////////////////////////////////////////////////// void CXGame::LoadLatest() { if(!m_strLastSaveGame.empty()) { Load(m_strLastSaveGame); m_pServer->m_pISystem->BindChildren(); //m_pSystem->GetIInput()->GetIKeyboard()->ClearKeyState(); } }; ////////////////////////////////////////////////////////////////////////// class CCVarSaveDump : public ICVarDumpSink { private: FILE *m_pFile; public: CCVarSaveDump(FILE *pFile) { m_pFile=pFile; } virtual void OnElementFound(ICVar *pCVar) { if (pCVar && (pCVar->GetFlags() & VF_DUMPTODISK)) { string szValue = pCVar->GetString(); int pos; // replace \ with \\ pos = 1; for(;;) { pos = szValue.find_first_of("\\", pos); if (pos == string::npos) { break; } szValue.replace(pos, 1, "\\\\", 2); pos+=2; } // replace " with \" pos = 1; for(;;) { pos = szValue.find_first_of("\"", pos); if (pos == string::npos) { break; } szValue.replace(pos, 1, "\\\"", 2); pos+=2; } string szLine = pCVar->GetName(); szLine += " = \""; szLine += szValue; szLine += "\"\r\n"; fputs(szLine.c_str(), m_pFile); } } }; ////////////////////////////////////////////////////////////////////////// class CActionMapDumpSink : public IActionMapDumpSink { private: CXGame *m_pGame; FILE *m_pFile; public: CActionMapDumpSink(CXGame *pGame, FILE *pFile) { m_pGame=pGame; m_pFile=pFile; fputs("Input:ResetAllBindings();\r\n", m_pFile); } virtual void OnElementFound(const char *pszActionMapName, IActionMap *pActionMap) { char pszKey[256]; char pszMod[256]; ActionsEnumMap &ActionsMap=m_pGame->GetActionsEnumMap(); ActionsEnumMapItor It=ActionsMap.begin(); while (It!=ActionsMap.end()) { ActionInfo &Info=It->second; for (int i=0;iGetBinding(Info.nId, i, pszKey, pszMod); if (strlen(pszKey)) { if (strcmp(pszKey, "\\") == 0) { strcpy(pszKey, "\\\\"); } else if (strcmp(pszKey, "\"") == 0) { strcpy(pszKey, "\\\""); } char szLine[1024] = {0}; sprintf(szLine, "Input:BindAction(\"%s\", \"%s\", \"%s\", %d);\r\n", It->first.c_str(), pszKey, pszActionMapName, i); fputs(szLine, m_pFile); } } ++It; } } }; ////////////////////////////////////////////////////////////////////////// void CXGame::SaveConfiguration( const char *pszSystemCfg,const char *pszGameCfg,const char *sProfileName) { if(m_pSystem->IsQuitting()) { // shutdown the client if there is one (SERVERSYNC vars get restored and SaveConfiguration() can save the right config) ShutdownClient(); } else { if(IsClient() && !IsServer()) // only a client assert(0); // shouldn't be - saving config while connected to a client means you save the server synced variables of the server } string sSystemCfg = pszSystemCfg; string sGameCfg = pszGameCfg; if (sProfileName) { sSystemCfg=string("Profiles/Player/")+sProfileName+"_"+sSystemCfg; sGameCfg=string("Profiles/Player/")+sProfileName+"_"+sGameCfg; } FILE *pFile=fxopen(sSystemCfg.c_str(), "wb"); if (pFile) { fputs("-- [System-Configuration]\r\n", pFile); fputs("-- Attention: This file is generated by the system, do not modify! Editing is not recommended! \r\n\r\n", pFile); CCVarSaveDump SaveDump(pFile); m_pSystem->GetIConsole()->DumpCVars(&SaveDump); //m_pConsole->DumpCVars(&SaveDump); fclose(pFile); } if (m_pIActionMapManager) { pFile=fxopen(sGameCfg.c_str(), "wb"); if (pFile) { fputs("-- [Game-Configuration]\r\n", pFile); fputs("-- Attention: This file will be overwritten when updated, so dont add lines ! Editing is not recommended !\r\n\r\n", pFile); CActionMapDumpSink SaveActionMaps(this, pFile); m_pIActionMapManager->GetActionMaps(&SaveActionMaps); char sValue[32]; sprintf(sValue, "%4.4f", m_pSystem->GetIInput()->GetIMouse()->GetSensitvity()); fputs(string(string("Input:SetMouseSensitivity(")+string(sValue)+string(");\r\n")).c_str(), pFile); m_pIActionMapManager->GetInvertedMouse() ? strcpy(sValue, "1") : strcpy(sValue, "nil"); fputs(string(string("Input:SetInvertedMouse(")+string(sValue)+string(");\r\n")).c_str(), pFile); //Input:BindCommandToKey("#System:ShowDebugger();", "f8", 1); //fputs("Input:BindCommandToKey(\"#System:ShowDebugger();\", \"f8\", 1);\r\n" ,pFile); //Input:BindCommandToKey("\\SkipCutScene","F7",1); fputs("Input:BindCommandToKey(\"\\\\SkipCutScene\",\"F7\",1);\r\n",pFile); fputs("Input:BindCommandToKey(\"\\\\SkipCutScene\",\"spacebar\",1);\r\n",pFile); fclose(pFile); } } } ////////////////////////////////////////////////////////////////////////// void CXGame::LoadConfiguration(const string &sSystemCfg,const string &sGameCfg) { m_pSystem->LoadConfiguration(sSystemCfg); FILE *pFile=fxopen(sGameCfg.c_str(), "rb"); if (!pFile) { // if for some reason the game config is not found // (first time, new installation etc.) char szBuffer[512]; strcpy(szBuffer,"Input:BindCommandToKey(\"\\\\SkipCutScene\",\"F7\",1);"); m_pSystem->GetIScriptSystem()->ExecuteBuffer(szBuffer,strlen(szBuffer)); strcpy(szBuffer,"Input:BindCommandToKey(\"\\\\SkipCutScene\",\"spacebar\",1);"); m_pSystem->GetIScriptSystem()->ExecuteBuffer(szBuffer,strlen(szBuffer)); return; } char szLine[512]; char szBuffer[512]; while (fgets(szLine,512,pFile)) { // skip comments if (szLine[0]=='-') continue; // extract command if (!strstr(szLine,";")) continue; // check for malicious commands bool bValid=false; if (strstr(szLine,"#")) { // someone is trying to bind script code // to a key - silently skip this line continue; } else if (strstr(szLine,"Input:ResetAllBindings")) { // valid command bValid=true; } else if (strstr(szLine,"Input:BindAction")) { // valid command bValid=true; } else if (strstr(szLine,"Input:SetMouseSensitivity")) { // valid command bValid=true; } else if (strstr(szLine,"Input:SetInvertedMouse")) { // valid command bValid=true; } else if (strstr(szLine,"Input:BindCommandToKey")) { //if (strstr(szLine,"SkipCutScene")) // valid command bValid=true; } if (bValid) { strcpy(szBuffer,szLine); m_pSystem->GetIScriptSystem()->ExecuteBuffer(szBuffer,strlen(szBuffer)); } else { m_pSystem->GetILog()->Log("Invalid game cfg:%s",szLine); } } fclose(pFile); //m_pScriptSystem->ExecuteFile(sGameCfg.c_str(), false); //m_pScriptSystem->ExecuteFile("GameCfgOverride.Lua",false); //? } ////////////////////////////////////////////////////////////////////////// void CXGame::RemoveConfiguration(string &sSystemCfg,string &sGameCfg,const char *sProfileName) { if (sProfileName) { sSystemCfg=string("Profiles/Player/")+sProfileName+"_"+sSystemCfg; sGameCfg=string("Profiles/Player/")+sProfileName+"_"+sGameCfg; } #if defined(LINUX) remove( sSystemCfg.c_str() ); remove( sGameCfg.c_str() ); #else DeleteFile(sSystemCfg.c_str()); DeleteFile(sGameCfg.c_str()); #endif // remove the folder string path = "profiles/player/"; path += sProfileName; path += "/"; m_pSystem->Deltree(path.c_str(), 1); } ////////////////////////////////////////////////////////////////////////// //[PETAR] // DO NOT UPDATE THIS FUNCTION ITS HERE TO ENABLE THAT ALL NEWER VERSIONS // SUPPORT LOADING OLDER SAVEFILES bool CXGame::LoadFromStream_RELEASEVERSION(CStream &stm, bool isdemo, CScriptObjectStream &scriptStream) { IBitStream *pBitStream=GetIBitStream(); IEntitySystem *pEntitySystem=m_pSystem->GetIEntitySystem(); IEntityClassRegistry *pECR=GetClassRegistry(); IEntity *pEnt=NULL; CEntityDesc ed; int localPlayerId=0; string sLevelName; string sMissionName; stm.Read(sLevelName); stm.Read(sMissionName); // read dummy save date and time unsigned char bDummy; unsigned short wDummy; stm.Read(bDummy); // hour stm.Read(bDummy); // minute stm.Read(bDummy); // second stm.Read(bDummy); // day stm.Read(bDummy); // month stm.Read(wDummy); // year // load savegame name string sFilename; stm.Read(sFilename); // load the number of entities, for loading screen bar int nEnt; stm.Read(nEnt); bool bS=IsServer(); bool bC=IsClient(); assert(!IsMultiplayer()); VERIFY_COOKIE_NO(stm,0x22); // Load EAX preset int nPreset; CS_REVERB_PROPERTIES tProps; m_pSystem->GetISoundSystem()->GetCurrentEaxEnvironment(nPreset,tProps); stm.Read(nPreset); if (nPreset==-1) { stm.ReadBits((BYTE *)&tProps,sizeof(CS_REVERB_PROPERTIES)); } VERIFY_COOKIE_NO(stm,0x12); // load saved cvars string varname,val; int nCount,i; stm.Read(nCount); IConsole *pCon=m_pSystem->GetIConsole(); for (i=0;iGetIConsole()->GetCVar(varname.c_str()); if (!pCVar) { m_pSystem->GetILog()->Log("\001 WARNING, CVar %s(%s) was saved but is not present",varname.c_str(),val.c_str()); } else pCVar->Set(val.c_str()); } else { m_pSystem->GetILog()->LogError("CXGame::LoadFromStream %d/%d critical error",i,nCount); stm.Debug(); m_bIsLoadingLevelFromFile = false; return false; } } //i if(m_pSystem->GetISoundSystem()) m_pSystem->GetISoundSystem()->Silence(); m_pSystem->GetISoundSystem()->Mute(true); bool bLoadBar = false; IConsole *pConsole = m_pSystem->GetIConsole(); assert(pConsole); if(stricmp(g_LevelName->GetString(),sLevelName.c_str()) != 0 || !m_pServer || (stricmp(m_pServer->m_GameContext.strMission.c_str(),sMissionName.c_str()) != 0)) { m_pLog->LogToConsole("Loading %s / %s", sLevelName.c_str(), sMissionName.c_str()); if (m_pServer) ShutdownServer(); if (isdemo) { //StartupClient(); m_pClient->DemoConnect(); LoadLevelCS( false,sLevelName.c_str(), sMissionName.c_str(), false); } else { GetISystem()->GetIInput()->EnableEventPosting(false); m_pSystem->GetIInput()->GetIKeyboard()->ClearKeyState(); LoadLevelCS(false,sLevelName.c_str(), sMissionName.c_str(), false); //m_pClient->Connect("localhost"); m_pSystem->GetIInput()->GetIKeyboard()->ClearKeyState(); GetISystem()->GetIInput()->EnableEventPosting(true); }; } else { bLoadBar = 1; string sLoadingScreenTexture = m_currentLevelFolder + "/loadscreen_" + m_currentLevel + ".dds"; pConsole->SetLoadingImage( sLoadingScreenTexture.c_str() ); pConsole->Clear(); pConsole->ResetProgressBar(nEnt + 3); pConsole->SetScrollMax(600); pConsole->ShowConsole(1); DeleteMessage("Switch"); // no switching during loading // local player has to exit all areas before starting to delete entities IEntity *pIMyPlayer = GetMyPlayer(); if( pIMyPlayer ) { IEntityContainer *pIContainer = pIMyPlayer->GetContainer(); if (pIContainer) { CPlayer *pPlayer = NULL; if (pIContainer->QueryContainerInterface(CIT_IPLAYER, (void**)&pPlayer)) m_XAreaMgr.ExitAllAreas( pPlayer->m_AreaUser ); } } m_pSystem->GetI3DEngine()->RestoreTerrainFromDisk(); m_pSystem->GetIMovieSystem()->Reset( false ); m_pLog->Log("REMOVING entities:"); IEntityItPtr pEntities=pEntitySystem->GetEntityIterator(); pEntities->MoveFirst(); IEntity *pEnt=NULL; while((pEnt=pEntities->Next())!=NULL) { EntityClass *pClass=pECR->GetByClass(pEnt->GetEntityClassName()); if (m_pWeaponSystemEx->IsProjectileClass(pClass->ClassId)) continue; #ifdef _DEBUG m_pLog->Log("REMOVING entity classname %s classid=%02d id=%3id ",pClass->strClassName.c_str(),(int)pClass->ClassId,pEnt->GetId()); #endif pEntitySystem->RemoveEntity(pEnt->GetId()); } pConsole->TickProgressBar(); // advance progress pEntitySystem->Update(); SoftReset(); m_pEntitySystem->Reset(); pConsole->TickProgressBar(); // advance progress } // PETAR lets delete all guys since they will be spawned anyway m_pSystem->GetAISystem()->Reset(); IAISystem *pAISystem = m_pSystem->GetAISystem(); // adaptive balancing if (pAISystem) { if (cv_game_Difficulty->GetIVal()) { float fAcc,fAgg,fHealth; if (pAISystem->GetAutoBalanceInterface()) { pAISystem->GetAutoBalanceInterface()->GetMultipliers(fAcc,fAgg,fHealth); cv_game_Aggression->Set(fAgg); cv_game_Accuracy->Set(fAcc); cv_game_Health->Set(fHealth); } } } //[petar] load autobalancing stuff int nAllowedDeaths; stm.Read(nAllowedDeaths); pAISystem->GetAutoBalanceInterface()->SetAllowedDeathCount(nAllowedDeaths); // apparently these 20 updates are needed to setup everything, // from hud to netwrok stream etc. do not remove it // or savegame won't load for (int i = 0; i<20; i++) Update(); if (bLoadBar) { pConsole->TickProgressBar(); // advance progress } VERIFY_COOKIE_NO(stm,0x3c); // loading reserver IDs for dynacally created saved entities int dynReservedIDsNumber=0; stm.Read(dynReservedIDsNumber); for( ; dynReservedIDsNumber>0; --dynReservedIDsNumber ) { int reservedId; stm.Read((int&)reservedId); pEntitySystem->MarkId( reservedId ); } VERIFY_COOKIE_NO(stm,0x73); // load hud objectives if (m_pUIHud) { GetScriptSystem()->BeginCall("Hud", "OnLoadOld"); GetScriptSystem()->PushFuncParam(m_pUIHud->GetScript()); GetScriptSystem()->PushFuncParam(scriptStream.GetScriptObject()); GetScriptSystem()->EndCall(); } VERIFY_COOKIE_NO(stm,61); while (!stm.EOS()) { BYTE cChunk=0; stm.Read(cChunk); switch(cChunk) { case CHUNK_ENTITY: { EntityId id; EntityClassId ClassID; pBitStream->ReadBitStream(stm,ClassID,eEntityClassId); EntityClass *pClass=pECR->GetByClassId(ClassID); ASSERT(pClass); ed.className=pClass->strClassName; ed.ClassId=pClass->ClassId; stm.Read(id); ed.id=id; // [kirill] if this entity was dynamicly created - ID was marked when dynReservedIDsNumber loaded, to prevent // from being taked by some other dynamically spawned non-saved entity. So now we load it and let's free the id if (pEntitySystem->IsDynamicEntityId( id )) pEntitySystem->ClearId(id); // position and angles are read later - // with pEnt->Load( ////////////////////////////////////////////////////////////////////////// //[marco] position and angles must be read before spawining the entity - must // be consistent with load level! Vec3d vPos,vAngles; if (!stm.Read(vPos)) CryError("Error while reading position for entity id=%d",id); if (!stm.Read(vAngles)) CryError("Error while reading position for entity id=%d",id); ed.pos=vPos; ed.angles=vAngles; ////////////////////////////////////////////////////////////////////////// // renderer stuff float fScale; stm.Read(fScale); int dwRendFlags; stm.Read(dwRendFlags); unsigned char uViewDistRatio; stm.Read(uViewDistRatio); unsigned char uLodRatio; stm.Read(uLodRatio); string MatName; stm.Read(MatName); bool bHidden=false; stm.Read(bHidden); ////////////////////////////////////////////////////////////////////////// VERIFY_COOKIE_NO(stm,76); string name; stm.Read(name); if (m_pLog->GetVerbosityLevel()>=5) m_pLog->Log("LOADED entity classname %s classid=%02d id=%3id ",pClass->strClassName.c_str(),(int)pClass->ClassId,id); ////////////////////////////////////////////////////////////////////////// VERIFY_COOKIE_NO(stm,77); stm.AlignRead(); _SmartScriptObject props(m_pScriptSystem); LoadProperties(props, stm, m_pScriptSystem, "_root"); _SmartScriptObject propsi(m_pScriptSystem); LoadProperties(propsi, stm, m_pScriptSystem, "_root"); _SmartScriptObject events(m_pScriptSystem); LoadProperties(events, stm, m_pScriptSystem, "_root"); VERIFY_COOKIE_NO(stm,78); //m_pScriptSystem->BeginCall("dump"); //m_pScriptSystem->PushFuncParam(props); //m_pScriptSystem->EndCall(); //ASSERT(!pEntitySystem->GetEntity(id)); // entity already exists in map //IEntity* dbgEnt=pEntitySystem->GetEntity(id); if (pEntitySystem->GetEntity(id)) { CryError("entity classname %s classid=%d id=%d ALREADY EXISTING IN THE MAP",pClass->strClassName.c_str(),(int)pClass->ClassId,id); } ed.pProperties=props; ed.pPropertiesInstance=propsi; ed.name = name; pEnt=pEntitySystem->SpawnEntity(ed); //ASSERT(pEnt); if (!pEnt) CryError("entity classname %s classid=%02d id=%3id CANNOT BE SPAWNED",pClass->strClassName.c_str(),(int)pClass->ClassId,id); if(id==0) // it's a local player localPlayerId = ed.id; ////////////////////////////////////////////////////////////////////////// // render flags pEnt->SetRndFlags(dwRendFlags); pEnt->SetScale(fScale); pEnt->SetViewDistRatio(uViewDistRatio); pEnt->SetLodRatio(uLodRatio); if (!MatName.empty()) { IMatInfo *pMtl = GetSystem()->GetI3DEngine()->FindMaterial(MatName.c_str()); if (pMtl) pEnt->SetMaterial(pMtl); } pEnt->Hide(bHidden); ////////////////////////////////////////////////////////////////////////// ///pEnt->SetName(name.c_str()); IScriptObject *so = pEnt->GetScriptObject(); ASSERT(so); //so->SetValue("Properties", props); //so->SetValue("PropertiesInstance", propsi); so->SetValue("Events", events); CPlayer *pPlayer=NULL; if(pEnt->GetContainer()) pEnt->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**) &pPlayer); VERIFY_COOKIE_NO(stm,45); int health = 0; stm.Read(health); VERIFY_COOKIE_NO(stm,46); if(pPlayer) { if(health<=0) { pEnt->GetCharInterface()->KillCharacter(0); #ifdef _DEBUG m_pLog->Log("DEAD entity classname %s classid=%02d id=%3id ",pClass->strClassName.c_str(),(int)pClass->ClassId,pEnt->GetId()); #endif //pEntitySystem->RemoveEntity(pEnt->GetId()); }; }; bool b = pEnt->LoadRELEASE(stm,scriptStream.GetScriptObject()); if (!b) CryError("entity classname %s classid=%02d id=%3id CANNOT BE LOADED",pClass->strClassName.c_str(),(int)pClass->ClassId,id); //ASSERT(b); // [anton] proper state serialization was absent BasicEntity.lua, // we'll have to at least make sure that activated rigid bodies that were initially not active // don't load velocity from active state IPhysicalEntity *pPhys = pEnt->GetPhysics(); pe_status_dynamics sd; if (pPhys && pPhys->GetType()==PE_RIGID && pPhys->GetStatus(&sd) && sd.mass==0) { pe_action_set_velocity asv; asv.v.Set(0,0,0); asv.w.Set(0,0,0); pPhys->Action(&asv); } if(pPlayer) { //[kirill] the OnReset called from OnInit which is called when entity is spawned // if(health>0) // { // // call on reset for the spawned entity // m_pScriptSystem->BeginCall(pEnt->GetEntityClassName(),"OnReset"); // m_pScriptSystem->PushFuncParam(pEnt->GetScriptObject()); // m_pScriptSystem->EndCall(); // }; pPlayer->LoadGame_PATCH_1(stm); }; break; } case CHUNK_PLAYER: { EntityId wPlayerID = 0; bool b = stm.Read(wPlayerID); ASSERT(b); if(wPlayerID==0) // we write 0 for localplayer on save wPlayerID = localPlayerId; m_pClient->SetPlayerID(wPlayerID); pEnt=pEntitySystem->GetEntity(wPlayerID); // if( wPlayerID==0 ) // pEnt=m_pClient->m_pISystem->GetLocalPlayer(); if (!pEnt) CryError("player id=%3id NOT FOUND",wPlayerID); //ASSERT(pEnt); CPlayer *pPlayer=NULL; if(pEnt->GetContainer()) pEnt->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**) &pPlayer); ASSERT(pPlayer); stm.Read(pPlayer->m_bFirstPerson); SetViewMode(!pPlayer->m_bFirstPerson); // hack, but works // do we want to overwrite health with half of maximum if(p_restorehalfhealth->GetIVal()) { pPlayer->m_stats.health = 255; // [marco] danger! this should be set by // gamerules but it gets overwritten by the save checkpoint //m_pSystem->GetILog()->Log("player health=%d",pPlayer->m_stats.health); // [kirill] // this was requested by UBI. It's expected here that current health value is the maximum //Everytime Jack dies he should respawn with half of his hit points instead of full health. //Same mechanics for Val, she should get half her hit points everytime Jack respawns. pPlayer->m_stats.health/=2; } if (pPlayer->m_stats.health<128) pPlayer->m_stats.health = 128; IEntityCamera *pCam=pEnt->GetCamera(); ASSERT(pCam); Vec3d vPos; stm.Read(vPos); pCam->SetPos(vPos); pEnt->SetPos(vPos); m_pLog->Log("PLAYER %d (%f %f %f) ", wPlayerID, vPos.x, vPos.y, vPos.z); Vec3d vAngles; stm.Read(vAngles); pCam->SetAngles(vAngles); pEnt->SetAngles(vAngles); m_pClient->m_PlayerProcessingCmd.SetDeltaAngles(vAngles); GetSystem()->SetViewCamera( pCam->GetCamera() ); GetSystem()->GetISoundSystem()->SetListener(pCam->GetCamera(),Vec3(0,0,0)); if(!isdemo) { CXServer::XSlotMap::iterator itor; ASSERT(m_pServer->GetSlotsMap().size()==1); itor = m_pServer->GetSlotsMap().begin(); CXServerSlot *pSSlot=itor->second; // serverslot associated with the player pSSlot->SetPlayerID(wPlayerID); pSSlot->SetGameState(CGS_INPROGRESS); // start game imediatly }; break; } case CHUNK_AI: { // find for which entity this chunk is int nID; stm.Read(nID); IEntity *pEntity = m_pEntitySystem->GetEntity(nID); if (pEntity) { CPlayer *pPlayer=0; if (pEntity->GetContainer()) { if (pEntity->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**)&pPlayer)) pPlayer->LoadAIState_RELEASE(stm); } } VERIFY_COOKIE_NO(stm,13); } break; default: ASSERT(0); }; if (bLoadBar) { pConsole->TickProgressBar(); // advance progress } } { // [Anton] - allow entities to restore pointer links between them during post load step // [kirill] restore all the bindings IEntityItPtr pEntities=pEntitySystem->GetEntityIterator(); pEntities->MoveFirst(); IEntity *pEnt=NULL; while((pEnt=pEntities->Next())!=NULL) pEnt->PostLoad(); } pEntitySystem->Update(); m_pSystem->GetIMovieSystem()->PlayOnLoadSequences(); // yes, we reset this twice, the first time to remove all entity-pointers and now to restore them m_pClient->Reset(); m_bIsLoadingLevelFromFile = false; m_pSystem->GetISoundSystem()->Mute(false); m_bMapLoadedFromCheckpoint=true; m_pEntitySystem->PauseTimers(false,true); // m_pLog->Log("HIDE CONSOLE"); m_pRenderer->ClearColorBuffer(Vec3(0,0,0)); m_pSystem->GetIConsole()->ResetProgressBar(0); m_pSystem->GetIConsole()->ShowConsole(false); m_pSystem->GetIConsole()->SetScrollMax(600/2); if (nPreset!=-1) m_pSystem->GetISoundSystem()->SetEaxListenerEnvironment(nPreset,NULL); else m_pSystem->GetISoundSystem()->SetEaxListenerEnvironment(nPreset,&tProps); GotoGame(1); return true; } ////////////////////////////////////////////////////////////////////////// //[KIRILL] // DO NOT UPDATE THIS FUNCTION ITS HERE TO ENABLE THAT ALL NEWER VERSIONS // SUPPORT LOADING OLDER SAVEFILES - from PATCH 1 bool CXGame::LoadFromStream_PATCH_1(CStream &stm, bool isdemo, CScriptObjectStream &scriptStream) { IBitStream *pBitStream=GetIBitStream(); IEntitySystem *pEntitySystem=m_pSystem->GetIEntitySystem(); IEntityClassRegistry *pECR=GetClassRegistry(); IEntity *pEnt=NULL; CEntityDesc ed; int localPlayerId=0; string sLevelName; string sMissionName; stm.Read(sLevelName); stm.Read(sMissionName); // read dummy save date and time unsigned char bDummy; unsigned short wDummy; stm.Read(bDummy); // hour stm.Read(bDummy); // minute stm.Read(bDummy); // second stm.Read(bDummy); // day stm.Read(bDummy); // month stm.Read(wDummy); // year // load savegame name string sFilename; stm.Read(sFilename); // load the number of entities, for loading screen bar int nEnt; stm.Read(nEnt); bool bS=IsServer(); bool bC=IsClient(); assert(!IsMultiplayer()); VERIFY_COOKIE_NO(stm,0x22); // Load EAX preset int nPreset; CS_REVERB_PROPERTIES tProps; m_pSystem->GetISoundSystem()->GetCurrentEaxEnvironment(nPreset,tProps); stm.Read(nPreset); if (nPreset==-1) { stm.ReadBits((BYTE *)&tProps,sizeof(CS_REVERB_PROPERTIES)); } VERIFY_COOKIE_NO(stm,0x12); // load saved cvars string varname,val; int nCount,i; stm.Read(nCount); IConsole *pCon=m_pSystem->GetIConsole(); for (i=0;iGetIConsole()->GetCVar(varname.c_str()); if (!pCVar) { m_pSystem->GetILog()->Log("\001 WARNING, CVar %s(%s) was saved but is not present",varname.c_str(),val.c_str()); } else pCVar->Set(val.c_str()); } else { m_pSystem->GetILog()->LogError("CXGame::LoadFromStream %d/%d critical error",i,nCount); stm.Debug(); m_bIsLoadingLevelFromFile = false; return false; } } //i if(m_pSystem->GetISoundSystem()) m_pSystem->GetISoundSystem()->Silence(); m_pSystem->GetISoundSystem()->Mute(true); bool bLoadBar = false; IConsole *pConsole = m_pSystem->GetIConsole(); assert(pConsole); if(stricmp(g_LevelName->GetString(),sLevelName.c_str()) != 0 || !m_pServer || (stricmp(m_pServer->m_GameContext.strMission.c_str(),sMissionName.c_str()) != 0)) { m_pLog->LogToConsole("Loading %s / %s", sLevelName.c_str(), sMissionName.c_str()); if (m_pServer) ShutdownServer(); if (isdemo) { //StartupClient(); m_pClient->DemoConnect(); LoadLevelCS( false,sLevelName.c_str(), sMissionName.c_str(), false); } else { GetISystem()->GetIInput()->EnableEventPosting(false); //m_pSystem->GetIInput()->GetIKeyboard()->ClearKeyState(); LoadLevelCS(false,sLevelName.c_str(), sMissionName.c_str(), false); //m_pClient->Connect("localhost"); //m_pSystem->GetIInput()->GetIKeyboard()->ClearKeyState(); GetISystem()->GetIInput()->EnableEventPosting(true); }; } else { bLoadBar = 1; string sLoadingScreenTexture = m_currentLevelFolder + "/loadscreen_" + m_currentLevel + ".dds"; pConsole->SetLoadingImage( sLoadingScreenTexture.c_str() ); pConsole->Clear(); pConsole->ResetProgressBar(nEnt + 3); pConsole->SetScrollMax(600); pConsole->ShowConsole(1); DeleteMessage("Switch"); // no switching during loading // local player has to exit all areas before starting to delete entities IEntity *pIMyPlayer = GetMyPlayer(); if( pIMyPlayer ) { IEntityContainer *pIContainer = pIMyPlayer->GetContainer(); if (pIContainer) { CPlayer *pPlayer = NULL; if (pIContainer->QueryContainerInterface(CIT_IPLAYER, (void**)&pPlayer)) m_XAreaMgr.ExitAllAreas( pPlayer->m_AreaUser ); } } m_pSystem->GetI3DEngine()->RestoreTerrainFromDisk(); m_pSystem->GetIMovieSystem()->Reset( false ); m_pLog->Log("REMOVING entities:"); IEntityItPtr pEntities=pEntitySystem->GetEntityIterator(); pEntities->MoveFirst(); IEntity *pEnt=NULL; while((pEnt=pEntities->Next())!=NULL) { EntityClass *pClass=pECR->GetByClass(pEnt->GetEntityClassName()); if (m_pWeaponSystemEx->IsProjectileClass(pClass->ClassId)) continue; #ifdef _DEBUG m_pLog->Log("REMOVING entity classname %s classid=%02d id=%3id ",pClass->strClassName.c_str(),(int)pClass->ClassId,pEnt->GetId()); #endif pEntitySystem->RemoveEntity(pEnt->GetId()); } pConsole->TickProgressBar(); // advance progress pEntitySystem->Update(); SoftReset(); m_pEntitySystem->Reset(); pConsole->TickProgressBar(); // advance progress } // PETAR lets delete all guys since they will be spawned anyway m_pSystem->GetAISystem()->Reset(); IAISystem *pAISystem = m_pSystem->GetAISystem(); // adaptive balancing if (pAISystem) { if (cv_game_Difficulty->GetIVal()) { float fAcc,fAgg,fHealth; if (pAISystem->GetAutoBalanceInterface()) { pAISystem->GetAutoBalanceInterface()->GetMultipliers(fAcc,fAgg,fHealth); cv_game_Aggression->Set(fAgg); cv_game_Accuracy->Set(fAcc); cv_game_Health->Set(fHealth); } } } //[petar] load autobalancing stuff int nAllowedDeaths; stm.Read(nAllowedDeaths); pAISystem->GetAutoBalanceInterface()->SetAllowedDeathCount(nAllowedDeaths); // apparently these 20 updates are needed to setup everything, // from hud to netwrok stream etc. do not remove it // or savegame won't load for (int i = 0; i<20; i++) Update(); if (bLoadBar) { pConsole->TickProgressBar(); // advance progress } VERIFY_COOKIE_NO(stm,0x3c); // loading reserver IDs for dynacally created saved entities int dynReservedIDsNumber=0; stm.Read(dynReservedIDsNumber); for( ; dynReservedIDsNumber>0; --dynReservedIDsNumber ) { int reservedId; stm.Read((int&)reservedId); pEntitySystem->MarkId( reservedId ); } // only load this in case of older save VERIFY_COOKIE_NO(stm,0x73); // load hud objectives if (m_pUIHud) { GetScriptSystem()->BeginCall("Hud", "OnLoadOld"); GetScriptSystem()->PushFuncParam(m_pUIHud->GetScript()); GetScriptSystem()->PushFuncParam(scriptStream.GetScriptObject()); GetScriptSystem()->EndCall(); } VERIFY_COOKIE_NO(stm,61); while (!stm.EOS()) { BYTE cChunk=0; stm.Read(cChunk); switch(cChunk) { case CHUNK_ENTITY: { EntityId id; EntityClassId ClassID; pBitStream->ReadBitStream(stm,ClassID,eEntityClassId); EntityClass *pClass=pECR->GetByClassId(ClassID); ASSERT(pClass); ed.className=pClass->strClassName; ed.ClassId=pClass->ClassId; stm.Read(id); ed.id=id; // [kirill] if this entity was dynamicly created - ID was marked when dynReservedIDsNumber loaded, to prevent // from being taked by some other dynamically spawned non-saved entity. So now we load it and let's free the id if (pEntitySystem->IsDynamicEntityId( id )) pEntitySystem->ClearId(id); // position and angles are read later - // with pEnt->Load( ////////////////////////////////////////////////////////////////////////// //[marco] position and angles must be read before spawining the entity - must // be consistent with load level! Vec3d vPos,vAngles; if (!stm.Read(vPos)) CryError("Error while reading position for entity id=%d",id); if (!stm.Read(vAngles)) CryError("Error while reading position for entity id=%d",id); ed.pos=vPos; ed.angles=vAngles; ////////////////////////////////////////////////////////////////////////// // renderer stuff float fScale; stm.Read(fScale); int dwRendFlags; stm.Read(dwRendFlags); unsigned char uViewDistRatio; stm.Read(uViewDistRatio); unsigned char uLodRatio; stm.Read(uLodRatio); string MatName; stm.Read(MatName); bool bHidden=false; stm.Read(bHidden); ////////////////////////////////////////////////////////////////////////// VERIFY_COOKIE_NO(stm,76); string name; stm.Read(name); if (m_pLog->GetVerbosityLevel()>=5) m_pLog->Log("LOADED entity classname %s classid=%02d id=%3id ",pClass->strClassName.c_str(),(int)pClass->ClassId,id); ////////////////////////////////////////////////////////////////////////// VERIFY_COOKIE_NO(stm,77); stm.AlignRead(); _SmartScriptObject props(m_pScriptSystem); LoadProperties(props, stm, m_pScriptSystem, "_root"); _SmartScriptObject propsi(m_pScriptSystem); LoadProperties(propsi, stm, m_pScriptSystem, "_root"); _SmartScriptObject events(m_pScriptSystem); LoadProperties(events, stm, m_pScriptSystem, "_root"); VERIFY_COOKIE_NO(stm,78); //m_pScriptSystem->BeginCall("dump"); //m_pScriptSystem->PushFuncParam(props); //m_pScriptSystem->EndCall(); //ASSERT(!pEntitySystem->GetEntity(id)); // entity already exists in map //IEntity* dbgEnt=pEntitySystem->GetEntity(id); if (pEntitySystem->GetEntity(id)) { CryError("entity classname %s classid=%d id=%d ALREADY EXISTING IN THE MAP",pClass->strClassName.c_str(),(int)pClass->ClassId,id); } ed.pProperties=props; ed.pPropertiesInstance=propsi; ed.name = name; pEnt=pEntitySystem->SpawnEntity(ed); //ASSERT(pEnt); if (!pEnt) CryError("entity classname %s classid=%02d id=%3id CANNOT BE SPAWNED",pClass->strClassName.c_str(),(int)pClass->ClassId,id); if(id==0) // it's a local player localPlayerId = ed.id; ////////////////////////////////////////////////////////////////////////// // render flags pEnt->SetRndFlags(dwRendFlags); pEnt->SetScale(fScale); pEnt->SetViewDistRatio(uViewDistRatio); pEnt->SetLodRatio(uLodRatio); if (!MatName.empty()) { IMatInfo *pMtl = GetSystem()->GetI3DEngine()->FindMaterial(MatName.c_str()); if (pMtl) pEnt->SetMaterial(pMtl); } pEnt->Hide(bHidden); ////////////////////////////////////////////////////////////////////////// ///pEnt->SetName(name.c_str()); IScriptObject *so = pEnt->GetScriptObject(); ASSERT(so); //so->SetValue("Properties", props); //so->SetValue("PropertiesInstance", propsi); so->SetValue("Events", events); CPlayer *pPlayer=NULL; if(pEnt->GetContainer()) pEnt->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**) &pPlayer); VERIFY_COOKIE_NO(stm,45); int health = 0; stm.Read(health); VERIFY_COOKIE_NO(stm,46); if(pPlayer) { if(health<=0) { pEnt->GetCharInterface()->KillCharacter(0); #ifdef _DEBUG m_pLog->Log("DEAD entity classname %s classid=%02d id=%3id ",pClass->strClassName.c_str(),(int)pClass->ClassId,pEnt->GetId()); #endif //pEntitySystem->RemoveEntity(pEnt->GetId()); }; }; bool b = pEnt->LoadPATCH1(stm,scriptStream.GetScriptObject()); if (!b) CryError("entity classname %s classid=%02d id=%3id CANNOT BE LOADED",pClass->strClassName.c_str(),(int)pClass->ClassId,id); //ASSERT(b); // [anton] proper state serialization was absent BasicEntity.lua, // we'll have to at least make sure that activated rigid bodies that were initially not active // don't load velocity from active state IPhysicalEntity *pPhys = pEnt->GetPhysics(); pe_status_dynamics sd; if (pPhys && pPhys->GetType()==PE_RIGID && pPhys->GetStatus(&sd) && sd.mass==0) { pe_action_set_velocity asv; asv.v.Set(0,0,0); asv.w.Set(0,0,0); pPhys->Action(&asv); } // update position if ended up under terrain and outdoors if(pPlayer) { if(id==0) { I3DEngine *pEngine = m_pSystem->GetI3DEngine(); if (pEngine && pAISystem) { Vec3d pos = pEnt->GetPos(); IVisArea *pArea; int nBuildingid; if (!pAISystem->CheckInside(pos,nBuildingid,pArea)) { float newz = pEngine->GetTerrainElevation(pos.x,pos.y); if (newz>pos.z) pos.z=newz+0.1f; pEnt->SetPos(pos); } } } //[kirill] the OnReset called from OnInit which is called when entity is spawned // if(health>0) // { // // call on reset for the spawned entity // m_pScriptSystem->BeginCall(pEnt->GetEntityClassName(),"OnReset"); // m_pScriptSystem->PushFuncParam(pEnt->GetScriptObject()); // m_pScriptSystem->EndCall(); // }; pPlayer->LoadGame_PATCH_1(stm); if (pEnt->GetAI()) { char sName[255]; stm.Read(sName,255); pEnt->GetAI()->SetName(sName); } }; break; } case CHUNK_PLAYER: { EntityId wPlayerID = 0; bool b = stm.Read(wPlayerID); ASSERT(b); if(wPlayerID==0) // we write 0 for localplayer on save wPlayerID = localPlayerId; m_pClient->SetPlayerID(wPlayerID); pEnt=pEntitySystem->GetEntity(wPlayerID); // if( wPlayerID==0 ) // pEnt=m_pClient->m_pISystem->GetLocalPlayer(); if (!pEnt) CryError("player id=%3id NOT FOUND",wPlayerID); //ASSERT(pEnt); CPlayer *pPlayer=NULL; if(pEnt->GetContainer()) pEnt->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**) &pPlayer); ASSERT(pPlayer); stm.Read(pPlayer->m_bFirstPerson); SetViewMode(!pPlayer->m_bFirstPerson); // hack, but works /* [kirill] moved this to int CScriptObjectGame::TouchCheckPoint(IFunctionHandler *pH) needed to fix quickLoad restoreHealth problem // do we want to overwrite health with half of maximum if(p_restorehalfhealth->GetIVal()) { pPlayer->m_stats.health = 255; // [marco] danger! this should be set by // gamerules but it gets overwritten by the save checkpoint //m_pSystem->GetILog()->Log("player health=%d",pPlayer->m_stats.health); // [kirill] // this was requested by UBI. It's expected here that current health value is the maximum //Everytime Jack dies he should respawn with half of his hit points instead of full health. //Same mechanics for Val, she should get half her hit points everytime Jack respawns. pPlayer->m_stats.health/=2; } if (pPlayer->m_stats.health<128) pPlayer->m_stats.health = 128; */ IEntityCamera *pCam=pEnt->GetCamera(); ASSERT(pCam); Vec3d vPos; stm.Read(vPos); pCam->SetPos(vPos); //pEnt->SetPos(vPos); m_pLog->Log("PLAYER %d (%f %f %f) ", wPlayerID, vPos.x, vPos.y, vPos.z); Vec3d vAngles; stm.Read(vAngles); pCam->SetAngles(vAngles); //[kirill] //why do we do it here? entity angles are set when entity is loaded //pEnt->SetAngles(vAngles); m_pClient->m_PlayerProcessingCmd.SetDeltaAngles(vAngles); GetSystem()->SetViewCamera( pCam->GetCamera() ); GetSystem()->GetISoundSystem()->SetListener(pCam->GetCamera(),Vec3(0,0,0)); if(!isdemo) { CXServer::XSlotMap::iterator itor; ASSERT(m_pServer->GetSlotsMap().size()==1); itor = m_pServer->GetSlotsMap().begin(); CXServerSlot *pSSlot=itor->second; // serverslot associated with the player pSSlot->SetPlayerID(wPlayerID); pSSlot->SetGameState(CGS_INPROGRESS); // start game imediatly }; break; } case CHUNK_AI: { // find for which entity this chunk is int nID; stm.Read(nID); IEntity *pEntity = m_pEntitySystem->GetEntity(nID); if ( nID == 0 ) // it's local player pEntity = m_pClient->m_pISystem->GetLocalPlayer(); if (pEntity) { m_pLog->Log("Now loading AICHUNK for entity %s", pEntity->GetName()); CPlayer *pPlayer=0; CVehicle *pVehicle=0; if (pEntity->GetContainer()) { if (pEntity->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void**)&pPlayer)) pPlayer->LoadAIState_PATCH_1(stm); if (pEntity->GetContainer()->QueryContainerInterface(CIT_IVEHICLE,(void**)&pVehicle)) pVehicle->LoadAIState(stm, scriptStream); } else if( pEntity->GetAI() ) { pEntity->GetAI()->Load(stm); IScriptSystem *pScriptSystem = GetSystem()->GetIScriptSystem(); HSCRIPTFUNCTION loadOverallFunction=NULL; // if( pEntity->GetScriptObject() && pEntity->GetScriptObject()->GetValue("OnLoadOverall", loadOverallFunction) ) // { // pScriptSystem->BeginCall(loadOverallFunction); // pScriptSystem->PushFuncParam(pEntity->GetScriptObject()); // pScriptSystem->PushFuncParam(scriptStream.GetScriptObject()); // pScriptSystem->EndCall(); // } } } VERIFY_COOKIE_NO(stm,13); } break; case CHUNK_INGAME_SEQUENCE: { #if !defined(LINUX) IMovieSystem *pMovies = m_pSystem->GetIMovieSystem(); char szName[1024]; stm.Read(szName,1024); float fTime; stm.Read(fTime); IAnimSequence *pSeq = pMovies->FindSequence(szName); pMovies->PlaySequence(pSeq,false); pMovies->SetPlayingTime(pSeq,fTime); #endif } break; case CHUNK_HUD: { // load hud/clientstuff viewlayers data if (m_pUIHud) { GetScriptSystem()->BeginCall("Hud", "OnLoad"); GetScriptSystem()->PushFuncParam(m_pUIHud->GetScript()); GetScriptSystem()->PushFuncParam(scriptStream.GetScriptObject()); GetScriptSystem()->EndCall(); } _SmartScriptObject pClientStuff(m_pScriptSystem,true); if(m_pScriptSystem->GetGlobalValue("ClientStuff",pClientStuff)) { m_pScriptSystem->BeginCall("ClientStuff","OnLoad"); m_pScriptSystem->PushFuncParam(pClientStuff); m_pScriptSystem->PushFuncParam(scriptStream.GetScriptObject()); m_pScriptSystem->EndCall(); } } break; default: ASSERT(0); }; if (bLoadBar) { pConsole->TickProgressBar(); // advance progress } } { // [Anton] - allow entities to restore pointer links between them during post load step // [kirill] restore all the bindings IEntityItPtr pEntities=pEntitySystem->GetEntityIterator(); pEntities->MoveFirst(); IEntity *pEnt=NULL; while((pEnt=pEntities->Next())!=NULL) pEnt->PostLoad(); } pEntitySystem->Update(); m_pSystem->GetIMovieSystem()->PlayOnLoadSequences(); // yes, we reset this twice, the first time to remove all entity-pointers and now to restore them m_pClient->Reset(); m_bIsLoadingLevelFromFile = false; m_pSystem->GetISoundSystem()->Mute(false); m_bMapLoadedFromCheckpoint=true; m_pEntitySystem->PauseTimers(false,true); // m_pLog->Log("HIDE CONSOLE"); m_pRenderer->ClearColorBuffer(Vec3(0,0,0)); m_pSystem->GetIConsole()->ResetProgressBar(0); m_pSystem->GetIConsole()->ShowConsole(false); m_pSystem->GetIConsole()->SetScrollMax(600/2); if (nPreset!=-1) m_pSystem->GetISoundSystem()->SetEaxListenerEnvironment(nPreset,NULL); else m_pSystem->GetISoundSystem()->SetEaxListenerEnvironment(nPreset,&tProps); GotoGame(1); m_nDEBUG_TIMING = 0; return true; };