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 ************
|
// ************ SCLY ************
|
||||||
void CAreaCooker::WritePrimeSCLY(IOutputStream& rOut)
|
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);
|
mVersion <= ePrime ? rOut.WriteLong(1) : rOut.WriteByte(1);
|
||||||
|
|
||||||
u32 NumLayers = mpArea->mScriptLayers.size();
|
u32 NumLayers = mpArea->mScriptLayers.size();
|
||||||
rOut.WriteLong(NumLayers);
|
rOut.WriteLong(NumLayers);
|
||||||
|
|
||||||
u32 LayerSizesStart = rOut.Tell();
|
u32 LayerSizesStart = rOut.Tell();
|
||||||
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
|
for (u32 LayerIdx = 0; LayerIdx < NumLayers; LayerIdx++)
|
||||||
rOut.WriteLong(0);
|
rOut.WriteLong(0);
|
||||||
|
|
||||||
// SCLY
|
// SCLY
|
||||||
|
CScriptCooker ScriptCooker(mVersion, true);
|
||||||
std::vector<u32> LayerSizes(NumLayers);
|
std::vector<u32> LayerSizes(NumLayers);
|
||||||
|
|
||||||
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
|
for (u32 LayerIdx = 0; LayerIdx < NumLayers; LayerIdx++)
|
||||||
{
|
{
|
||||||
u32 LayerStart = rOut.Tell();
|
u32 LayerStart = rOut.Tell();
|
||||||
CScriptCooker::WriteLayer(mVersion, mpArea->mScriptLayers[iLyr], rOut);
|
ScriptCooker.WriteLayer(rOut, mpArea->mScriptLayers[LayerIdx]);
|
||||||
LayerSizes[iLyr] = rOut.Tell() - LayerStart;
|
|
||||||
|
// 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();
|
u32 LayersEnd = rOut.Tell();
|
||||||
rOut.Seek(LayerSizesStart, SEEK_SET);
|
rOut.Seek(LayerSizesStart, SEEK_SET);
|
||||||
|
|
||||||
for (u32 iLyr = 0; iLyr < NumLayers; iLyr++)
|
for (u32 LayerIdx = 0; LayerIdx < NumLayers; LayerIdx++)
|
||||||
rOut.WriteLong(LayerSizes[iLyr]);
|
rOut.WriteLong(LayerSizes[LayerIdx]);
|
||||||
|
|
||||||
rOut.Seek(LayersEnd, SEEK_SET);
|
rOut.Seek(LayersEnd, SEEK_SET);
|
||||||
FinishSection(false);
|
FinishSection(false);
|
||||||
|
@ -217,31 +229,31 @@ void CAreaCooker::WritePrimeSCLY(IOutputStream& rOut)
|
||||||
// SCGN
|
// SCGN
|
||||||
if (mVersion == eEchoesDemo)
|
if (mVersion == eEchoesDemo)
|
||||||
{
|
{
|
||||||
// IMPORTANT TODO - REGENERATE SCGN LAYER
|
rOut.WriteFourCC( FOURCC('SCGN') );
|
||||||
/*rOut.WriteString("SCGN", 4);
|
|
||||||
rOut.WriteByte(1);
|
rOut.WriteByte(1);
|
||||||
CScriptCooker::WriteLayer(mVersion, mpArea->mpGeneratorLayer, rOut);
|
ScriptCooker.WriteGeneratedLayer(rOut);
|
||||||
FinishSection(false);*/
|
FinishSection(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAreaCooker::WriteEchoesSCLY(IOutputStream& rOut)
|
void CAreaCooker::WriteEchoesSCLY(IOutputStream& rOut)
|
||||||
{
|
{
|
||||||
// SCLY
|
// 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.WriteFourCC( FOURCC('SCLY') );
|
||||||
rOut.WriteByte(0x1);
|
rOut.WriteByte(1);
|
||||||
rOut.WriteLong(iLyr);
|
rOut.WriteLong(LayerIdx);
|
||||||
CScriptCooker::WriteLayer(mVersion, mpArea->mScriptLayers[iLyr], rOut);
|
ScriptCooker.WriteLayer(rOut, mpArea->mScriptLayers[LayerIdx]);
|
||||||
FinishSection(true);
|
FinishSection(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SCGN
|
// SCGN
|
||||||
// IMPORTANT TODO - REGENERATE SCGN
|
rOut.WriteFourCC( FOURCC('SCGN') );
|
||||||
rOut.WriteString("SCGN", 4);
|
rOut.WriteByte(1);
|
||||||
rOut.WriteByte(0x1);
|
ScriptCooker.WriteGeneratedLayer(rOut);
|
||||||
//CScriptCooker::WriteLayer(mVersion, mpArea->mpGeneratorLayer, rOut);
|
|
||||||
FinishSection(true);
|
FinishSection(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
#include "CScriptCooker.h"
|
#include "CScriptCooker.h"
|
||||||
#include "Core/Resource/Script/CLink.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;
|
u32 SizeOffset = 0, PropStart = 0;
|
||||||
|
|
||||||
if (mVersion >= eEchoesDemo && !InSingleStruct)
|
if (mGame >= eEchoesDemo && !InSingleStruct)
|
||||||
{
|
{
|
||||||
mpSCLY->WriteLong(pProp->ID());
|
rOut.WriteLong(pProp->ID());
|
||||||
SizeOffset = mpSCLY->Tell();
|
SizeOffset = rOut.Tell();
|
||||||
mpSCLY->WriteShort(0x0);
|
rOut.WriteShort(0x0);
|
||||||
PropStart = mpSCLY->Tell();
|
PropStart = rOut.Tell();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (pProp->Type())
|
switch (pProp->Type())
|
||||||
|
@ -19,91 +19,91 @@ void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
|
||||||
case eBoolProperty:
|
case eBoolProperty:
|
||||||
{
|
{
|
||||||
TBoolProperty *pBoolCast = static_cast<TBoolProperty*>(pProp);
|
TBoolProperty *pBoolCast = static_cast<TBoolProperty*>(pProp);
|
||||||
mpSCLY->WriteByte(pBoolCast->Get() ? 1 : 0);
|
rOut.WriteBool(pBoolCast->Get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eByteProperty:
|
case eByteProperty:
|
||||||
{
|
{
|
||||||
TByteProperty *pByteCast = static_cast<TByteProperty*>(pProp);
|
TByteProperty *pByteCast = static_cast<TByteProperty*>(pProp);
|
||||||
mpSCLY->WriteByte(pByteCast->Get());
|
rOut.WriteByte(pByteCast->Get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eShortProperty:
|
case eShortProperty:
|
||||||
{
|
{
|
||||||
TShortProperty *pShortCast = static_cast<TShortProperty*>(pProp);
|
TShortProperty *pShortCast = static_cast<TShortProperty*>(pProp);
|
||||||
mpSCLY->WriteShort(pShortCast->Get());
|
rOut.WriteShort(pShortCast->Get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eLongProperty:
|
case eLongProperty:
|
||||||
{
|
{
|
||||||
TLongProperty *pLongCast = static_cast<TLongProperty*>(pProp);
|
TLongProperty *pLongCast = static_cast<TLongProperty*>(pProp);
|
||||||
mpSCLY->WriteLong(pLongCast->Get());
|
rOut.WriteLong(pLongCast->Get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eEnumProperty:
|
case eEnumProperty:
|
||||||
{
|
{
|
||||||
TEnumProperty *pEnumCast = static_cast<TEnumProperty*>(pProp);
|
TEnumProperty *pEnumCast = static_cast<TEnumProperty*>(pProp);
|
||||||
mpSCLY->WriteLong(pEnumCast->Get());
|
rOut.WriteLong(pEnumCast->Get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eBitfieldProperty:
|
case eBitfieldProperty:
|
||||||
{
|
{
|
||||||
TBitfieldProperty *pBitfieldCast = static_cast<TBitfieldProperty*>(pProp);
|
TBitfieldProperty *pBitfieldCast = static_cast<TBitfieldProperty*>(pProp);
|
||||||
mpSCLY->WriteLong(pBitfieldCast->Get());
|
rOut.WriteLong(pBitfieldCast->Get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eFloatProperty:
|
case eFloatProperty:
|
||||||
{
|
{
|
||||||
TFloatProperty *pFloatCast = static_cast<TFloatProperty*>(pProp);
|
TFloatProperty *pFloatCast = static_cast<TFloatProperty*>(pProp);
|
||||||
mpSCLY->WriteFloat(pFloatCast->Get());
|
rOut.WriteFloat(pFloatCast->Get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eStringProperty:
|
case eStringProperty:
|
||||||
{
|
{
|
||||||
TStringProperty *pStringCast = static_cast<TStringProperty*>(pProp);
|
TStringProperty *pStringCast = static_cast<TStringProperty*>(pProp);
|
||||||
mpSCLY->WriteString(pStringCast->Get());
|
rOut.WriteString(pStringCast->Get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eVector3Property:
|
case eVector3Property:
|
||||||
{
|
{
|
||||||
TVector3Property *pVectorCast = static_cast<TVector3Property*>(pProp);
|
TVector3Property *pVectorCast = static_cast<TVector3Property*>(pProp);
|
||||||
pVectorCast->Get().Write(*mpSCLY);
|
pVectorCast->Get().Write(rOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eColorProperty:
|
case eColorProperty:
|
||||||
{
|
{
|
||||||
TColorProperty *pColorCast = static_cast<TColorProperty*>(pProp);
|
TColorProperty *pColorCast = static_cast<TColorProperty*>(pProp);
|
||||||
pColorCast->Get().Write(*mpSCLY, false);
|
pColorCast->Get().Write(rOut, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eSoundProperty:
|
case eSoundProperty:
|
||||||
{
|
{
|
||||||
TSoundProperty *pSoundCast = static_cast<TSoundProperty*>(pProp);
|
TSoundProperty *pSoundCast = static_cast<TSoundProperty*>(pProp);
|
||||||
mpSCLY->WriteLong(pSoundCast->Get());
|
rOut.WriteLong(pSoundCast->Get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eAssetProperty:
|
case eAssetProperty:
|
||||||
{
|
{
|
||||||
TAssetProperty *pAssetCast = static_cast<TAssetProperty*>(pProp);
|
TAssetProperty *pAssetCast = static_cast<TAssetProperty*>(pProp);
|
||||||
pAssetCast->Get().Write(*mpSCLY);
|
pAssetCast->Get().Write(rOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eCharacterProperty:
|
case eCharacterProperty:
|
||||||
{
|
{
|
||||||
TCharacterProperty *pCharCast = static_cast<TCharacterProperty*>(pProp);
|
TCharacterProperty *pCharCast = static_cast<TCharacterProperty*>(pProp);
|
||||||
pCharCast->Get().Write(*mpSCLY);
|
pCharCast->Get().Write(rOut);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,25 +111,25 @@ void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
|
||||||
{
|
{
|
||||||
TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp);
|
TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp);
|
||||||
std::vector<u8> Buffer = pSplineCast->Get();
|
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
|
else
|
||||||
{
|
{
|
||||||
if (mVersion < eReturns)
|
if (mGame < eReturns)
|
||||||
{
|
{
|
||||||
mpSCLY->WriteShort(0);
|
rOut.WriteShort(0);
|
||||||
mpSCLY->WriteLong(0);
|
rOut.WriteLong(0);
|
||||||
mpSCLY->WriteByte(1);
|
rOut.WriteByte(1);
|
||||||
mpSCLY->WriteFloat(0);
|
rOut.WriteFloat(0);
|
||||||
mpSCLY->WriteFloat(1);
|
rOut.WriteFloat(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mpSCLY->WriteLong(0);
|
rOut.WriteLong(0);
|
||||||
mpSCLY->WriteFloat(0);
|
rOut.WriteFloat(0);
|
||||||
mpSCLY->WriteFloat(1);
|
rOut.WriteFloat(1);
|
||||||
mpSCLY->WriteShort(0);
|
rOut.WriteShort(0);
|
||||||
mpSCLY->WriteByte(1);
|
rOut.WriteByte(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,14 +153,14 @@ void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
|
||||||
|
|
||||||
if (!pTemp->IsSingleProperty())
|
if (!pTemp->IsSingleProperty())
|
||||||
{
|
{
|
||||||
if (mVersion <= ePrime)
|
if (mGame <= ePrime)
|
||||||
mpSCLY->WriteLong(PropertiesToWrite.size());
|
rOut.WriteLong(PropertiesToWrite.size());
|
||||||
else
|
else
|
||||||
mpSCLY->WriteShort((u16) PropertiesToWrite.size());
|
rOut.WriteShort((u16) PropertiesToWrite.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 iProp = 0; iProp < PropertiesToWrite.size(); iProp++)
|
for (u32 iProp = 0; iProp < PropertiesToWrite.size(); iProp++)
|
||||||
WriteProperty(PropertiesToWrite[iProp], pTemp->IsSingleProperty());
|
WriteProperty(rOut, PropertiesToWrite[iProp], pTemp->IsSingleProperty());
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -168,10 +168,10 @@ void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
|
||||||
case eArrayProperty:
|
case eArrayProperty:
|
||||||
{
|
{
|
||||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
|
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
|
||||||
mpSCLY->WriteLong(pArray->Count());
|
rOut.WriteLong(pArray->Count());
|
||||||
|
|
||||||
for (u32 iProp = 0; iProp < pArray->Count(); iProp++)
|
for (u32 iProp = 0; iProp < pArray->Count(); iProp++)
|
||||||
WriteProperty(pArray->PropertyByIndex(iProp), true);
|
WriteProperty(rOut, pArray->PropertyByIndex(iProp), true);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -180,133 +180,128 @@ void CScriptCooker::WriteProperty(IProperty *pProp, bool InSingleStruct)
|
||||||
|
|
||||||
if (SizeOffset != 0)
|
if (SizeOffset != 0)
|
||||||
{
|
{
|
||||||
u32 PropEnd = mpSCLY->Tell();
|
u32 PropEnd = rOut.Tell();
|
||||||
mpSCLY->Seek(SizeOffset, SEEK_SET);
|
rOut.Seek(SizeOffset, SEEK_SET);
|
||||||
mpSCLY->WriteShort((u16) (PropEnd - PropStart));
|
rOut.WriteShort((u16) (PropEnd - PropStart));
|
||||||
mpSCLY->Seek(PropEnd, SEEK_SET);
|
rOut.Seek(PropEnd, SEEK_SET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CScriptCooker::WriteLayerMP1(CScriptLayer *pLayer)
|
// ************ PUBLIC ************
|
||||||
|
void CScriptCooker::WriteInstance(IOutputStream& rOut, CScriptObject *pInstance)
|
||||||
{
|
{
|
||||||
u32 LayerStart = mpSCLY->Tell();
|
ASSERT(pInstance->Area()->Game() == mGame);
|
||||||
mpSCLY->WriteByte(0); // Unknown value
|
|
||||||
mpSCLY->WriteLong(pLayer->NumInstances());
|
|
||||||
|
|
||||||
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
// 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
|
||||||
CScriptObject *pInstance = pLayer->InstanceByIndex(iInst);
|
bool IsPrime1 = (mGame <= ePrime);
|
||||||
WriteInstanceMP1(pInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 LayerSize = mpSCLY->Tell() - LayerStart;
|
u32 ObjectType = pInstance->ObjectTypeID();
|
||||||
u32 NumPadBytes = 32 - (LayerSize % 32);
|
IsPrime1 ? rOut.WriteByte((u8) ObjectType) : rOut.WriteLong(ObjectType);
|
||||||
if (NumPadBytes == 32) NumPadBytes = 0;
|
|
||||||
|
|
||||||
for (u32 iPad = 0; iPad < NumPadBytes; iPad++)
|
u32 SizeOffset = rOut.Tell();
|
||||||
mpSCLY->WriteByte(0);
|
IsPrime1 ? rOut.WriteLong(0) : rOut.WriteShort(0);
|
||||||
}
|
|
||||||
|
|
||||||
void CScriptCooker::WriteInstanceMP1(CScriptObject *pInstance)
|
|
||||||
{
|
|
||||||
mpSCLY->WriteByte((u8) pInstance->ObjectTypeID());
|
|
||||||
|
|
||||||
u32 SizeOffset = mpSCLY->Tell();
|
|
||||||
mpSCLY->WriteLong(0);
|
|
||||||
u32 InstanceStart = mpSCLY->Tell();
|
|
||||||
|
|
||||||
|
u32 InstanceStart = rOut.Tell();
|
||||||
u32 InstanceID = (pInstance->Layer()->AreaIndex() << 26) | pInstance->InstanceID();
|
u32 InstanceID = (pInstance->Layer()->AreaIndex() << 26) | pInstance->InstanceID();
|
||||||
mpSCLY->WriteLong(InstanceID);
|
rOut.WriteLong(InstanceID);
|
||||||
mpSCLY->WriteLong(pInstance->NumLinks(eOutgoing));
|
|
||||||
|
u32 NumLinks = pInstance->NumLinks(eOutgoing);
|
||||||
|
IsPrime1 ? rOut.WriteLong(NumLinks) : rOut.WriteShort((u16) NumLinks);
|
||||||
|
|
||||||
for (u32 iLink = 0; iLink < pInstance->NumLinks(eOutgoing); iLink++)
|
for (u32 iLink = 0; iLink < pInstance->NumLinks(eOutgoing); iLink++)
|
||||||
{
|
{
|
||||||
CLink *pLink = pInstance->Link(eOutgoing, iLink);
|
CLink *pLink = pInstance->Link(eOutgoing, iLink);
|
||||||
mpSCLY->WriteLong(pLink->State());
|
rOut.WriteLong(pLink->State());
|
||||||
mpSCLY->WriteLong(pLink->Message());
|
rOut.WriteLong(pLink->Message());
|
||||||
mpSCLY->WriteLong(pLink->ReceiverID());
|
rOut.WriteLong(pLink->ReceiverID());
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteProperty(pInstance->Properties(), false);
|
WriteProperty(rOut, pInstance->Properties(), false);
|
||||||
u32 InstanceEnd = mpSCLY->Tell();
|
u32 InstanceEnd = rOut.Tell();
|
||||||
|
|
||||||
mpSCLY->Seek(SizeOffset, SEEK_SET);
|
rOut.Seek(SizeOffset, SEEK_SET);
|
||||||
mpSCLY->WriteLong(InstanceEnd - InstanceStart);
|
u32 Size = InstanceEnd - InstanceStart;
|
||||||
mpSCLY->Seek(InstanceEnd, SEEK_SET);
|
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();
|
ASSERT(pLayer->Area()->Game() == mGame);
|
||||||
mpSCLY->WriteByte(0x1);
|
|
||||||
mpSCLY->WriteLong(pLayer->NumInstances());
|
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++)
|
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
||||||
{
|
{
|
||||||
CScriptObject *pInstance = pLayer->InstanceByIndex(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;
|
// GenericCreature instances in DKCR always write to both SCLY and SCGN
|
||||||
u32 NumPadBytes = 32 - (LayerSize % 32);
|
if (mGame == eReturns && pInstance->ObjectTypeID() == FOURCC('GCTR'))
|
||||||
if (NumPadBytes == 32) NumPadBytes = 0;
|
mGeneratedObjects.push_back(pInstance);
|
||||||
|
|
||||||
for (u32 iPad = 0; iPad < NumPadBytes; iPad++)
|
// Instances receiving a Generate/Activate message (MP2) or a
|
||||||
mpSCLY->WriteByte(0);
|
// Generate/Attach message (MP3+) should be written to SCGN, not SCLY
|
||||||
}
|
else
|
||||||
}
|
|
||||||
|
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
CLink *pLink = pInstance->Link(eOutgoing, iLink);
|
for (u32 LinkIdx = 0; LinkIdx < pInstance->NumLinks(eIncoming); LinkIdx++)
|
||||||
mpSCLY->WriteLong(pLink->State());
|
{
|
||||||
mpSCLY->WriteLong(pLink->Message());
|
CLink *pLink = pInstance->Link(eIncoming, LinkIdx);
|
||||||
mpSCLY->WriteLong(pLink->ReceiverID());
|
|
||||||
|
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
|
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;
|
rOut.WriteByte(1); // Version
|
||||||
Cooker.mpSCLY = &rOut;
|
rOut.WriteLong(mGeneratedObjects.size());
|
||||||
Cooker.mVersion = Game;
|
|
||||||
|
|
||||||
if (Game <= ePrime)
|
for (u32 InstIdx = 0; InstIdx < mGeneratedObjects.size(); InstIdx++)
|
||||||
Cooker.WriteInstanceMP1(pInstance);
|
WriteInstance(rOut, mGeneratedObjects[InstIdx]);
|
||||||
else
|
|
||||||
Cooker.WriteInstanceMP2(pInstance);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef CSCRIPTCOOKER_H
|
#ifndef CSCRIPTCOOKER_H
|
||||||
#define CSCRIPTCOOKER_H
|
#define CSCRIPTCOOKER_H
|
||||||
|
|
||||||
|
#include "CSectionMgrOut.h"
|
||||||
#include "Core/Resource/Script/CScriptLayer.h"
|
#include "Core/Resource/Script/CScriptLayer.h"
|
||||||
#include "Core/Resource/Script/CScriptObject.h"
|
#include "Core/Resource/Script/CScriptObject.h"
|
||||||
#include <Common/EGame.h>
|
#include <Common/EGame.h>
|
||||||
|
@ -8,19 +9,21 @@
|
||||||
|
|
||||||
class CScriptCooker
|
class CScriptCooker
|
||||||
{
|
{
|
||||||
IOutputStream *mpSCLY;
|
EGame mGame;
|
||||||
EGame mVersion;
|
std::vector<CScriptObject*> mGeneratedObjects;
|
||||||
|
bool mWriteGeneratedSeparately;
|
||||||
|
|
||||||
CScriptCooker() {}
|
void WriteProperty(IOutputStream& rOut,IProperty *pProp, bool InSingleStruct);
|
||||||
void WriteProperty(IProperty *pProp, bool InSingleStruct);
|
|
||||||
void WriteLayerMP1(CScriptLayer *pLayer);
|
|
||||||
void WriteInstanceMP1(CScriptObject *pInstance);
|
|
||||||
void WriteLayerMP2(CScriptLayer *pLayer);
|
|
||||||
void WriteInstanceMP2(CScriptObject *pInstance);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void WriteLayer(EGame Game, CScriptLayer *pLayer, IOutputStream& rOut);
|
CScriptCooker(EGame Game, bool WriteGeneratedObjectsSeparately = true)
|
||||||
static void CookInstance(EGame Game, CScriptObject *pInstance, IOutputStream& rOut);
|
: 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
|
#endif // CSCRIPTCOOKER_H
|
||||||
|
|
|
@ -143,28 +143,25 @@ void CAreaLoader::ReadSCLYPrime()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SCGN
|
// SCGN
|
||||||
if (mVersion == eEchoesDemo)
|
CScriptLayer *pGenLayer = nullptr;
|
||||||
|
|
||||||
|
if (mVersion >= eEchoesDemo)
|
||||||
{
|
{
|
||||||
mpSectionMgr->ToSection(mScriptGeneratorBlockNum);
|
mpSectionMgr->ToSection(mScriptGeneratorBlockNum);
|
||||||
|
CFourCC SCGN = mpMREA->ReadFourCC();
|
||||||
|
|
||||||
CFourCC SCGN(*mpMREA);
|
if (SCGN != FOURCC('SCGN'))
|
||||||
if (SCGN != "SCGN")
|
|
||||||
Log::FileError(mpMREA->GetSourceString(), mpMREA->Tell() - 4, "Invalid SCGN magic: " + SCGN.ToString());
|
Log::FileError(mpMREA->GetSourceString(), mpMREA->Tell() - 4, "Invalid SCGN magic: " + SCGN.ToString());
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mpMREA->Seek(0x1, SEEK_CUR);
|
mpMREA->Seek(0x1, SEEK_CUR);
|
||||||
CScriptLayer *pLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
pGenLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
||||||
|
|
||||||
if (pLayer)
|
|
||||||
{
|
|
||||||
MergeGeneratedLayer(pLayer);
|
|
||||||
delete pLayer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetUpObjects();
|
SetUpObjects(pGenLayer);
|
||||||
|
delete pGenLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAreaLoader::ReadLightsPrime()
|
void CAreaLoader::ReadLightsPrime()
|
||||||
|
@ -310,7 +307,6 @@ void CAreaLoader::ReadSCLYEchoes()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SCGN
|
// SCGN
|
||||||
// we want to regenerate the SCGN layer on cook - for now just move everything back to its original layer
|
|
||||||
CFourCC SCGN(*mpMREA);
|
CFourCC SCGN(*mpMREA);
|
||||||
if (SCGN != "SCGN")
|
if (SCGN != "SCGN")
|
||||||
{
|
{
|
||||||
|
@ -320,14 +316,8 @@ void CAreaLoader::ReadSCLYEchoes()
|
||||||
|
|
||||||
mpMREA->Seek(0x1, SEEK_CUR); // Skipping unknown
|
mpMREA->Seek(0x1, SEEK_CUR); // Skipping unknown
|
||||||
CScriptLayer *pGeneratedLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
CScriptLayer *pGeneratedLayer = CScriptLoader::LoadLayer(*mpMREA, mpArea, mVersion);
|
||||||
|
SetUpObjects(pGeneratedLayer);
|
||||||
if (pGeneratedLayer)
|
|
||||||
{
|
|
||||||
MergeGeneratedLayer(pGeneratedLayer);
|
|
||||||
delete pGeneratedLayer;
|
delete pGeneratedLayer;
|
||||||
}
|
|
||||||
|
|
||||||
SetUpObjects();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ************ CORRUPTION ************
|
// ************ CORRUPTION ************
|
||||||
|
@ -606,61 +596,66 @@ void CAreaLoader::ReadEGMC()
|
||||||
mpArea->mpPoiToWorldMap = gpResourceStore->LoadResource(EGMC, eStaticGeometryMap);
|
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);
|
CScriptLayer *pLayer = mpArea->mScriptLayers[LayerIdx];
|
||||||
u32 InstanceID = pObj->InstanceID();
|
|
||||||
|
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)
|
// 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 (mpArea->InstanceByID(InstanceID) != nullptr)
|
||||||
|
|
||||||
if (pDupe)
|
|
||||||
{
|
{
|
||||||
Log::Write("Duplicate SCGN object: [" + pObj->Template()->Name() + "] " + pObj->InstanceName() + " (" + TString::HexString(pObj->InstanceID(), 8, false) + ")");
|
Log::Write("Duplicate SCGN object: [" + pInst->Template()->Name() + "] " + pInst->InstanceName() + " (" + TString::HexString(pInst->InstanceID(), 8, false) + ")");
|
||||||
pLayer->RemoveInstance(pObj);
|
pGenLayer->RemoveInstance(pInst);
|
||||||
delete pObj;
|
delete pInst;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 LayerIdx = (InstanceID >> 26) & 0x3F;
|
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
|
// 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];
|
CScriptObject *pInst = Iter->second;
|
||||||
|
|
||||||
for (u32 iObj = 0; iObj < pLayer->NumInstances(); iObj++)
|
|
||||||
{
|
|
||||||
// Add object to object map
|
|
||||||
CScriptObject *pObj = (*pLayer)[iObj];
|
|
||||||
mpArea->mObjectMap[pObj->InstanceID()] = pObj;
|
|
||||||
|
|
||||||
// Store outgoing connections
|
// 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);
|
mConnectionMap[pLink->ReceiverID()].push_back(pLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove "-component" garbage from MP1 instance names
|
// Remove "-component" garbage from MP1 instance names
|
||||||
if (mVersion <= ePrime)
|
if (mVersion <= ePrime)
|
||||||
{
|
{
|
||||||
TString InstanceName = pObj->InstanceName();
|
TString InstanceName = pInst->InstanceName();
|
||||||
|
|
||||||
while (InstanceName.EndsWith("-component"))
|
while (InstanceName.EndsWith("-component"))
|
||||||
InstanceName = InstanceName.ChopBack(10);
|
InstanceName = InstanceName.ChopBack(10);
|
||||||
|
|
||||||
pObj->SetName(InstanceName);
|
pInst->SetName(InstanceName);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,8 +77,7 @@ class CAreaLoader
|
||||||
void ReadPATH();
|
void ReadPATH();
|
||||||
void ReadPTLA();
|
void ReadPTLA();
|
||||||
void ReadEGMC();
|
void ReadEGMC();
|
||||||
void MergeGeneratedLayer(CScriptLayer *pLayer);
|
void SetUpObjects(CScriptLayer *pGenLayer);
|
||||||
void SetUpObjects();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static CGameArea* LoadMREA(IInputStream& rMREA, CResourceEntry *pEntry);
|
static CGameArea* LoadMREA(IInputStream& rMREA, CResourceEntry *pEntry);
|
||||||
|
|
|
@ -70,7 +70,9 @@ public:
|
||||||
rNode.OriginalInstanceID = pInst->InstanceID();
|
rNode.OriginalInstanceID = pInst->InstanceID();
|
||||||
|
|
||||||
CVectorOutStream Out(&rNode.InstanceData, IOUtil::eBigEndian);
|
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.
|
// Replace instance ID with 0xFFFFFFFF to force it to generate a new one.
|
||||||
Out.Seek(0x6, SEEK_SET);
|
Out.Seek(0x6, SEEK_SET);
|
||||||
|
|
|
@ -64,7 +64,8 @@ CDeleteSelectionCommand::CDeleteSelectionCommand(CWorldEditor *pEditor, const QS
|
||||||
}
|
}
|
||||||
|
|
||||||
CVectorOutStream PropertyDataOut(&rNode.InstanceData, IOUtil::eBigEndian);
|
CVectorOutStream PropertyDataOut(&rNode.InstanceData, IOUtil::eBigEndian);
|
||||||
CScriptCooker::CookInstance(eReturns, pInst, PropertyDataOut);
|
CScriptCooker Cooker(pEditor->CurrentGame());
|
||||||
|
Cooker.WriteInstance(PropertyDataOut, pInst);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue