Added support for tracking extra dependencies in Corruption areas (necessary to avoid crashes)

This commit is contained in:
Aruki 2017-07-26 01:30:52 -06:00
parent 95d0279027
commit f980bc7536
9 changed files with 122 additions and 25 deletions

View File

@ -314,10 +314,11 @@ void CAreaDependencyTree::Serialize(IArchive& rArc)
rArc << SERIAL_CONTAINER("LayerOffsets", mLayerOffsets, "Offset");
}
void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer)
void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps)
{
if (!pLayer) return;
mLayerOffsets.push_back(mChildren.size());
std::set<CAssetID> UsedIDs;
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
{
@ -326,10 +327,16 @@ void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer)
// Note: MP2+ need to track all instances (not just instances with dependencies) to be able to build the layer module list
if (pTree->NumChildren() > 0 || pLayer->Area()->Game() >= eEchoesDemo)
{
mChildren.push_back(pTree);
pTree->GetAllResourceReferences(UsedIDs);
}
else
delete pTree;
}
for (u32 iDep = 0; iDep < rkExtraDeps.size(); iDep++)
AddDependency(rkExtraDeps[iDep]);
}
void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<u32>& rModuleLayerOffsetsOut) const
@ -351,8 +358,10 @@ void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>
for (u32 iInst = StartIdx; iInst < EndIdx; iInst++)
{
CScriptInstanceDependency *pInst = static_cast<CScriptInstanceDependency*>(mChildren[iInst]);
ASSERT(pInst->Type() == eDNT_ScriptInstance);
IDependencyNode *pNode = mChildren[iInst];
if (pNode->Type() != eDNT_ScriptInstance) continue;
CScriptInstanceDependency *pInst = static_cast<CScriptInstanceDependency*>(pNode);
u32 ObjType = pInst->ObjectType();
if (UsedObjectTypes.find(ObjType) == UsedObjectTypes.end())

View File

@ -215,7 +215,7 @@ public:
virtual EDependencyNodeType Type() const;
virtual void Serialize(IArchive& rArc);
void AddScriptLayer(CScriptLayer *pLayer);
void AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps);
void GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<u32>& rModuleLayerOffsetsOut) const;
// Accessors

View File

@ -405,31 +405,44 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
for (u32 iChild = StartIdx; iChild < EndIdx; iChild++)
{
CScriptInstanceDependency *pInst = static_cast<CScriptInstanceDependency*>(pTree->ChildByIndex(iChild));
ASSERT(pInst->Type() == eDNT_ScriptInstance);
mIsPlayerActor = (pInst->ObjectType() == 0x4C || pInst->ObjectType() == FOURCC('PLAC'));
IDependencyNode *pNode = pTree->ChildByIndex(iChild);
for (u32 iDep = 0; iDep < pInst->NumChildren(); iDep++)
if (pNode->Type() == eDNT_ScriptInstance)
{
CPropertyDependency *pDep = static_cast<CPropertyDependency*>(pInst->ChildByIndex(iDep));
CScriptInstanceDependency *pInst = static_cast<CScriptInstanceDependency*>(pNode);
mIsPlayerActor = (pInst->ObjectType() == 0x4C || pInst->ObjectType() == FOURCC('PLAC'));
// For MP3, exclude the CMDL/CSKR properties for the suit assets - only include default character assets
if (mGame == eCorruption && mIsPlayerActor)
for (u32 iDep = 0; iDep < pInst->NumChildren(); iDep++)
{
TString PropID = pDep->PropertyID();
CPropertyDependency *pDep = static_cast<CPropertyDependency*>(pInst->ChildByIndex(iDep));
if ( PropID == "0x846397A8" || PropID == "0x685A4C01" ||
PropID == "0x9834ECC9" || PropID == "0x188B8960" ||
PropID == "0x134A81E3" || PropID == "0x4ABF030C" ||
PropID == "0x9BF030DC" || PropID == "0x981263D3" ||
PropID == "0x8A8D5AA5" || PropID == "0xE4734608" ||
PropID == "0x3376814D" || PropID == "0x797CA77E" ||
PropID == "0x0EBEC440" || PropID == "0xBC0952D8" ||
PropID == "0xA8778E57" || PropID == "0x1CB10DBE" )
continue;
// For MP3, exclude the CMDL/CSKR properties for the suit assets - only include default character assets
if (mGame == eCorruption && mIsPlayerActor)
{
TString PropID = pDep->PropertyID();
if ( PropID == "0x846397A8" || PropID == "0x685A4C01" ||
PropID == "0x9834ECC9" || PropID == "0x188B8960" ||
PropID == "0x134A81E3" || PropID == "0x4ABF030C" ||
PropID == "0x9BF030DC" || PropID == "0x981263D3" ||
PropID == "0x8A8D5AA5" || PropID == "0xE4734608" ||
PropID == "0x3376814D" || PropID == "0x797CA77E" ||
PropID == "0x0EBEC440" || PropID == "0xBC0952D8" ||
PropID == "0xA8778E57" || PropID == "0x1CB10DBE" )
continue;
}
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
}
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
}
else if (pNode->Type() == eDNT_ResourceDependency)
{
CResourceDependency *pResDep = static_cast<CResourceDependency*>(pNode);
AddDependency(pResDep->ID(), rAssetsOut, pAudioGroupsOut);
}
else
{
ASSERT(false); // unhandled case!
}
}
}

View File

@ -195,7 +195,7 @@ void CAnimationParameters::SetResource(const CAssetID& rkID)
if (!pEntry)
Log::Error("Invalid resource ID passed to CAnimationParameters: " + rkID.ToString());
else if (pEntry->ResourceType() != eAnimSet)
else if (pEntry->ResourceType() != eAnimSet && pEntry->ResourceType() != eCharacter)
Log::Error("Resource with invalid type passed to CAnimationParameters: " + pEntry->CookedAssetPath().GetFileName());
}
}

