Rewrote a chunk of the script cooker. SCGN script layer is now generated and written at cook time.

This commit is contained in:
Aruki 2017-06-27 06:13:42 -06:00
parent 2081835ae6
commit 4dc11023df
7 changed files with 233 additions and 226 deletions

View File

@ -185,31 +185,43 @@ void CAreaCooker::WriteAreaData(IOutputStream& rOut)
// ************ SCLY ************
void CAreaCooker::WritePrimeSCLY(IOutputStream& rOut)
{
rOut.WriteString("SCLY", 4);
// This function covers both Prime 1 and the Echoes demo.
// The Echoes demo has a similar SCLY format but with minor layout differences and with SCGN.
rOut.WriteFourCC( FOURCC('SCLY') );
mVersion <= ePrime ? rOut.WriteLong(1) : rOut.WriteByte(1);
u32 NumLayers = mpArea->mScriptLayers.size();
rOut.WriteLong(NumLayers);
u32 LayerSizesStart = rOut.Tell();
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
for (u32 LayerIdx = 0; LayerIdx < NumLayers; LayerIdx++)
rOut.WriteLong(0);
// SCLY
CScriptCooker ScriptCooker(mVersion, true);
std::vector<u32> LayerSizes(NumLayers);
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
for (u32 LayerIdx = 0; LayerIdx < NumLayers; LayerIdx++)
{
u32 LayerStart = rOut.Tell();
CScriptCooker::WriteLayer(mVersion, mpArea->mScriptLayers[iLyr], rOut);
LayerSizes[iLyr] = rOut.Tell() - LayerStart;
ScriptCooker.WriteLayer(rOut, mpArea->mScriptLayers[LayerIdx]);
// Pad the layer to 32 bytes
u32 LayerSize = rOut.Tell() - LayerStart;
u32 PaddedSize = (LayerSize + 31) & ~31;
u32 NumPadBytes = PaddedSize - LayerSize;
for (u32 Pad = 0; Pad < NumPadBytes; Pad++)
rOut.WriteByte(0);
LayerSizes[LayerIdx] = PaddedSize;
}
u32 LayersEnd = rOut.Tell();
rOut.Seek(LayerSizesStart, SEEK_SET);
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
rOut.WriteLong(LayerSizes[iLyr]);
for (u32 LayerIdx = 0; LayerIdx < NumLayers; LayerIdx++)
rOut.WriteLong(LayerSizes[LayerIdx]);
rOut.Seek(LayersEnd, SEEK_SET);
FinishSection(false);
@ -217,31 +229,31 @@ void CAreaCooker::WritePrimeSCLY(IOutputStream& rOut)
// SCGN
if (mVersion == eEchoesDemo)
{
// IMPORTANT TODO - REGENERATE SCGN LAYER
/*rOut.WriteString("SCGN", 4);
rOut.WriteFourCC( FOURCC('SCGN') );
rOut.WriteByte(1);
CScriptCooker::WriteLayer(mVersion, mpArea->mpGeneratorLayer, rOut);
FinishSection(false);*/
ScriptCooker.WriteGeneratedLayer(rOut);
FinishSection(false);
}
}
void CAreaCooker::WriteEchoesSCLY(IOutputStream& rOut)
{
// SCLY
for (u32 iLyr = 0; iLyr < mpArea->mScriptLayers.size(); iLyr++)
CScriptCooker ScriptCooker(mVersion);
for (u32 LayerIdx = 0; LayerIdx < mpArea->mScriptLayers.size(); LayerIdx++)
{
rOut.WriteString("SCLY", 4);
rOut.WriteByte(0x1);
rOut.WriteLong(iLyr);
CScriptCooker::WriteLayer(mVersion, mpArea->mScriptLayers[iLyr], rOut);
rOut.WriteFourCC( FOURCC('SCLY') );
rOut.WriteByte(1);
rOut.WriteLong(LayerIdx);
ScriptCooker.WriteLayer(rOut, mpArea->mScriptLayers[LayerIdx]);
FinishSection(true);
}
// SCGN
// IMPORTANT TODO - REGENERATE SCGN
rOut.WriteString("SCGN", 4);
rOut.WriteByte(0x1);
//CScriptCooker::WriteLayer(mVersion, mpArea->mpGeneratorLayer, rOut);
rOut.WriteFourCC( FOURCC('SCGN') );
rOut.WriteByte(1);
ScriptCooker.WriteGeneratedLayer(rOut);
FinishSection(true);
}

View File

@ -1,16 +1,16 @@
#include "CScriptCooker.h"
#include "Core/Resource/Script/CLink.h"
void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
void CScriptCooker::WriteProperty(IOutputStream& rOut,IProperty *pProp, bool InSingleStruct)
{
u32 SizeOffset = 0, PropStart = 0;
if (mVersion >= eEchoesDemo && !InSingleStruct)
if (mGame >= eEchoesDemo && !InSingleStruct)
{
mpSCLY->WriteLong(pProp->ID());
SizeOffset = mpSCLY->Tell();
mpSCLY->WriteShort(0x0);
PropStart = mpSCLY->Tell();
rOut.WriteLong(pProp->ID());
SizeOffset = rOut.Tell();
rOut.WriteShort(0x0);
PropStart = rOut.Tell();
}
switch (pProp->Type())
@ -19,91 +19,91 @@ void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
case eBoolProperty:
{
TBoolProperty *pBoolCast = static_cast<TBoolProperty*>(pProp);
mpSCLY->WriteByte(pBoolCast->Get() ? 1 : 0);
rOut.WriteBool(pBoolCast->Get());
break;
}
case eByteProperty:
{
TByteProperty *pByteCast = static_cast<TByteProperty*>(pProp);
mpSCLY->WriteByte(pByteCast->Get());
rOut.WriteByte(pByteCast->Get());
break;
}
case eShortProperty:
{
TShortProperty *pShortCast = static_cast<TShortProperty*>(pProp);
mpSCLY->WriteShort(pShortCast->Get());
rOut.WriteShort(pShortCast->Get());
break;
}
case eLongProperty:
{
TLongProperty *pLongCast = static_cast<TLongProperty*>(pProp);
mpSCLY->WriteLong(pLongCast->Get());
rOut.WriteLong(pLongCast->Get());
break;
}
case eEnumProperty:
{
TEnumProperty *pEnumCast = static_cast<TEnumProperty*>(pProp);
mpSCLY->WriteLong(pEnumCast->Get());
rOut.WriteLong(pEnumCast->Get());
break;
}
case eBitfieldProperty:
{
TBitfieldProperty *pBitfieldCast = static_cast<TBitfieldProperty*>(pProp);
mpSCLY->WriteLong(pBitfieldCast->Get());
rOut.WriteLong(pBitfieldCast->Get());
break;
}
case eFloatProperty:
{
TFloatProperty *pFloatCast = static_cast<TFloatProperty*>(pProp);
mpSCLY->WriteFloat(pFloatCast->Get());
rOut.WriteFloat(pFloatCast->Get());
break;
}
case eStringProperty:
{
TStringProperty *pStringCast = static_cast<TStringProperty*>(pProp);
mpSCLY->WriteString(pStringCast->Get());
rOut.WriteString(pStringCast->Get());
break;
}
case eVector3Property:
{
TVector3Property *pVectorCast = static_cast<TVector3Property*>(pProp);
pVectorCast->Get().Write(*mpSCLY);
pVectorCast->Get().Write(rOut);
break;
}
case eColorProperty:
{
TColorProperty *pColorCast = static_cast<TColorProperty*>(pProp);
pColorCast->Get().Write(*mpSCLY, false);
pColorCast->Get().Write(rOut, false);
break;
}
case eSoundProperty:
{
TSoundProperty *pSoundCast = static_cast<TSoundProperty*>(pProp);
mpSCLY->WriteLong(pSoundCast->Get());
rOut.WriteLong(pSoundCast->Get());
break;
}
case eAssetProperty:
{
TAssetProperty *pAssetCast = static_cast<TAssetProperty*>(pProp);
pAssetCast->Get().Write(*mpSCLY);
pAssetCast->Get().Write(rOut);
break;
}
case eCharacterProperty:
{
TCharacterProperty *pCharCast = static_cast<TCharacterProperty*>(pProp);
pCharCast->Get().Write(*mpSCLY);
pCharCast->Get().Write(rOut);
break;
}
@ -111,25 +111,25 @@ void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
{
TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp);
std::vector<u8> Buffer = pSplineCast->Get();
if (!Buffer.empty()) mpSCLY->WriteBytes(Buffer.data(), Buffer.size());
if (!Buffer.empty()) rOut.WriteBytes(Buffer.data(), Buffer.size());
else
{
if (mVersion < eReturns)
if (mGame < eReturns)
{
mpSCLY->WriteShort(0);
mpSCLY->WriteLong(0);
mpSCLY->WriteByte(1);
mpSCLY->WriteFloat(0);
mpSCLY->WriteFloat(1);
rOut.WriteShort(0);
rOut.WriteLong(0);
rOut.WriteByte(1);
rOut.WriteFloat(0);
rOut.WriteFloat(1);
}
else
{
mpSCLY->WriteLong(0);
mpSCLY->WriteFloat(0);
mpSCLY->WriteFloat(1);
mpSCLY->WriteShort(0);
mpSCLY->WriteByte(1);
rOut.WriteLong(0);
rOut.WriteFloat(0);
rOut.WriteFloat(1);
rOut.WriteShort(0);
rOut.WriteByte(1);
}
}
@ -153,14 +153,14 @@ void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
if (!pTemp->IsSingleProperty())
{
if (mVersion <= ePrime)
mpSCLY->WriteLong(PropertiesToWrite.size());
if (mGame <= ePrime)
rOut.WriteLong(PropertiesToWrite.size());
else
mpSCLY->WriteShort((u16) PropertiesToWrite.size());
rOut.WriteShort((u16) PropertiesToWrite.size());
}
for (u32 iProp = 0; iProp < PropertiesToWrite.size(); iProp++)
WriteProperty(PropertiesToWrite[iProp], pTemp->IsSingleProperty());
WriteProperty(rOut, PropertiesToWrite[iProp], pTemp->IsSingleProperty());
break;
}
@ -168,10 +168,10 @@ void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
case eArrayProperty:
{
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
mpSCLY->WriteLong(pArray->Count());
rOut.WriteLong(pArray->Count());
for (u32 iProp = 0; iProp < pArray->Count(); iProp++)
WriteProperty(pArray->PropertyByIndex(iProp), true);
WriteProperty(rOut, pArray->PropertyByIndex(iProp), true);
break;
}
@ -180,133 +180,128 @@ void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
if (SizeOffset != 0)
{
u32 PropEnd = mpSCLY->Tell();
mpSCLY->Seek(SizeOffset, SEEK_SET);
mpSCLY->WriteShort((u16) (PropEnd - PropStart));
mpSCLY->Seek(PropEnd, SEEK_SET);
u32 PropEnd = rOut.Tell();
rOut.Seek(SizeOffset, SEEK_SET);
rOut.WriteShort((u16) (PropEnd - PropStart));
rOut.Seek(PropEnd, SEEK_SET);
}
}
void CScriptCooker::WriteLayerMP1(CScriptLayer *pLayer)
// ************ PUBLIC ************
void CScriptCooker::WriteInstance(IOutputStream& rOut, CScriptObject *pInstance)
{
u32 LayerStart = mpSCLY->Tell();
mpSCLY->WriteByte(0); // Unknown value
mpSCLY->WriteLong(pLayer->NumInstances());
ASSERT(pInstance->Area()->Game() == mGame);
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
{
CScriptObject *pInstance = pLayer->InstanceByIndex(iInst);
WriteInstanceMP1(pInstance);
}
// Note the format is pretty much the same between games; the main difference is a
// number of fields changed size between MP1 and 2, but they're still the same fields
bool IsPrime1 = (mGame <= ePrime);
u32 LayerSize = mpSCLY->Tell() - LayerStart;
u32 NumPadBytes = 32 - (LayerSize % 32);
if (NumPadBytes == 32) NumPadBytes = 0;
u32 ObjectType = pInstance->ObjectTypeID();
IsPrime1 ? rOut.WriteByte((u8) ObjectType) : rOut.WriteLong(ObjectType);
for (u32 iPad = 0; iPad < NumPadBytes; iPad++)
mpSCLY->WriteByte(0);
}
void CScriptCooker::WriteInstanceMP1(CScriptObject *pInstance)
{
mpSCLY->WriteByte((u8) pInstance->ObjectTypeID());
u32 SizeOffset = mpSCLY->Tell();
mpSCLY->WriteLong(0);
u32 InstanceStart = mpSCLY->Tell();
u32 SizeOffset = rOut.Tell();
IsPrime1 ? rOut.WriteLong(0) : rOut.WriteShort(0);
u32 InstanceStart = rOut.Tell();
u32 InstanceID = (pInstance->Layer()->AreaIndex() << 26) | pInstance->InstanceID();
mpSCLY->WriteLong(InstanceID);
mpSCLY->WriteLong(pInstance->NumLinks(eOutgoing));
rOut.WriteLong(InstanceID);
u32 NumLinks = pInstance->NumLinks(eOutgoing);
IsPrime1 ? rOut.WriteLong(NumLinks) : rOut.WriteShort((u16) NumLinks);
for (u32 iLink = 0; iLink < pInstance->NumLinks(eOutgoing); iLink++)
{
CLink *pLink = pInstance->Link(eOutgoing, iLink);
mpSCLY->WriteLong(pLink->State());
mpSCLY->WriteLong(pLink->Message());
mpSCLY->WriteLong(pLink->ReceiverID());
rOut.WriteLong(pLink->State());
rOut.WriteLong(pLink->Message());
rOut.WriteLong(pLink->ReceiverID());
}
WriteProperty(pInstance->Properties(), false);
u32 InstanceEnd = mpSCLY->Tell();
WriteProperty(rOut, pInstance->Properties(), false);
u32 InstanceEnd = rOut.Tell();
mpSCLY->Seek(SizeOffset, SEEK_SET);
mpSCLY->WriteLong(InstanceEnd - InstanceStart);
mpSCLY->Seek(InstanceEnd, SEEK_SET);
rOut.Seek(SizeOffset, SEEK_SET);
u32 Size = InstanceEnd - InstanceStart;
IsPrime1 ? rOut.WriteLong(Size) : rOut.WriteShort((u16) Size);
rOut.Seek(InstanceEnd, SEEK_SET);
}
void CScriptCooker::WriteLayerMP2(CScriptLayer *pLayer)
void CScriptCooker::WriteLayer(IOutputStream& rOut, CScriptLayer *pLayer)
{
u32 LayerStart = mpSCLY->Tell();
mpSCLY->WriteByte(0x1);
mpSCLY->WriteLong(pLayer->NumInstances());
ASSERT(pLayer->Area()->Game() == mGame);
rOut.WriteByte( mGame <= ePrime ? 0 : 1 ); // Version
u32 InstanceCountOffset = rOut.Tell();
u32 NumWrittenInstances = 0;
rOut.WriteLong(0);
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
{
CScriptObject *pInstance = pLayer->InstanceByIndex(iInst);
WriteInstanceMP2(pInstance);
}
if (mVersion == eEchoesDemo)
// Is this a generated instance?
bool ShouldWrite = true;
if (mWriteGeneratedSeparately)
{
u32 LayerSize = mpSCLY->Tell() - LayerStart;
u32 NumPadBytes = 32 - (LayerSize % 32);
if (NumPadBytes == 32) NumPadBytes = 0;
// GenericCreature instances in DKCR always write to both SCLY and SCGN
if (mGame == eReturns && pInstance->ObjectTypeID() == FOURCC('GCTR'))
mGeneratedObjects.push_back(pInstance);
for (u32 iPad = 0; iPad < NumPadBytes; iPad++)
mpSCLY->WriteByte(0);
}
}
void CScriptCooker::WriteInstanceMP2(CScriptObject *pInstance)
{
mpSCLY->WriteLong(pInstance->ObjectTypeID());
u32 SizeOffset = mpSCLY->Tell();
mpSCLY->WriteShort(0);
u32 InstanceStart = mpSCLY->Tell();
u32 InstanceID = (pInstance->Layer()->AreaIndex() << 26) | pInstance->InstanceID();
mpSCLY->WriteLong(InstanceID);
mpSCLY->WriteShort((u16) pInstance->NumLinks(eOutgoing));
for (u32 iLink = 0; iLink < pInstance->NumLinks(eOutgoing); iLink++)
// Instances receiving a Generate/Activate message (MP2) or a
// Generate/Attach message (MP3+) should be written to SCGN, not SCLY
else
{
CLink *pLink = pInstance->Link(eOutgoing, iLink);
mpSCLY->WriteLong(pLink->State());
mpSCLY->WriteLong(pLink->Message());
mpSCLY->WriteLong(pLink->ReceiverID());
for (u32 LinkIdx = 0; LinkIdx < pInstance->NumLinks(eIncoming); LinkIdx++)
{
CLink *pLink = pInstance->Link(eIncoming, LinkIdx);
if (mGame <= eEchoes)
{
if (pLink->State() == FOURCC('GRNT') && pLink->Message() == FOURCC('ACTV'))
{
ShouldWrite = false;
break;
}
}
WriteProperty(pInstance->Properties(), false);
u32 InstanceEnd = mpSCLY->Tell();
mpSCLY->Seek(SizeOffset, SEEK_SET);
mpSCLY->WriteShort((u16) (InstanceEnd - InstanceStart));
mpSCLY->Seek(InstanceEnd, SEEK_SET);
}
// ************ STATIC ************
void CScriptCooker::WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream& rOut)
{
CScriptCooker Cooker;
Cooker.mpSCLY = &rOut;
Cooker.mVersion = Game;
if (Game <= ePrime)
Cooker.WriteLayerMP1(pLayer);
else
Cooker.WriteLayerMP2(pLayer);
{
if (pLink->Message() == FOURCC('ATCH'))
{
if (pLink->State() == FOURCC('GRNT') || pLink->State() == FOURCC('GRN0') || pLink->State() == FOURCC('GRN1'))
{
ShouldWrite = false;
break;
}
}
}
}
if (!ShouldWrite)
mGeneratedObjects.push_back(pInstance);
}
}
if (ShouldWrite)
{
WriteInstance(rOut, pInstance);
NumWrittenInstances++;
}
}
u32 LayerEnd = rOut.Tell();
rOut.GoTo(InstanceCountOffset);
rOut.WriteLong(NumWrittenInstances);
rOut.GoTo(LayerEnd);
}
void CScriptCooker::CookInstance(EGame Game, CScriptObject *pInstance, IOutputStream& rOut)
void CScriptCooker::WriteGeneratedLayer(IOutputStream& rOut)
{
CScriptCooker Cooker;
Cooker.mpSCLY = &rOut;
Cooker.mVersion = Game;
rOut.WriteByte(1); // Version
rOut.WriteLong(mGeneratedObjects.size());
if (Game <= ePrime)
Cooker.WriteInstanceMP1(pInstance);
else
Cooker.WriteInstanceMP2(pInstance);
for (u32 InstIdx = 0; InstIdx < mGeneratedObjects.size(); InstIdx++)
WriteInstance(rOut, mGeneratedObjects[InstIdx]);
}

View File

@ -1,6 +1,7 @@
#ifndef CSCRIPTCOOKER_H
#define CSCRIPTCOOKER_H
#include "CSectionMgrOut.h"
#include "Core/Resource/Script/CScriptLayer.h"
#include "Core/Resource/Script/CScriptObject.h"
#include <Common/EGame.h>
@ -8,19 +9,21 @@
class CScriptCooker
{
IOutputStream *mpSCLY;
EGame mVersion;
EGame mGame;
std::vector<CScriptObject*> mGeneratedObjects;
bool mWriteGeneratedSeparately;
CScriptCooker() {}
void WriteProperty(IProperty *pProp, bool InSingleStruct);
void WriteLayerMP1(CScriptLayer *pLayer);
void WriteInstanceMP1(CScriptObject *pInstance);
void WriteLayerMP2(CScriptLayer *pLayer);
void WriteInstanceMP2(CScriptObject *pInstance);
void WriteProperty(IOutputStream& rOut,IProperty *pProp, bool InSingleStruct);
public:
static void WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream& rOut);
static void CookInstance(EGame Game, CScriptObject *pInstance, IOutputStream& rOut);
CScriptCooker(EGame Game, bool WriteGeneratedObjectsSeparately = true)
: mGame(Game)
, mWriteGeneratedSeparately(WriteGeneratedObjectsSeparately && mGame >= eEchoesDemo)
{}
void WriteInstance(IOutputStream& rOut, CScriptObject *pInstance);
void WriteLayer(IOutputStream& rOut, CScriptLayer *pLayer);
void WriteGeneratedLayer(IOutputStream& rOut);
};
#endif // CSCRIPTCOOKER_H

