Rewrote a chunk of the script cooker. SCGN script layer is now generated and written at cook time.
This commit is contained in:
parent
2081835ae6
commit
4dc11023df
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue