#include "common.h" #include "main.h" #include "smallHeap.h" #include "templates.h" #include "General.h" #include "ModelInfo.h" #include "Streaming.h" #include "FileLoader.h" #include "Script.h" #include "Timer.h" #include "Camera.h" #include "World.h" #include "Zones.h" #include "Garages.h" #include "Frontend.h" #include "Physical.h" #include "ColStore.h" #include "VarConsole.h" #include "Pools.h" CPool *CColStore::ms_pColPool; bool CColStore::m_onlyBB; #ifndef MASTER bool bDispColInMem; #endif // LCS: file done except unused: // CColStore::LoadCol(int,char const*) // CColStore::LoadAllBoundingBoxes(void) // CColStore::Write(base::cRelocatableChunkWriter &) const CVector& LevelPos(eLevelName level) { static CVector pos[4] = { CVector(1060.0f, -800.0f, 0.0f), CVector(1060.0f, -800.0f, 0.0f), CVector(350.0f, -624.0f, 0.0f), CVector(-670.0f, -511.0f, 0.0f) }; return pos[level]; }; static eLevelName PosLevel(const CVector &pos) { static eLevelName lastPlayerLevel = LEVEL_INDUSTRIAL; static eLevelName lastOtherLevel = LEVEL_INDUSTRIAL; if(Abs(FindPlayerCoors().x - pos.x) < 5.0f && Abs(FindPlayerCoors().y - pos.y) < 5.0f && Abs(FindPlayerCoors().z - pos.z) < 5.0f){ if(CGame::currLevel != LEVEL_GENERIC) lastPlayerLevel = CGame::currLevel; return lastPlayerLevel; }else{ eLevelName lvl = CTheZones::GetLevelFromPosition(&pos); if(lvl != LEVEL_GENERIC) lastOtherLevel = lvl; return lastOtherLevel; } } void CColStore::Initialise(void) { if(ms_pColPool == nil){ ms_pColPool = new CPool(COLSTORESIZE, "CollisionFiles"); AddColSlot("generic"); // slot 0. not streamed } #ifndef MASTER VarConsole.Add("Display collision in memory", &bDispColInMem, true); #endif } void CColStore::Shutdown(void) { int i; for(i = 0; i < COLSTORESIZE; i++) RemoveColSlot(i); if(ms_pColPool) delete ms_pColPool; #ifdef FIX_BUGS ms_pColPool = nil; #endif } int CColStore::AddColSlot(const char *name) { ColDef *def = ms_pColPool->New(); assert(def); def->isLoaded = false; def->unused = 0; def->bounds.left = 1000000.0f; def->bounds.top = 1000000.0f; def->bounds.right = -1000000.0f; def->bounds.bottom = -1000000.0f; def->minIndex = INT16_MAX; def->maxIndex = INT16_MIN; strcpy(def->name, name); return ms_pColPool->GetJustIndex(def); } void CColStore::RemoveColSlot(int slot) { if(GetSlot(slot)){ if(GetSlot(slot)->isLoaded) RemoveCol(slot); ms_pColPool->Delete(GetSlot(slot)); } } int CColStore::FindColSlot(const char *name) { ColDef *def; int size = ms_pColPool->GetSize(); for(int i = 0; i < size; i++){ def = GetSlot(i); if(def && !CGeneral::faststricmp(def->name, name)) return i; } return -1; } char* CColStore::GetColName(int32 slot) { return GetSlot(slot)->name; } CRect& CColStore::GetBoundingBox(int32 slot) { return GetSlot(slot)->bounds; } void CColStore::IncludeModelIndex(int32 slot, int32 modelIndex) { ColDef *def = GetSlot(slot); if(modelIndex < def->minIndex) def->minIndex = modelIndex; if(modelIndex > def->maxIndex) def->maxIndex = modelIndex; } bool CColStore::LoadCol(int32 slot, uint8 *buffer, int32 bufsize) { bool success; ColDef *def = GetSlot(slot); if(def->minIndex > def->maxIndex) success = CFileLoader::LoadCollisionFileFirstTime(buffer, bufsize, slot); else success = CFileLoader::LoadCollisionFile(buffer, bufsize, slot); if(success) def->isLoaded = true; else debug("Failed to load Collision\n"); return success; } struct ColChunkEntry { int32 modelId; // -1 marks end CColModel *colModel; }; void CColStore::LoadColCHK(int32 slot, void *data, void *chunk) { ColDef *def = GetSlot(slot); def->chunk = chunk; CStreaming::RegisterPointer(&def->chunk, 1, true); for(ColChunkEntry *entry = (ColChunkEntry*)data; entry->modelId != -1; entry++){ CBaseModelInfo *mi = CModelInfo::GetModelInfo(entry->modelId); mi->SetColModel(entry->colModel, true); // we own this? can that work? CStreaming::RegisterPointer(&mi->m_colModel, 1, true); } def->isLoaded = true; } CColModel nullCollision; void CColStore::RemoveCol(int32 slot) { int id; ColDef *def = GetSlot(slot); def->isLoaded = false; for(id = 0; id < MODELINFOSIZE; id++){ CBaseModelInfo *mi = CModelInfo::GetModelInfo(id); if(mi){ CColModel *col = mi->GetColModel(); if(col && col->level == slot) col->RemoveCollisionVolumes(); } } if(gUseChunkFiles){ for(id = 0; id < MODELINFOSIZE; id++){ CBaseModelInfo *mi = CModelInfo::GetModelInfo(id); if(mi){ CColModel *col = mi->GetColModel(); if(col && col->level == slot){ mi->SetColModel(&nullCollision); CStreaming::UnregisterPointer(&mi->m_colModel, 1); } } } if(def->chunk){ CStreaming::UnregisterPointer(&def->chunk, 1); cSmallHeap::msInstance.Free(def->chunk); def->chunk = nil; } } } void CColStore::LoadAllCollision(void) { int i; for(i = 1; i < COLSTORESIZE; i++) if(GetSlot(i)) CStreaming::RequestCol(i, 0); CStreaming::LoadAllRequestedModels(false); } void CColStore::RemoveAllCollision(void) { int i; for(i = 1; i < COLSTORESIZE; i++) if(GetSlot(i)) if(CStreaming::CanRemoveCol(i)) CStreaming::RemoveCol(i); } static bool bLoadAtSecondPosition; static CVector secondPosition; void CColStore::AddCollisionNeededAtPosn(const CVector &pos) { bLoadAtSecondPosition = true; secondPosition = pos; } void CColStore::LoadCollision(const CVector &pos, eLevelName level) { int i; if(CStreaming::ms_disableStreaming) return; if(level == LEVEL_GENERIC) level = PosLevel(pos); eLevelName allowedLevel = (eLevelName)CTheScripts::AllowedCollision[0]; if(allowedLevel == LEVEL_GENERIC) allowedLevel = (eLevelName)CTheScripts::AllowedCollision[1]; bool requestedSomething = false; for(i = 1; i < COLSTORESIZE; i++){ if(GetSlot(i) == nil || !DoScriptsWantThisIn(i)) continue; bool wantThisOne = false; if(strcmp(GetColName(i), "indust") == 0){ if(allowedLevel != LEVEL_GENERIC && level != LEVEL_INDUSTRIAL) wantThisOne = allowedLevel == LEVEL_INDUSTRIAL; else wantThisOne = level == LEVEL_INDUSTRIAL; }else if(GetBoundingBox(i).IsPointInside(LevelPos(level))) wantThisOne = true; else if(allowedLevel != LEVEL_GENERIC && GetBoundingBox(i).IsPointInside(LevelPos(allowedLevel))) wantThisOne = true; /* // LCS: removed if(GetBoundingBox(i).IsPointInside(pos) || bLoadAtSecondPosition && GetBoundingBox(i).IsPointInside(secondPosition, -119.0f) || strcmp(GetColName(i), "yacht") == 0){ wantThisOne = true; }else{ for (int j = 0; j < MAX_CLEANUP; j++) { CPhysical* pEntity = nil; cleanup_entity_struct* pCleanup = &CTheScripts::MissionCleanUp.m_sEntities[i]; if (pCleanup->type == CLEANUP_CAR) { pEntity = CPools::GetVehiclePool()->GetAt(pCleanup->id); if (!pEntity || pEntity->GetStatus() == STATUS_WRECKED) continue; } else if (pCleanup->type == CLEANUP_CHAR) { pEntity = CPools::GetPedPool()->GetAt(pCleanup->id); if (!pEntity || ((CPed*)pEntity)->DyingOrDead()) continue; } if (pEntity && !pEntity->bDontLoadCollision && !pEntity->bIsFrozen) { if (GetBoundingBox(i).IsPointInside(pEntity->GetPosition(), -80.0f)) wantThisOne = true; } } } */ if(wantThisOne){ CStreaming::RequestCol(i, STREAMFLAGS_PRIORITY); requestedSomething = true; }else CStreaming::RemoveCol(i); } if(requestedSomething){ CTimer::Suspend(); // BUG? request was done with priority but now loading non-priority? CStreaming::LoadAllRequestedModels(false); CGarages::SetupAnyGaragesForThisIsland(); CTimer::Resume(); } bLoadAtSecondPosition = false; } void CColStore::RequestCollision(const CVector &pos) { int i; for(i = 1; i < COLSTORESIZE; i++) if(GetSlot(i) && DoScriptsWantThisIn(i) && GetBoundingBox(i).IsPointInside(LevelPos(PosLevel(pos)), -115.0f)) CStreaming::RequestCol(i, STREAMFLAGS_PRIORITY); } void CColStore::EnsureCollisionIsInMemory(const CVector &pos) { /* // LCS: removed int i; if(CStreaming::ms_disableStreaming) return; for(i = 1; i < COLSTORESIZE; i++) if(GetSlot(i) && GetBoundingBox(i).IsPointInside(pos, -110.0f) && !CStreaming::HasColLoaded(i)){ CStreaming::RequestCol(i, 0); if(TheCamera.GetScreenFadeStatus() == FADE_0) FrontEndMenuManager.MessageScreen("LOADCOL", false); CTimer::Suspend(); CStreaming::LoadAllRequestedModels(false); CTimer::Resume(); } */ } bool CColStore::DoScriptsWantThisIn(int32 slot) { if(slot == 0) return false; ColDef *coldef = GetSlot(slot); if(coldef == nil) return false; if(strcmp(coldef->name, "fortstaunton") == 0) return !CTheScripts::IsFortStauntonDestroyed(); if(strcmp(coldef->name, "fortdestroyed") == 0) return CTheScripts::IsFortStauntonDestroyed(); return true; } bool CColStore::HasCollisionLoaded(eLevelName level) { int i; const CVector &pos = LevelPos(level); for(i = 1; i < COLSTORESIZE; i++) if(GetSlot(i) && DoScriptsWantThisIn(i) && (!CGeneral::faststricmp(GetColName(i), "indust") && level == LEVEL_INDUSTRIAL || GetBoundingBox(i).IsPointInside(pos)) && !GetSlot(i)->isLoaded) return false; return true; } bool CColStore::HasCollisionLoaded(const CVector &pos) { return HasCollisionLoaded(PosLevel(pos)); } void CColStore::Load(bool onlyBB, CPool *pool) { ms_pColPool = pool; m_onlyBB = onlyBB; }