View File

@ -143,28 +143,25 @@ void CAreaLoader::ReadSCLYPrime()
}
// SCGN
if (mVersion == eEchoesDemo)
CScriptLayer *pGenLayer = nullptr;
if (mVersion >= eEchoesDemo)
{
mpSectionMgr->ToSection(mScriptGeneratorBlockNum);
CFourCC SCGN = mpMREA->ReadFourCC();
CFourCC SCGN(*mpMREA);
if (SCGN != "SCGN")
if (SCGN != FOURCC('SCGN'))
Log::FileError(mpMREA->GetSourceString(), mpMREA->Tell() - 4, "Invalid SCGN magic: " + SCGN.ToString());
else
{
mpMREA->Seek(0x1, SEEK_CUR);
CScriptLayer *pLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
if (pLayer)
{
MergeGeneratedLayer(pLayer);
delete pLayer;
}
pGenLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
}
}
SetUpObjects();
SetUpObjects(pGenLayer);
delete pGenLayer;
}
void CAreaLoader::ReadLightsPrime()
@ -310,7 +307,6 @@ void CAreaLoader::ReadSCLYEchoes()
}
// SCGN
// we want to regenerate the SCGN layer on cook - for now just move everything back to its original layer
CFourCC SCGN(*mpMREA);
if (SCGN != "SCGN")
{
@ -320,14 +316,8 @@ void CAreaLoader::ReadSCLYEchoes()
mpMREA->Seek(0x1, SEEK_CUR); // Skipping unknown
CScriptLayer *pGeneratedLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
if (pGeneratedLayer)
{
MergeGeneratedLayer(pGeneratedLayer);
SetUpObjects(pGeneratedLayer);
delete pGeneratedLayer;
}
SetUpObjects();
}
// ************ CORRUPTION ************
@ -606,61 +596,66 @@ void CAreaLoader::ReadEGMC()
mpArea->mpPoiToWorldMap = gpResourceStore->LoadResource(EGMC, eStaticGeometryMap);
}
void CAreaLoader::MergeGeneratedLayer(CScriptLayer *pLayer)
void CAreaLoader::SetUpObjects(CScriptLayer *pGenLayer)
{
while (pLayer->NumInstances() != 0)
// Create instance map
for (u32 LayerIdx = 0; LayerIdx < mpArea->NumScriptLayers(); LayerIdx++)
{
CScriptObject *pObj = pLayer->InstanceByIndex(0);
u32 InstanceID = pObj->InstanceID();
CScriptLayer *pLayer = mpArea->mScriptLayers[LayerIdx];
for (u32 InstIdx = 0; InstIdx < pLayer->NumInstances(); InstIdx++)
{
CScriptObject *pInst = pLayer->InstanceByIndex(InstIdx);
u32 InstanceID = pInst->InstanceID();
CScriptObject *pExisting = mpArea->InstanceByID(InstanceID);
ASSERT(pExisting == nullptr);
mpArea->mObjectMap[InstanceID] = pInst;
}
}
// Merge objects from the generated layer back into the regular script layers
while (pGenLayer->NumInstances() != 0)
{
CScriptObject *pInst = pGenLayer->InstanceByIndex(0);
u32 InstanceID = pInst->InstanceID();
// Check if this is a duplicate of an existing instance (this only happens with DKCR GenericCreature as far as I'm aware)
CScriptObject *pDupe = mpArea->InstanceByID(InstanceID);
if (pDupe)
if (mpArea->InstanceByID(InstanceID) != nullptr)
{
Log::Write("Duplicate SCGN object: [" + pObj->Template()->Name() + "] " + pObj->InstanceName() + " (" + TString::HexString(pObj->InstanceID(), 8, false) + ")");
pLayer->RemoveInstance(pObj);
delete pObj;
Log::Write("Duplicate SCGN object: [" + pInst->Template()->Name() + "] " + pInst->InstanceName() + " (" + TString::HexString(pInst->InstanceID(), 8, false) + ")");
pGenLayer->RemoveInstance(pInst);
delete pInst;
}
else
{
u32 LayerIdx = (InstanceID >> 26) & 0x3F;
pObj->SetLayer( mpArea->ScriptLayer(LayerIdx) );
pInst->SetLayer( mpArea->ScriptLayer(LayerIdx) );
mpArea->mObjectMap[InstanceID] = pInst;
}
}
}
void CAreaLoader::SetUpObjects()
{
// Iterate over all objects
for (u32 iLyr = 0; iLyr < mpArea->NumScriptLayers(); iLyr++)
for (auto Iter = mpArea->mObjectMap.begin(); Iter != mpArea->mObjectMap.end(); Iter++)
{
CScriptLayer *pLayer = mpArea->mScriptLayers[iLyr];
for (u32 iObj = 0; iObj < pLayer->NumInstances(); iObj++)
{
// Add object to object map
CScriptObject *pObj = (*pLayer)[iObj];
mpArea->mObjectMap[pObj->InstanceID()] = pObj;
CScriptObject *pInst = Iter->second;
// Store outgoing connections
for (u32 iCon = 0; iCon < pObj->NumLinks(eOutgoing); iCon++)
for (u32 iCon = 0; iCon < pInst->NumLinks(eOutgoing); iCon++)
{
CLink *pLink = pObj->Link(eOutgoing, iCon);
CLink *pLink = pInst->Link(eOutgoing, iCon);
mConnectionMap[pLink->ReceiverID()].push_back(pLink);
}
// Remove "-component" garbage from MP1 instance names
if (mVersion <= ePrime)
{
TString InstanceName = pObj->InstanceName();
TString InstanceName = pInst->InstanceName();
while (InstanceName.EndsWith("-component"))
InstanceName = InstanceName.ChopBack(10);
pObj->SetName(InstanceName);
}
pInst->SetName(InstanceName);
}
}

View File

@ -77,8 +77,7 @@ class CAreaLoader
void ReadPATH();
void ReadPTLA();
void ReadEGMC();
void MergeGeneratedLayer(CScriptLayer *pLayer);
void SetUpObjects();
void SetUpObjects(CScriptLayer *pGenLayer);
public:
static CGameArea* LoadMREA(IInputStream& rMREA, CResourceEntry *pEntry);

View File

@ -70,7 +70,9 @@ public:
rNode.OriginalInstanceID = pInst->InstanceID();
CVectorOutStream Out(&rNode.InstanceData, IOUtil::eBigEndian);
CScriptCooker::CookInstance(eReturns, static_cast<CScriptNode*>(*It)->Instance(), Out);
CScriptCooker Cooker(mGame);
Cooker.WriteInstance(Out, static_cast<CScriptNode*>(*It)->Instance());
// Replace instance ID with 0xFFFFFFFF to force it to generate a new one.
Out.Seek(0x6, SEEK_SET);

View File

@ -64,7 +64,8 @@ CDeleteSelectionCommand::CDeleteSelectionCommand(CWorldEditor *pEditor, const QS
}
CVectorOutStream PropertyDataOut(&rNode.InstanceData, IOUtil::eBigEndian);
CScriptCooker::CookInstance(eReturns, pInst, PropertyDataOut);
CScriptCooker Cooker(pEditor->CurrentGame());
Cooker.WriteInstance(PropertyDataOut, pInst);
}
else