View File

@ -48,9 +48,18 @@ CDependencyTree* CGameArea::BuildDependencyTree() const
pTree->AddDependency(mpPoiToWorldMap);
}
// Extra deps
for (u32 iDep = 0; iDep < mExtraAreaDeps.size(); iDep++)
pTree->AddDependency(mExtraAreaDeps[iDep]);
// Layer dependencies
std::vector<CAssetID> DummyDeps;
for (u32 iLayer = 0; iLayer < mScriptLayers.size(); iLayer++)
pTree->AddScriptLayer(mScriptLayers[iLayer]);
{
const std::vector<CAssetID>& rkExtras = (mExtraLayerDeps.size() > iLayer ? mExtraLayerDeps[iLayer] : DummyDeps);
pTree->AddScriptLayer(mScriptLayers[iLayer], rkExtras);
}
return pTree;
}
@ -242,3 +251,13 @@ void CGameArea::DeleteInstance(CScriptObject *pInstance)
delete pInstance;
}
void CGameArea::ClearExtraDependencies()
{
if (mExtraAreaDeps.empty() || !mExtraLayerDeps.empty())
{
mExtraAreaDeps.clear();
mExtraLayerDeps.clear();
Entry()->UpdateDependencies();
}
}

View File

@ -60,6 +60,9 @@ class CGameArea : public CResource
CAssetID mPortalAreaID;
// Object to Static Geometry Map
TResPtr<CPoiToWorld> mpPoiToWorldMap;
// Dependencies
std::vector<CAssetID> mExtraAreaDeps;
std::vector< std::vector<CAssetID> > mExtraLayerDeps;
public:
CGameArea(CResourceEntry *pEntry = 0);
@ -80,6 +83,7 @@ public:
u32 SuggestedID = -1, u32 SuggestedLayerIndex = -1);
void AddInstanceToArea(CScriptObject *pInstance);
void DeleteInstance(CScriptObject *pInstance);
void ClearExtraDependencies();
// Inline Accessors
inline u32 WorldIndex() const { return mWorldIndex; }

View File

@ -412,6 +412,52 @@ void CAreaLoader::ReadGeometryCorruption()
mpArea->MergeTerrain();
}
void CAreaLoader::ReadDependenciesCorruption()
{
mpSectionMgr->ToSection(mDependenciesBlockNum);
// Read the offsets first so we can read the deps directly into their corresponding arrays
u32 NumDeps = mpMREA->ReadLong();
u32 DepsStart = mpMREA->Tell();
mpMREA->Skip(NumDeps * 0xC);
u32 NumOffsets = mpMREA->ReadLong();
std::vector<u32> Offsets(NumOffsets);
for (u32 OffsetIdx = 0; OffsetIdx < NumOffsets; OffsetIdx++)
Offsets[OffsetIdx] = mpMREA->ReadLong();
mpMREA->GoTo(DepsStart);
// Read layer dependencies
u32 NumLayers = NumOffsets - 1;
mpArea->mExtraLayerDeps.resize(NumLayers);
for (u32 LayerIdx = 0; LayerIdx < NumLayers; LayerIdx++)
{
u32 NumLayerDeps = Offsets[LayerIdx+1] - Offsets[LayerIdx];
mpArea->mExtraLayerDeps[LayerIdx].reserve(NumLayerDeps);
for (u32 DepIdx = 0; DepIdx < NumLayerDeps; DepIdx++)
{
CAssetID AssetID(*mpMREA, eCorruption);
mpMREA->Skip(4);
mpArea->mExtraLayerDeps[LayerIdx].push_back(AssetID);
}
}
// Read area dependencies
u32 NumAreaDeps = NumDeps - Offsets[NumLayers];
mpArea->mExtraAreaDeps.reserve(NumAreaDeps);
for (u32 DepIdx = 0; DepIdx < NumAreaDeps; DepIdx++)
{
CAssetID AssetID(*mpMREA, eCorruption);
mpMREA->Skip(4);
mpArea->mExtraAreaDeps.push_back(AssetID);
}
}
void CAreaLoader::ReadLightsCorruption()
{
mpSectionMgr->ToSection(mLightsBlockNum);
@ -733,6 +779,7 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
case eCorruptionProto:
Loader.ReadHeaderCorruption();
Loader.ReadGeometryPrime();
Loader.ReadDependenciesCorruption();
Loader.ReadSCLYEchoes();
Loader.ReadCollision();
Loader.ReadLightsCorruption();
@ -744,6 +791,7 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
case eReturns:
Loader.ReadHeaderCorruption();
Loader.ReadGeometryCorruption();
Loader.ReadDependenciesCorruption();
Loader.ReadSCLYEchoes();
Loader.ReadCollision();
if (Loader.mVersion == eCorruption)

View File

@ -67,6 +67,7 @@ class CAreaLoader
// Corruption
void ReadHeaderCorruption();
void ReadGeometryCorruption();
void ReadDependenciesCorruption();
void ReadLightsCorruption();
// Common

View File

@ -439,6 +439,9 @@ bool CWorldEditor::Save()
bool SaveEGMCSuccess = mpArea->PoiToWorldMap() ? mpArea->PoiToWorldMap()->Entry()->Save() : true;
bool SaveWorldSuccess = mpWorld->Entry()->Save();
if (SaveAreaSuccess)
mpArea->ClearExtraDependencies();
if (SaveAreaSuccess || SaveEGMCSuccess || SaveWorldSuccess)
gpEdApp->NotifyAssetsModified();