mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-15 16:16:14 +00:00
Merge branch 'master' into release
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
#include "CAreaAttributes.h"
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include "Core/Resource/Script/CGameTemplate.h"
|
||||
#include "Core/Resource/Script/CScriptLayer.h"
|
||||
|
||||
CAreaAttributes::CAreaAttributes(CScriptObject *pObj)
|
||||
@@ -13,48 +13,30 @@ CAreaAttributes::~CAreaAttributes()
|
||||
|
||||
void CAreaAttributes::SetObject(CScriptObject *pObj)
|
||||
{
|
||||
mpObj = pObj;
|
||||
mGame = pObj->Template()->MasterTemplate()->Game();
|
||||
CScriptTemplate* pTemplate = pObj->Template();
|
||||
CStructProperty* pProperties = pTemplate->Properties();
|
||||
|
||||
mpObject = pObj;
|
||||
mGame = pTemplate->GameTemplate()->Game();
|
||||
mNeedSky = CBoolRef(pObj->PropertyData(), pProperties->ChildByIndex(1));
|
||||
|
||||
if (mGame == EGame::Prime)
|
||||
mOverrideSky = CAssetRef(pObj->PropertyData(), pProperties->ChildByIndex(7));
|
||||
else if (mGame > EGame::Prime)
|
||||
mOverrideSky = CAssetRef(pObj->PropertyData(), pProperties->ChildByID(0xD208C9FA));
|
||||
}
|
||||
|
||||
bool CAreaAttributes::IsLayerEnabled() const
|
||||
{
|
||||
return mpObj->Layer()->IsActive();
|
||||
return mpObject->Layer()->IsActive();
|
||||
}
|
||||
|
||||
bool CAreaAttributes::IsSkyEnabled() const
|
||||
{
|
||||
CPropertyStruct *pBaseStruct = mpObj->Properties();
|
||||
|
||||
switch (mGame)
|
||||
{
|
||||
case ePrime:
|
||||
case eEchoesDemo:
|
||||
case eEchoes:
|
||||
case eCorruptionProto:
|
||||
case eCorruption:
|
||||
case eReturns:
|
||||
return static_cast<TBoolProperty*>(pBaseStruct->PropertyByIndex(1))->Get();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return mNeedSky.IsValid() ? mNeedSky.Get() : false;
|
||||
}
|
||||
|
||||
CModel* CAreaAttributes::SkyModel() const
|
||||
{
|
||||
CPropertyStruct *pBaseStruct = mpObj->Properties();
|
||||
|
||||
switch (mGame)
|
||||
{
|
||||
case ePrime:
|
||||
return gpResourceStore->LoadResource<CModel>( static_cast<TAssetProperty*>(pBaseStruct->PropertyByIndex(7))->Get() );
|
||||
case eEchoesDemo:
|
||||
case eEchoes:
|
||||
case eCorruptionProto:
|
||||
case eCorruption:
|
||||
case eReturns:
|
||||
return gpResourceStore->LoadResource<CModel>( static_cast<TAssetProperty*>(pBaseStruct->PropertyByID(0xD208C9FA))->Get() );
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
return mOverrideSky.IsValid() ? gpResourceStore->LoadResource<CModel>(mOverrideSky.Get()) : nullptr;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
#define CAREAATTRIBUTES_H
|
||||
|
||||
#include "Core/Resource/Script/CScriptObject.h"
|
||||
#include "Core/Resource/Script/Property/Properties.h"
|
||||
|
||||
class CAreaAttributes
|
||||
{
|
||||
CScriptObject* mpObject;
|
||||
EGame mGame;
|
||||
CScriptObject *mpObj;
|
||||
|
||||
CBoolRef mNeedSky;
|
||||
CAssetRef mOverrideSky;
|
||||
|
||||
public:
|
||||
CAreaAttributes(CScriptObject *pObj);
|
||||
@@ -16,7 +20,7 @@ public:
|
||||
bool IsSkyEnabled() const;
|
||||
CModel* SkyModel() const;
|
||||
|
||||
inline CScriptObject* Instance() const { return mpObj; }
|
||||
inline CScriptObject* Instance() const { return mpObject; }
|
||||
};
|
||||
|
||||
#endif // CAREAATTRIBUTES_H
|
||||
|
||||
@@ -41,13 +41,13 @@ void CAudioManager::LoadAssets()
|
||||
}
|
||||
|
||||
// Load audio lookup table + sfx name list
|
||||
TString AudioLookupName = (mpProject->Game() < eEchoesDemo ? "sound_lookup" : "sound_lookup_ATBL");
|
||||
TString AudioLookupName = (mpProject->Game() < EGame::EchoesDemo ? "sound_lookup" : "sound_lookup_ATBL");
|
||||
CAssetID AudioLookupID = mpProject->FindNamedResource(AudioLookupName);
|
||||
|
||||
if (AudioLookupID.IsValid())
|
||||
mpAudioLookupTable = mpProject->ResourceStore()->LoadResource<CAudioLookupTable>(AudioLookupID);
|
||||
|
||||
if (mpProject->Game() >= eEchoesDemo)
|
||||
if (mpProject->Game() >= EGame::EchoesDemo)
|
||||
{
|
||||
CAssetID SfxNameListID = mpProject->FindNamedResource("audio_name_lookup_STLC");
|
||||
|
||||
@@ -77,7 +77,7 @@ SSoundInfo CAudioManager::GetSoundInfo(u32 SoundID)
|
||||
if (Iter != mSfxIdMap.end())
|
||||
Out.pAudioGroup = Iter->second;
|
||||
|
||||
if (mpProject->Game() >= eEchoesDemo)
|
||||
if (mpProject->Game() >= EGame::EchoesDemo)
|
||||
Out.Name = mpSfxNameList->StringByIndex(Out.DefineID);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ void CAudioManager::LogSoundInfo(u32 SoundID)
|
||||
|
||||
if (SoundInfo.DefineID != 0xFFFF)
|
||||
{
|
||||
if (mpProject->Game() >= eEchoesDemo)
|
||||
if (mpProject->Game() >= EGame::EchoesDemo)
|
||||
Log::Write("Sound Name: " + SoundInfo.Name);
|
||||
|
||||
Log::Write("Sound ID: " + TString::HexString(SoundInfo.SoundID, 4));
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define CLIGHTPARAMETERS_H
|
||||
|
||||
#include "Core/Resource/Area/CGameArea.h"
|
||||
#include "Core/Resource/Script/IProperty.h"
|
||||
#include "Core/Resource/Script/Property/Properties.h"
|
||||
|
||||
enum EWorldLightingOptions
|
||||
{
|
||||
@@ -14,48 +14,35 @@ enum EWorldLightingOptions
|
||||
|
||||
class CLightParameters
|
||||
{
|
||||
CPropertyStruct *mpStruct;
|
||||
EGame mGame;
|
||||
|
||||
TLongProperty *mpLightLayer;
|
||||
TEnumProperty *mpWorldLightingOptions;
|
||||
CIntRef mLightLayer;
|
||||
TEnumRef<EWorldLightingOptions> mWorldLightingOptions;
|
||||
|
||||
public:
|
||||
CLightParameters(CPropertyStruct *pStruct, EGame Game)
|
||||
: mpStruct(pStruct)
|
||||
, mGame(Game)
|
||||
, mpLightLayer(nullptr)
|
||||
, mpWorldLightingOptions(nullptr)
|
||||
CLightParameters(CStructRef InStruct, EGame Game)
|
||||
{
|
||||
if (mpStruct)
|
||||
if (InStruct.IsValid())
|
||||
{
|
||||
if (mGame <= ePrime)
|
||||
if (Game <= EGame::Prime)
|
||||
{
|
||||
mpWorldLightingOptions = TPropCast<TEnumProperty>(mpStruct->PropertyByIndex(0x7));
|
||||
mpLightLayer = TPropCast<TLongProperty>(mpStruct->PropertyByIndex(0xD));
|
||||
mWorldLightingOptions = TEnumRef<EWorldLightingOptions>(InStruct.DataPointer(), InStruct.Property()->ChildByIndex(0x7));
|
||||
mLightLayer = CIntRef(InStruct.DataPointer(), InStruct.Property()->ChildByIndex(0xD));
|
||||
}
|
||||
else
|
||||
{
|
||||
mpWorldLightingOptions = TPropCast<TEnumProperty>(mpStruct->PropertyByID(0x6B5E7509));
|
||||
mpLightLayer = TPropCast<TLongProperty>(mpStruct->PropertyByID(0x1F715FD3));
|
||||
mWorldLightingOptions = TEnumRef<EWorldLightingOptions>(InStruct.DataPointer(), InStruct.Property()->ChildByID(0x6B5E7509));
|
||||
mLightLayer = CIntRef(InStruct.DataPointer(), InStruct.Property()->ChildByID(0x1F715FD3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int LightLayerIndex() const
|
||||
{
|
||||
if (!mpLightLayer)
|
||||
return 0;
|
||||
else
|
||||
return mpLightLayer->Get();
|
||||
return mLightLayer.IsValid() ? mLightLayer.Get() : 0;
|
||||
}
|
||||
|
||||
inline EWorldLightingOptions WorldLightingOptions() const
|
||||
{
|
||||
if (mpWorldLightingOptions)
|
||||
return (EWorldLightingOptions) mpWorldLightingOptions->Get();
|
||||
else
|
||||
return eNormalLighting;
|
||||
return mWorldLightingOptions.IsValid() ? mWorldLightingOptions.Get() : eNormalLighting;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@ TEMPLATE = lib
|
||||
DESTDIR = $$BUILD_DIR/Core
|
||||
DEFINES += GLEW_STATIC
|
||||
|
||||
win32 {
|
||||
QMAKE_CXXFLAGS += -std:c++17
|
||||
}
|
||||
unix {
|
||||
target.path = /usr/lib
|
||||
QMAKE_CXXFLAGS += /WX
|
||||
@@ -26,11 +29,9 @@ CONFIG (debug, debug|release) {
|
||||
# Debug Libs
|
||||
LIBS += -L$$BUILD_DIR/Common/ -lCommond \
|
||||
-L$$BUILD_DIR/Math/ -lMathd \
|
||||
-L$$EXTERNALS_DIR/assimp/lib/ -lassimp-vc140-mtd \
|
||||
-L$$EXTERNALS_DIR/lzo-2.09/lib/ -llzo2d \
|
||||
-L$$EXTERNALS_DIR/nodtool/build/debug/lib/ -lnod \
|
||||
-L$$EXTERNALS_DIR/nodtool/build/debug/logvisor/ -llogvisor \
|
||||
-L$$EXTERNALS_DIR/tinyxml2/lib/ -ltinyxml2d \
|
||||
-L$$EXTERNALS_DIR/assimp/lib/Debug -lassimp-vc140-mt \
|
||||
-L$$EXTERNALS_DIR/nod/lib/Debug -lnod \
|
||||
-L$$EXTERNALS_DIR/nod/logvisor/Debug -llogvisor \
|
||||
-L$$EXTERNALS_DIR/zlib/lib/ -lzlibd
|
||||
|
||||
# Debug Target Dependencies
|
||||
@@ -48,11 +49,9 @@ CONFIG (release, debug|release) {
|
||||
# Release Libs
|
||||
LIBS += -L$$BUILD_DIR/Common/ -lCommon \
|
||||
-L$$BUILD_DIR/Math/ -lMath \
|
||||
-L$$EXTERNALS_DIR/assimp/lib/ -lassimp-vc140-mt \
|
||||
-L$$EXTERNALS_DIR/lzo-2.09/lib/ -llzo2 \
|
||||
-L$$EXTERNALS_DIR/nodtool/build/release/lib/ -lnod \
|
||||
-L$$EXTERNALS_DIR/nodtool/build/release/logvisor -llogvisor \
|
||||
-L$$EXTERNALS_DIR/tinyxml2/lib/ -ltinyxml2 \
|
||||
-L$$EXTERNALS_DIR/assimp/lib/Release -lassimp-vc140-mt \
|
||||
-L$$EXTERNALS_DIR/nod/lib/Release -lnod \
|
||||
-L$$EXTERNALS_DIR/nod/logvisor/Release -llogvisor \
|
||||
-L$$EXTERNALS_DIR/zlib/lib/ -lzlib
|
||||
|
||||
# Release Target Dependencies
|
||||
@@ -63,18 +62,19 @@ CONFIG (release, debug|release) {
|
||||
}
|
||||
|
||||
# Debug/Release Libs
|
||||
LIBS += -L$$EXTERNALS_DIR/glew-2.0.0/lib/Release/x64 -lglew32s \
|
||||
LIBS += -L$$EXTERNALS_DIR/glew-2.1.0/lib/Release/x64 -lglew32s \
|
||||
-lopengl32
|
||||
|
||||
# Include Paths
|
||||
INCLUDEPATH += $$PWE_MAIN_INCLUDE \
|
||||
$$EXTERNALS_DIR/assimp/include \
|
||||
$$EXTERNALS_DIR/glew-2.0.0/include \
|
||||
$$EXTERNALS_DIR/lzo-2.09/include \
|
||||
$$EXTERNALS_DIR/nodtool/include \
|
||||
$$EXTERNALS_DIR/nodtool/logvisor/include \
|
||||
$$EXTERNALS_DIR/tinyxml2/include \
|
||||
$$EXTERNALS_DIR/zlib/include
|
||||
$$EXTERNALS_DIR/CodeGen/include \
|
||||
$$EXTERNALS_DIR/glew-2.1.0/include \
|
||||
$$EXTERNALS_DIR/lzo-2.10/include \
|
||||
$$EXTERNALS_DIR/nod/include \
|
||||
$$EXTERNALS_DIR/nod/logvisor/include \
|
||||
$$EXTERNALS_DIR/tinyxml2 \
|
||||
$$EXTERNALS_DIR/zlib
|
||||
|
||||
# Header Files
|
||||
HEADERS += \
|
||||
@@ -91,7 +91,6 @@ HEADERS += \
|
||||
Resource/Cooker/CMaterialCooker.h \
|
||||
Resource/Cooker/CModelCooker.h \
|
||||
Resource/Cooker/CSectionMgrOut.h \
|
||||
Resource/Cooker/CTemplateWriter.h \
|
||||
Resource/Cooker/CTextureEncoder.h \
|
||||
Resource/Cooker/CWorldCooker.h \
|
||||
Resource/Factory/CAnimSetLoader.h \
|
||||
@@ -103,7 +102,6 @@ HEADERS += \
|
||||
Resource/Factory/CScanLoader.h \
|
||||
Resource/Factory/CScriptLoader.h \
|
||||
Resource/Factory/CStringLoader.h \
|
||||
Resource/Factory/CTemplateLoader.h \
|
||||
Resource/Factory/CTextureDecoder.h \
|
||||
Resource/Factory/CWorldLoader.h \
|
||||
Resource/Model/CBasicModel.h \
|
||||
@@ -111,11 +109,9 @@ HEADERS += \
|
||||
Resource/Model/CStaticModel.h \
|
||||
Resource/Model/CVertex.h \
|
||||
Resource/Model/SSurface.h \
|
||||
Resource/Script/CMasterTemplate.h \
|
||||
Resource/Script/CScriptLayer.h \
|
||||
Resource/Script/CScriptObject.h \
|
||||
Resource/Script/CScriptTemplate.h \
|
||||
Resource/Script/EPropertyType.h \
|
||||
Resource/Script/EVolumeShape.h \
|
||||
Resource/CCollisionMesh.h \
|
||||
Resource/CCollisionMeshGroup.h \
|
||||
@@ -162,11 +158,7 @@ HEADERS += \
|
||||
OpenGL/CVertexBuffer.h \
|
||||
OpenGL/GLCommon.h \
|
||||
ScriptExtra/CRadiusSphereExtra.h \
|
||||
Resource/EGame.h \
|
||||
Resource/Cooker/CAreaCooker.h \
|
||||
Resource/Script/IPropertyValue.h \
|
||||
Resource/Script/IPropertyTemplate.h \
|
||||
Resource/Script/IProperty.h \
|
||||
Resource/Model/EVertexAttribute.h \
|
||||
Render/FRenderOptions.h \
|
||||
Scene/FShowFlags.h \
|
||||
@@ -231,7 +223,34 @@ HEADERS += \
|
||||
IProgressNotifier.h \
|
||||
IUIRelay.h \
|
||||
Resource/CResTypeFilter.h \
|
||||
GameProject/COpeningBanner.h
|
||||
GameProject/COpeningBanner.h \
|
||||
Resource/Script/Property/CPropertyNameGenerator.h \
|
||||
Resource/Script/Property/IProperty.h \
|
||||
Resource/Script/Property/CEnumProperty.h \
|
||||
Resource/Script/Property/CFlagsProperty.h \
|
||||
Resource/Script/Property/CAssetProperty.h \
|
||||
Resource/Script/Property/CPointerProperty.h \
|
||||
Resource/Script/Property/CArrayProperty.h \
|
||||
Resource/Script/Property/Properties.h \
|
||||
Resource/Script/Property/TPropertyRef.h \
|
||||
Resource/Script/Property/CBoolProperty.h \
|
||||
Resource/Script/Property/CByteProperty.h \
|
||||
Resource/Script/Property/CShortProperty.h \
|
||||
Resource/Script/Property/CIntProperty.h \
|
||||
Resource/Script/Property/CFloatProperty.h \
|
||||
Resource/Script/Property/CStringProperty.h \
|
||||
Resource/Script/Property/CSoundProperty.h \
|
||||
Resource/Script/Property/CAnimationProperty.h \
|
||||
Resource/Script/Property/CSequenceProperty.h \
|
||||
Resource/Script/Property/CSplineProperty.h \
|
||||
Resource/Script/Property/CAnimationSetProperty.h \
|
||||
Resource/Script/Property/CVectorProperty.h \
|
||||
Resource/Script/Property/CColorProperty.h \
|
||||
Resource/Script/Property/CStructProperty.h \
|
||||
Resource/Script/Property/CGuidProperty.h \
|
||||
Resource/Script/CGameTemplate.h \
|
||||
Resource/Script/NPropertyMap.h \
|
||||
Resource/Script/NGameList.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
@@ -243,7 +262,6 @@ SOURCES += \
|
||||
Resource/Area/CGameArea.cpp \
|
||||
Resource/Cooker/CMaterialCooker.cpp \
|
||||
Resource/Cooker/CModelCooker.cpp \
|
||||
Resource/Cooker/CTemplateWriter.cpp \
|
||||
Resource/Cooker/CTextureEncoder.cpp \
|
||||
Resource/Cooker/CWorldCooker.cpp \
|
||||
Resource/Factory/CAnimSetLoader.cpp \
|
||||
@@ -255,14 +273,12 @@ SOURCES += \
|
||||
Resource/Factory/CScanLoader.cpp \
|
||||
Resource/Factory/CScriptLoader.cpp \
|
||||
Resource/Factory/CStringLoader.cpp \
|
||||
Resource/Factory/CTemplateLoader.cpp \
|
||||
Resource/Factory/CTextureDecoder.cpp \
|
||||
Resource/Factory/CWorldLoader.cpp \
|
||||
Resource/Model/CBasicModel.cpp \
|
||||
Resource/Model/CModel.cpp \
|
||||
Resource/Model/CStaticModel.cpp \
|
||||
Resource/Model/SSurface.cpp \
|
||||
Resource/Script/CMasterTemplate.cpp \
|
||||
Resource/Script/CScriptObject.cpp \
|
||||
Resource/Script/CScriptTemplate.cpp \
|
||||
Resource/CCollisionMesh.cpp \
|
||||
@@ -296,8 +312,6 @@ SOURCES += \
|
||||
OpenGL/GLCommon.cpp \
|
||||
ScriptExtra/CRadiusSphereExtra.cpp \
|
||||
Resource/Cooker/CAreaCooker.cpp \
|
||||
Resource/Script/IPropertyTemplate.cpp \
|
||||
Resource/Script/IProperty.cpp \
|
||||
Scene/FShowFlags.cpp \
|
||||
Scene/CScene.cpp \
|
||||
Scene/CSceneIterator.cpp \
|
||||
@@ -340,4 +354,22 @@ SOURCES += \
|
||||
CompressionUtil.cpp \
|
||||
IUIRelay.cpp \
|
||||
GameProject\COpeningBanner.cpp \
|
||||
IProgressNotifier.cpp
|
||||
IProgressNotifier.cpp \
|
||||
Resource/Script/Property/CPropertyNameGenerator.cpp \
|
||||
Resource/Script/Property/IProperty.cpp \
|
||||
Resource/Script/Property/CStructProperty.cpp \
|
||||
Resource/Script/Property/CFlagsProperty.cpp \
|
||||
Resource/Script/CGameTemplate.cpp \
|
||||
Resource/Script/NPropertyMap.cpp \
|
||||
Resource/Script/NGameList.cpp
|
||||
|
||||
# Codegen
|
||||
CODEGEN_DIR = $$EXTERNALS_DIR/CodeGen
|
||||
CODEGEN_OUT_PATH = $$BUILD_DIR/Core/codegen_build/auto_codegen.cpp
|
||||
CODEGEN_SRC_PATH = $$PWD
|
||||
include($$EXTERNALS_DIR/CodeGen/codegen.pri)
|
||||
|
||||
# Library Sources
|
||||
SOURCES += $$EXTERNALS_DIR/lzo-2.10/src/lzo_init.c \
|
||||
$$EXTERNALS_DIR/lzo-2.10/src/lzo1x_9x.c \
|
||||
$$EXTERNALS_DIR/lzo-2.10/src/lzo1x_d1.c
|
||||
|
||||
@@ -43,7 +43,7 @@ void ApplyGeneratedName(CResourceEntry *pEntry, const TString& rkDir, const TStr
|
||||
|
||||
// trying to keep these as consistent with Retro's naming scheme as possible, and
|
||||
// for some reason in MP3 they started using all lowercase folder names...
|
||||
if (pEntry->Game() >= eCorruptionProto)
|
||||
if (pEntry->Game() >= EGame::CorruptionProto)
|
||||
SanitizedDir = SanitizedDir.ToLower();
|
||||
|
||||
pNewDir = pEntry->ResourceStore()->GetVirtualDirectory(SanitizedDir, true);
|
||||
@@ -245,9 +245,9 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||
{
|
||||
CMaterialPass *pPass = pMat->Pass(iPass);
|
||||
|
||||
bool IsLightmap = ( (pArea->Game() <= eEchoes && pMat->Options().HasFlag(CMaterial::eLightmap) && iPass == 0) ||
|
||||
(pArea->Game() >= eCorruptionProto && pPass->Type() == "DIFF") );
|
||||
bool IsBloomLightmap = (pArea->Game() >= eCorruptionProto && pPass->Type() == "BLOL");
|
||||
bool IsLightmap = ( (pArea->Game() <= EGame::Echoes && pMat->Options().HasFlag(CMaterial::eLightmap) && iPass == 0) ||
|
||||
(pArea->Game() >= EGame::CorruptionProto && pPass->Type() == "DIFF") );
|
||||
bool IsBloomLightmap = (pArea->Game() >= EGame::CorruptionProto && pPass->Type() == "BLOL");
|
||||
|
||||
TString TexName;
|
||||
|
||||
@@ -283,7 +283,8 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||
|
||||
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
|
||||
{
|
||||
CScriptObject *pInst = pLayer->InstanceByIndex(iInst);
|
||||
CScriptObject* pInst = pLayer->InstanceByIndex(iInst);
|
||||
CStructProperty* pProperties = pInst->Template()->Properties();
|
||||
|
||||
if (pInst->ObjectTypeID() == 0x42 || pInst->ObjectTypeID() == FOURCC('POIN'))
|
||||
{
|
||||
@@ -291,13 +292,13 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||
|
||||
if (Name.StartsWith("POI_", false))
|
||||
{
|
||||
TIDString ScanIDString = (pProj->Game() <= ePrime ? "0x4:0x0" : "0xBDBEC295:0xB94E9BE7");
|
||||
TAssetProperty *pScanProperty = TPropCast<TAssetProperty>(pInst->PropertyByIDString(ScanIDString));
|
||||
TIDString ScanIDString = (pProj->Game() <= EGame::Prime ? "0x4:0x0" : "0xBDBEC295:0xB94E9BE7");
|
||||
CAssetProperty *pScanProperty = TPropCast<CAssetProperty>(pProperties->ChildByIDString(ScanIDString));
|
||||
ASSERT(pScanProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
|
||||
|
||||
if (pScanProperty)
|
||||
{
|
||||
CAssetID ScanID = pScanProperty->Get();
|
||||
CAssetID ScanID = pScanProperty->Value(pInst->PropertyData());
|
||||
CResourceEntry *pEntry = pStore->FindEntry(ScanID);
|
||||
|
||||
if (pEntry && !pEntry->IsNamed())
|
||||
@@ -326,13 +327,13 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||
|
||||
if (Name.EndsWith(".STRG", false))
|
||||
{
|
||||
u32 StringPropID = (pProj->Game() <= ePrime ? 0x4 : 0x9182250C);
|
||||
TAssetProperty *pStringProperty = TPropCast<TAssetProperty>(pInst->Properties()->PropertyByID(StringPropID));
|
||||
u32 StringPropID = (pProj->Game() <= EGame::Prime ? 0x4 : 0x9182250C);
|
||||
CAssetProperty *pStringProperty = TPropCast<CAssetProperty>(pProperties->ChildByID(StringPropID));
|
||||
ASSERT(pStringProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
|
||||
|
||||
if (pStringProperty)
|
||||
{
|
||||
CAssetID StringID = pStringProperty->Get();
|
||||
CAssetID StringID = pStringProperty->Value(pInst->PropertyData());
|
||||
CResourceEntry *pEntry = pStore->FindEntry(StringID);
|
||||
|
||||
if (pEntry && !pEntry->IsNamed())
|
||||
@@ -352,13 +353,13 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||
else if (pInst->ObjectTypeID() == 0x0 || pInst->ObjectTypeID() == FOURCC('ACTR') ||
|
||||
pInst->ObjectTypeID() == 0x8 || pInst->ObjectTypeID() == FOURCC('PLAT'))
|
||||
{
|
||||
u32 ModelPropID = (pProj->Game() <= ePrime ? (pInst->ObjectTypeID() == 0x0 ? 0xA : 0x6) : 0xC27FFA8F);
|
||||
TAssetProperty *pModelProperty = TPropCast<TAssetProperty>(pInst->Properties()->PropertyByID(ModelPropID));
|
||||
u32 ModelPropID = (pProj->Game() <= EGame::Prime ? (pInst->ObjectTypeID() == 0x0 ? 0xA : 0x6) : 0xC27FFA8F);
|
||||
CAssetProperty *pModelProperty = TPropCast<CAssetProperty>(pProperties->ChildByID(ModelPropID));
|
||||
ASSERT(pModelProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
|
||||
|
||||
if (pModelProperty)
|
||||
{
|
||||
CAssetID ModelID = pModelProperty->Get();
|
||||
CAssetID ModelID = pModelProperty->Value(pInst->PropertyData());
|
||||
CResourceEntry *pEntry = pStore->FindEntry(ModelID);
|
||||
|
||||
if (pEntry && !pEntry->IsCategorized())
|
||||
@@ -414,8 +415,8 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||
{
|
||||
CMaterialPass *pPass = pMat->Pass(iPass);
|
||||
|
||||
bool IsLightmap = ( (pMat->Version() <= eEchoes && pMat->Options().HasFlag(CMaterial::eLightmap) && iPass == 0) ||
|
||||
(pMat->Version() >= eCorruptionProto && pPass->Type() == "DIFF") );
|
||||
bool IsLightmap = ( (pMat->Version() <= EGame::Echoes && pMat->Options().HasFlag(CMaterial::eLightmap) && iPass == 0) ||
|
||||
(pMat->Version() >= EGame::CorruptionProto && pPass->Type() == "DIFF") );
|
||||
|
||||
if (IsLightmap)
|
||||
{
|
||||
@@ -484,7 +485,7 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||
// Generate animation format names
|
||||
// Hacky syntax because animsets are under eAnimSet in MP1/2 and eCharacter in MP3/DKCR
|
||||
Log::Write("Processing animation data");
|
||||
CResourceIterator *pIter = (pProj->Game() <= eEchoes ? (CResourceIterator*) new TResourceIterator<eAnimSet> : (CResourceIterator*) new TResourceIterator<eCharacter>);
|
||||
CResourceIterator *pIter = (pProj->Game() <= EGame::Echoes ? (CResourceIterator*) new TResourceIterator<eAnimSet> : (CResourceIterator*) new TResourceIterator<eCharacter>);
|
||||
CResourceIterator& It = *pIter;
|
||||
|
||||
for (; It; ++It)
|
||||
@@ -504,7 +505,7 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||
if (pkChar->pSkeleton) ApplyGeneratedName(pkChar->pSkeleton->Entry(), SetDir, CharName);
|
||||
if (pkChar->pSkin) ApplyGeneratedName(pkChar->pSkin->Entry(), SetDir, CharName);
|
||||
|
||||
if (pProj->Game() >= eCorruptionProto && pProj->Game() <= eCorruption && pkChar->ID == 0)
|
||||
if (pProj->Game() >= EGame::CorruptionProto && pProj->Game() <= EGame::Corruption && pkChar->ID == 0)
|
||||
{
|
||||
CResourceEntry *pAnimDataEntry = gpResourceStore->FindEntry( pkChar->AnimDataID );
|
||||
|
||||
@@ -606,7 +607,7 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||
CScan *pScan = (CScan*) It->Load();
|
||||
TString ScanName;
|
||||
|
||||
if (pProj->Game() >= eEchoesDemo)
|
||||
if (pProj->Game() >= EGame::EchoesDemo)
|
||||
{
|
||||
CAssetID DisplayAsset = pScan->LogbookDisplayAssetID();
|
||||
CResourceEntry *pEntry = pStore->FindEntry(DisplayAsset);
|
||||
@@ -621,7 +622,7 @@ void GenerateAssetNames(CGameProject *pProj)
|
||||
|
||||
ApplyGeneratedName(pScan->Entry(), It->DirectoryPath(), ScanName);
|
||||
|
||||
if (!ScanName.IsEmpty() && pProj->Game() <= ePrime)
|
||||
if (!ScanName.IsEmpty() && pProj->Game() <= EGame::Prime)
|
||||
{
|
||||
CAssetID FrameID = pScan->GuiFrame();
|
||||
CResourceEntry *pEntry = pStore->FindEntry(FrameID);
|
||||
|
||||
@@ -36,7 +36,7 @@ bool CAssetNameMap::SaveAssetNames(TString Path /*= ""*/)
|
||||
if (Path.IsEmpty())
|
||||
Path = DefaultNameMapPath(mIDLength);
|
||||
|
||||
EGame Game = (mIDLength == e32Bit ? ePrime : eCorruption);
|
||||
EGame Game = (mIDLength == e32Bit ? EGame::Prime : EGame::Corruption);
|
||||
CXMLWriter Writer(Path, "AssetNameMap", 0, Game);
|
||||
Serialize(Writer);
|
||||
return Writer.Save();
|
||||
@@ -58,7 +58,7 @@ bool CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rO
|
||||
|
||||
else
|
||||
{
|
||||
EGame Game = (ID.Length() == e32Bit ? ePrime : eCorruption);
|
||||
EGame Game = (ID.Length() == e32Bit ? EGame::Prime : EGame::Corruption);
|
||||
rOutDirectory = CResourceStore::StaticDefaultResourceDirPath(Game);
|
||||
rOutName = ID.ToString();
|
||||
rOutAutoGenDir = true;
|
||||
@@ -133,7 +133,7 @@ void CAssetNameMap::CopyFromStore(CResourceStore *pStore /*= gpResourceStore*/)
|
||||
// ************ PRIVATE ************
|
||||
void CAssetNameMap::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL_CONTAINER("AssetNameMap", mMap, "Asset");
|
||||
rArc << SerialParameter("AssetNameMap", mMap);
|
||||
|
||||
if (rArc.IsReader())
|
||||
PostLoadValidate();
|
||||
|
||||
@@ -28,7 +28,11 @@ class CAssetNameMap
|
||||
|
||||
void Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL_AUTO(Name) << SERIAL_AUTO(Directory) << SERIAL_AUTO(Type) << SERIAL_AUTO(AutoGenName) << SERIAL_AUTO(AutoGenDir);
|
||||
rArc << SerialParameter("Name", Name)
|
||||
<< SerialParameter("Directory", Directory)
|
||||
<< SerialParameter("Type", Type)
|
||||
<< SerialParameter("AutoGenName", AutoGenName)
|
||||
<< SerialParameter("AutoGenDir", AutoGenDir);
|
||||
}
|
||||
|
||||
bool operator<(const SAssetNameInfo& rkOther) const
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#include "CDependencyTree.h"
|
||||
#include "Core/GameProject/CGameProject.h"
|
||||
#include "Core/Resource/Animation/CAnimSet.h"
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include "Core/Resource/Script/CGameTemplate.h"
|
||||
#include "Core/Resource/Script/CScriptLayer.h"
|
||||
#include "Core/Resource/Script/CScriptObject.h"
|
||||
|
||||
CDependencyNodeFactory gDependencyNodeFactory;
|
||||
#include "Core/Resource/Script/NGameList.h"
|
||||
|
||||
// ************ IDependencyNode ************
|
||||
IDependencyNode::~IDependencyNode()
|
||||
@@ -31,6 +30,24 @@ void IDependencyNode::GetAllResourceReferences(std::set<CAssetID>& rOutSet) cons
|
||||
mChildren[iChild]->GetAllResourceReferences(rOutSet);
|
||||
}
|
||||
|
||||
// Serialization constructor
|
||||
IDependencyNode* IDependencyNode::ArchiveConstructor(EDependencyNodeType Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case eDNT_DependencyTree: return new CDependencyTree;
|
||||
case eDNT_ResourceDependency: return new CResourceDependency;
|
||||
case eDNT_ScriptInstance: return new CScriptInstanceDependency;
|
||||
case eDNT_ScriptProperty: return new CPropertyDependency;
|
||||
case eDNT_CharacterProperty: return new CCharPropertyDependency;
|
||||
case eDNT_SetCharacter: return new CSetCharacterDependency;
|
||||
case eDNT_SetAnimation: return new CSetAnimationDependency;
|
||||
case eDNT_AnimEvent: return new CAnimEventDependency;
|
||||
case eDNT_Area: return new CAreaDependencyTree;
|
||||
default: ASSERT(false); return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ************ CDependencyTree ************
|
||||
EDependencyNodeType CDependencyTree::Type() const
|
||||
{
|
||||
@@ -39,7 +56,7 @@ EDependencyNodeType CDependencyTree::Type() const
|
||||
|
||||
void CDependencyTree::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
|
||||
rArc << SerialParameter("Children", mChildren);
|
||||
}
|
||||
|
||||
void CDependencyTree::AddChild(IDependencyNode *pNode)
|
||||
@@ -78,7 +95,7 @@ EDependencyNodeType CResourceDependency::Type() const
|
||||
|
||||
void CResourceDependency::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL("ID", mID);
|
||||
rArc << SerialParameter("ID", mID);
|
||||
}
|
||||
|
||||
void CResourceDependency::GetAllResourceReferences(std::set<CAssetID>& rOutSet) const
|
||||
@@ -99,7 +116,7 @@ EDependencyNodeType CPropertyDependency::Type() const
|
||||
|
||||
void CPropertyDependency::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL("PropertyID", mIDString);
|
||||
rArc << SerialParameter("PropertyID", mIDString);
|
||||
CResourceDependency::Serialize(rArc);
|
||||
}
|
||||
|
||||
@@ -112,7 +129,7 @@ EDependencyNodeType CCharPropertyDependency::Type() const
|
||||
void CCharPropertyDependency::Serialize(IArchive& rArc)
|
||||
{
|
||||
CPropertyDependency::Serialize(rArc);
|
||||
rArc << SERIAL("CharIndex", mUsedChar);
|
||||
rArc << SerialParameter("CharIndex", mUsedChar);
|
||||
}
|
||||
|
||||
// ************ CScriptInstanceDependency ************
|
||||
@@ -123,8 +140,8 @@ EDependencyNodeType CScriptInstanceDependency::Type() const
|
||||
|
||||
void CScriptInstanceDependency::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL("ObjectType", mObjectType)
|
||||
<< SERIAL_ABSTRACT_CONTAINER("Properties", mChildren, "Property", &gDependencyNodeFactory);
|
||||
rArc << SerialParameter("ObjectType", mObjectType)
|
||||
<< SerialParameter("Properties", mChildren);
|
||||
}
|
||||
|
||||
// Static
|
||||
@@ -132,28 +149,32 @@ CScriptInstanceDependency* CScriptInstanceDependency::BuildTree(CScriptObject *p
|
||||
{
|
||||
CScriptInstanceDependency *pInst = new CScriptInstanceDependency();
|
||||
pInst->mObjectType = pInstance->ObjectTypeID();
|
||||
ParseStructDependencies(pInst, pInstance->Properties());
|
||||
ParseStructDependencies(pInst, pInstance, pInstance->Template()->Properties());
|
||||
return pInst;
|
||||
}
|
||||
|
||||
void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependency *pInst, CPropertyStruct *pStruct)
|
||||
void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependency* pInst, CScriptObject* pInstance, CStructProperty *pStruct)
|
||||
{
|
||||
// Recursive function for parsing script dependencies and loading them into the script instance dependency
|
||||
for (u32 iProp = 0; iProp < pStruct->Count(); iProp++)
|
||||
void* pPropertyData = pInstance->PropertyData();
|
||||
|
||||
for (u32 PropertyIdx = 0; PropertyIdx < pStruct->NumChildren(); PropertyIdx++)
|
||||
{
|
||||
IProperty *pProp = pStruct->PropertyByIndex(iProp);
|
||||
IProperty *pProp = pStruct->ChildByIndex(PropertyIdx);
|
||||
EPropertyType Type = pProp->Type();
|
||||
|
||||
if (Type == eStructProperty || Type == eArrayProperty)
|
||||
ParseStructDependencies(pInst, static_cast<CPropertyStruct*>(pProp));
|
||||
// Technically we aren't parsing array children, but it's not really worth refactoring this function
|
||||
// to support it when there aren't any array properties that contain any asset references anyway...
|
||||
if (Type == EPropertyType::Struct)
|
||||
ParseStructDependencies(pInst, pInstance, TPropCast<CStructProperty>(pProp));
|
||||
|
||||
else if (Type == eSoundProperty)
|
||||
else if (Type == EPropertyType::Sound)
|
||||
{
|
||||
u32 SoundID = static_cast<TSoundProperty*>(pProp)->Get();
|
||||
u32 SoundID = TPropCast<CSoundProperty>(pProp)->Value(pPropertyData);
|
||||
|
||||
if (SoundID != -1)
|
||||
{
|
||||
CGameProject *pProj = pStruct->Instance()->Area()->Entry()->Project();
|
||||
CGameProject *pProj = pInstance->Area()->Entry()->Project();
|
||||
SSoundInfo Info = pProj->AudioManager()->GetSoundInfo(SoundID);
|
||||
|
||||
if (Info.pAudioGroup)
|
||||
@@ -164,9 +185,9 @@ void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependenc
|
||||
}
|
||||
}
|
||||
|
||||
else if (Type == eAssetProperty)
|
||||
else if (Type == EPropertyType::Asset)
|
||||
{
|
||||
CAssetID ID = static_cast<TAssetProperty*>(pProp)->Get();
|
||||
CAssetID ID = TPropCast<CAssetProperty>(pProp)->Value(pPropertyData);
|
||||
|
||||
if (ID.IsValid())
|
||||
{
|
||||
@@ -175,16 +196,15 @@ void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependenc
|
||||
}
|
||||
}
|
||||
|
||||
else if (Type == eCharacterProperty)
|
||||
else if (Type == EPropertyType::AnimationSet)
|
||||
{
|
||||
TCharacterProperty *pChar = static_cast<TCharacterProperty*>(pProp);
|
||||
CAnimationParameters Params = pChar->Get();
|
||||
CAnimationParameters Params = TPropCast<CAnimationSetProperty>(pProp)->Value(pPropertyData);
|
||||
CAssetID ID = Params.ID();
|
||||
|
||||
if (ID.IsValid())
|
||||
{
|
||||
// Character sets are removed starting in MP3, so we only need char property dependencies in Echoes and earlier
|
||||
if (pStruct->Instance()->Area()->Game() <= eEchoes)
|
||||
if (pStruct->Game() <= EGame::Echoes)
|
||||
{
|
||||
CCharPropertyDependency *pDep = new CCharPropertyDependency(pProp->IDString(true), ID, Params.CharacterIndex());
|
||||
pInst->mChildren.push_back(pDep);
|
||||
@@ -207,8 +227,8 @@ EDependencyNodeType CSetCharacterDependency::Type() const
|
||||
|
||||
void CSetCharacterDependency::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL("CharSetIndex", mCharSetIndex)
|
||||
<< SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
|
||||
rArc << SerialParameter("CharSetIndex", mCharSetIndex)
|
||||
<< SerialParameter("Children", mChildren);
|
||||
}
|
||||
|
||||
CSetCharacterDependency* CSetCharacterDependency::BuildTree(const SSetCharacter& rkChar)
|
||||
@@ -252,8 +272,8 @@ EDependencyNodeType CSetAnimationDependency::Type() const
|
||||
|
||||
void CSetAnimationDependency::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL_CONTAINER("CharacterIndices", mCharacterIndices, "Index")
|
||||
<< SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
|
||||
rArc << SerialParameter("CharacterIndices", mCharacterIndices)
|
||||
<< SerialParameter("Children", mChildren);
|
||||
}
|
||||
|
||||
CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOwnerSet, u32 AnimIndex)
|
||||
@@ -279,7 +299,7 @@ CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOw
|
||||
const CAnimPrimitive& rkPrim = *Iter;
|
||||
pTree->AddDependency(rkPrim.Animation());
|
||||
|
||||
if (pkOwnerSet->Game() >= eEchoesDemo)
|
||||
if (pkOwnerSet->Game() >= EGame::EchoesDemo)
|
||||
{
|
||||
CAnimEventData *pEvents = pkOwnerSet->AnimationEventData(rkPrim.ID());
|
||||
ASSERT(pEvents && !pEvents->Entry());
|
||||
@@ -299,7 +319,7 @@ EDependencyNodeType CAnimEventDependency::Type() const
|
||||
void CAnimEventDependency::Serialize(IArchive& rArc)
|
||||
{
|
||||
CResourceDependency::Serialize(rArc);
|
||||
rArc << SERIAL("CharacterIndex", mCharIndex);
|
||||
rArc << SerialParameter("CharacterIndex", mCharIndex);
|
||||
}
|
||||
|
||||
// ************ CAreaDependencyTree ************
|
||||
@@ -311,7 +331,7 @@ EDependencyNodeType CAreaDependencyTree::Type() const
|
||||
void CAreaDependencyTree::Serialize(IArchive& rArc)
|
||||
{
|
||||
CDependencyTree::Serialize(rArc);
|
||||
rArc << SERIAL_CONTAINER("LayerOffsets", mLayerOffsets, "Offset");
|
||||
rArc << SerialParameter("LayerOffsets", mLayerOffsets);
|
||||
}
|
||||
|
||||
void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer, const std::vector<CAssetID>& rkExtraDeps)
|
||||
@@ -326,7 +346,7 @@ void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer, const std::vector
|
||||
ASSERT(pTree != nullptr);
|
||||
|
||||
// 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)
|
||||
if (pTree->NumChildren() > 0 || pLayer->Area()->Game() >= EGame::EchoesDemo)
|
||||
{
|
||||
mChildren.push_back(pTree);
|
||||
pTree->GetAllResourceReferences(UsedIDs);
|
||||
@@ -341,7 +361,7 @@ void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer, const std::vector
|
||||
|
||||
void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>& rModuleDepsOut, std::vector<u32>& rModuleLayerOffsetsOut) const
|
||||
{
|
||||
CMasterTemplate *pMaster = CMasterTemplate::MasterForGame(Game);
|
||||
CGameTemplate *pGame = NGameList::GetGameTemplate(Game);
|
||||
|
||||
// Output module list will be split per-script layer
|
||||
// The output offset list contains two offsets per layer - start index and end index
|
||||
@@ -367,7 +387,7 @@ void CAreaDependencyTree::GetModuleDependencies(EGame Game, std::vector<TString>
|
||||
if (UsedObjectTypes.find(ObjType) == UsedObjectTypes.end())
|
||||
{
|
||||
// Get the module list for this object type and check whether any of them are new before adding them to the output list
|
||||
CScriptTemplate *pTemplate = pMaster->TemplateByID(ObjType);
|
||||
CScriptTemplate *pTemplate = pGame->TemplateByID(ObjType);
|
||||
const std::vector<TString>& rkModules = pTemplate->RequiredModules();
|
||||
|
||||
for (u32 iMod = 0; iMod < rkModules.size(); iMod++)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
class CScriptLayer;
|
||||
class CScriptObject;
|
||||
class CPropertyStruct;
|
||||
class CStructProperty;
|
||||
class CAnimSet;
|
||||
class CAnimationParameters;
|
||||
struct SSetCharacter;
|
||||
@@ -40,6 +40,9 @@ public:
|
||||
virtual void GetAllResourceReferences(std::set<CAssetID>& rOutSet) const;
|
||||
virtual bool HasDependency(const CAssetID& rkID) const;
|
||||
|
||||
// Serialization constructor
|
||||
static IDependencyNode* ArchiveConstructor(EDependencyNodeType Type);
|
||||
|
||||
// Accessors
|
||||
inline u32 NumChildren() const { return mChildren.size(); }
|
||||
inline IDependencyNode* ChildByIndex(u32 Index) const { return mChildren[Index]; }
|
||||
@@ -142,7 +145,7 @@ public:
|
||||
// Static
|
||||
static CScriptInstanceDependency* BuildTree(CScriptObject *pInstance);
|
||||
protected:
|
||||
static void ParseStructDependencies(CScriptInstanceDependency *pTree, CPropertyStruct *pStruct);
|
||||
static void ParseStructDependencies(CScriptInstanceDependency *pTree, CScriptObject* pInstance, CStructProperty *pStruct);
|
||||
};
|
||||
|
||||
// Node representing an animset character. Indicates what index the character is within the animset.
|
||||
@@ -223,28 +226,5 @@ public:
|
||||
inline u32 ScriptLayerOffset(u32 LayerIdx) const { return mLayerOffsets[LayerIdx]; }
|
||||
};
|
||||
|
||||
// Dependency node factory for serialization
|
||||
class CDependencyNodeFactory
|
||||
{
|
||||
public:
|
||||
IDependencyNode* SpawnObject(u32 NodeID)
|
||||
{
|
||||
switch (NodeID)
|
||||
{
|
||||
case eDNT_DependencyTree: return new CDependencyTree;
|
||||
case eDNT_ResourceDependency: return new CResourceDependency;
|
||||
case eDNT_ScriptInstance: return new CScriptInstanceDependency;
|
||||
case eDNT_ScriptProperty: return new CPropertyDependency;
|
||||
case eDNT_CharacterProperty: return new CCharPropertyDependency;
|
||||
case eDNT_SetCharacter: return new CSetCharacterDependency;
|
||||
case eDNT_SetAnimation: return new CSetAnimationDependency;
|
||||
case eDNT_AnimEvent: return new CAnimEventDependency;
|
||||
case eDNT_Area: return new CAreaDependencyTree;
|
||||
default: ASSERT(false); return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
extern CDependencyNodeFactory gDependencyNodeFactory;
|
||||
|
||||
#endif // CDEPENDENCYTREE
|
||||
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
#include "CResourceStore.h"
|
||||
#include "Core/CompressionUtil.h"
|
||||
#include "Core/Resource/CWorld.h"
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include "Core/Resource/Script/CGameTemplate.h"
|
||||
#include <Common/AssertMacro.h>
|
||||
#include <Common/CScopedTimer.h>
|
||||
#include <Common/FileIO.h>
|
||||
#include <Common/FileUtil.h>
|
||||
#include <Common/Serialization/CXMLWriter.h>
|
||||
|
||||
#include <nod/nod.hpp>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#define LOAD_PAKS 1
|
||||
@@ -27,8 +29,8 @@ CGameExporter::CGameExporter(EDiscType DiscType, EGame Game, bool FrontEnd, EReg
|
||||
, mFrontEnd(FrontEnd)
|
||||
, mpProgress(nullptr)
|
||||
{
|
||||
ASSERT(mGame != eUnknownGame);
|
||||
ASSERT(mRegion != eRegion_Unknown);
|
||||
ASSERT(mGame != EGame::Invalid);
|
||||
ASSERT(mRegion != ERegion::Unknown);
|
||||
}
|
||||
|
||||
bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAssetNameMap *pNameMap, CGameInfo *pGameInfo, IProgressNotifier *pProgress)
|
||||
@@ -112,15 +114,15 @@ bool CGameExporter::ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot)
|
||||
|
||||
switch (mGame)
|
||||
{
|
||||
case ePrime:
|
||||
case EGame::Prime:
|
||||
return ( (mDiscType == eDT_WiiDeAsobu && pkNode->getName() == "MP1JPN") ||
|
||||
(mDiscType == eDT_Trilogy && pkNode->getName() == "MP1") );
|
||||
|
||||
case eEchoes:
|
||||
case EGame::Echoes:
|
||||
return ( (mDiscType == eDT_WiiDeAsobu && pkNode->getName() == "MP2JPN") ||
|
||||
(mDiscType == eDT_Trilogy && pkNode->getName() == "MP2") );
|
||||
|
||||
case eCorruption:
|
||||
case EGame::Corruption:
|
||||
return (mDiscType == eDT_Trilogy && pkNode->getName() == "MP3");
|
||||
|
||||
default:
|
||||
@@ -140,15 +142,15 @@ bool CGameExporter::ShouldExportDiscNode(const nod::Node *pkNode, bool IsInRoot)
|
||||
|
||||
switch (mGame)
|
||||
{
|
||||
case ePrime:
|
||||
case EGame::Prime:
|
||||
return ( (mDiscType == eDT_WiiDeAsobu && pkNode->getName() == "rs5mp1jpn_p.dol") ||
|
||||
(mDiscType == eDT_Trilogy && pkNode->getName() == "rs5mp1_p.dol") );
|
||||
|
||||
case eEchoes:
|
||||
case EGame::Echoes:
|
||||
return ( (mDiscType == eDT_WiiDeAsobu && pkNode->getName() == "rs5mp2jpn_p.dol") ||
|
||||
(mDiscType == eDT_Trilogy && pkNode->getName() == "rs5mp2_p.dol") );
|
||||
|
||||
case eCorruption:
|
||||
case EGame::Corruption:
|
||||
return (mDiscType == eDT_Trilogy && pkNode->getName() == "rs5mp3_p.dol");
|
||||
|
||||
default:
|
||||
@@ -176,11 +178,11 @@ bool CGameExporter::ExtractDiscData()
|
||||
FileUtil::MakeDirectory(AbsDiscDir);
|
||||
|
||||
// Extract disc filesystem
|
||||
nod::Partition *pDataPartition = mpDisc->getDataPartition();
|
||||
nod::IPartition *pDataPartition = mpDisc->getDataPartition();
|
||||
nod::ExtractionContext Context;
|
||||
Context.force = false;
|
||||
Context.progressCB = [&](const std::string& rkDesc, float ProgressPercent) {
|
||||
mpProgress->Report((int) (ProgressPercent * 10000), 10000, rkDesc);
|
||||
Context.progressCB = [&](const std::string_view rkDesc, float ProgressPercent) {
|
||||
mpProgress->Report((int) (ProgressPercent * 10000), 10000, rkDesc.data());
|
||||
};
|
||||
|
||||
TString FilesDir = AbsDiscDir + "files/";
|
||||
@@ -223,7 +225,7 @@ bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TStr
|
||||
|
||||
if (Iter->getKind() == nod::Node::Kind::File)
|
||||
{
|
||||
TString FilePath = rkDir + Iter->getName();
|
||||
TString FilePath = rkDir + Iter->getName().data();
|
||||
bool Success = Iter->extractToDirectory(*rkDir.ToUTF16(), rkContext);
|
||||
if (!Success) return false;
|
||||
|
||||
@@ -237,7 +239,7 @@ bool CGameExporter::ExtractDiscNodeRecursive(const nod::Node *pkNode, const TStr
|
||||
|
||||
else
|
||||
{
|
||||
TString Subdir = rkDir + Iter->getName() + "/";
|
||||
TString Subdir = rkDir + Iter->getName().data() + "/";
|
||||
bool Success = FileUtil::MakeDirectory(Subdir);
|
||||
if (!Success) return false;
|
||||
|
||||
@@ -274,7 +276,7 @@ void CGameExporter::LoadPaks()
|
||||
CPackage *pPackage = new CPackage(mpProject, PakPath.GetFileName(false), RelPakPath);
|
||||
|
||||
// MP1-MP3Proto
|
||||
if (mGame < eCorruption)
|
||||
if (mGame < EGame::Corruption)
|
||||
{
|
||||
u32 PakVersion = Pak.ReadLong();
|
||||
Pak.Seek(0x4, SEEK_CUR);
|
||||
@@ -392,7 +394,7 @@ void CGameExporter::LoadPaks()
|
||||
mResourceMap[ResID] = SResourceInstance { PakPath, ResID, Type, Offset, Size, Compressed, false };
|
||||
|
||||
// Check for duplicate resources (unnecessary for DKCR)
|
||||
if (mGame != eReturns)
|
||||
if (mGame != EGame::DKCReturns)
|
||||
{
|
||||
if (Type == "MREA")
|
||||
{
|
||||
@@ -434,9 +436,9 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
|
||||
// Handle compression
|
||||
if (rkResource.Compressed)
|
||||
{
|
||||
bool ZlibCompressed = (mGame <= eEchoesDemo || mGame == eReturns);
|
||||
bool ZlibCompressed = (mGame <= EGame::EchoesDemo || mGame == EGame::DKCReturns);
|
||||
|
||||
if (mGame <= eCorruptionProto)
|
||||
if (mGame <= EGame::CorruptionProto)
|
||||
{
|
||||
std::vector<u8> CompressedData(rkResource.PakSize);
|
||||
|
||||
@@ -682,14 +684,14 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||
{
|
||||
// World names are basically formatted differently in every game...
|
||||
// MP1 demo - Remove ! from the beginning
|
||||
if (mGame == ePrimeDemo)
|
||||
if (mGame == EGame::PrimeDemo)
|
||||
{
|
||||
if (WorldName.StartsWith('!'))
|
||||
WorldName = WorldName.ChopFront(1);
|
||||
}
|
||||
|
||||
// MP1 - Remove prefix characters and ending date
|
||||
else if (mGame == ePrime)
|
||||
else if (mGame == EGame::Prime)
|
||||
{
|
||||
WorldName = WorldName.ChopFront(2);
|
||||
bool StartedDate = false;
|
||||
@@ -708,7 +710,7 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||
}
|
||||
|
||||
// MP2 demo - Use text between the first and second underscores
|
||||
else if (mGame == eEchoesDemo)
|
||||
else if (mGame == EGame::EchoesDemo)
|
||||
{
|
||||
u32 UnderscoreA = WorldName.IndexOf('_');
|
||||
u32 UnderscoreB = WorldName.IndexOf('_', UnderscoreA + 1);
|
||||
@@ -718,7 +720,7 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||
}
|
||||
|
||||
// MP2 - Remove text before first underscore and after last underscore, strip remaining underscores (except multiplayer maps, which have one underscore)
|
||||
else if (mGame == eEchoes)
|
||||
else if (mGame == EGame::Echoes)
|
||||
{
|
||||
u32 FirstUnderscore = WorldName.IndexOf('_');
|
||||
u32 LastUnderscore = WorldName.LastIndexOf('_');
|
||||
@@ -732,7 +734,7 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||
}
|
||||
|
||||
// MP3 proto - Remove ! from the beginning and all text after last underscore
|
||||
else if (mGame == eCorruptionProto)
|
||||
else if (mGame == EGame::CorruptionProto)
|
||||
{
|
||||
if (WorldName.StartsWith('!'))
|
||||
WorldName = WorldName.ChopFront(1);
|
||||
@@ -742,7 +744,7 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||
}
|
||||
|
||||
// MP3 - Remove text after last underscore
|
||||
else if (mGame == eCorruption)
|
||||
else if (mGame == EGame::Corruption)
|
||||
{
|
||||
u32 LastUnderscore = WorldName.LastIndexOf('_');
|
||||
|
||||
@@ -751,7 +753,7 @@ TString CGameExporter::MakeWorldName(CAssetID WorldID)
|
||||
}
|
||||
|
||||
// DKCR - Remove text prior to first underscore
|
||||
else if (mGame == eReturns)
|
||||
else if (mGame == EGame::DKCReturns)
|
||||
{
|
||||
u32 Underscore = WorldName.IndexOf('_');
|
||||
WorldName = WorldName.ChopFront(Underscore + 1);
|
||||
|
||||
@@ -24,7 +24,7 @@ bool CGameInfo::LoadGameInfo(TString Path)
|
||||
|
||||
bool CGameInfo::SaveGameInfo(TString Path /*= ""*/)
|
||||
{
|
||||
ASSERT(mGame != eUnknownGame); // can't save game info that was never loaded
|
||||
ASSERT(mGame != EGame::Invalid); // can't save game info that was never loaded
|
||||
|
||||
if (Path.IsEmpty()) Path = GetDefaultGameInfoPath(mGame);
|
||||
CXMLWriter Writer(Path, "GameInfo", 0, mGame);
|
||||
@@ -35,16 +35,16 @@ bool CGameInfo::SaveGameInfo(TString Path /*= ""*/)
|
||||
void CGameInfo::Serialize(IArchive& rArc)
|
||||
{
|
||||
// Validate game
|
||||
if (rArc.IsReader() && mGame != eUnknownGame)
|
||||
if (rArc.IsReader() && mGame != EGame::Invalid)
|
||||
{
|
||||
ASSERT(mGame == rArc.Game());
|
||||
}
|
||||
|
||||
// Serialize data
|
||||
rArc << SERIAL_CONTAINER("GameBuilds", mBuilds, "Build");
|
||||
rArc << SerialParameter("GameBuilds", mBuilds);
|
||||
|
||||
if (mGame <= ePrime)
|
||||
rArc << SERIAL_CONTAINER("AreaNameMap", mAreaNameMap, "AreaName");
|
||||
if (mGame <= EGame::Prime)
|
||||
rArc << SerialParameter("AreaNameMap", mAreaNameMap);
|
||||
}
|
||||
|
||||
TString CGameInfo::GetBuildName(float BuildVer, ERegion Region) const
|
||||
@@ -69,9 +69,9 @@ TString CGameInfo::GetAreaName(const CAssetID &rkID) const
|
||||
// ************ STATIC ************
|
||||
EGame CGameInfo::RoundGame(EGame Game)
|
||||
{
|
||||
if (Game == ePrimeDemo) return ePrime;
|
||||
if (Game == eEchoesDemo) return eEchoes;
|
||||
if (Game == eCorruptionProto) return eCorruption;
|
||||
if (Game == EGame::PrimeDemo) return EGame::Prime;
|
||||
if (Game == EGame::EchoesDemo) return EGame::Echoes;
|
||||
if (Game == EGame::CorruptionProto) return EGame::Corruption;
|
||||
return Game;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ TString CGameInfo::GetDefaultGameInfoPath(EGame Game)
|
||||
{
|
||||
Game = RoundGame(Game);
|
||||
|
||||
if (Game == eUnknownGame)
|
||||
if (Game == EGame::Invalid)
|
||||
return "";
|
||||
|
||||
TString GameName = GetGameShortName(Game);
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
const TString gkGameInfoDir = "../resources/gameinfo";
|
||||
const TString gkGameInfoExt = "xml";
|
||||
|
||||
//@todo merge this class into CGameTemplate
|
||||
// they serve similar purposes, no real reason for them to be different classes
|
||||
class CGameInfo
|
||||
{
|
||||
EGame mGame;
|
||||
@@ -24,7 +26,9 @@ class CGameInfo
|
||||
|
||||
void Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL_AUTO(Version) << SERIAL_AUTO(Region) << SERIAL_AUTO(Name);
|
||||
rArc << SerialParameter("Version", Version)
|
||||
<< SerialParameter("Region", Region)
|
||||
<< SerialParameter("Name", Name);
|
||||
}
|
||||
};
|
||||
std::vector<SBuildInfo> mBuilds;
|
||||
@@ -34,7 +38,7 @@ class CGameInfo
|
||||
|
||||
public:
|
||||
CGameInfo()
|
||||
: mGame(eUnknownGame)
|
||||
: mGame(EGame::Invalid)
|
||||
{}
|
||||
|
||||
bool LoadGameInfo(EGame Game);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "CGameProject.h"
|
||||
#include "IUIRelay.h"
|
||||
#include "Core/Resource/Factory/CTemplateLoader.h"
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include "Core/Resource/Script/CGameTemplate.h"
|
||||
#include <Common/Serialization/XML.h>
|
||||
#include <nod/nod.hpp>
|
||||
|
||||
@@ -36,10 +35,10 @@ bool CGameProject::Save()
|
||||
|
||||
bool CGameProject::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL("Name", mProjectName)
|
||||
<< SERIAL("Region", mRegion)
|
||||
<< SERIAL("GameID", mGameID)
|
||||
<< SERIAL("BuildVersion", mBuildVersion);
|
||||
rArc << SerialParameter("Name", mProjectName)
|
||||
<< SerialParameter("Region", mRegion)
|
||||
<< SerialParameter("GameID", mGameID)
|
||||
<< SerialParameter("BuildVersion", mBuildVersion);
|
||||
|
||||
// Serialize package list
|
||||
std::vector<TString> PackageList;
|
||||
@@ -50,7 +49,7 @@ bool CGameProject::Serialize(IArchive& rArc)
|
||||
PackageList.push_back( mPackages[iPkg]->DefinitionPath(true) );
|
||||
}
|
||||
|
||||
rArc << SERIAL_CONTAINER("Packages", PackageList, "Package");
|
||||
rArc << SerialParameter("Packages", PackageList);
|
||||
|
||||
// Load packages
|
||||
if (rArc.IsReader())
|
||||
@@ -82,9 +81,9 @@ bool CGameProject::BuildISO(const TString& rkIsoPath, IProgressNotifier *pProgre
|
||||
ASSERT( FileUtil::IsValidPath(rkIsoPath, false) );
|
||||
ASSERT( !IsWiiDeAsobu() && !IsTrilogy() );
|
||||
|
||||
auto ProgressCallback = [&](float ProgressPercent, const nod::SystemString& rkInfoString, size_t)
|
||||
auto ProgressCallback = [&](float ProgressPercent, const nod::SystemStringView& rkInfoString, size_t)
|
||||
{
|
||||
pProgress->Report((int) (ProgressPercent * 10000), 10000, TWideString(rkInfoString).ToUTF8());
|
||||
pProgress->Report((int) (ProgressPercent * 10000), 10000, TWideString(rkInfoString.data()).ToUTF8());
|
||||
};
|
||||
|
||||
pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName());
|
||||
@@ -108,9 +107,9 @@ bool CGameProject::MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso
|
||||
ASSERT( IsWiiDeAsobu() || IsTrilogy() );
|
||||
ASSERT( pOriginalIso != nullptr );
|
||||
|
||||
auto ProgressCallback = [&](float ProgressPercent, const nod::SystemString& rkInfoString, size_t)
|
||||
auto ProgressCallback = [&](float ProgressPercent, const nod::SystemStringView& rkInfoString, size_t)
|
||||
{
|
||||
pProgress->Report((int) (ProgressPercent * 10000), 10000, TWideString(rkInfoString).ToUTF8());
|
||||
pProgress->Report((int) (ProgressPercent * 10000), 10000, TWideString(rkInfoString.data()).ToUTF8());
|
||||
};
|
||||
|
||||
pProgress->SetTask(0, "Building " + rkIsoPath.GetFileName());
|
||||
@@ -266,7 +265,6 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CTemplateLoader::LoadGameTemplates(pProj->mGame);
|
||||
pProj->mProjFileLock.Lock(ProjPath);
|
||||
pProj->mpGameInfo->LoadGameInfo(pProj->mGame);
|
||||
pProj->mpAudioManager->LoadAssets();
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "CResourceStore.h"
|
||||
#include "Core/CAudioManager.h"
|
||||
#include "Core/IProgressNotifier.h"
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include "Core/Resource/Script/CGameTemplate.h"
|
||||
#include <Common/CAssetID.h>
|
||||
#include <Common/EGame.h>
|
||||
#include <Common/FileUtil.h>
|
||||
@@ -45,8 +45,8 @@ class CGameProject
|
||||
// Private Constructor
|
||||
CGameProject()
|
||||
: mProjectName("Unnamed Project")
|
||||
, mGame(eUnknownGame)
|
||||
, mRegion(eRegion_Unknown)
|
||||
, mGame(EGame::Invalid)
|
||||
, mRegion(ERegion::Unknown)
|
||||
, mGameID("000000")
|
||||
, mBuildVersion(0.f)
|
||||
, mpResourceStore(nullptr)
|
||||
@@ -103,8 +103,8 @@ public:
|
||||
inline TString GameID() const { return mGameID; }
|
||||
inline float BuildVersion() const { return mBuildVersion; }
|
||||
inline bool IsWiiBuild() const { return mBuildVersion >= 3.f; }
|
||||
inline bool IsTrilogy() const { return mGame <= eCorruption && mBuildVersion >= 3.593f; }
|
||||
inline bool IsWiiDeAsobu() const { return mGame <= eCorruption && mBuildVersion >= 3.570f && mBuildVersion < 3.593f; }
|
||||
inline bool IsTrilogy() const { return mGame <= EGame::Corruption && mBuildVersion >= 3.593f; }
|
||||
inline bool IsWiiDeAsobu() const { return mGame <= EGame::Corruption && mBuildVersion >= 3.570f && mBuildVersion < 3.593f; }
|
||||
};
|
||||
|
||||
#endif // CGAMEPROJECT_H
|
||||
|
||||
@@ -29,15 +29,15 @@ bool CPackage::Save()
|
||||
TString DefPath = DefinitionPath(false);
|
||||
FileUtil::MakeDirectory(DefPath.GetFileDirectory());
|
||||
|
||||
CXMLWriter Writer(DefPath, "PackageDefinition", 0, mpProject ? mpProject->Game() : eUnknownGame);
|
||||
CXMLWriter Writer(DefPath, "PackageDefinition", 0, mpProject ? mpProject->Game() : EGame::Invalid);
|
||||
Serialize(Writer);
|
||||
return Writer.Save();
|
||||
}
|
||||
|
||||
void CPackage::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL("NeedsRecook", mNeedsRecook)
|
||||
<< SERIAL_CONTAINER("NamedResources", mResources, "Resource");
|
||||
rArc << SerialParameter("NeedsRecook", mNeedsRecook)
|
||||
<< SerialParameter("NamedResources", mResources);
|
||||
}
|
||||
|
||||
void CPackage::AddResource(const TString& rkName, const CAssetID& rkID, const CFourCC& rkType)
|
||||
@@ -82,7 +82,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||
}
|
||||
|
||||
EGame Game = mpProject->Game();
|
||||
u32 Alignment = (Game <= eCorruptionProto ? 0x20 : 0x40);
|
||||
u32 Alignment = (Game <= EGame::CorruptionProto ? 0x20 : 0x40);
|
||||
u32 AlignmentMinusOne = Alignment - 1;
|
||||
|
||||
u32 TocOffset = 0;
|
||||
@@ -92,7 +92,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||
u32 ResDataSize = 0;
|
||||
|
||||
// Write MP1 pak header
|
||||
if (Game <= eCorruptionProto)
|
||||
if (Game <= EGame::CorruptionProto)
|
||||
{
|
||||
Pak.WriteLong(0x00030005); // Major/Minor Version
|
||||
Pak.WriteLong(0); // Unknown
|
||||
@@ -188,7 +188,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||
// Update table info
|
||||
SResourceTableInfo& rTableInfo = ResourceTableData[ResIdx];
|
||||
rTableInfo.pEntry = pEntry;
|
||||
rTableInfo.Offset = (Game <= eEchoes ? AssetOffset : AssetOffset - ResDataOffset);
|
||||
rTableInfo.Offset = (Game <= EGame::Echoes ? AssetOffset : AssetOffset - ResDataOffset);
|
||||
|
||||
// Load resource data
|
||||
CFileInStream CookedAsset(pEntry->CookedAssetPath(), IOUtil::eBigEndian);
|
||||
@@ -201,12 +201,12 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||
// Check if this asset should be compressed; there are a few resource types that are
|
||||
// always compressed, and some types that are compressed if they're over a certain size
|
||||
EResType Type = pEntry->ResourceType();
|
||||
u32 CompressThreshold = (Game <= eCorruptionProto ? 0x400 : 0x80);
|
||||
u32 CompressThreshold = (Game <= EGame::CorruptionProto ? 0x400 : 0x80);
|
||||
|
||||
bool ShouldAlwaysCompress = (Type == eTexture || Type == eModel || Type == eSkin ||
|
||||
Type == eAnimSet || Type == eAnimation || Type == eFont);
|
||||
|
||||
if (Game >= eCorruption)
|
||||
if (Game >= EGame::Corruption)
|
||||
{
|
||||
ShouldAlwaysCompress = ShouldAlwaysCompress ||
|
||||
(Type == eCharacter || Type == eSourceAnimData || Type == eScan ||
|
||||
@@ -234,7 +234,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||
std::vector<u8> CompressedData(ResourceData.size() * 2);
|
||||
bool Success = false;
|
||||
|
||||
if (Game <= eEchoesDemo || Game == eReturns)
|
||||
if (Game <= EGame::EchoesDemo || Game == EGame::DKCReturns)
|
||||
Success = CompressionUtil::CompressZlib(ResourceData.data(), ResourceData.size(), CompressedData.data(), CompressedData.size(), CompressedSize);
|
||||
else
|
||||
Success = CompressionUtil::CompressLZOSegmented(ResourceData.data(), ResourceData.size(), CompressedData.data(), CompressedSize, false);
|
||||
@@ -242,7 +242,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||
// Make sure that the compressed data is actually smaller, accounting for padding + uncompressed size value
|
||||
if (Success)
|
||||
{
|
||||
u32 CompressionHeaderSize = (Game <= eCorruptionProto ? 4 : 0x10);
|
||||
u32 CompressionHeaderSize = (Game <= EGame::CorruptionProto ? 4 : 0x10);
|
||||
u32 PaddedUncompressedSize = (ResourceSize + AlignmentMinusOne) & ~AlignmentMinusOne;
|
||||
u32 PaddedCompressedSize = (CompressedSize + CompressionHeaderSize + AlignmentMinusOne) & ~AlignmentMinusOne;
|
||||
Success = (PaddedCompressedSize < PaddedUncompressedSize);
|
||||
@@ -252,7 +252,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||
if (Success)
|
||||
{
|
||||
// Write MP1/2 compressed asset
|
||||
if (Game <= eCorruptionProto)
|
||||
if (Game <= EGame::CorruptionProto)
|
||||
{
|
||||
Pak.WriteLong(ResourceSize);
|
||||
}
|
||||
@@ -292,7 +292,7 @@ void CPackage::Cook(IProgressNotifier *pProgress)
|
||||
else
|
||||
{
|
||||
// Write table of contents for real
|
||||
if (Game >= eCorruption)
|
||||
if (Game >= EGame::Corruption)
|
||||
{
|
||||
Pak.Seek(TocOffset, SEEK_SET);
|
||||
Pak.WriteLong(3); // Always 3 pak sections
|
||||
|
||||
@@ -17,7 +17,9 @@ struct SNamedResource
|
||||
|
||||
void Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL_AUTO(Name) << SERIAL_AUTO(ID) << SERIAL_AUTO(Type);
|
||||
rArc << SerialParameter("Name", Name)
|
||||
<< SerialParameter("ID", ID)
|
||||
<< SerialParameter("Type", Type);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -127,9 +127,9 @@ void CResourceEntry::SerializeEntryInfo(IArchive& rArc, bool MetadataOnly)
|
||||
{
|
||||
CAssetID ID = mID;
|
||||
|
||||
rArc << SERIAL("AssetID", ID)
|
||||
<< SERIAL("Type", mpTypeInfo)
|
||||
<< SERIAL("Flags", mFlags);
|
||||
rArc << SerialParameter("AssetID", ID)
|
||||
<< SerialParameter("Type", mpTypeInfo)
|
||||
<< SerialParameter("Flags", mFlags);
|
||||
|
||||
// Don't allow the file to override our asset ID if we already have a valid one.
|
||||
if (rArc.IsReader() && !mID.IsValid())
|
||||
@@ -140,9 +140,9 @@ void CResourceEntry::SerializeEntryInfo(IArchive& rArc, bool MetadataOnly)
|
||||
{
|
||||
TString Dir = (mpDirectory ? mpDirectory->FullPath() : "");
|
||||
|
||||
rArc << SERIAL("Name", mName)
|
||||
<< SERIAL("Directory", Dir)
|
||||
<< SERIAL_ABSTRACT("Dependencies", mpDependencies, &gDependencyNodeFactory);
|
||||
rArc << SerialParameter("Name", mName)
|
||||
<< SerialParameter("Directory", Dir)
|
||||
<< SerialParameter("Dependencies", mpDependencies);
|
||||
|
||||
if (rArc.IsReader())
|
||||
{
|
||||
@@ -618,7 +618,7 @@ CGameProject* CResourceEntry::Project() const
|
||||
|
||||
EGame CResourceEntry::Game() const
|
||||
{
|
||||
return mpStore ? mpStore->Game() : eUnknownGame;
|
||||
return mpStore ? mpStore->Game() : EGame::Invalid;
|
||||
}
|
||||
|
||||
void CResourceEntry::SetFlag(EResEntryFlag Flag)
|
||||
|
||||
@@ -18,7 +18,7 @@ CResourceStore *gpEditorStore = nullptr;
|
||||
// Constructor for editor store
|
||||
CResourceStore::CResourceStore(const TString& rkDatabasePath)
|
||||
: mpProj(nullptr)
|
||||
, mGame(ePrime)
|
||||
, mGame(EGame::Prime)
|
||||
, mDatabaseCacheDirty(false)
|
||||
{
|
||||
mpDatabaseRoot = new CVirtualDirectory(this);
|
||||
@@ -29,7 +29,7 @@ CResourceStore::CResourceStore(const TString& rkDatabasePath)
|
||||
// Main constructor for game projects and game exporter
|
||||
CResourceStore::CResourceStore(CGameProject *pProject)
|
||||
: mpProj(nullptr)
|
||||
, mGame(eUnknownGame)
|
||||
, mGame(EGame::Invalid)
|
||||
, mpDatabaseRoot(nullptr)
|
||||
, mDatabaseCacheDirty(false)
|
||||
{
|
||||
@@ -62,17 +62,17 @@ void RecursiveGetListOfEmptyDirectories(CVirtualDirectory *pDir, TStringList& rO
|
||||
bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
|
||||
{
|
||||
// Serialize resources
|
||||
if (rArc.ParamBegin("Resources"))
|
||||
if (rArc.ParamBegin("Resources", 0))
|
||||
{
|
||||
// Serialize resources
|
||||
u32 ResourceCount = mResourceEntries.size();
|
||||
rArc << SERIAL_AUTO(ResourceCount);
|
||||
rArc << SerialParameter("ResourceCount", ResourceCount);
|
||||
|
||||
if (rArc.IsReader())
|
||||
{
|
||||
for (u32 ResIdx = 0; ResIdx < ResourceCount; ResIdx++)
|
||||
{
|
||||
if (rArc.ParamBegin("Resource"))
|
||||
if (rArc.ParamBegin("Resource", 0))
|
||||
{
|
||||
CResourceEntry *pEntry = CResourceEntry::BuildFromArchive(this, rArc);
|
||||
ASSERT( FindEntry(pEntry->ID()) == nullptr );
|
||||
@@ -85,7 +85,7 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
|
||||
{
|
||||
for (CResourceIterator It(this); It; ++It)
|
||||
{
|
||||
if (rArc.ParamBegin("Resource"))
|
||||
if (rArc.ParamBegin("Resource", 0))
|
||||
{
|
||||
It->SerializeEntryInfo(rArc, false);
|
||||
rArc.ParamEnd();
|
||||
@@ -101,7 +101,7 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc)
|
||||
if (!rArc.IsReader())
|
||||
RecursiveGetListOfEmptyDirectories(mpDatabaseRoot, EmptyDirectories);
|
||||
|
||||
rArc << SERIAL_CONTAINER_AUTO(EmptyDirectories, "Directory");
|
||||
rArc << SerialParameter("EmptyDirectories", EmptyDirectories);
|
||||
|
||||
if (rArc.IsReader())
|
||||
{
|
||||
@@ -218,7 +218,7 @@ void CResourceStore::CloseProject()
|
||||
delete mpDatabaseRoot;
|
||||
mpDatabaseRoot = nullptr;
|
||||
mpProj = nullptr;
|
||||
mGame = eUnknownGame;
|
||||
mGame = EGame::Invalid;
|
||||
}
|
||||
|
||||
CVirtualDirectory* CResourceStore::GetVirtualDirectory(const TString& rkPath, bool AllowCreate)
|
||||
@@ -622,5 +622,5 @@ bool CResourceStore::IsValidResourcePath(const TString& rkPath, const TString& r
|
||||
|
||||
TString CResourceStore::StaticDefaultResourceDirPath(EGame Game)
|
||||
{
|
||||
return (Game < eCorruptionProto ? "Uncategorized/" : "uncategorized/");
|
||||
return (Game < EGame::CorruptionProto ? "Uncategorized/" : "uncategorized/");
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// ************ CCharacterUsageMap ************
|
||||
bool CCharacterUsageMap::IsCharacterUsed(const CAssetID& rkID, u32 CharacterIndex) const
|
||||
{
|
||||
if (mpStore->Game() >= eCorruptionProto) return true;
|
||||
if (mpStore->Game() >= EGame::CorruptionProto) return true;
|
||||
auto Find = mUsageMap.find(rkID);
|
||||
if (Find == mUsageMap.end()) return false;
|
||||
|
||||
@@ -214,7 +214,7 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
|
||||
|
||||
// Is this entry valid?
|
||||
bool IsValid = ResType != eMidi &&
|
||||
(ResType != eAudioGroup || mGame >= eEchoesDemo) &&
|
||||
(ResType != eAudioGroup || mGame >= EGame::EchoesDemo) &&
|
||||
(ResType != eWorld || !pCurEntry) &&
|
||||
(ResType != eArea || !pCurEntry || pCurEntry->ResourceType() == eWorld);
|
||||
|
||||
@@ -232,7 +232,7 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con
|
||||
// New area - toggle duplicates and find character usages
|
||||
if (ResType == eArea)
|
||||
{
|
||||
if (mGame <= eEchoes)
|
||||
if (mGame <= EGame::Echoes)
|
||||
mCharacterUsageMap.FindUsagesForArea(mpWorld, pEntry);
|
||||
|
||||
mAreaUsedAssets.clear();
|
||||
@@ -417,7 +417,7 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
|
||||
CPropertyDependency *pDep = static_cast<CPropertyDependency*>(pInst->ChildByIndex(iDep));
|
||||
|
||||
// For MP3, exclude the CMDL/CSKR properties for the suit assets - only include default character assets
|
||||
if (mGame == eCorruption && mIsPlayerActor)
|
||||
if (mGame == EGame::Corruption && mIsPlayerActor)
|
||||
{
|
||||
TString PropID = pDep->PropertyID();
|
||||
|
||||
@@ -467,7 +467,7 @@ void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<C
|
||||
EResType ResType = pEntry->ResourceType();
|
||||
|
||||
// If this is an audio group, for MP1, save it in the output set. For MP2, treat audio groups as a normal dependency.
|
||||
if (mGame <= ePrime && ResType == eAudioGroup)
|
||||
if (mGame <= EGame::Prime && ResType == eAudioGroup)
|
||||
{
|
||||
if (pAudioGroupsOut)
|
||||
pAudioGroupsOut->insert(rkID);
|
||||
@@ -534,7 +534,7 @@ void CAreaDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntr
|
||||
else if (Type == eDNT_SetCharacter)
|
||||
{
|
||||
// Note: For MP1/2 PlayerActor, always treat as if Empty Suit is the only used one
|
||||
const u32 kEmptySuitIndex = (mGame >= eEchoesDemo ? 3 : 5);
|
||||
const u32 kEmptySuitIndex = (mGame >= EGame::EchoesDemo ? 3 : 5);
|
||||
|
||||
CSetCharacterDependency *pChar = static_cast<CSetCharacterDependency*>(pNode);
|
||||
u32 SetIndex = pChar->CharSetIndex();
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
mTaskCount = Math::Max(mTaskCount, TaskIndex + 1);
|
||||
}
|
||||
|
||||
void Report(int StepIndex, int StepCount, const TString& rkStepDesc)
|
||||
void Report(int StepIndex, int StepCount, const TString& rkStepDesc = "")
|
||||
{
|
||||
ASSERT(mTaskCount >= 1);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
class IUIRelay
|
||||
{
|
||||
public:
|
||||
virtual void AsyncMessageBox(const TString& rkInfoBoxTitle, const TString& rkMessage) = 0;
|
||||
virtual bool AskYesNoQuestion(const TString& rkInfoBoxTitle, const TString& rkQuestion) = 0;
|
||||
};
|
||||
extern IUIRelay *gpUIRelay;
|
||||
|
||||
@@ -481,7 +481,7 @@ bool CShaderGenerator::CreatePixelShader(const CMaterial& rkMat)
|
||||
|
||||
if (rkMat.Options() & CMaterial::ePunchthrough)
|
||||
{
|
||||
if (rkMat.Version() < eCorruptionProto)
|
||||
if (rkMat.Version() < EGame::CorruptionProto)
|
||||
{
|
||||
ShaderCode << " if (Prev.a <= 0.25) discard;\n"
|
||||
<< " else Prev.a = 1.0;\n\n";
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
}
|
||||
|
||||
// Animation dependencies
|
||||
if (Game() <= eEchoes)
|
||||
if (Game() <= EGame::Echoes)
|
||||
{
|
||||
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
||||
{
|
||||
@@ -151,7 +151,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
else if (Game() <= eCorruption)
|
||||
else if (Game() <= EGame::Corruption)
|
||||
{
|
||||
const SSetCharacter& rkChar = mCharacters[0];
|
||||
std::set<CAnimPrimitive> PrimitiveSet;
|
||||
@@ -228,7 +228,7 @@ public:
|
||||
{
|
||||
ASSERT(Index >= 0 && Index < NumAnimations());
|
||||
|
||||
if (Game() <= ePrime)
|
||||
if (Game() <= EGame::Prime)
|
||||
{
|
||||
const CAnimPrimitive& rkPrim = mAnimPrimitives[Index];
|
||||
return rkPrim.Animation() ? rkPrim.Animation()->EventData() : nullptr;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <iostream>
|
||||
|
||||
CAnimationParameters::CAnimationParameters()
|
||||
: mGame(ePrime)
|
||||
: mGame(EGame::Prime)
|
||||
, mCharIndex(0)
|
||||
, mAnimIndex(0)
|
||||
, mUnknown2(0)
|
||||
@@ -15,6 +15,7 @@ CAnimationParameters::CAnimationParameters()
|
||||
|
||||
CAnimationParameters::CAnimationParameters(EGame Game)
|
||||
: mGame(Game)
|
||||
, mCharacterID( CAssetID::InvalidID(Game) )
|
||||
, mCharIndex(0)
|
||||
, mAnimIndex(0)
|
||||
, mUnknown2(0)
|
||||
@@ -29,20 +30,20 @@ CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game)
|
||||
, mUnknown2(0)
|
||||
, mUnknown3(0)
|
||||
{
|
||||
if (Game <= eEchoes)
|
||||
if (Game <= EGame::Echoes)
|
||||
{
|
||||
mCharacterID = CAssetID(rSCLY, Game);
|
||||
mCharIndex = rSCLY.ReadLong();
|
||||
mAnimIndex = rSCLY.ReadLong();
|
||||
}
|
||||
|
||||
else if (Game <= eCorruption)
|
||||
else if (Game <= EGame::Corruption)
|
||||
{
|
||||
mCharacterID = CAssetID(rSCLY, Game);
|
||||
mAnimIndex = rSCLY.ReadLong();
|
||||
}
|
||||
|
||||
else if (Game == eReturns)
|
||||
else if (Game == EGame::DKCReturns)
|
||||
{
|
||||
u8 Flags = rSCLY.ReadByte();
|
||||
|
||||
@@ -79,7 +80,7 @@ CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game)
|
||||
|
||||
void CAnimationParameters::Write(IOutputStream& rSCLY)
|
||||
{
|
||||
if (mGame <= eEchoes)
|
||||
if (mGame <= EGame::Echoes)
|
||||
{
|
||||
if (mCharacterID.IsValid())
|
||||
{
|
||||
@@ -95,7 +96,7 @@ void CAnimationParameters::Write(IOutputStream& rSCLY)
|
||||
}
|
||||
}
|
||||
|
||||
else if (mGame <= eCorruption)
|
||||
else if (mGame <= EGame::Corruption)
|
||||
{
|
||||
if (mCharacterID.IsValid())
|
||||
{
|
||||
@@ -136,6 +137,25 @@ void CAnimationParameters::Write(IOutputStream& rSCLY)
|
||||
}
|
||||
}
|
||||
|
||||
void CAnimationParameters::Serialize(IArchive& rArc)
|
||||
{
|
||||
if (rArc.IsReader())
|
||||
mGame = rArc.Game();
|
||||
|
||||
rArc << SerialParameter("AnimationSetAsset", mCharacterID);
|
||||
|
||||
if (mGame <= EGame::Echoes)
|
||||
rArc << SerialParameter("CharacterID", mCharIndex);
|
||||
|
||||
rArc << SerialParameter("AnimationID", mAnimIndex);
|
||||
|
||||
if (mGame >= EGame::DKCReturns)
|
||||
{
|
||||
rArc << SerialParameter("Unknown0", mUnknown2)
|
||||
<< SerialParameter("Unknown1", mUnknown3);
|
||||
}
|
||||
}
|
||||
|
||||
const SSetCharacter* CAnimationParameters::GetCurrentSetCharacter(s32 NodeIndex /*= -1*/)
|
||||
{
|
||||
CAnimSet *pSet = AnimSet();
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
CAnimationParameters(EGame Game);
|
||||
CAnimationParameters(IInputStream& rSCLY, EGame Game);
|
||||
void Write(IOutputStream& rSCLY);
|
||||
void Serialize(IArchive& rArc);
|
||||
|
||||
const SSetCharacter* GetCurrentSetCharacter(s32 NodeIndex = -1);
|
||||
CModel* GetCurrentModel(s32 NodeIndex = -1);
|
||||
@@ -34,11 +35,36 @@ public:
|
||||
inline void SetCharIndex(u32 Index) { mCharIndex = Index; }
|
||||
inline void SetAnimIndex(u32 Index) { mAnimIndex = Index; }
|
||||
|
||||
inline void SetGame(EGame Game)
|
||||
{
|
||||
mGame = Game;
|
||||
|
||||
if (!mCharacterID.IsValid())
|
||||
{
|
||||
mCharacterID = CAssetID::InvalidID(mGame);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT( mCharacterID.Length() == CAssetID::GameIDLength(mGame) );
|
||||
}
|
||||
}
|
||||
|
||||
u32 Unknown(u32 Index);
|
||||
void SetResource(const CAssetID& rkID);
|
||||
void SetUnknown(u32 Index, u32 Value);
|
||||
|
||||
// Operators
|
||||
inline CAnimationParameters& operator=(const CAnimationParameters& rkOther)
|
||||
{
|
||||
mGame = rkOther.mGame;
|
||||
mCharacterID = rkOther.mCharacterID;
|
||||
mCharIndex = rkOther.mCharIndex;
|
||||
mAnimIndex = rkOther.mAnimIndex;
|
||||
mUnknown2 = rkOther.mUnknown2;
|
||||
mUnknown3 = rkOther.mUnknown3;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator==(const CAnimationParameters& rkOther) const
|
||||
{
|
||||
return ( (mGame == rkOther.mGame) &&
|
||||
|
||||
@@ -56,7 +56,7 @@ CMetaTransTrans::CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput,
|
||||
ASSERT(Type == eMTT_Trans || Type == eMTT_PhaseTrans);
|
||||
mType = Type;
|
||||
|
||||
if (Game <= eEchoes)
|
||||
if (Game <= EGame::Echoes)
|
||||
{
|
||||
mUnknownA = rInput.ReadFloat();
|
||||
mUnknownB = rInput.ReadLong();
|
||||
|
||||
@@ -42,7 +42,7 @@ CDependencyTree* CGameArea::BuildDependencyTree() const
|
||||
|
||||
pTree->AddDependency(mPathID);
|
||||
|
||||
if (Game() >= eEchoesDemo)
|
||||
if (Game() >= EGame::EchoesDemo)
|
||||
{
|
||||
pTree->AddDependency(mPortalAreaID);
|
||||
pTree->AddDependency(mpPoiToWorldMap);
|
||||
@@ -224,7 +224,7 @@ CScriptObject* CGameArea::SpawnInstance(CScriptTemplate *pTemplate,
|
||||
pInstance->SetRotation(rkRotation.ToEuler());
|
||||
pInstance->SetScale(rkScale);
|
||||
pInstance->SetName(pTemplate->Name());
|
||||
if (pTemplate->Game() < eEchoesDemo) pInstance->SetActive(true);
|
||||
if (pTemplate->Game() < EGame::EchoesDemo) pInstance->SetActive(true);
|
||||
pLayer->AddInstance(pInstance, SuggestedLayerIndex);
|
||||
mObjectMap[InstanceID] = pInstance;
|
||||
return pInstance;
|
||||
|
||||
@@ -21,7 +21,7 @@ ECollisionFlag CCollisionMaterial::SurfaceType(EGame Game) const
|
||||
const ECollisionFlag* pkFlagArray;
|
||||
u32 Num;
|
||||
|
||||
if (Game <= ePrime)
|
||||
if (Game <= EGame::Prime)
|
||||
{
|
||||
pkFlagArray = skPrimeTypeHierarchy;
|
||||
Num = sizeof(skPrimeTypeHierarchy) / sizeof(ECollisionFlag);
|
||||
@@ -79,5 +79,5 @@ bool CCollisionMaterial::IsFloor() const
|
||||
|
||||
bool CCollisionMaterial::IsUnstandable(EGame Game) const
|
||||
{
|
||||
return HasFlag(eCF_JumpNotAllowed) || (Game >= eCorruptionProto && !HasFlag(eCF_Floor) && HasAnyFlags(eCF_Wall | eCF_Ceiling));
|
||||
return HasFlag(eCF_JumpNotAllowed) || (Game >= EGame::CorruptionProto && !HasFlag(eCF_Floor) && HasAnyFlags(eCF_Wall | eCF_Ceiling));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "CLight.h"
|
||||
#include "Core/Render/CGraphics.h"
|
||||
#include <Common/Common.h>
|
||||
#include <cmath>
|
||||
#include <float.h>
|
||||
|
||||
@@ -127,6 +128,52 @@ void CLight::SetAngleAtten(float AngleCoefA, float AngleCoefB, float AngleCoefC)
|
||||
mAngleAttenCoefficients.Z = AngleCoefC;
|
||||
}
|
||||
|
||||
CStructProperty* CLight::GetProperties() const
|
||||
{
|
||||
//@todo MP1 properties only
|
||||
//@todo we cannot display full properties because a lot of them are discarded on load
|
||||
static CStructProperty* pProperties = nullptr;
|
||||
|
||||
if (!pProperties)
|
||||
{
|
||||
pProperties = (CStructProperty*) IProperty::CreateIntrinsic(EPropertyType::Struct,
|
||||
EGame::Prime,
|
||||
0,
|
||||
"Light");
|
||||
|
||||
CChoiceProperty* pLightType = (CChoiceProperty*) IProperty::CreateIntrinsic(EPropertyType::Choice,
|
||||
pProperties,
|
||||
MEMBER_OFFSET(CLight, mType),
|
||||
"LightType");
|
||||
pLightType->AddValue("LocalAmbient", eLocalAmbient);
|
||||
pLightType->AddValue("Directional", eDirectional);
|
||||
pLightType->AddValue("Spot", eSpot);
|
||||
pLightType->AddValue("Custom", eCustom);
|
||||
|
||||
IProperty::CreateIntrinsic(EPropertyType::Color,
|
||||
pProperties,
|
||||
MEMBER_OFFSET(CLight, mColor),
|
||||
"Color");
|
||||
|
||||
IProperty::CreateIntrinsic(EPropertyType::Vector,
|
||||
pProperties,
|
||||
MEMBER_OFFSET(CLight, mPosition),
|
||||
"Position");
|
||||
|
||||
IProperty::CreateIntrinsic(EPropertyType::Vector,
|
||||
pProperties,
|
||||
MEMBER_OFFSET(CLight, mDirection),
|
||||
"Direction");
|
||||
|
||||
IProperty::CreateIntrinsic(EPropertyType::Float,
|
||||
pProperties,
|
||||
MEMBER_OFFSET(CLight, mSpotCutoff),
|
||||
"SpotCutoff");
|
||||
}
|
||||
|
||||
return pProperties;
|
||||
}
|
||||
|
||||
// ************ OTHER ************
|
||||
void CLight::Load() const
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef CLIGHT_H
|
||||
#define CLIGHT_H
|
||||
|
||||
#include "Core/Resource/Script/Property/Properties.h"
|
||||
#include <Common/CColor.h>
|
||||
#include <Common/FileIO/IInputStream.h>
|
||||
#include <Math/CVector3f.h>
|
||||
@@ -62,6 +63,8 @@ public:
|
||||
void SetDistAtten(float DistCoefA, float DistCoefB, float DistCoefC);
|
||||
void SetAngleAtten(float AngleCoefA, float AngleCoefB, float AngleCoefC);
|
||||
|
||||
CStructProperty* GetProperties() const;
|
||||
|
||||
// Other
|
||||
void Load() const;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Core/Render/CRenderer.h"
|
||||
#include "Core/OpenGL/GLCommon.h"
|
||||
#include "Core/OpenGL/CShaderGenerator.h"
|
||||
#include <Common/CHashFNV1A.h>
|
||||
#include <Common/Hash/CFNV1A.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <GL/glew.h>
|
||||
@@ -18,7 +18,7 @@ CMaterial::CMaterial()
|
||||
, mShaderStatus(eNoShader)
|
||||
, mRecalcHash(true)
|
||||
, mEnableBloom(false)
|
||||
, mVersion(eUnknownGame)
|
||||
, mVersion(EGame::Invalid)
|
||||
, mOptions(eNoSettings)
|
||||
, mVtxDesc(eNoAttributes)
|
||||
, mBlendSrcFac(GL_ONE)
|
||||
@@ -34,7 +34,7 @@ CMaterial::CMaterial(EGame Version, FVertexDescription VtxDesc)
|
||||
: mpShader(nullptr)
|
||||
, mShaderStatus(eNoShader)
|
||||
, mRecalcHash(true)
|
||||
, mEnableBloom(Version == eCorruption)
|
||||
, mEnableBloom(Version == EGame::Corruption)
|
||||
, mVersion(Version)
|
||||
, mOptions(eDepthWrite)
|
||||
, mVtxDesc(VtxDesc)
|
||||
@@ -48,7 +48,7 @@ CMaterial::CMaterial(EGame Version, FVertexDescription VtxDesc)
|
||||
mpShader = nullptr;
|
||||
mShaderStatus = eNoShader;
|
||||
mRecalcHash = true;
|
||||
mEnableBloom = (Version == eCorruption);
|
||||
mEnableBloom = (Version == EGame::Corruption);
|
||||
mVersion = Version;
|
||||
mOptions = eDepthWrite;
|
||||
mVtxDesc = VtxDesc;
|
||||
@@ -243,9 +243,9 @@ u64 CMaterial::HashParameters()
|
||||
{
|
||||
if (mRecalcHash)
|
||||
{
|
||||
CHashFNV1A Hash(CHashFNV1A::e64Bit);
|
||||
CFNV1A Hash(CFNV1A::e64Bit);
|
||||
|
||||
Hash.HashLong(mVersion);
|
||||
Hash.HashLong((int) mVersion);
|
||||
Hash.HashLong(mOptions);
|
||||
Hash.HashLong(mVtxDesc);
|
||||
Hash.HashData(mKonstColors, sizeof(CColor) * 4);
|
||||
|
||||
@@ -112,7 +112,7 @@ public:
|
||||
inline void SetOptions(FMaterialOptions Options) { mOptions = Options; Update(); }
|
||||
inline void SetVertexDescription(FVertexDescription Desc) { mVtxDesc = Desc; Update(); }
|
||||
inline void SetBlendMode(GLenum SrcFac, GLenum DstFac) { mBlendSrcFac = SrcFac; mBlendDstFac = DstFac; mRecalcHash = true; }
|
||||
inline void SetKonst(CColor& Konst, u32 KIndex) { mKonstColors[KIndex] = Konst; Update(); }
|
||||
inline void SetKonst(const CColor& Konst, u32 KIndex) { mKonstColors[KIndex] = Konst; Update(); }
|
||||
inline void SetIndTexture(CTexture *pTex) { mpIndirectTexture = pTex; }
|
||||
inline void SetLightingEnabled(bool Enabled) { mLightingEnabled = Enabled; Update(); }
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ CMaterialPass* CMaterialPass::Clone(CMaterial *pParent)
|
||||
return pOut;
|
||||
}
|
||||
|
||||
void CMaterialPass::HashParameters(CHashFNV1A& rHash)
|
||||
void CMaterialPass::HashParameters(CFNV1A& rHash)
|
||||
{
|
||||
if (mEnabled)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "ETevEnums.h"
|
||||
#include "Core/Render/FRenderOptions.h"
|
||||
#include <Common/CFourCC.h>
|
||||
#include <Common/CHashFNV1A.h>
|
||||
#include <Common/Hash/CFNV1A.h>
|
||||
|
||||
class CMaterial;
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
CMaterialPass(CMaterial *pParent);
|
||||
~CMaterialPass();
|
||||
CMaterialPass* Clone(CMaterial *pParent);
|
||||
void HashParameters(CHashFNV1A& rHash);
|
||||
void HashParameters(CFNV1A& rHash);
|
||||
void LoadTexture(u32 PassIndex);
|
||||
void SetAnimCurrent(FRenderOptions Options, u32 PassIndex);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class CResTypeFilter
|
||||
std::set<EResType> mAcceptedTypes;
|
||||
|
||||
public:
|
||||
CResTypeFilter() { }
|
||||
CResTypeFilter() : mGame(EGame::Invalid) { }
|
||||
CResTypeFilter(EGame Game, const TString& rkTypeList) { FromString(Game, rkTypeList); }
|
||||
|
||||
void SetAcceptedTypes(EGame Game, const TStringList& rkTypes)
|
||||
@@ -47,6 +47,12 @@ public:
|
||||
SetAcceptedTypes(Game, rkString.Split(","));
|
||||
}
|
||||
|
||||
void Serialize(IArchive& rArc)
|
||||
{
|
||||
if (rArc.IsReader()) mGame = rArc.Game();
|
||||
rArc << SerialParameter("AcceptedTypes", mAcceptedTypes, SH_Proxy);
|
||||
}
|
||||
|
||||
inline bool Accepts(EResType Type) const
|
||||
{
|
||||
return mAcceptedTypes.find(Type) != mAcceptedTypes.end();
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
std::unordered_map<EResType, CResTypeInfo*> CResTypeInfo::smTypeMap;
|
||||
|
||||
CResTypeInfo::CResTypeInfo(EResType Type, const TString& rkTypeName)
|
||||
CResTypeInfo::CResTypeInfo(EResType Type, const TString& rkTypeName, const TString& rkRetroExtension)
|
||||
: mType(Type)
|
||||
, mTypeName(rkTypeName)
|
||||
, mRetroExtension(rkRetroExtension)
|
||||
, mCanBeSerialized(false)
|
||||
, mCanHaveDependencies(true)
|
||||
{
|
||||
@@ -16,12 +17,6 @@ CResTypeInfo::CResTypeInfo(EResType Type, const TString& rkTypeName)
|
||||
smTypeMap[Type] = this;
|
||||
}
|
||||
|
||||
CResTypeInfo::~CResTypeInfo()
|
||||
{
|
||||
// shouldn't happen - we want to just create these at launch and keep them around forever
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
bool CResTypeInfo::IsInGame(EGame Game) const
|
||||
{
|
||||
for (u32 iGame = 0; iGame < mCookedExtensions.size(); iGame++)
|
||||
@@ -35,8 +30,8 @@ bool CResTypeInfo::IsInGame(EGame Game) const
|
||||
CFourCC CResTypeInfo::CookedExtension(EGame Game) const
|
||||
{
|
||||
// Default to MP1
|
||||
if (Game == eUnknownGame)
|
||||
Game = ePrime;
|
||||
if (Game == EGame::Invalid)
|
||||
Game = EGame::Prime;
|
||||
|
||||
for (u32 iGame = 0; iGame < mCookedExtensions.size(); iGame++)
|
||||
{
|
||||
@@ -63,7 +58,7 @@ CResTypeInfo* CResTypeInfo::TypeForCookedExtension(EGame Game, CFourCC Ext)
|
||||
{
|
||||
// Extensions can vary between games, but we're not likely to be calling this function for different games very often.
|
||||
// So, to speed things up a little, cache the lookup results in a map.
|
||||
static EGame sCachedGame = eUnknownGame;
|
||||
static EGame sCachedGame = EGame::Invalid;
|
||||
static std::map<CFourCC, CResTypeInfo*> sCachedTypeMap;
|
||||
Ext = Ext.ToUpper();
|
||||
|
||||
@@ -113,7 +108,7 @@ void Serialize(IArchive& rArc, CResTypeInfo*& rpType)
|
||||
Ext = rpType->CookedExtension(rArc.Game());
|
||||
}
|
||||
|
||||
rArc.SerializePrimitive(Ext);
|
||||
rArc.SerializePrimitive(Ext, 0);
|
||||
|
||||
if (rArc.IsReader())
|
||||
{
|
||||
@@ -122,6 +117,27 @@ void Serialize(IArchive& rArc, CResTypeInfo*& rpType)
|
||||
}
|
||||
}
|
||||
|
||||
void Serialize(IArchive& rArc, EResType& rType)
|
||||
{
|
||||
CFourCC Extension;
|
||||
|
||||
if (rArc.IsWriter())
|
||||
{
|
||||
CResTypeInfo* pTypeInfo = CResTypeInfo::FindTypeInfo(rType);
|
||||
ASSERT(pTypeInfo != nullptr);
|
||||
Extension = pTypeInfo->CookedExtension(rArc.Game());
|
||||
}
|
||||
|
||||
rArc.SerializePrimitive(Extension, 0);
|
||||
|
||||
if (rArc.IsReader())
|
||||
{
|
||||
CResTypeInfo* pTypeInfo = CResTypeInfo::TypeForCookedExtension(rArc.Game(), Extension);
|
||||
ASSERT(pTypeInfo != nullptr);
|
||||
rType = pTypeInfo->Type();
|
||||
}
|
||||
}
|
||||
|
||||
// ************ CREATION ************
|
||||
CResTypeInfo::CResTypeInfoFactory CResTypeInfo::smTypeInfoFactory;
|
||||
|
||||
@@ -132,16 +148,16 @@ CResTypeInfo::CResTypeInfoFactory::CResTypeInfoFactory()
|
||||
|
||||
void CResTypeInfo::CResTypeInfoFactory::AddExtension(CResTypeInfo *pType, CFourCC Ext, EGame FirstGame, EGame LastGame)
|
||||
{
|
||||
ASSERT(FirstGame >= ePrimeDemo && LastGame <= eReturns && FirstGame <= LastGame);
|
||||
ASSERT(FirstGame != eUnknownGame && LastGame != eUnknownGame);
|
||||
ASSERT(FirstGame >= EGame::PrimeDemo && LastGame <= EGame::DKCReturns && FirstGame <= LastGame);
|
||||
ASSERT(FirstGame != EGame::Invalid && LastGame != EGame::Invalid);
|
||||
|
||||
for (int iGame = FirstGame; iGame <= LastGame; iGame++)
|
||||
for (int GameIdx = (int) FirstGame; GameIdx <= (int) LastGame; GameIdx++)
|
||||
{
|
||||
#if !PUBLIC_RELEASE
|
||||
ASSERT(!pType->IsInGame((EGame) iGame));
|
||||
ASSERT(!pType->IsInGame((EGame) GameIdx));
|
||||
#endif
|
||||
|
||||
CResTypeInfo::SGameExtension Info { (EGame) iGame, Ext };
|
||||
CResTypeInfo::SGameExtension Info { (EGame) GameIdx, Ext };
|
||||
pType->mCookedExtensions.push_back(Info);
|
||||
}
|
||||
|
||||
@@ -153,236 +169,236 @@ void CResTypeInfo::CResTypeInfoFactory::AddExtension(CResTypeInfo *pType, CFourC
|
||||
void CResTypeInfo::CResTypeInfoFactory::InitTypes()
|
||||
{
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAnimation, "Animation");
|
||||
AddExtension(pType, "ANIM", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAnimation, "Animation", "ani");
|
||||
AddExtension(pType, "ANIM", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAnimCollisionPrimData, "Animation Collision Primitive Data");
|
||||
AddExtension(pType, "CPRM", eReturns, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAnimCollisionPrimData, "Animation Collision Primitive Data", "?");
|
||||
AddExtension(pType, "CPRM", EGame::DKCReturns, EGame::DKCReturns);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAnimEventData, "Animation Event Data");
|
||||
AddExtension(pType, "EVNT", ePrimeDemo, ePrime);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAnimEventData, "Animation Event Data", "evnt");
|
||||
AddExtension(pType, "EVNT", EGame::PrimeDemo, EGame::Prime);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAnimSet, "Animation Character Set");
|
||||
AddExtension(pType, "ANCS", ePrimeDemo, eEchoes);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAnimSet, "Animation Character Set", "acs");
|
||||
AddExtension(pType, "ANCS", EGame::PrimeDemo, EGame::Echoes);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eArea, "Area");
|
||||
AddExtension(pType, "MREA", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eArea, "Area", "mrea");
|
||||
AddExtension(pType, "MREA", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAudioAmplitudeData, "Audio Amplitude Data");
|
||||
AddExtension(pType, "CAAD", eCorruption, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAudioAmplitudeData, "Audio Amplitude Data", "?");
|
||||
AddExtension(pType, "CAAD", EGame::Corruption, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAudioGroup, "Audio Group");
|
||||
AddExtension(pType, "AGSC", ePrimeDemo, eEchoes);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAudioGroup, "Audio Group", "agsc");
|
||||
AddExtension(pType, "AGSC", EGame::PrimeDemo, EGame::Echoes);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAudioMacro, "Audio Macro");
|
||||
AddExtension(pType, "CAUD", eCorruptionProto, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAudioMacro, "Audio Macro", "caud");
|
||||
AddExtension(pType, "CAUD", EGame::CorruptionProto, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAudioSample, "Audio Sample");
|
||||
AddExtension(pType, "CSMP", eCorruptionProto, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAudioSample, "Audio Sample", "csmp");
|
||||
AddExtension(pType, "CSMP", EGame::CorruptionProto, EGame::DKCReturns);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAudioLookupTable, "Audio Lookup Table");
|
||||
AddExtension(pType, "ATBL", ePrimeDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eAudioLookupTable, "Audio Lookup Table", "atbl");
|
||||
AddExtension(pType, "ATBL", EGame::PrimeDemo, EGame::Corruption);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eBinaryData, "Generic Data");
|
||||
AddExtension(pType, "DUMB", ePrimeDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eBinaryData, "Generic Data", "dat");
|
||||
AddExtension(pType, "DUMB", EGame::PrimeDemo, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eBurstFireData, "Burst Fire Data");
|
||||
AddExtension(pType, "BFRC", eCorruptionProto, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eBurstFireData, "Burst Fire Data", "bfre.bfrc");
|
||||
AddExtension(pType, "BFRC", EGame::CorruptionProto, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eCharacter, "Character");
|
||||
AddExtension(pType, "CHAR", eCorruptionProto, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eCharacter, "Character", "char");
|
||||
AddExtension(pType, "CHAR", EGame::CorruptionProto, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eDependencyGroup, "Dependency Group");
|
||||
AddExtension(pType, "DGRP", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eDependencyGroup, "Dependency Group", "?");
|
||||
AddExtension(pType, "DGRP", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eDynamicCollision, "Dynamic Collision");
|
||||
AddExtension(pType, "DCLN", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eDynamicCollision, "Dynamic Collision", "dcln");
|
||||
AddExtension(pType, "DCLN", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eFont, "Font");
|
||||
AddExtension(pType, "FONT", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eFont, "Font", "rpff");
|
||||
AddExtension(pType, "FONT", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eGuiFrame, "Gui Frame");
|
||||
AddExtension(pType, "FRME", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eGuiFrame, "Gui Frame", "frme");
|
||||
AddExtension(pType, "FRME", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eGuiKeyFrame, "Gui Keyframe");
|
||||
AddExtension(pType, "KFAM", ePrimeDemo, ePrimeDemo);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eGuiKeyFrame, "Gui Keyframe", "?");
|
||||
AddExtension(pType, "KFAM", EGame::PrimeDemo, EGame::PrimeDemo);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eHintSystem, "Hint System Data");
|
||||
AddExtension(pType, "HINT", ePrime, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eHintSystem, "Hint System Data", "hint");
|
||||
AddExtension(pType, "HINT", EGame::Prime, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eMapArea, "Area Map");
|
||||
AddExtension(pType, "MAPA", ePrimeDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eMapArea, "Area Map", "mapa");
|
||||
AddExtension(pType, "MAPA", EGame::PrimeDemo, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eMapWorld, "World Map");
|
||||
AddExtension(pType, "MAPW", ePrimeDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eMapWorld, "World Map", "mapw");
|
||||
AddExtension(pType, "MAPW", EGame::PrimeDemo, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eMapUniverse, "Universe Map");
|
||||
AddExtension(pType, "MAPU", ePrimeDemo, eEchoes);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eMapUniverse, "Universe Map", "mapu");
|
||||
AddExtension(pType, "MAPU", EGame::PrimeDemo, EGame::Echoes);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eMidi, "MIDI");
|
||||
AddExtension(pType, "CSNG", ePrimeDemo, eEchoes);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eMidi, "MIDI", "?");
|
||||
AddExtension(pType, "CSNG", EGame::PrimeDemo, EGame::Echoes);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eModel, "Model");
|
||||
AddExtension(pType, "CMDL", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eModel, "Model", "cmdl");
|
||||
AddExtension(pType, "CMDL", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticle, "Particle System");
|
||||
AddExtension(pType, "PART", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticle, "Particle System", "gpsm.part");
|
||||
AddExtension(pType, "PART", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleCollisionResponse, "Collision Response Particle System");
|
||||
AddExtension(pType, "CRSC", ePrimeDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleCollisionResponse, "Collision Response Particle System", "crsm.crsc");
|
||||
AddExtension(pType, "CRSC", EGame::PrimeDemo, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleDecal, "Decal Particle System");
|
||||
AddExtension(pType, "DPSC", ePrimeDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleDecal, "Decal Particle System", "dpsm.dpsc");
|
||||
AddExtension(pType, "DPSC", EGame::PrimeDemo, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleElectric, "Electric Particle System");
|
||||
AddExtension(pType, "ELSC", ePrimeDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleElectric, "Electric Particle System", "elsm.elsc");
|
||||
AddExtension(pType, "ELSC", EGame::PrimeDemo, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleSorted, "Sorted Particle System");
|
||||
AddExtension(pType, "SRSC", eEchoesDemo, eEchoes);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleSorted, "Sorted Particle System", "srsm.srsc");
|
||||
AddExtension(pType, "SRSC", EGame::EchoesDemo, EGame::Echoes);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleSpawn, "Spawn Particle System");
|
||||
AddExtension(pType, "SPSC", eEchoesDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleSpawn, "Spawn Particle System", "spsm.spsc");
|
||||
AddExtension(pType, "SPSC", EGame::EchoesDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleSwoosh, "Swoosh Particle System");
|
||||
AddExtension(pType, "SWHC", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleSwoosh, "Swoosh Particle System", "swsh.swhc");
|
||||
AddExtension(pType, "SWHC", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleTransform, "Transform Particle System");
|
||||
AddExtension(pType, "XFSC", eReturns, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleTransform, "Transform Particle System", "xfsm.xfsc");
|
||||
AddExtension(pType, "XFSC", EGame::DKCReturns, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleWeapon, "Weapon Particle System");
|
||||
AddExtension(pType, "WPSC", ePrimeDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eParticleWeapon, "Weapon Particle System", "wpsm.wpsc");
|
||||
AddExtension(pType, "WPSC", EGame::PrimeDemo, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(ePathfinding, "Pathfinding Mesh");
|
||||
AddExtension(pType, "PATH", ePrimeDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(ePathfinding, "Pathfinding Mesh", "path");
|
||||
AddExtension(pType, "PATH", EGame::PrimeDemo, EGame::Corruption);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(ePortalArea, "Portal Area");
|
||||
AddExtension(pType, "PTLA", eEchoesDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(ePortalArea, "Portal Area", "?");
|
||||
AddExtension(pType, "PTLA", EGame::EchoesDemo, EGame::Corruption);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eRuleSet, "Rule Set");
|
||||
AddExtension(pType, "RULE", eEchoesDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eRuleSet, "Rule Set", "rule");
|
||||
AddExtension(pType, "RULE", EGame::EchoesDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSaveArea, "Area Save Info");
|
||||
AddExtension(pType, "SAVA", eCorruptionProto, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSaveArea, "Area Save Info", "sava");
|
||||
AddExtension(pType, "SAVA", EGame::CorruptionProto, EGame::Corruption);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSaveWorld, "World Save Info");
|
||||
AddExtension(pType, "SAVW", ePrime, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSaveWorld, "World Save Info", "savw");
|
||||
AddExtension(pType, "SAVW", EGame::Prime, EGame::DKCReturns);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eScan, "Scan");
|
||||
AddExtension(pType, "SCAN", ePrimeDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eScan, "Scan", "scan");
|
||||
AddExtension(pType, "SCAN", EGame::PrimeDemo, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSkeleton, "Skeleton");
|
||||
AddExtension(pType, "CINF", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSkeleton, "Skeleton", "cin");
|
||||
AddExtension(pType, "CINF", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSkin, "Skin");
|
||||
AddExtension(pType, "CSKR", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSkin, "Skin", "cskr");
|
||||
AddExtension(pType, "CSKR", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSourceAnimData, "Source Animation Data");
|
||||
AddExtension(pType, "SAND", eCorruptionProto, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSourceAnimData, "Source Animation Data", "sand");
|
||||
AddExtension(pType, "SAND", EGame::CorruptionProto, EGame::Corruption);
|
||||
pType->mCanHaveDependencies = false; // all dependencies are added to the CHAR dependency tree
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSpatialPrimitive, "Spatial Primitive");
|
||||
AddExtension(pType, "CSPP", eEchoesDemo, eEchoes);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eSpatialPrimitive, "Spatial Primitive", "?");
|
||||
AddExtension(pType, "CSPP", EGame::EchoesDemo, EGame::Echoes);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStateMachine, "State Machine");
|
||||
AddExtension(pType, "AFSM", ePrimeDemo, eEchoes);
|
||||
AddExtension(pType, "FSM2", eCorruptionProto, eCorruption);
|
||||
AddExtension(pType, "FSMC", eReturns, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStateMachine, "State Machine", "afsm");
|
||||
AddExtension(pType, "AFSM", EGame::PrimeDemo, EGame::Echoes);
|
||||
AddExtension(pType, "FSM2", EGame::CorruptionProto, EGame::Corruption);
|
||||
AddExtension(pType, "FSMC", EGame::DKCReturns, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStateMachine2, "State Machine 2");
|
||||
AddExtension(pType, "FSM2", eEchoesDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStateMachine2, "State Machine 2", "fsm2");
|
||||
AddExtension(pType, "FSM2", EGame::EchoesDemo, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStaticGeometryMap, "Static Scan Map");
|
||||
AddExtension(pType, "EGMC", eEchoesDemo, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStaticGeometryMap, "Static Scan Map", "egmc");
|
||||
AddExtension(pType, "EGMC", EGame::EchoesDemo, EGame::Corruption);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStreamedAudio, "Streamed Audio");
|
||||
AddExtension(pType, "STRM", eCorruptionProto, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStreamedAudio, "Streamed Audio", "?");
|
||||
AddExtension(pType, "STRM", EGame::CorruptionProto, EGame::DKCReturns);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStringList, "String List");
|
||||
AddExtension(pType, "STLC", eEchoesDemo, eCorruptionProto);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStringList, "String List", "stlc");
|
||||
AddExtension(pType, "STLC", EGame::EchoesDemo, EGame::CorruptionProto);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStringTable, "String Table");
|
||||
AddExtension(pType, "STRG", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eStringTable, "String Table", "strg");
|
||||
AddExtension(pType, "STRG", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eTexture, "Texture");
|
||||
AddExtension(pType, "TXTR", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eTexture, "Texture", "txtr");
|
||||
AddExtension(pType, "TXTR", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eTweak, "Tweak Data");
|
||||
AddExtension(pType, "CTWK", ePrimeDemo, ePrime);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eTweak, "Tweak Data", "ctwk");
|
||||
AddExtension(pType, "CTWK", EGame::PrimeDemo, EGame::Prime);
|
||||
pType->mCanHaveDependencies = false;
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eUserEvaluatorData, "User Evaluator Data");
|
||||
AddExtension(pType, "USRC", eCorruptionProto, eCorruption);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eUserEvaluatorData, "User Evaluator Data", "user.usrc");
|
||||
AddExtension(pType, "USRC", EGame::CorruptionProto, EGame::Corruption);
|
||||
}
|
||||
{
|
||||
CResTypeInfo *pType = new CResTypeInfo(eWorld, "World");
|
||||
AddExtension(pType, "MLVL", ePrimeDemo, eReturns);
|
||||
CResTypeInfo *pType = new CResTypeInfo(eWorld, "World", "mwld");
|
||||
AddExtension(pType, "MLVL", EGame::PrimeDemo, EGame::DKCReturns);
|
||||
pType->mCanBeSerialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,15 @@ class CResTypeInfo
|
||||
EResType mType;
|
||||
TString mTypeName;
|
||||
std::vector<SGameExtension> mCookedExtensions;
|
||||
TString mRetroExtension; // File extension in Retro's directory tree. We don't use it directly but it is needed for generating asset ID hashes
|
||||
bool mCanBeSerialized;
|
||||
bool mCanHaveDependencies;
|
||||
|
||||
static std::unordered_map<EResType, CResTypeInfo*> smTypeMap;
|
||||
|
||||
// Private Methods
|
||||
CResTypeInfo(EResType Type, const TString& rkTypeName);
|
||||
~CResTypeInfo();
|
||||
CResTypeInfo(EResType Type, const TString& rkTypeName, const TString& rkRetroExtension);
|
||||
~CResTypeInfo() {}
|
||||
|
||||
// Public Methods
|
||||
public:
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
inline TString Source() const { return mpEntry ? mpEntry->CookedAssetPath(true).GetFileName() : ""; }
|
||||
inline TString FullSource() const { return mpEntry ? mpEntry->CookedAssetPath(true) : ""; }
|
||||
inline CAssetID ID() const { return mpEntry ? mpEntry->ID() : CAssetID::skInvalidID64; }
|
||||
inline EGame Game() const { return mpEntry ? mpEntry->Game() : eUnknownGame; }
|
||||
inline EGame Game() const { return mpEntry ? mpEntry->Game() : EGame::Invalid; }
|
||||
inline bool IsReferenced() const { return mRefCount > 0; }
|
||||
inline void Lock() { mRefCount++; }
|
||||
inline void Release() { mRefCount--; }
|
||||
|
||||
@@ -46,10 +46,18 @@ public:
|
||||
|
||||
void Serialize(IArchive& rArc)
|
||||
{
|
||||
TString Str;
|
||||
if (rArc.IsWriter()) Str = ToString();
|
||||
rArc.SerializePrimitive(Str);
|
||||
if (rArc.IsReader()) *this = FromString(Str);
|
||||
if (rArc.IsBinaryFormat())
|
||||
{
|
||||
rArc.SerializePrimitive(m[0], 0);
|
||||
rArc.SerializePrimitive(m[1], 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
TString Str;
|
||||
if (rArc.IsWriter()) Str = ToString();
|
||||
rArc.SerializePrimitive(Str, 0);
|
||||
if (rArc.IsReader()) *this = FromString(Str);
|
||||
}
|
||||
}
|
||||
|
||||
// Operators
|
||||
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
CDependencyTree *pTree = new CDependencyTree();
|
||||
|
||||
// Corruption's SCAN has a list of all assets - just grab that
|
||||
if (Game() >= eCorruptionProto)
|
||||
if (Game() >= EGame::CorruptionProto)
|
||||
{
|
||||
for (u32 iDep = 0; iDep < mDependencyList.size(); iDep++)
|
||||
{
|
||||
@@ -80,18 +80,18 @@ public:
|
||||
}
|
||||
|
||||
// Otherwise add all the dependencies we need from the properties
|
||||
if (Game() <= ePrime)
|
||||
if (Game() <= EGame::Prime)
|
||||
pTree->AddDependency(mFrameID);
|
||||
|
||||
pTree->AddDependency(mpStringTable);
|
||||
|
||||
if (Game() <= ePrime)
|
||||
if (Game() <= EGame::Prime)
|
||||
{
|
||||
for (u32 iImg = 0; iImg < 4; iImg++)
|
||||
pTree->AddDependency(mScanImageTextures[iImg]);
|
||||
}
|
||||
|
||||
else if (Game() <= eEchoes)
|
||||
else if (Game() <= EGame::Echoes)
|
||||
{
|
||||
pTree->AddDependency(mPostOverrideTexture);
|
||||
pTree->AddDependency(mLogbookModel);
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
{
|
||||
// STRGs can reference FONTs with the &font=; formatting tag and TXTRs with the &image=; tag
|
||||
CDependencyTree *pTree = new CDependencyTree();
|
||||
EIDLength IDLength = (Game() <= eEchoes ? e32Bit : e64Bit);
|
||||
EIDLength IDLength = (Game() <= EGame::Echoes ? e32Bit : e64Bit);
|
||||
|
||||
for (u32 iLang = 0; iLang < mLangTables.size(); iLang++)
|
||||
{
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
// Font
|
||||
if (TagName == "font")
|
||||
{
|
||||
if (Game() >= eCorruptionProto)
|
||||
if (Game() >= EGame::CorruptionProto)
|
||||
{
|
||||
ASSERT(ParamString.StartsWith("0x"));
|
||||
ParamString = ParamString.ChopFront(2);
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
{
|
||||
TString Param = *Iter;
|
||||
|
||||
if (Game() >= eCorruptionProto)
|
||||
if (Game() >= EGame::CorruptionProto)
|
||||
{
|
||||
ASSERT(Param.StartsWith("0x"));
|
||||
Param = Param.ChopFront(2);
|
||||
|
||||
@@ -92,87 +92,87 @@ u32 CWorld::AreaIndex(CAssetID AreaID) const
|
||||
// ************ SERIALIZATION ************
|
||||
void CWorld::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL("Name", mName)
|
||||
<< SERIAL("NameString", mpWorldName);
|
||||
rArc << SerialParameter("Name", mName)
|
||||
<< SerialParameter("NameString", mpWorldName);
|
||||
|
||||
if (rArc.Game() == eEchoesDemo || rArc.Game() == eEchoes)
|
||||
rArc << SERIAL("DarkNameString", mpDarkWorldName);
|
||||
if (rArc.Game() == EGame::EchoesDemo || rArc.Game() == EGame::Echoes)
|
||||
rArc << SerialParameter("DarkNameString", mpDarkWorldName);
|
||||
|
||||
rArc << SERIAL("WorldSaveInfo", mpSaveWorld)
|
||||
<< SERIAL("WorldMap", mpMapWorld)
|
||||
<< SERIAL("DefaultSkyModel", mpDefaultSkybox);
|
||||
rArc << SerialParameter("WorldSaveInfo", mpSaveWorld)
|
||||
<< SerialParameter("WorldMap", mpMapWorld)
|
||||
<< SerialParameter("DefaultSkyModel", mpDefaultSkybox);
|
||||
|
||||
if (rArc.Game() >= eEchoesDemo && rArc.Game() <= eCorruption)
|
||||
rArc << SERIAL("TempleKeyWorldIndex", mTempleKeyWorldIndex);
|
||||
if (rArc.Game() >= EGame::EchoesDemo && rArc.Game() <= EGame::Corruption)
|
||||
rArc << SerialParameter("TempleKeyWorldIndex", mTempleKeyWorldIndex);
|
||||
|
||||
if (rArc.Game() == eReturns)
|
||||
rArc << SERIAL("TimeAttackData", mTimeAttackData);
|
||||
if (rArc.Game() == EGame::DKCReturns)
|
||||
rArc << SerialParameter("TimeAttackData", mTimeAttackData);
|
||||
|
||||
if (rArc.Game() == ePrime)
|
||||
rArc << SERIAL_CONTAINER("MemoryRelays", mMemoryRelays, "MemoryRelay");
|
||||
if (rArc.Game() == EGame::Prime)
|
||||
rArc << SerialParameter("MemoryRelays", mMemoryRelays);
|
||||
|
||||
rArc << SERIAL_CONTAINER("Areas", mAreas, "Area");
|
||||
rArc << SerialParameter("Areas", mAreas);
|
||||
}
|
||||
|
||||
void Serialize(IArchive& rArc, CWorld::STimeAttackData& rData)
|
||||
{
|
||||
rArc << SERIAL("HasTimeAttack", rData.HasTimeAttack)
|
||||
<< SERIAL("ActNumber", rData.ActNumber)
|
||||
<< SERIAL("BronzeTime", rData.BronzeTime)
|
||||
<< SERIAL("SilverTime", rData.SilverTime)
|
||||
<< SERIAL("GoldTime", rData.GoldTime)
|
||||
<< SERIAL("ShinyGoldTime", rData.ShinyGoldTime);
|
||||
rArc << SerialParameter("HasTimeAttack", rData.HasTimeAttack)
|
||||
<< SerialParameter("ActNumber", rData.ActNumber)
|
||||
<< SerialParameter("BronzeTime", rData.BronzeTime)
|
||||
<< SerialParameter("SilverTime", rData.SilverTime)
|
||||
<< SerialParameter("GoldTime", rData.GoldTime)
|
||||
<< SerialParameter("ShinyGoldTime", rData.ShinyGoldTime);
|
||||
}
|
||||
|
||||
void Serialize(IArchive& rArc, CWorld::SMemoryRelay& rMemRelay)
|
||||
{
|
||||
rArc << SERIAL_HEX("MemoryRelayID", rMemRelay.InstanceID)
|
||||
<< SERIAL_HEX("TargetID", rMemRelay.TargetID)
|
||||
<< SERIAL("Message", rMemRelay.Message)
|
||||
<< SERIAL("Active", rMemRelay.Active);
|
||||
rArc << SerialParameter("MemoryRelayID", rMemRelay.InstanceID, SH_HexDisplay)
|
||||
<< SerialParameter("TargetID", rMemRelay.TargetID, SH_HexDisplay)
|
||||
<< SerialParameter("Message", rMemRelay.Message)
|
||||
<< SerialParameter("Active", rMemRelay.Active);
|
||||
}
|
||||
|
||||
void Serialize(IArchive& rArc, CWorld::SArea& rArea)
|
||||
{
|
||||
rArc << SERIAL("Name", rArea.InternalName)
|
||||
<< SERIAL("NameString", rArea.pAreaName)
|
||||
<< SERIAL("MREA", rArea.AreaResID)
|
||||
<< SERIAL("ID", rArea.AreaID)
|
||||
<< SERIAL("Transform", rArea.Transform)
|
||||
<< SERIAL("BoundingBox", rArea.AetherBox)
|
||||
<< SERIAL("AllowPakDuplicates", rArea.AllowPakDuplicates)
|
||||
<< SERIAL_CONTAINER("AttachedAreas", rArea.AttachedAreaIDs, "AreaIndex")
|
||||
<< SERIAL_CONTAINER("RelModules", rArea.RelFilenames, "Module")
|
||||
<< SERIAL_CONTAINER("RelOffsets", rArea.RelOffsets, "Offset")
|
||||
<< SERIAL_CONTAINER("Docks", rArea.Docks, "Dock")
|
||||
<< SERIAL_CONTAINER("Layers", rArea.Layers, "Layer");
|
||||
rArc << SerialParameter("Name", rArea.InternalName)
|
||||
<< SerialParameter("NameString", rArea.pAreaName)
|
||||
<< SerialParameter("MREA", rArea.AreaResID)
|
||||
<< SerialParameter("ID", rArea.AreaID)
|
||||
<< SerialParameter("Transform", rArea.Transform)
|
||||
<< SerialParameter("BoundingBox", rArea.AetherBox)
|
||||
<< SerialParameter("AllowPakDuplicates", rArea.AllowPakDuplicates)
|
||||
<< SerialParameter("AttachedAreas", rArea.AttachedAreaIDs)
|
||||
<< SerialParameter("RelModules", rArea.RelFilenames)
|
||||
<< SerialParameter("RelOffsets", rArea.RelOffsets)
|
||||
<< SerialParameter("Docks", rArea.Docks)
|
||||
<< SerialParameter("Layers", rArea.Layers);
|
||||
}
|
||||
|
||||
void Serialize(IArchive& rArc, CWorld::SArea::SDock& rDock)
|
||||
{
|
||||
rArc << SERIAL_CONTAINER("ConnectingDocks", rDock.ConnectingDocks, "ConnectingDock")
|
||||
<< SERIAL_CONTAINER("DockCoords", rDock.DockCoordinates, "Coord");
|
||||
rArc << SerialParameter("ConnectingDocks", rDock.ConnectingDocks)
|
||||
<< SerialParameter("DockCoords", rDock.DockCoordinates);
|
||||
}
|
||||
|
||||
void Serialize(IArchive& rArc, CWorld::SArea::SDock::SConnectingDock& rDock)
|
||||
{
|
||||
rArc << SERIAL("AreaIndex", rDock.AreaIndex)
|
||||
<< SERIAL("DockIndex", rDock.DockIndex);
|
||||
rArc << SerialParameter("AreaIndex", rDock.AreaIndex)
|
||||
<< SerialParameter("DockIndex", rDock.DockIndex);
|
||||
}
|
||||
|
||||
void Serialize(IArchive& rArc, CWorld::SArea::SLayer& rLayer)
|
||||
{
|
||||
rArc << SERIAL("Name", rLayer.LayerName)
|
||||
<< SERIAL("Active", rLayer.Active);
|
||||
rArc << SerialParameter("Name", rLayer.LayerName)
|
||||
<< SerialParameter("Active", rLayer.Active);
|
||||
|
||||
if (rArc.Game() >= eCorruption)
|
||||
if (rArc.Game() >= EGame::Corruption)
|
||||
{
|
||||
rArc << SERIAL("StateID", rLayer.LayerStateID);
|
||||
rArc << SerialParameter("StateID", rLayer.LayerStateID);
|
||||
}
|
||||
}
|
||||
|
||||
void Serialize(IArchive& rArc, CWorld::SAudioGrp& rAudioGrp)
|
||||
{
|
||||
rArc << SERIAL("GroupID", rAudioGrp.GroupID)
|
||||
<< SERIAL("AGSC", rAudioGrp.ResID);
|
||||
rArc << SerialParameter("GroupID", rAudioGrp.GroupID)
|
||||
<< SerialParameter("AGSC", rAudioGrp.ResID);
|
||||
}
|
||||
|
||||
@@ -35,14 +35,14 @@ void CAreaCooker::DetermineSectionNumbersPrime()
|
||||
|
||||
switch (mVersion)
|
||||
{
|
||||
case ePrimeDemo:
|
||||
case ePrime:
|
||||
case EGame::PrimeDemo:
|
||||
case EGame::Prime:
|
||||
GeometrySections = 1 + (7 * OriginalMeshCount); // Accounting for materials
|
||||
break;
|
||||
case eEchoesDemo:
|
||||
case EGame::EchoesDemo:
|
||||
GeometrySections = 2 + (9 * OriginalMeshCount); // Account for materials + AROT
|
||||
break;
|
||||
case eEchoes:
|
||||
case EGame::Echoes:
|
||||
GeometrySections = 3 + (9 * OriginalMeshCount); // Acount for materials + AROT + an unknown section
|
||||
break;
|
||||
}
|
||||
@@ -52,13 +52,13 @@ void CAreaCooker::DetermineSectionNumbersPrime()
|
||||
|
||||
// Set section numbers
|
||||
u32 SecNum = GeometrySections;
|
||||
if (mVersion <= ePrime) mAROTSecNum = SecNum++;
|
||||
if (mVersion >= eEchoesDemo) mFFFFSecNum = SecNum++;
|
||||
if (mVersion <= EGame::Prime) mAROTSecNum = SecNum++;
|
||||
if (mVersion >= EGame::EchoesDemo) mFFFFSecNum = SecNum++;
|
||||
|
||||
if (mVersion >= eEchoesDemo)
|
||||
if (mVersion >= EGame::EchoesDemo)
|
||||
{
|
||||
mSCLYSecNum = SecNum;
|
||||
SecNum += (mVersion >= eEchoes ? mpArea->mScriptLayers.size() : 1);
|
||||
SecNum += (mVersion >= EGame::Echoes ? mpArea->mScriptLayers.size() : 1);
|
||||
mSCGNSecNum = SecNum++;
|
||||
}
|
||||
else
|
||||
@@ -70,7 +70,7 @@ void CAreaCooker::DetermineSectionNumbersPrime()
|
||||
mVISISecNum = SecNum++;
|
||||
mPATHSecNum = SecNum++;
|
||||
|
||||
if (mVersion >= eEchoesDemo)
|
||||
if (mVersion >= EGame::EchoesDemo)
|
||||
{
|
||||
mPTLASecNum = SecNum++;
|
||||
mEGMCSecNum = SecNum++;
|
||||
@@ -98,18 +98,18 @@ void CAreaCooker::WritePrimeHeader(IOutputStream& rOut)
|
||||
rOut.WriteLong(GetMREAVersion(mVersion));
|
||||
mpArea->mTransform.Write(rOut);
|
||||
rOut.WriteLong(mpArea->mOriginalWorldMeshCount);
|
||||
if (mVersion >= eEchoes) rOut.WriteLong(mpArea->mScriptLayers.size());
|
||||
if (mVersion >= EGame::Echoes) rOut.WriteLong(mpArea->mScriptLayers.size());
|
||||
rOut.WriteLong(mpArea->mSectionDataBuffers.size());
|
||||
|
||||
rOut.WriteLong(mGeometrySecNum);
|
||||
rOut.WriteLong(mSCLYSecNum);
|
||||
if (mVersion >= eEchoesDemo) rOut.WriteLong(mSCGNSecNum);
|
||||
if (mVersion >= EGame::EchoesDemo) rOut.WriteLong(mSCGNSecNum);
|
||||
rOut.WriteLong(mCollisionSecNum);
|
||||
rOut.WriteLong(mUnknownSecNum);
|
||||
rOut.WriteLong(mLightsSecNum);
|
||||
rOut.WriteLong(mVISISecNum);
|
||||
rOut.WriteLong(mPATHSecNum);
|
||||
if (mVersion <= ePrime) rOut.WriteLong(mAROTSecNum);
|
||||
if (mVersion <= EGame::Prime) rOut.WriteLong(mAROTSecNum);
|
||||
|
||||
else
|
||||
{
|
||||
@@ -118,9 +118,9 @@ void CAreaCooker::WritePrimeHeader(IOutputStream& rOut)
|
||||
rOut.WriteLong(mEGMCSecNum);
|
||||
}
|
||||
|
||||
if (mVersion >= eEchoesDemo)
|
||||
if (mVersion >= EGame::EchoesDemo)
|
||||
{
|
||||
if (mVersion >= eEchoes) rOut.WriteLong(mCompressedBlocks.size());
|
||||
if (mVersion >= EGame::Echoes) rOut.WriteLong(mCompressedBlocks.size());
|
||||
rOut.WriteToBoundary(32, 0);
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ void CAreaCooker::WritePrimeHeader(IOutputStream& rOut)
|
||||
rOut.WriteLong(mSectionSizes[iSec]);
|
||||
rOut.WriteToBoundary(32, 0);
|
||||
|
||||
if (mVersion >= eEchoes)
|
||||
if (mVersion >= EGame::Echoes)
|
||||
WriteCompressionHeader(rOut);
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ void CAreaCooker::WritePrimeSCLY(IOutputStream& rOut)
|
||||
// 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 <= EGame::Prime ? rOut.WriteLong(1) : rOut.WriteByte(1);
|
||||
|
||||
u32 NumLayers = mpArea->mScriptLayers.size();
|
||||
rOut.WriteLong(NumLayers);
|
||||
@@ -227,7 +227,7 @@ void CAreaCooker::WritePrimeSCLY(IOutputStream& rOut)
|
||||
FinishSection(false);
|
||||
|
||||
// SCGN
|
||||
if (mVersion == eEchoesDemo)
|
||||
if (mVersion == EGame::EchoesDemo)
|
||||
{
|
||||
rOut.WriteFourCC( FOURCC('SCGN') );
|
||||
rOut.WriteByte(1);
|
||||
@@ -327,7 +327,7 @@ void CAreaCooker::FinishSection(bool SingleSectionBlock)
|
||||
mSectionSizes.push_back(SecSize);
|
||||
|
||||
// Only track compressed blocks for MP2+. Write everything to one block for MP1.
|
||||
if (mVersion >= eEchoes)
|
||||
if (mVersion >= EGame::Echoes)
|
||||
{
|
||||
// Finish the current block if this is a single section block OR if the new section would push the block over the size limit.
|
||||
if (mCurBlock.NumSections > 0 && (mCurBlock.DecompressedSize + SecSize > kSizeThreshold || SingleSectionBlock))
|
||||
@@ -350,8 +350,8 @@ void CAreaCooker::FinishBlock()
|
||||
if (mCurBlock.NumSections == 0) return;
|
||||
|
||||
std::vector<u8> CompressedBuf(mCompressedData.Size() * 2);
|
||||
bool EnableCompression = (mVersion >= eEchoes) && mpArea->mUsesCompression && !gkForceDisableCompression;
|
||||
bool UseZlib = (mVersion == eReturns);
|
||||
bool EnableCompression = (mVersion >= EGame::Echoes) && mpArea->mUsesCompression && !gkForceDisableCompression;
|
||||
bool UseZlib = (mVersion == EGame::DKCReturns);
|
||||
|
||||
u32 CompressedSize = 0;
|
||||
bool WriteCompressedData = false;
|
||||
@@ -394,7 +394,7 @@ bool CAreaCooker::CookMREA(CGameArea *pArea, IOutputStream& rOut)
|
||||
Cooker.mpArea = pArea;
|
||||
Cooker.mVersion = pArea->Game();
|
||||
|
||||
if (Cooker.mVersion <= eEchoes)
|
||||
if (Cooker.mVersion <= EGame::Echoes)
|
||||
Cooker.DetermineSectionNumbersPrime();
|
||||
else
|
||||
Cooker.DetermineSectionNumbersCorruption();
|
||||
@@ -413,13 +413,13 @@ bool CAreaCooker::CookMREA(CGameArea *pArea, IOutputStream& rOut)
|
||||
}
|
||||
|
||||
// Write SCLY
|
||||
if (Cooker.mVersion <= eEchoesDemo)
|
||||
if (Cooker.mVersion <= EGame::EchoesDemo)
|
||||
Cooker.WritePrimeSCLY(Cooker.mSectionData);
|
||||
else
|
||||
Cooker.WriteEchoesSCLY(Cooker.mSectionData);
|
||||
|
||||
// Write post-SCLY data sections
|
||||
u32 PostSCLY = (Cooker.mVersion <= ePrime ? Cooker.mSCLYSecNum + 1 : Cooker.mSCGNSecNum + 1);
|
||||
u32 PostSCLY = (Cooker.mVersion <= EGame::Prime ? Cooker.mSCLYSecNum + 1 : Cooker.mSCGNSecNum + 1);
|
||||
for (u32 iSec = PostSCLY; iSec < pArea->mSectionDataBuffers.size(); iSec++)
|
||||
{
|
||||
if (iSec == Cooker.mModulesSecNum)
|
||||
@@ -435,7 +435,7 @@ bool CAreaCooker::CookMREA(CGameArea *pArea, IOutputStream& rOut)
|
||||
Cooker.FinishBlock();
|
||||
|
||||
// Write to actual file
|
||||
if (Cooker.mVersion <= eEchoes)
|
||||
if (Cooker.mVersion <= EGame::Echoes)
|
||||
Cooker.WritePrimeHeader(rOut);
|
||||
else
|
||||
Cooker.WriteCorruptionHeader(rOut);
|
||||
@@ -448,13 +448,13 @@ u32 CAreaCooker::GetMREAVersion(EGame Version)
|
||||
{
|
||||
switch (Version)
|
||||
{
|
||||
case ePrimeDemo: return 0xC;
|
||||
case ePrime: return 0xF;
|
||||
case eEchoesDemo: return 0x15;
|
||||
case eEchoes: return 0x19;
|
||||
case eCorruptionProto: return 0x1D;
|
||||
case eCorruption: return 0x1E;
|
||||
case eReturns: return 0x20;
|
||||
default: return 0;
|
||||
case EGame::PrimeDemo: return 0xC;
|
||||
case EGame::Prime: return 0xF;
|
||||
case EGame::EchoesDemo: return 0x15;
|
||||
case EGame::Echoes: return 0x19;
|
||||
case EGame::CorruptionProto: return 0x1D;
|
||||
case EGame::Corruption: return 0x1E;
|
||||
case EGame::DKCReturns: return 0x20;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ void CMaterialCooker::WriteMaterialPrime(IOutputStream& rOut)
|
||||
bool HasKonst = (NumKonst > 0);
|
||||
u32 Flags;
|
||||
|
||||
if (mVersion <= ePrime)
|
||||
if (mVersion <= EGame::Prime)
|
||||
Flags = 0x1003;
|
||||
else
|
||||
Flags = 0x4002;
|
||||
@@ -178,13 +178,13 @@ void CMaterialCooker::WriteMaterialPrime(IOutputStream& rOut)
|
||||
// Vertex description
|
||||
u32 VtxFlags = ConvertFromVertexDescription( mpMat->VtxDesc() );
|
||||
|
||||
if (mVersion < eEchoes)
|
||||
if (mVersion < EGame::Echoes)
|
||||
VtxFlags &= 0x00FFFFFF;
|
||||
|
||||
rOut.WriteLong(VtxFlags);
|
||||
|
||||
// Echoes unknowns
|
||||
if (mVersion == eEchoes)
|
||||
if (mVersion == EGame::Echoes)
|
||||
{
|
||||
rOut.WriteLong(mpMat->EchoesUnknownA());
|
||||
rOut.WriteLong(mpMat->EchoesUnknownB());
|
||||
@@ -359,10 +359,10 @@ void CMaterialCooker::WriteCookedMatSet(CMaterialSet *pSet, EGame Version, IOutp
|
||||
|
||||
switch (Version)
|
||||
{
|
||||
case ePrimeDemo:
|
||||
case ePrime:
|
||||
case eEchoesDemo:
|
||||
case eEchoes:
|
||||
case EGame::PrimeDemo:
|
||||
case EGame::Prime:
|
||||
case EGame::EchoesDemo:
|
||||
case EGame::Echoes:
|
||||
Cooker.WriteMatSetPrime(rOut);
|
||||
break;
|
||||
}
|
||||
@@ -376,10 +376,10 @@ void CMaterialCooker::WriteCookedMaterial(CMaterial *pMat, EGame Version, IOutpu
|
||||
|
||||
switch (Version)
|
||||
{
|
||||
case ePrimeDemo:
|
||||
case ePrime:
|
||||
case eEchoesDemo:
|
||||
case eEchoes:
|
||||
case EGame::PrimeDemo:
|
||||
case EGame::Prime:
|
||||
case EGame::EchoesDemo:
|
||||
case EGame::Echoes:
|
||||
Cooker.WriteMaterialPrime(rOut);
|
||||
break;
|
||||
// TODO: Corruption/Uncooked
|
||||
|
||||
@@ -168,7 +168,7 @@ void CModelCooker::WriteModelPrime(IOutputStream& rOut)
|
||||
{
|
||||
CVertex *pVert = &pPrimitive->Vertices[iVert];
|
||||
|
||||
if (mVersion == eEchoes)
|
||||
if (mVersion == EGame::Echoes)
|
||||
{
|
||||
for (u32 iMtxAttribs = 0; iMtxAttribs < 8; iMtxAttribs++)
|
||||
if (VtxAttribs & (ePosMtx << iMtxAttribs))
|
||||
@@ -232,10 +232,10 @@ bool CModelCooker::CookCMDL(CModel *pModel, IOutputStream& rOut)
|
||||
|
||||
switch (pModel->Game())
|
||||
{
|
||||
case ePrimeDemo:
|
||||
case ePrime:
|
||||
case eEchoesDemo:
|
||||
case eEchoes:
|
||||
case EGame::PrimeDemo:
|
||||
case EGame::Prime:
|
||||
case EGame::EchoesDemo:
|
||||
case EGame::Echoes:
|
||||
Cooker.WriteModelPrime(rOut);
|
||||
return true;
|
||||
|
||||
@@ -248,17 +248,17 @@ u32 CModelCooker::GetCMDLVersion(EGame Version)
|
||||
{
|
||||
switch (Version)
|
||||
{
|
||||
case ePrimeDemo:
|
||||
case ePrime:
|
||||
case EGame::PrimeDemo:
|
||||
case EGame::Prime:
|
||||
return 0x2;
|
||||
case eEchoesDemo:
|
||||
case EGame::EchoesDemo:
|
||||
return 0x3;
|
||||
case eEchoes:
|
||||
case EGame::Echoes:
|
||||
return 0x4;
|
||||
case eCorruptionProto:
|
||||
case eCorruption:
|
||||
case EGame::CorruptionProto:
|
||||
case EGame::Corruption:
|
||||
return 0x5;
|
||||
case eReturns:
|
||||
case EGame::DKCReturns:
|
||||
return 0xA;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
@@ -1,121 +1,149 @@
|
||||
#include "CScriptCooker.h"
|
||||
#include "Core/Resource/Script/CLink.h"
|
||||
#include <Core/Resource/Script/Property/CArrayProperty.h>
|
||||
#include <Core/Resource/Script/Property/CAssetProperty.h>
|
||||
#include <Core/Resource/Script/Property/CEnumProperty.h>
|
||||
#include <Core/Resource/Script/Property/CFlagsProperty.h>
|
||||
|
||||
void CScriptCooker::WriteProperty(IOutputStream& rOut,IProperty *pProp, bool InSingleStruct)
|
||||
void CScriptCooker::WriteProperty(IOutputStream& rOut, IProperty* pProperty, bool InAtomicStruct)
|
||||
{
|
||||
u32 SizeOffset = 0, PropStart = 0;
|
||||
void* pData = (mpArrayItemData ? mpArrayItemData : mpObject->PropertyData());
|
||||
|
||||
if (mGame >= eEchoesDemo && !InSingleStruct)
|
||||
if (mGame >= EGame::EchoesDemo && !InAtomicStruct)
|
||||
{
|
||||
rOut.WriteLong(pProp->ID());
|
||||
rOut.WriteLong(pProperty->ID());
|
||||
SizeOffset = rOut.Tell();
|
||||
rOut.WriteShort(0x0);
|
||||
PropStart = rOut.Tell();
|
||||
}
|
||||
|
||||
switch (pProp->Type())
|
||||
switch (pProperty->Type())
|
||||
{
|
||||
|
||||
case eBoolProperty:
|
||||
case EPropertyType::Bool:
|
||||
{
|
||||
TBoolProperty *pBoolCast = static_cast<TBoolProperty*>(pProp);
|
||||
rOut.WriteBool(pBoolCast->Get());
|
||||
CBoolProperty* pBool = TPropCast<CBoolProperty>(pProperty);
|
||||
rOut.WriteBool( pBool->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case eByteProperty:
|
||||
case EPropertyType::Byte:
|
||||
{
|
||||
TByteProperty *pByteCast = static_cast<TByteProperty*>(pProp);
|
||||
rOut.WriteByte(pByteCast->Get());
|
||||
CByteProperty* pByte = TPropCast<CByteProperty>(pProperty);
|
||||
rOut.WriteByte( pByte->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case eShortProperty:
|
||||
case EPropertyType::Short:
|
||||
{
|
||||
TShortProperty *pShortCast = static_cast<TShortProperty*>(pProp);
|
||||
rOut.WriteShort(pShortCast->Get());
|
||||
CShortProperty* pShort = TPropCast<CShortProperty>(pProperty);
|
||||
rOut.WriteShort( pShort->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case eLongProperty:
|
||||
case EPropertyType::Int:
|
||||
{
|
||||
TLongProperty *pLongCast = static_cast<TLongProperty*>(pProp);
|
||||
rOut.WriteLong(pLongCast->Get());
|
||||
CIntProperty* pInt = TPropCast<CIntProperty>(pProperty);
|
||||
rOut.WriteLong( pInt->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case eEnumProperty:
|
||||
case EPropertyType::Float:
|
||||
{
|
||||
TEnumProperty *pEnumCast = static_cast<TEnumProperty*>(pProp);
|
||||
rOut.WriteLong(pEnumCast->Get());
|
||||
CFloatProperty* pFloat = TPropCast<CFloatProperty>(pProperty);
|
||||
rOut.WriteFloat( pFloat->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case eBitfieldProperty:
|
||||
case EPropertyType::Choice:
|
||||
{
|
||||
TBitfieldProperty *pBitfieldCast = static_cast<TBitfieldProperty*>(pProp);
|
||||
rOut.WriteLong(pBitfieldCast->Get());
|
||||
CChoiceProperty* pChoice = TPropCast<CChoiceProperty>(pProperty);
|
||||
rOut.WriteLong( pChoice->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case eFloatProperty:
|
||||
case EPropertyType::Enum:
|
||||
{
|
||||
TFloatProperty *pFloatCast = static_cast<TFloatProperty*>(pProp);
|
||||
rOut.WriteFloat(pFloatCast->Get());
|
||||
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProperty);
|
||||
rOut.WriteLong( pEnum->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case eStringProperty:
|
||||
case EPropertyType::Flags:
|
||||
{
|
||||
TStringProperty *pStringCast = static_cast<TStringProperty*>(pProp);
|
||||
rOut.WriteString(pStringCast->Get());
|
||||
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProperty);
|
||||
rOut.WriteLong( pFlags->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case eVector3Property:
|
||||
case EPropertyType::String:
|
||||
{
|
||||
TVector3Property *pVectorCast = static_cast<TVector3Property*>(pProp);
|
||||
pVectorCast->Get().Write(rOut);
|
||||
CStringProperty* pString = TPropCast<CStringProperty>(pProperty);
|
||||
rOut.WriteString( pString->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case eColorProperty:
|
||||
case EPropertyType::Vector:
|
||||
{
|
||||
TColorProperty *pColorCast = static_cast<TColorProperty*>(pProp);
|
||||
pColorCast->Get().Write(rOut, false);
|
||||
CVectorProperty* pVector = TPropCast<CVectorProperty>(pProperty);
|
||||
pVector->ValueRef(pData).Write(rOut);
|
||||
break;
|
||||
}
|
||||
|
||||
case eSoundProperty:
|
||||
case EPropertyType::Color:
|
||||
{
|
||||
TSoundProperty *pSoundCast = static_cast<TSoundProperty*>(pProp);
|
||||
rOut.WriteLong(pSoundCast->Get());
|
||||
CColorProperty* pColor = TPropCast<CColorProperty>(pProperty);
|
||||
pColor->ValueRef(pData).Write(rOut);
|
||||
break;
|
||||
}
|
||||
|
||||
case eAssetProperty:
|
||||
case EPropertyType::Asset:
|
||||
{
|
||||
TAssetProperty *pAssetCast = static_cast<TAssetProperty*>(pProp);
|
||||
pAssetCast->Get().Write(rOut);
|
||||
CAssetProperty* pAsset = TPropCast<CAssetProperty>(pProperty);
|
||||
pAsset->ValueRef(pData).Write(rOut);
|
||||
break;
|
||||
}
|
||||
|
||||
case eCharacterProperty:
|
||||
case EPropertyType::Sound:
|
||||
{
|
||||
TCharacterProperty *pCharCast = static_cast<TCharacterProperty*>(pProp);
|
||||
pCharCast->Get().Write(rOut);
|
||||
CSoundProperty* pSound = TPropCast<CSoundProperty>(pProperty);
|
||||
rOut.WriteLong( pSound->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case eMayaSplineProperty:
|
||||
case EPropertyType::Animation:
|
||||
{
|
||||
TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp);
|
||||
std::vector<u8> Buffer = pSplineCast->Get();
|
||||
if (!Buffer.empty()) rOut.WriteBytes(Buffer.data(), Buffer.size());
|
||||
CAnimationProperty* pAnim = TPropCast<CAnimationProperty>(pProperty);
|
||||
rOut.WriteLong( pAnim->Value(pData) );
|
||||
break;
|
||||
}
|
||||
|
||||
case EPropertyType::AnimationSet:
|
||||
{
|
||||
CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(pProperty);
|
||||
pAnimSet->ValueRef(pData).Write(rOut);
|
||||
break;
|
||||
}
|
||||
|
||||
case EPropertyType::Sequence:
|
||||
{
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
|
||||
case EPropertyType::Spline:
|
||||
{
|
||||
CSplineProperty* pSpline = TPropCast<CSplineProperty>(pProperty);
|
||||
std::vector<char>& rBuffer = pSpline->ValueRef(pData);
|
||||
|
||||
if (!rBuffer.empty())
|
||||
{
|
||||
rOut.WriteBytes( rBuffer.data(), rBuffer.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mGame < eReturns)
|
||||
if (mGame < EGame::DKCReturns)
|
||||
{
|
||||
rOut.WriteShort(0);
|
||||
rOut.WriteLong(0);
|
||||
@@ -132,47 +160,63 @@ void CScriptCooker::WriteProperty(IOutputStream& rOut,IProperty *pProp, bool InS
|
||||
rOut.WriteByte(1);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case eStructProperty:
|
||||
case EPropertyType::Guid:
|
||||
{
|
||||
CPropertyStruct *pStruct = static_cast<CPropertyStruct*>(pProp);
|
||||
CStructTemplate *pTemp = static_cast<CStructTemplate*>(pStruct->Template());
|
||||
CGuidProperty* pGuid = TPropCast<CGuidProperty>(pProperty);
|
||||
std::vector<char>& rBuffer = pGuid->ValueRef(pData);
|
||||
|
||||
if (rBuffer.empty())
|
||||
rBuffer.resize(16, 0);
|
||||
|
||||
rOut.WriteBytes( rBuffer.data(), rBuffer.size() );
|
||||
break;
|
||||
}
|
||||
|
||||
case EPropertyType::Struct:
|
||||
{
|
||||
CStructProperty* pStruct = TPropCast<CStructProperty>(pProperty);
|
||||
std::vector<IProperty*> PropertiesToWrite;
|
||||
|
||||
for (u32 iProp = 0; iProp < pStruct->Count(); iProp++)
|
||||
for (u32 ChildIdx = 0; ChildIdx < pStruct->NumChildren(); ChildIdx++)
|
||||
{
|
||||
IProperty *pSubProp = pStruct->PropertyByIndex(iProp);\
|
||||
IProperty *pChild = pStruct->ChildByIndex(ChildIdx);
|
||||
|
||||
if (pTemp->IsSingleProperty() || pSubProp->ShouldCook())
|
||||
PropertiesToWrite.push_back(pSubProp);
|
||||
if (pStruct->IsAtomic() || pChild->ShouldCook(pData))
|
||||
PropertiesToWrite.push_back(pChild);
|
||||
}
|
||||
|
||||
if (!pTemp->IsSingleProperty())
|
||||
if (!pStruct->IsAtomic())
|
||||
{
|
||||
if (mGame <= ePrime)
|
||||
if (mGame <= EGame::Prime)
|
||||
rOut.WriteLong(PropertiesToWrite.size());
|
||||
else
|
||||
rOut.WriteShort((u16) PropertiesToWrite.size());
|
||||
}
|
||||
|
||||
for (u32 iProp = 0; iProp < PropertiesToWrite.size(); iProp++)
|
||||
WriteProperty(rOut, PropertiesToWrite[iProp], pTemp->IsSingleProperty());
|
||||
for (u32 PropertyIdx = 0; PropertyIdx < PropertiesToWrite.size(); PropertyIdx++)
|
||||
WriteProperty(rOut, PropertiesToWrite[PropertyIdx], pStruct->IsAtomic());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case eArrayProperty:
|
||||
case EPropertyType::Array:
|
||||
{
|
||||
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
|
||||
rOut.WriteLong(pArray->Count());
|
||||
CArrayProperty* pArray = TPropCast<CArrayProperty>(pProperty);
|
||||
u32 Count = pArray->ArrayCount(pData);
|
||||
rOut.WriteLong(Count);
|
||||
|
||||
for (u32 iProp = 0; iProp < pArray->Count(); iProp++)
|
||||
WriteProperty(rOut, pArray->PropertyByIndex(iProp), true);
|
||||
void* pOldItemData = mpArrayItemData;
|
||||
|
||||
for (u32 ElementIdx = 0; ElementIdx < pArray->ArrayCount(pData); ElementIdx++)
|
||||
{
|
||||
mpArrayItemData = pArray->ItemPointer(pData, ElementIdx);
|
||||
WriteProperty(rOut, pArray->ItemArchetype(), true);
|
||||
}
|
||||
|
||||
mpArrayItemData = pOldItemData;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -194,7 +238,7 @@ void CScriptCooker::WriteInstance(IOutputStream& rOut, CScriptObject *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);
|
||||
bool IsPrime1 = (mGame <= EGame::Prime);
|
||||
|
||||
u32 ObjectType = pInstance->ObjectTypeID();
|
||||
IsPrime1 ? rOut.WriteByte((u8) ObjectType) : rOut.WriteLong(ObjectType);
|
||||
@@ -209,15 +253,16 @@ void CScriptCooker::WriteInstance(IOutputStream& rOut, CScriptObject *pInstance)
|
||||
u32 NumLinks = pInstance->NumLinks(eOutgoing);
|
||||
IsPrime1 ? rOut.WriteLong(NumLinks) : rOut.WriteShort((u16) NumLinks);
|
||||
|
||||
for (u32 iLink = 0; iLink < pInstance->NumLinks(eOutgoing); iLink++)
|
||||
for (u32 LinkIdx = 0; LinkIdx < NumLinks; LinkIdx++)
|
||||
{
|
||||
CLink *pLink = pInstance->Link(eOutgoing, iLink);
|
||||
CLink *pLink = pInstance->Link(eOutgoing, LinkIdx);
|
||||
rOut.WriteLong(pLink->State());
|
||||
rOut.WriteLong(pLink->Message());
|
||||
rOut.WriteLong(pLink->ReceiverID());
|
||||
}
|
||||
|
||||
WriteProperty(rOut, pInstance->Properties(), false);
|
||||
mpObject = pInstance;
|
||||
WriteProperty(rOut, pInstance->Template()->Properties(), false);
|
||||
u32 InstanceEnd = rOut.Tell();
|
||||
|
||||
rOut.Seek(SizeOffset, SEEK_SET);
|
||||
@@ -230,7 +275,7 @@ void CScriptCooker::WriteLayer(IOutputStream& rOut, CScriptLayer *pLayer)
|
||||
{
|
||||
ASSERT(pLayer->Area()->Game() == mGame);
|
||||
|
||||
rOut.WriteByte( mGame <= ePrime ? 0 : 1 ); // Version
|
||||
rOut.WriteByte( mGame <= EGame::Prime ? 0 : 1 ); // Version
|
||||
|
||||
u32 InstanceCountOffset = rOut.Tell();
|
||||
u32 NumWrittenInstances = 0;
|
||||
@@ -246,7 +291,7 @@ void CScriptCooker::WriteLayer(IOutputStream& rOut, CScriptLayer *pLayer)
|
||||
if (mWriteGeneratedSeparately)
|
||||
{
|
||||
// GenericCreature instances in DKCR always write to both SCLY and SCGN
|
||||
if (mGame == eReturns && pInstance->ObjectTypeID() == FOURCC('GCTR'))
|
||||
if (mGame == EGame::DKCReturns && pInstance->ObjectTypeID() == FOURCC('GCTR'))
|
||||
mGeneratedObjects.push_back(pInstance);
|
||||
|
||||
// Instances receiving a Generate/Activate message (MP2) or a
|
||||
@@ -257,7 +302,7 @@ void CScriptCooker::WriteLayer(IOutputStream& rOut, CScriptLayer *pLayer)
|
||||
{
|
||||
CLink *pLink = pInstance->Link(eIncoming, LinkIdx);
|
||||
|
||||
if (mGame <= eEchoes)
|
||||
if (mGame <= EGame::Echoes)
|
||||
{
|
||||
if (pLink->State() == FOURCC('GRNT') && pLink->Message() == FOURCC('ACTV'))
|
||||
{
|
||||
@@ -302,6 +347,6 @@ void CScriptCooker::WriteGeneratedLayer(IOutputStream& rOut)
|
||||
rOut.WriteByte(1); // Version
|
||||
rOut.WriteLong(mGeneratedObjects.size());
|
||||
|
||||
for (u32 InstIdx = 0; InstIdx < mGeneratedObjects.size(); InstIdx++)
|
||||
WriteInstance(rOut, mGeneratedObjects[InstIdx]);
|
||||
for (u32 ObjectIdx = 0; ObjectIdx < mGeneratedObjects.size(); ObjectIdx++)
|
||||
WriteInstance(rOut, mGeneratedObjects[ObjectIdx]);
|
||||
}
|
||||
|
||||
@@ -10,15 +10,19 @@
|
||||
class CScriptCooker
|
||||
{
|
||||
EGame mGame;
|
||||
CScriptObject* mpObject;
|
||||
void* mpArrayItemData;
|
||||
std::vector<CScriptObject*> mGeneratedObjects;
|
||||
bool mWriteGeneratedSeparately;
|
||||
|
||||
void WriteProperty(IOutputStream& rOut,IProperty *pProp, bool InSingleStruct);
|
||||
void WriteProperty(IOutputStream& rOut, IProperty* pProperty, bool InAtomicStruct);
|
||||
|
||||
public:
|
||||
CScriptCooker(EGame Game, bool WriteGeneratedObjectsSeparately = true)
|
||||
: mGame(Game)
|
||||
, mWriteGeneratedSeparately(WriteGeneratedObjectsSeparately && mGame >= eEchoesDemo)
|
||||
, mpObject(nullptr)
|
||||
, mpArrayItemData(nullptr)
|
||||
, mWriteGeneratedSeparately(WriteGeneratedObjectsSeparately && mGame >= EGame::EchoesDemo)
|
||||
{}
|
||||
|
||||
void WriteInstance(IOutputStream& rOut, CScriptObject *pInstance);
|
||||
|
||||
@@ -1,841 +0,0 @@
|
||||
#include "CTemplateWriter.h"
|
||||
#include "CAreaCooker.h"
|
||||
#include <Common/FileUtil.h>
|
||||
|
||||
#include <tinyxml2.h>
|
||||
|
||||
using namespace tinyxml2;
|
||||
TString CTemplateWriter::smTemplatesDir = "../templates/";
|
||||
|
||||
CTemplateWriter::CTemplateWriter()
|
||||
{
|
||||
}
|
||||
|
||||
void CTemplateWriter::SavePropertyTemplate(IPropertyTemplate *pTemp)
|
||||
{
|
||||
// Check for a source file in the template's hierarchy; that indicates it's part of a struct template, not a script template
|
||||
TString SourceFile = pTemp->FindStructSource();
|
||||
|
||||
// Struct
|
||||
if (!SourceFile.IsEmpty())
|
||||
{
|
||||
CMasterTemplate *pMaster = pTemp->MasterTemplate();
|
||||
auto StructIt = pMaster->mStructTemplates.find(SourceFile);
|
||||
|
||||
if (StructIt != pMaster->mStructTemplates.end())
|
||||
{
|
||||
CStructTemplate *pStruct = StructIt->second;
|
||||
CTemplateWriter::SaveStructTemplate(pStruct);
|
||||
}
|
||||
}
|
||||
|
||||
// Script
|
||||
else if (pTemp->ScriptTemplate())
|
||||
CTemplateWriter::SaveScriptTemplate(pTemp->ScriptTemplate());
|
||||
|
||||
// Error
|
||||
else
|
||||
Log::Error("Couldn't save property template " + pTemp->IDString(true) + "; no struct template source path or script template found");
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveAllTemplates()
|
||||
{
|
||||
// Create directory
|
||||
std::list<CMasterTemplate*> MasterList = CMasterTemplate::MasterList();
|
||||
FileUtil::MakeDirectory(smTemplatesDir);
|
||||
|
||||
// Resave property list
|
||||
SavePropertyList();
|
||||
|
||||
// Resave master templates
|
||||
for (auto it = MasterList.begin(); it != MasterList.end(); it++)
|
||||
SaveGameTemplates(*it);
|
||||
|
||||
// Resave game list
|
||||
XMLDocument GameList;
|
||||
|
||||
XMLDeclaration *pDecl = GameList.NewDeclaration();
|
||||
GameList.LinkEndChild(pDecl);
|
||||
|
||||
XMLElement *pBase = GameList.NewElement("GameList");
|
||||
pBase->SetAttribute("version", 4);
|
||||
GameList.LinkEndChild(pBase);
|
||||
|
||||
XMLElement *pProperties = GameList.NewElement("properties");
|
||||
pProperties->SetText("Properties.xml");
|
||||
pBase->LinkEndChild(pProperties);
|
||||
|
||||
for (auto it = MasterList.begin(); it != MasterList.end(); it++)
|
||||
{
|
||||
CMasterTemplate *pMaster = *it;
|
||||
|
||||
XMLElement *pGame = GameList.NewElement("game");
|
||||
pBase->LinkEndChild(pGame);
|
||||
|
||||
XMLElement *pGameName = GameList.NewElement("name");
|
||||
pGameName->SetText(*pMaster->mGameName);
|
||||
pGame->LinkEndChild(pGameName);
|
||||
|
||||
XMLElement *pAreaVersion = GameList.NewElement("mrea");
|
||||
u32 VersionNumber = CAreaCooker::GetMREAVersion(pMaster->Game());
|
||||
pAreaVersion->SetText(*TString::HexString(VersionNumber, 2));
|
||||
pGame->LinkEndChild(pAreaVersion);
|
||||
|
||||
XMLElement *pTempPath = GameList.NewElement("master");
|
||||
pTempPath->SetText(*pMaster->mSourceFile);
|
||||
pGame->LinkEndChild(pTempPath);
|
||||
}
|
||||
|
||||
TString GameListName = smTemplatesDir + "GameList.xml";
|
||||
GameList.SaveFile(*GameListName);
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveGameTemplates(CMasterTemplate *pMaster)
|
||||
{
|
||||
// Create directory
|
||||
TString OutFile = smTemplatesDir + pMaster->mSourceFile;
|
||||
TString OutDir = OutFile.GetFileDirectory();
|
||||
FileUtil::MakeDirectory(OutDir);
|
||||
|
||||
// Resave script templates
|
||||
for (auto it = pMaster->mTemplates.begin(); it != pMaster->mTemplates.end(); it++)
|
||||
SaveScriptTemplate(it->second);
|
||||
|
||||
// Resave struct templates
|
||||
for (auto it = pMaster->mStructTemplates.begin(); it != pMaster->mStructTemplates.end(); it++)
|
||||
SaveStructTemplate(it->second);
|
||||
|
||||
// Resave master template
|
||||
XMLDocument Master;
|
||||
|
||||
XMLDeclaration *pDecl = Master.NewDeclaration();
|
||||
Master.LinkEndChild(pDecl);
|
||||
|
||||
XMLElement *pBase = Master.NewElement("MasterTemplate");
|
||||
pBase->SetAttribute("version", 4);
|
||||
Master.LinkEndChild(pBase);
|
||||
|
||||
// Write versions
|
||||
if (!pMaster->mGameVersions.empty())
|
||||
{
|
||||
XMLElement *pVersionsBlock = Master.NewElement("versions");
|
||||
pBase->LinkEndChild(pVersionsBlock);
|
||||
|
||||
for (auto it = pMaster->mGameVersions.begin(); it != pMaster->mGameVersions.end(); it++)
|
||||
{
|
||||
XMLElement *pVersion = Master.NewElement("version");
|
||||
pVersion->SetText(*(*it));
|
||||
pVersionsBlock->LinkEndChild(pVersion);
|
||||
}
|
||||
}
|
||||
|
||||
// Write script objects
|
||||
XMLElement *pObjects = Master.NewElement("objects");
|
||||
pBase->LinkEndChild(pObjects);
|
||||
|
||||
for (auto it = pMaster->mTemplates.begin(); it != pMaster->mTemplates.end(); it++)
|
||||
{
|
||||
u32 ObjID = (it->second)->ObjectID();
|
||||
|
||||
TString StrID;
|
||||
if (ObjID <= 0xFF)
|
||||
StrID = TString::HexString(ObjID, 2);
|
||||
else
|
||||
StrID = CFourCC(ObjID).ToString();
|
||||
|
||||
XMLElement *pObj = Master.NewElement("object");
|
||||
pObj->SetAttribute("ID", *StrID);
|
||||
pObj->SetAttribute("template", *(it->second)->mSourceFile);
|
||||
pObjects->LinkEndChild(pObj);
|
||||
}
|
||||
|
||||
// Write script states/messages
|
||||
for (u32 iType = 0; iType < 2; iType++)
|
||||
{
|
||||
TString Type = (iType == 0 ? "state" : "message");
|
||||
XMLElement *pElem = Master.NewElement(*(Type + "s"));
|
||||
pBase->LinkEndChild(pElem);
|
||||
|
||||
u32 Num = (iType == 0 ? pMaster->NumStates() : pMaster->NumMessages());
|
||||
|
||||
for (u32 iScr = 0; iScr < Num; iScr++)
|
||||
{
|
||||
u32 ID;
|
||||
TString Name;
|
||||
|
||||
if (iType == 0)
|
||||
{
|
||||
SState State = pMaster->StateByIndex(iScr);
|
||||
ID = State.ID;
|
||||
Name = State.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
SMessage Message = pMaster->MessageByIndex(iScr);
|
||||
ID = Message.ID;
|
||||
Name = Message.Name;
|
||||
}
|
||||
|
||||
TString StrID;
|
||||
if (ID <= 0xFF) StrID = TString::HexString(ID, 2);
|
||||
else StrID = CFourCC(ID).ToString();
|
||||
|
||||
XMLElement *pSubElem = Master.NewElement(*Type);
|
||||
pSubElem->SetAttribute("ID", *StrID);
|
||||
pSubElem->SetAttribute("name", *Name);
|
||||
pElem->LinkEndChild(pSubElem);
|
||||
}
|
||||
}
|
||||
|
||||
// Save file
|
||||
Master.SaveFile(*OutFile);
|
||||
}
|
||||
|
||||
void CTemplateWriter::SavePropertyList()
|
||||
{
|
||||
// Create XML
|
||||
XMLDocument List;
|
||||
|
||||
XMLDeclaration *pDecl = List.NewDeclaration();
|
||||
List.LinkEndChild(pDecl);
|
||||
|
||||
XMLElement *pBase = List.NewElement("Properties");
|
||||
pBase->SetAttribute("version", 4);
|
||||
List.LinkEndChild(pBase);
|
||||
|
||||
// Write properties
|
||||
for (auto it = CMasterTemplate::smPropertyNames.begin(); it != CMasterTemplate::smPropertyNames.end(); it++)
|
||||
{
|
||||
u32 ID = it->first;
|
||||
TString Name = it->second;
|
||||
|
||||
XMLElement *pElem = List.NewElement("property");
|
||||
pElem->SetAttribute("ID", *TString::HexString(ID));
|
||||
pElem->SetAttribute("name", *Name);
|
||||
pBase->LinkEndChild(pElem);
|
||||
}
|
||||
|
||||
TString OutFile = smTemplatesDir + "Properties.xml";
|
||||
List.SaveFile(*OutFile);
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveScriptTemplate(CScriptTemplate *pTemp)
|
||||
{
|
||||
CMasterTemplate *pMaster = pTemp->MasterTemplate();
|
||||
|
||||
// Create directory
|
||||
TString OutFile = smTemplatesDir + pMaster->GetDirectory() + pTemp->mSourceFile;
|
||||
TString OutDir = OutFile.GetFileDirectory();
|
||||
FileUtil::MakeDirectory(*OutDir);
|
||||
|
||||
// Create new document
|
||||
XMLDocument ScriptXML;
|
||||
|
||||
XMLDeclaration *pDecl = ScriptXML.NewDeclaration();
|
||||
ScriptXML.LinkEndChild(pDecl);
|
||||
|
||||
// Base element
|
||||
XMLElement *pRoot = ScriptXML.NewElement("ScriptTemplate");
|
||||
pRoot->SetAttribute("version", 4);
|
||||
ScriptXML.LinkEndChild(pRoot);
|
||||
|
||||
// Write object name
|
||||
XMLElement *pName = ScriptXML.NewElement("name");
|
||||
pName->SetText(*pTemp->Name());
|
||||
pRoot->LinkEndChild(pName);
|
||||
|
||||
// Write modules
|
||||
if (!pTemp->mModules.empty())
|
||||
{
|
||||
XMLElement *pModules = ScriptXML.NewElement("modules");
|
||||
pRoot->LinkEndChild(pModules);
|
||||
|
||||
for (u32 iMod = 0; iMod < pTemp->mModules.size(); iMod++)
|
||||
{
|
||||
XMLElement *pModule = ScriptXML.NewElement("module");
|
||||
pModule->SetText(*pTemp->mModules[iMod]);
|
||||
pModules->LinkEndChild(pModule);
|
||||
}
|
||||
}
|
||||
|
||||
// Write properties
|
||||
SaveProperties(&ScriptXML, pRoot, pTemp->mpBaseStruct);
|
||||
|
||||
// States/Messages [todo]
|
||||
XMLElement *pStates = ScriptXML.NewElement("states");
|
||||
pRoot->LinkEndChild(pStates);
|
||||
|
||||
XMLElement *pMessages = ScriptXML.NewElement("messages");
|
||||
pRoot->LinkEndChild(pMessages);
|
||||
|
||||
// Write editor properties
|
||||
XMLElement *pEditor = ScriptXML.NewElement("editor");
|
||||
pRoot->LinkEndChild(pEditor);
|
||||
|
||||
// Editor Properties
|
||||
XMLElement *pEditorProperties = ScriptXML.NewElement("properties");
|
||||
pEditor->LinkEndChild(pEditorProperties);
|
||||
|
||||
TString PropNames[6] = {
|
||||
"InstanceName", "Position", "Rotation",
|
||||
"Scale", "Active", "LightParameters"
|
||||
};
|
||||
|
||||
TIDString *pPropStrings[6] = {
|
||||
&pTemp->mNameIDString, &pTemp->mPositionIDString, &pTemp->mRotationIDString,
|
||||
&pTemp->mScaleIDString, &pTemp->mActiveIDString, &pTemp->mLightParametersIDString
|
||||
};
|
||||
|
||||
for (u32 iProp = 0; iProp < 6; iProp++)
|
||||
{
|
||||
if (!pPropStrings[iProp]->IsEmpty())
|
||||
{
|
||||
XMLElement *pProperty = ScriptXML.NewElement("property");
|
||||
pProperty->SetAttribute("name", *PropNames[iProp]);
|
||||
pProperty->SetAttribute("ID", **pPropStrings[iProp]);
|
||||
pEditorProperties->LinkEndChild(pProperty);
|
||||
}
|
||||
}
|
||||
|
||||
// Editor Assets
|
||||
XMLElement *pAssets = ScriptXML.NewElement("assets");
|
||||
pEditor->LinkEndChild(pAssets);
|
||||
|
||||
for (auto it = pTemp->mAssets.begin(); it != pTemp->mAssets.end(); it++)
|
||||
{
|
||||
TString Source = (it->AssetSource == CScriptTemplate::SEditorAsset::eFile ? "file" : "property");
|
||||
TString Type;
|
||||
|
||||
switch (it->AssetType)
|
||||
{
|
||||
case CScriptTemplate::SEditorAsset::eModel: Type = "model"; break;
|
||||
case CScriptTemplate::SEditorAsset::eAnimParams: Type = "animparams"; break;
|
||||
case CScriptTemplate::SEditorAsset::eBillboard: Type = "billboard"; break;
|
||||
case CScriptTemplate::SEditorAsset::eCollision: Type = "collision"; break;
|
||||
}
|
||||
|
||||
s32 Force = -1;
|
||||
if (it->AssetType == CScriptTemplate::SEditorAsset::eAnimParams)
|
||||
Force = it->ForceNodeIndex;
|
||||
|
||||
XMLElement *pAsset = ScriptXML.NewElement(*Type);
|
||||
pAsset->SetAttribute("source", *Source);
|
||||
if (Force >= 0) pAsset->SetAttribute("force", *TString::FromInt32(Force, 0, 10));
|
||||
pAsset->SetText(*it->AssetLocation);
|
||||
pAssets->LinkEndChild(pAsset);
|
||||
}
|
||||
|
||||
// Attachments
|
||||
if (!pTemp->mAttachments.empty())
|
||||
{
|
||||
XMLElement *pAttachments = ScriptXML.NewElement("attachments");
|
||||
pEditor->LinkEndChild(pAttachments);
|
||||
|
||||
for (auto it = pTemp->mAttachments.begin(); it != pTemp->mAttachments.end(); it++)
|
||||
{
|
||||
XMLElement *pAttachment = ScriptXML.NewElement("attachment");
|
||||
pAttachment->SetAttribute("propertyID", *it->AttachProperty);
|
||||
pAttachment->SetAttribute("locator", *it->LocatorName);
|
||||
pAttachments->LinkEndChild(pAttachment);
|
||||
|
||||
// Sub-properties
|
||||
if (it->AttachType != eAttach)
|
||||
{
|
||||
XMLElement *pAttachType = ScriptXML.NewElement("attach_type");
|
||||
pAttachType->SetText("follow");
|
||||
pAttachment->LinkEndChild(pAttachType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preview Scale
|
||||
if (pTemp->mPreviewScale != 1.f)
|
||||
{
|
||||
XMLElement *pPreviewScale = ScriptXML.NewElement("preview_scale");
|
||||
pPreviewScale->SetText(*TString::FromFloat(pTemp->mPreviewScale));
|
||||
pEditor->LinkEndChild(pPreviewScale);
|
||||
}
|
||||
|
||||
// Rot/Scale Type
|
||||
XMLElement *pRotType = ScriptXML.NewElement("rotation_type");
|
||||
pEditor->LinkEndChild(pRotType);
|
||||
pRotType->SetText(pTemp->mRotationType == CScriptTemplate::eRotationEnabled ? "enabled" : "disabled");
|
||||
|
||||
XMLElement *pScaleType = ScriptXML.NewElement("scale_type");
|
||||
pEditor->LinkEndChild(pScaleType);
|
||||
|
||||
if (pTemp->mScaleType != CScriptTemplate::eScaleVolume)
|
||||
pScaleType->SetText(pTemp->mScaleType == CScriptTemplate::eScaleEnabled ? "enabled" : "disabled");
|
||||
|
||||
else
|
||||
{
|
||||
pScaleType->SetText("volume");
|
||||
|
||||
// Volume Preview
|
||||
XMLElement *pVolume = ScriptXML.NewElement("preview_volume");
|
||||
pEditor->LinkEndChild(pVolume);
|
||||
|
||||
// Enum -> String conversion lambda to avoid redundant code
|
||||
auto GetVolumeString = [](EVolumeShape shape) -> TString
|
||||
{
|
||||
switch (shape)
|
||||
{
|
||||
case eBoxShape: return "Box";
|
||||
case eAxisAlignedBoxShape: return "AxisAlignedBox";
|
||||
case eEllipsoidShape: return "Ellipsoid";
|
||||
case eCylinderShape: return "Cylinder";
|
||||
case eConditionalShape: return "Conditional";
|
||||
default: return "INVALID";
|
||||
}
|
||||
};
|
||||
|
||||
pVolume->SetAttribute("shape", *GetVolumeString(pTemp->mVolumeShape));
|
||||
|
||||
if (pTemp->mVolumeScale != 1.f)
|
||||
pVolume->SetAttribute("scale", pTemp->mVolumeScale);
|
||||
|
||||
if (pTemp->mVolumeShape == eConditionalShape)
|
||||
{
|
||||
pVolume->SetAttribute("propertyID", *pTemp->mVolumeConditionIDString);
|
||||
|
||||
// Find conditional test property
|
||||
IPropertyTemplate *pProp = pTemp->mpBaseStruct->PropertyByIDString(pTemp->mVolumeConditionIDString);
|
||||
|
||||
// Write conditions
|
||||
for (auto it = pTemp->mVolumeConditions.begin(); it != pTemp->mVolumeConditions.end(); it++)
|
||||
{
|
||||
// Value should be an integer, or a boolean condition
|
||||
TString StrVal;
|
||||
|
||||
if (pProp->Type() == eBoolProperty)
|
||||
StrVal = (it->Value == 1 ? "true" : "false");
|
||||
else
|
||||
StrVal = TString::HexString((u32) it->Value, (it->Value > 0xFF ? 8 : 2));
|
||||
|
||||
XMLElement *pCondition = ScriptXML.NewElement("condition");
|
||||
pCondition->SetAttribute("value", *StrVal);
|
||||
pCondition->SetAttribute("shape", *GetVolumeString(it->Shape));
|
||||
if (it->Scale != 1.f) pCondition->SetAttribute("scale", it->Scale);
|
||||
pVolume->LinkEndChild(pCondition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write to file
|
||||
ScriptXML.SaveFile(*OutFile);
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveStructTemplate(CStructTemplate *pTemp)
|
||||
{
|
||||
// Create directory
|
||||
CMasterTemplate *pMaster = pTemp->MasterTemplate();
|
||||
TString OutFile = smTemplatesDir + pMaster->GetDirectory() + pTemp->mSourceFile;
|
||||
TString OutDir = OutFile.GetFileDirectory();
|
||||
TString Name = OutFile.GetFileName(false);
|
||||
FileUtil::MakeDirectory(OutDir);
|
||||
|
||||
// Create new document and write struct properties to it
|
||||
XMLDocument StructXML;
|
||||
|
||||
XMLDeclaration *pDecl = StructXML.NewDeclaration();
|
||||
StructXML.LinkEndChild(pDecl);
|
||||
|
||||
XMLElement *pRoot = StructXML.NewElement("struct");
|
||||
pRoot->SetAttribute("name", *Name);
|
||||
pRoot->SetAttribute("type", (pTemp->IsSingleProperty() ? "single" : "multi"));
|
||||
StructXML.LinkEndChild(pRoot);
|
||||
|
||||
SaveProperties(&StructXML, pRoot, pTemp);
|
||||
StructXML.SaveFile(*OutFile);
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveEnumTemplate(CEnumTemplate *pTemp)
|
||||
{
|
||||
// Create directory
|
||||
CMasterTemplate *pMaster = pTemp->MasterTemplate();
|
||||
TString OutFile = smTemplatesDir + pMaster->GetDirectory() + pTemp->mSourceFile;
|
||||
TString OutDir = OutFile.GetFileDirectory();
|
||||
TString Name = OutFile.GetFileName(false);
|
||||
FileUtil::MakeDirectory(OutDir);
|
||||
|
||||
// Create new document and write enumerators to it
|
||||
XMLDocument EnumXML;
|
||||
|
||||
XMLDeclaration *pDecl = EnumXML.NewDeclaration();
|
||||
EnumXML.LinkEndChild(pDecl);
|
||||
|
||||
XMLElement *pRoot = EnumXML.NewElement("enum");
|
||||
pRoot->SetAttribute("name", *Name);
|
||||
EnumXML.LinkEndChild(pRoot);
|
||||
|
||||
SaveEnumerators(&EnumXML, pRoot, pTemp);
|
||||
EnumXML.SaveFile(*OutFile);
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveBitfieldTemplate(CBitfieldTemplate *pTemp)
|
||||
{
|
||||
// Create directory
|
||||
CMasterTemplate *pMaster = pTemp->MasterTemplate();
|
||||
TString OutFile = smTemplatesDir + pMaster->GetDirectory() + pTemp->mSourceFile;
|
||||
TString OutDir = OutFile.GetFileDirectory();
|
||||
TString Name = pTemp->mSourceFile.GetFileName(false);
|
||||
FileUtil::MakeDirectory(OutDir);
|
||||
|
||||
// Create new document and write enumerators to it
|
||||
XMLDocument BitfieldXML;
|
||||
|
||||
XMLDeclaration *pDecl = BitfieldXML.NewDeclaration();
|
||||
BitfieldXML.LinkEndChild(pDecl);
|
||||
|
||||
XMLElement *pRoot = BitfieldXML.NewElement("bitfield");
|
||||
pRoot->SetAttribute("name", *Name);
|
||||
BitfieldXML.LinkEndChild(pRoot);
|
||||
|
||||
SaveBitFlags(&BitfieldXML, pRoot, pTemp);
|
||||
BitfieldXML.SaveFile(*OutFile);
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveProperties(XMLDocument *pDoc, XMLElement *pParent, CStructTemplate *pTemp)
|
||||
{
|
||||
// Create base element
|
||||
XMLElement *pPropsBlock = pDoc->NewElement("properties");
|
||||
pParent->LinkEndChild(pPropsBlock);
|
||||
|
||||
for (u32 iProp = 0; iProp < pTemp->Count(); iProp++)
|
||||
{
|
||||
// Get ID
|
||||
IPropertyTemplate *pProp = pTemp->PropertyByIndex(iProp);
|
||||
u32 ID = pProp->PropertyID();
|
||||
TString StrID = TString::HexString(ID, (ID > 0xFF ? 8 : 2));
|
||||
|
||||
// Create element
|
||||
XMLElement *pElem;
|
||||
|
||||
if (pProp->Type() == eStructProperty)
|
||||
pElem = pDoc->NewElement("struct");
|
||||
else if (pProp->Type() == eEnumProperty)
|
||||
pElem = pDoc->NewElement("enum");
|
||||
else if (pProp->Type() == eBitfieldProperty)
|
||||
pElem = pDoc->NewElement("bitfield");
|
||||
else if (pProp->Type() == eArrayProperty)
|
||||
pElem = pDoc->NewElement("array");
|
||||
else
|
||||
pElem = pDoc->NewElement("property");
|
||||
|
||||
pPropsBlock->LinkEndChild(pElem);
|
||||
|
||||
// Set common property parameters, starting with ID
|
||||
pElem->SetAttribute("ID", *StrID);
|
||||
|
||||
// Name
|
||||
TString Name = pProp->Name();
|
||||
|
||||
if (pProp->Game() >= eEchoesDemo && ID > 0xFF)
|
||||
{
|
||||
TString MasterName = CMasterTemplate::PropertyName(ID);
|
||||
|
||||
if (Name != MasterName)
|
||||
pElem->SetAttribute("name", *Name);
|
||||
}
|
||||
|
||||
else
|
||||
pElem->SetAttribute("name", *Name);
|
||||
|
||||
// Type
|
||||
if (pProp->Type() == eStructProperty)
|
||||
{
|
||||
CStructTemplate *pStruct = static_cast<CStructTemplate*>(pProp);
|
||||
|
||||
if (pStruct->mSourceFile.IsEmpty())
|
||||
pElem->SetAttribute("type", (pStruct->mIsSingleProperty ? "single" : "multi"));
|
||||
}
|
||||
|
||||
else if (TString(pElem->Name()) == "property")
|
||||
pElem->SetAttribute("type", *PropEnumToPropString(pProp->Type()));
|
||||
|
||||
// Versions
|
||||
CMasterTemplate *pMaster = pProp->MasterTemplate();
|
||||
u32 NumVersions = pProp->mAllowedVersions.size();
|
||||
|
||||
if (NumVersions > 0 && NumVersions != pMaster->mGameVersions.size())
|
||||
{
|
||||
XMLElement *pVersions = pDoc->NewElement("versions");
|
||||
pElem->LinkEndChild(pVersions);
|
||||
|
||||
for (u32 iVer = 0; iVer < pMaster->mGameVersions.size(); iVer++)
|
||||
{
|
||||
if (pProp->IsInVersion(iVer))
|
||||
{
|
||||
XMLElement *pVersion = pDoc->NewElement("version");
|
||||
pVersion->SetText(*pMaster->mGameVersions[iVer]);
|
||||
pVersions->LinkEndChild(pVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default
|
||||
if (pProp->CanHaveDefault() && pProp->Game() >= eEchoesDemo)
|
||||
{
|
||||
XMLElement *pDefault = pDoc->NewElement("default");
|
||||
pDefault->SetText(*pProp->DefaultToString());
|
||||
pElem->LinkEndChild(pDefault);
|
||||
}
|
||||
|
||||
// Description
|
||||
if (!pProp->Description().IsEmpty())
|
||||
{
|
||||
XMLElement *pDesc = pDoc->NewElement("description");
|
||||
pDesc->SetText(*pProp->Description());
|
||||
pElem->LinkEndChild(pDesc);
|
||||
}
|
||||
|
||||
// Range
|
||||
if (pProp->IsNumerical() && pProp->HasValidRange())
|
||||
{
|
||||
XMLElement *pRange = pDoc->NewElement("range");
|
||||
pRange->SetText(*pProp->RangeToString());
|
||||
pElem->LinkEndChild(pRange);
|
||||
}
|
||||
|
||||
// Suffix
|
||||
if (pProp->IsNumerical())
|
||||
{
|
||||
TString Suffix = pProp->Suffix();
|
||||
|
||||
if (!Suffix.IsEmpty())
|
||||
{
|
||||
XMLElement *pSuffix = pDoc->NewElement("suffix");
|
||||
pSuffix->SetText(*Suffix);
|
||||
pElem->LinkEndChild(pSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
// Cook Pref
|
||||
ECookPreference CookPref = pProp->CookPreference();
|
||||
|
||||
if (CookPref != eNoCookPreference)
|
||||
{
|
||||
XMLElement *pCookPref = pDoc->NewElement("cook_pref");
|
||||
pCookPref->SetText(CookPref == eAlwaysCook ? "always" : "never");
|
||||
pElem->LinkEndChild(pCookPref);
|
||||
}
|
||||
|
||||
// Asset-specific parameters
|
||||
if (pProp->Type() == eAssetProperty)
|
||||
{
|
||||
CAssetTemplate *pAsset = static_cast<CAssetTemplate*>(pProp);
|
||||
const CResTypeFilter& rkFilter = pAsset->TypeFilter();
|
||||
TString ExtensionsString = rkFilter.ToString();
|
||||
if (ExtensionsString.IsEmpty()) ExtensionsString = "UNKN";
|
||||
pElem->SetAttribute("extensions", *ExtensionsString);
|
||||
}
|
||||
|
||||
// Enum-specific parameters
|
||||
else if (pProp->Type() == eEnumProperty)
|
||||
{
|
||||
CEnumTemplate *pEnum = static_cast<CEnumTemplate*>(pProp);
|
||||
|
||||
if (pEnum->mSourceFile.IsEmpty())
|
||||
SaveEnumerators(pDoc, pElem, pEnum);
|
||||
|
||||
else
|
||||
{
|
||||
SaveEnumTemplate(pEnum);
|
||||
pElem->SetAttribute("template", *pEnum->mSourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Bitfield-specific parameters
|
||||
else if (pProp->Type() == eBitfieldProperty)
|
||||
{
|
||||
CBitfieldTemplate *pBitfield = static_cast<CBitfieldTemplate*>(pProp);
|
||||
|
||||
if (pBitfield->mSourceFile.IsEmpty())
|
||||
SaveBitFlags(pDoc, pElem, pBitfield);
|
||||
|
||||
else
|
||||
{
|
||||
SaveBitfieldTemplate(pBitfield);
|
||||
pElem->SetAttribute("template", *pBitfield->mSourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Struct/array-specific parameters
|
||||
else if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty)
|
||||
{
|
||||
// Element Name
|
||||
if (pProp->Type() == eArrayProperty)
|
||||
{
|
||||
CArrayTemplate *pArray = static_cast<CArrayTemplate*>(pProp);
|
||||
|
||||
if (!pArray->ElementName().IsEmpty())
|
||||
{
|
||||
XMLElement *pElement = pDoc->NewElement("element_name");
|
||||
pElement->SetText(*static_cast<CArrayTemplate*>(pProp)->ElementName());
|
||||
pElem->LinkEndChild(pElement);
|
||||
}
|
||||
}
|
||||
|
||||
// Sub-properties
|
||||
CStructTemplate *pStruct = static_cast<CStructTemplate*>(pProp);
|
||||
|
||||
if (pStruct->mSourceFile.IsEmpty())
|
||||
SaveProperties(pDoc, pElem, pStruct);
|
||||
|
||||
else
|
||||
{
|
||||
CStructTemplate *pOriginal = pMaster->StructAtSource(pStruct->mSourceFile);
|
||||
|
||||
if (pOriginal)
|
||||
SavePropertyOverrides(pDoc, pElem, pStruct, pOriginal);
|
||||
|
||||
pElem->SetAttribute("template", *pStruct->mSourceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTemplateWriter::SavePropertyOverrides(XMLDocument *pDoc, XMLElement *pParent, CStructTemplate *pStruct, CStructTemplate *pOriginal)
|
||||
{
|
||||
if (!pStruct->StructDataMatches(pOriginal))
|
||||
{
|
||||
// Create base element
|
||||
XMLElement *pPropsBlock = pDoc->NewElement("properties");
|
||||
pParent->LinkEndChild(pPropsBlock);
|
||||
|
||||
for (u32 iProp = 0; iProp < pStruct->Count(); iProp++)
|
||||
{
|
||||
IPropertyTemplate *pProp = pStruct->PropertyByIndex(iProp);
|
||||
IPropertyTemplate *pSource = pOriginal->PropertyByIndex(iProp);
|
||||
|
||||
if (!pProp->Matches(pSource))
|
||||
{
|
||||
// Create element
|
||||
XMLElement *pElem;
|
||||
|
||||
if (pProp->Type() == eStructProperty)
|
||||
pElem = pDoc->NewElement("struct");
|
||||
else if (pProp->Type() == eEnumProperty)
|
||||
pElem = pDoc->NewElement("enum");
|
||||
else if (pProp->Type() == eBitfieldProperty)
|
||||
pElem = pDoc->NewElement("bitfield");
|
||||
else if (pProp->Type() == eArrayProperty)
|
||||
pElem = pDoc->NewElement("array");
|
||||
else
|
||||
pElem = pDoc->NewElement("property");
|
||||
|
||||
pPropsBlock->LinkEndChild(pElem);
|
||||
|
||||
// ID
|
||||
u32 ID = pProp->PropertyID();
|
||||
pElem->SetAttribute("ID", *TString::HexString(pProp->PropertyID(), (ID > 0xFF ? 8 : 2)));
|
||||
|
||||
// Name
|
||||
if (pProp->Name() != pSource->Name())
|
||||
pElem->SetAttribute("name", *pProp->Name());
|
||||
|
||||
// Default
|
||||
if (pProp->CanHaveDefault() && !pProp->RawDefaultValue()->Matches(pSource->RawDefaultValue()))
|
||||
{
|
||||
XMLElement *pDefault = pDoc->NewElement("default");
|
||||
pDefault->SetText(*pProp->DefaultToString());
|
||||
pElem->LinkEndChild(pDefault);
|
||||
}
|
||||
|
||||
// Description
|
||||
if (pProp->Description() != pSource->Description())
|
||||
{
|
||||
XMLElement *pDesc = pDoc->NewElement("description");
|
||||
pDesc->SetText(*pProp->Description());
|
||||
pElem->LinkEndChild(pDesc);
|
||||
}
|
||||
|
||||
// Range
|
||||
if (pProp->IsNumerical())
|
||||
{
|
||||
TString Range = pProp->RangeToString();
|
||||
|
||||
if (Range != pSource->RangeToString())
|
||||
{
|
||||
XMLElement *pRange = pDoc->NewElement("range");
|
||||
pRange->SetText(*Range);
|
||||
pElem->LinkEndChild(pRange);
|
||||
}
|
||||
}
|
||||
|
||||
// Suffix
|
||||
if (pProp->Suffix() != pSource->Suffix())
|
||||
{
|
||||
XMLElement *pSuffix = pDoc->NewElement("suffix");
|
||||
pSuffix->SetText(*pProp->Suffix());
|
||||
pElem->LinkEndChild(pSuffix);
|
||||
}
|
||||
|
||||
// Cook Pref
|
||||
if (pProp->CookPreference() != pSource->CookPreference())
|
||||
{
|
||||
XMLElement *pCookPref = pDoc->NewElement("cook_pref");
|
||||
|
||||
TString PrefStr;
|
||||
if (pProp->CookPreference() == eAlwaysCook) PrefStr = "always";
|
||||
else if (pProp->CookPreference() == eNeverCook) PrefStr = "never";
|
||||
else PrefStr = "none";
|
||||
|
||||
pCookPref->SetText(*PrefStr);
|
||||
pElem->LinkEndChild(pCookPref);
|
||||
}
|
||||
|
||||
// Asset-specific parameters
|
||||
if (pProp->Type() == eAssetProperty)
|
||||
{
|
||||
CAssetTemplate *pAsset = static_cast<CAssetTemplate*>(pProp);
|
||||
CAssetTemplate *pSourceAsset = static_cast<CAssetTemplate*>(pSource);
|
||||
|
||||
if (pAsset->TypeFilter() != pSourceAsset->TypeFilter())
|
||||
{
|
||||
TString ExtensionsString = pAsset->TypeFilter().ToString();
|
||||
if (ExtensionsString.IsEmpty()) ExtensionsString = "UNKN";
|
||||
pElem->SetAttribute("extensions", *ExtensionsString);
|
||||
}
|
||||
}
|
||||
|
||||
// Struct/array-specific parameters
|
||||
else if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty)
|
||||
{
|
||||
CStructTemplate *pStruct = static_cast<CStructTemplate*>(pProp);
|
||||
CStructTemplate *pSourceStruct = static_cast<CStructTemplate*>(pSource);
|
||||
SavePropertyOverrides(pDoc, pElem, pStruct, pSourceStruct);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveEnumerators(XMLDocument *pDoc, XMLElement *pParent, CEnumTemplate *pTemp)
|
||||
{
|
||||
XMLElement *pEnumerators = pDoc->NewElement("enumerators");
|
||||
pParent->LinkEndChild(pEnumerators);
|
||||
|
||||
for (u32 iEnum = 0; iEnum < pTemp->NumEnumerators(); iEnum++)
|
||||
{
|
||||
XMLElement *pElem = pDoc->NewElement("enumerator");
|
||||
u32 EnumerID = pTemp->EnumeratorID(iEnum);
|
||||
pElem->SetAttribute("ID", *TString::HexString(EnumerID, (EnumerID > 0xFF ? 8 : 2)));
|
||||
pElem->SetAttribute("name", *pTemp->EnumeratorName(iEnum));
|
||||
pEnumerators->LinkEndChild(pElem);
|
||||
}
|
||||
}
|
||||
|
||||
void CTemplateWriter::SaveBitFlags(XMLDocument *pDoc, XMLElement *pParent, CBitfieldTemplate *pTemp)
|
||||
{
|
||||
XMLElement *pFlags = pDoc->NewElement("flags");
|
||||
pParent->LinkEndChild(pFlags);
|
||||
|
||||
for (u32 iFlag = 0; iFlag < pTemp->NumFlags(); iFlag++)
|
||||
{
|
||||
XMLElement *pElem = pDoc->NewElement("flag");
|
||||
pElem->SetAttribute("mask", *TString::HexString(pTemp->FlagMask(iFlag)));
|
||||
pElem->SetAttribute("name", *pTemp->FlagName(iFlag));
|
||||
pFlags->LinkEndChild(pElem);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef CTEMPLATEWRITER_H
|
||||
#define CTEMPLATEWRITER_H
|
||||
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include "Core/Resource/Script/CScriptTemplate.h"
|
||||
#include <tinyxml2.h>
|
||||
|
||||
class CTemplateWriter
|
||||
{
|
||||
CTemplateWriter();
|
||||
static TString smTemplatesDir;
|
||||
|
||||
public:
|
||||
static void SavePropertyTemplate(IPropertyTemplate *pTemp);
|
||||
static void SaveAllTemplates();
|
||||
static void SaveGameTemplates(CMasterTemplate *pMaster);
|
||||
static void SavePropertyList();
|
||||
static void SaveScriptTemplate(CScriptTemplate *pTemp);
|
||||
static void SaveStructTemplate(CStructTemplate *pTemp);
|
||||
static void SaveEnumTemplate(CEnumTemplate *pTemp);
|
||||
static void SaveBitfieldTemplate(CBitfieldTemplate *pTemp);
|
||||
static void SaveProperties(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CStructTemplate *pTemp);
|
||||
static void SavePropertyOverrides(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CStructTemplate *pStruct, CStructTemplate *pOriginal);
|
||||
static void SaveEnumerators(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CEnumTemplate *pTemp);
|
||||
static void SaveBitFlags(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CBitfieldTemplate *pTemp);
|
||||
};
|
||||
|
||||
#endif // CTEMPLATEWRITER_H
|
||||
@@ -22,15 +22,15 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||
|
||||
WorldNameID.Write(rMLVL);
|
||||
|
||||
if (Game == eEchoesDemo || Game == eEchoes)
|
||||
if (Game == EGame::EchoesDemo || Game == EGame::Echoes)
|
||||
{
|
||||
DarkWorldNameID.Write(rMLVL);
|
||||
}
|
||||
if (Game >= eEchoesDemo && Game <= eCorruption)
|
||||
if (Game >= EGame::EchoesDemo && Game <= EGame::Corruption)
|
||||
{
|
||||
rMLVL.WriteLong(pWorld->mTempleKeyWorldIndex);
|
||||
}
|
||||
if (Game == eReturns)
|
||||
if (Game == EGame::DKCReturns)
|
||||
{
|
||||
const CWorld::STimeAttackData& rkData = pWorld->mTimeAttackData;
|
||||
rMLVL.WriteBool(rkData.HasTimeAttack);
|
||||
@@ -49,7 +49,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||
DefaultSkyID.Write(rMLVL);
|
||||
|
||||
// Memory Relays
|
||||
if (Game == ePrime)
|
||||
if (Game == EGame::Prime)
|
||||
{
|
||||
rMLVL.WriteLong( pWorld->mMemoryRelays.size() );
|
||||
|
||||
@@ -65,7 +65,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||
|
||||
// Areas
|
||||
rMLVL.WriteLong(pWorld->mAreas.size());
|
||||
if (Game <= ePrime) rMLVL.WriteLong(1); // Unknown
|
||||
if (Game <= EGame::Prime) rMLVL.WriteLong(1); // Unknown
|
||||
std::set<CAssetID> AudioGroups;
|
||||
|
||||
for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++)
|
||||
@@ -83,7 +83,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||
rArea.AreaID.Write(rMLVL);
|
||||
|
||||
// Attached Areas
|
||||
if (Game <= eCorruption)
|
||||
if (Game <= EGame::Corruption)
|
||||
{
|
||||
rMLVL.WriteLong( rArea.AttachedAreaIDs.size() );
|
||||
|
||||
@@ -92,7 +92,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||
}
|
||||
|
||||
// Dependencies
|
||||
if (Game <= eEchoes)
|
||||
if (Game <= EGame::Echoes)
|
||||
{
|
||||
std::list<CAssetID> Dependencies;
|
||||
std::list<u32> LayerDependsOffsets;
|
||||
@@ -117,7 +117,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||
}
|
||||
|
||||
// Docks
|
||||
if (Game <= eCorruption)
|
||||
if (Game <= EGame::Corruption)
|
||||
{
|
||||
rMLVL.WriteLong( rArea.Docks.size() );
|
||||
|
||||
@@ -141,7 +141,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||
}
|
||||
|
||||
// Module Dependencies
|
||||
if (Game == eEchoesDemo || Game == eEchoes)
|
||||
if (Game == EGame::EchoesDemo || Game == EGame::Echoes)
|
||||
{
|
||||
std::vector<TString> ModuleNames;
|
||||
std::vector<u32> ModuleLayerOffsets;
|
||||
@@ -160,15 +160,15 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||
}
|
||||
|
||||
// Unknown
|
||||
if (Game == eReturns)
|
||||
if (Game == EGame::DKCReturns)
|
||||
rMLVL.WriteLong(0);
|
||||
|
||||
// Internal Name
|
||||
if (Game >= eEchoesDemo)
|
||||
if (Game >= EGame::EchoesDemo)
|
||||
rMLVL.WriteString(rArea.InternalName);
|
||||
}
|
||||
|
||||
if (Game <= eCorruption)
|
||||
if (Game <= EGame::Corruption)
|
||||
{
|
||||
// World Map
|
||||
CAssetID MapWorldID = pWorld->mpMapWorld ? pWorld->mpMapWorld->ID() : CAssetID::skInvalidID32;
|
||||
@@ -180,7 +180,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||
}
|
||||
|
||||
// Audio Groups
|
||||
if (Game <= ePrime)
|
||||
if (Game <= EGame::Prime)
|
||||
{
|
||||
// Create sorted list of audio groups (sort by group ID)
|
||||
std::vector<CAudioGroup*> SortedAudioGroups;
|
||||
@@ -244,7 +244,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
|
||||
rMLVL.WriteString(LayerNames[iLyr]);
|
||||
|
||||
// Layer Saved State IDs
|
||||
if (Game >= eCorruption)
|
||||
if (Game >= EGame::Corruption)
|
||||
{
|
||||
rMLVL.WriteLong(LayerStateIDs.size());
|
||||
|
||||
@@ -265,12 +265,12 @@ u32 CWorldCooker::GetMLVLVersion(EGame Version)
|
||||
{
|
||||
switch (Version)
|
||||
{
|
||||
case ePrimeDemo: return 0xD;
|
||||
case ePrime: return 0x11;
|
||||
case eEchoesDemo: return 0x14;
|
||||
case eEchoes: return 0x17;
|
||||
case eCorruption: return 0x19;
|
||||
case eReturns: return 0x1B;
|
||||
case EGame::PrimeDemo: return 0xD;
|
||||
case EGame::Prime: return 0x11;
|
||||
case EGame::EchoesDemo: return 0x14;
|
||||
case EGame::Echoes: return 0x17;
|
||||
case EGame::Corruption: return 0x19;
|
||||
case EGame::DKCReturns: return 0x1B;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,5 +74,8 @@ enum EResType
|
||||
eInvalidResType = -1
|
||||
};
|
||||
|
||||
// Defined in CResTypeInfo.cpp
|
||||
void Serialize(IArchive& rArc, EResType& rType);
|
||||
|
||||
#endif // ERESTYPE
|
||||
|
||||
|
||||
@@ -47,9 +47,9 @@ s32 CAnimEventLoader::LoadEventBase(IInputStream& rEVNT)
|
||||
{
|
||||
rEVNT.Skip(0x2);
|
||||
rEVNT.ReadString();
|
||||
rEVNT.Skip(mGame < eCorruptionProto ? 0x13 : 0x17);
|
||||
rEVNT.Skip(mGame < EGame::CorruptionProto ? 0x13 : 0x17);
|
||||
s32 CharacterIndex = rEVNT.ReadLong();
|
||||
rEVNT.Skip(mGame < eCorruptionProto ? 0x4 : 0x18);
|
||||
rEVNT.Skip(mGame < EGame::CorruptionProto ? 0x4 : 0x18);
|
||||
return CharacterIndex;
|
||||
}
|
||||
|
||||
@@ -69,13 +69,13 @@ void CAnimEventLoader::LoadUserEvent(IInputStream& rEVNT)
|
||||
void CAnimEventLoader::LoadEffectEvent(IInputStream& rEVNT)
|
||||
{
|
||||
s32 CharIndex = LoadEventBase(rEVNT);
|
||||
rEVNT.Skip(mGame < eCorruptionProto ? 0x8 : 0x4);
|
||||
rEVNT.Skip(mGame < EGame::CorruptionProto ? 0x8 : 0x4);
|
||||
CAssetID ParticleID(rEVNT, mGame);
|
||||
mpEventData->AddEvent(CharIndex, ParticleID);
|
||||
|
||||
if (mGame <= ePrime)
|
||||
if (mGame <= EGame::Prime)
|
||||
rEVNT.ReadString();
|
||||
else if (mGame <= eEchoes)
|
||||
else if (mGame <= EGame::Echoes)
|
||||
rEVNT.Skip(0x4);
|
||||
|
||||
rEVNT.Skip(0x8);
|
||||
@@ -86,11 +86,11 @@ void CAnimEventLoader::LoadSoundEvent(IInputStream& rEVNT)
|
||||
s32 CharIndex = LoadEventBase(rEVNT);
|
||||
|
||||
// Metroid Prime 1/2
|
||||
if (mGame <= eEchoes)
|
||||
if (mGame <= EGame::Echoes)
|
||||
{
|
||||
u32 SoundID = rEVNT.ReadLong() & 0xFFFF;
|
||||
rEVNT.Skip(0x8);
|
||||
if (mGame >= eEchoes) rEVNT.Skip(0xC);
|
||||
if (mGame >= EGame::Echoes) rEVNT.Skip(0xC);
|
||||
|
||||
if (SoundID != 0xFFFF)
|
||||
{
|
||||
@@ -134,7 +134,7 @@ CAnimEventData* CAnimEventLoader::LoadEVNT(IInputStream& rEVNT, CResourceEntry *
|
||||
{
|
||||
CAnimEventLoader Loader;
|
||||
Loader.mpEventData = new CAnimEventData(pEntry);
|
||||
Loader.mGame = ePrime;
|
||||
Loader.mGame = EGame::Prime;
|
||||
Loader.LoadEvents(rEVNT);
|
||||
return Loader.mpEventData;
|
||||
}
|
||||
@@ -143,7 +143,7 @@ CAnimEventData* CAnimEventLoader::LoadAnimSetEvents(IInputStream& rANCS)
|
||||
{
|
||||
CAnimEventLoader Loader;
|
||||
Loader.mpEventData = new CAnimEventData();
|
||||
Loader.mGame = eEchoes;
|
||||
Loader.mGame = EGame::Echoes;
|
||||
Loader.LoadEvents(rANCS);
|
||||
return Loader.mpEventData;
|
||||
}
|
||||
@@ -152,7 +152,7 @@ CAnimEventData* CAnimEventLoader::LoadCorruptionCharacterEventSet(IInputStream&
|
||||
{
|
||||
CAnimEventLoader Loader;
|
||||
Loader.mpEventData = new CAnimEventData();
|
||||
Loader.mGame = eCorruption;
|
||||
Loader.mGame = EGame::Corruption;
|
||||
|
||||
// Read event set header
|
||||
rCHAR.Skip(0x4); // Skip animation ID
|
||||
|
||||
@@ -116,8 +116,8 @@ CAnimSet* CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR)
|
||||
for (u32 ModelIdx = 0; ModelIdx < NumModels; ModelIdx++)
|
||||
{
|
||||
rCHAR.ReadString();
|
||||
CAssetID ModelID(rCHAR, eReturns);
|
||||
CAssetID SkinID(rCHAR, eReturns);
|
||||
CAssetID ModelID(rCHAR, EGame::DKCReturns);
|
||||
CAssetID SkinID(rCHAR, EGame::DKCReturns);
|
||||
rCHAR.Skip(0x18);
|
||||
|
||||
if (ModelIdx == 0)
|
||||
@@ -138,7 +138,7 @@ CAnimSet* CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR)
|
||||
for (u32 AnimIdx = 0; AnimIdx < NumAnims; AnimIdx++)
|
||||
{
|
||||
TString AnimName = rCHAR.ReadString();
|
||||
CAssetID AnimID(rCHAR, eReturns);
|
||||
CAssetID AnimID(rCHAR, EGame::DKCReturns);
|
||||
rCHAR.Skip(0x25);
|
||||
rChar.DKDependencies.push_back(AnimID);
|
||||
|
||||
@@ -229,7 +229,7 @@ CAnimSet* CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR)
|
||||
|
||||
for (u32 ResIdx = 0; ResIdx < NumResources; ResIdx++)
|
||||
{
|
||||
CAssetID ResID(rCHAR, eReturns);
|
||||
CAssetID ResID(rCHAR, EGame::DKCReturns);
|
||||
rCHAR.Skip(3);
|
||||
rChar.DKDependencies.push_back(ResID);
|
||||
}
|
||||
@@ -293,7 +293,7 @@ void CAnimSetLoader::LoadParticleResourceData(IInputStream& rFile, SSetCharacter
|
||||
for (u32 iSwoosh = 0; iSwoosh < SwooshCount; iSwoosh++)
|
||||
pChar->SwooshParticles.push_back( CAssetID(rFile, mGame) );
|
||||
|
||||
if (CharVersion >= 6 && mGame <= eEchoes) rFile.Seek(0x4, SEEK_CUR);
|
||||
if (CharVersion >= 6 && mGame <= EGame::Echoes) rFile.Seek(0x4, SEEK_CUR);
|
||||
|
||||
u32 ElectricCount = rFile.ReadLong();
|
||||
pChar->ElectricParticles.reserve(ElectricCount);
|
||||
@@ -301,7 +301,7 @@ void CAnimSetLoader::LoadParticleResourceData(IInputStream& rFile, SSetCharacter
|
||||
for (u32 iElec = 0; iElec < ElectricCount; iElec++)
|
||||
pChar->ElectricParticles.push_back( CAssetID(rFile, mGame) );
|
||||
|
||||
if (mGame >= eEchoes)
|
||||
if (mGame >= EGame::Echoes)
|
||||
{
|
||||
u32 SpawnCount = rFile.ReadLong();
|
||||
pChar->SpawnParticles.reserve(SpawnCount);
|
||||
@@ -311,7 +311,7 @@ void CAnimSetLoader::LoadParticleResourceData(IInputStream& rFile, SSetCharacter
|
||||
}
|
||||
|
||||
rFile.Seek(0x4, SEEK_CUR);
|
||||
if (mGame >= eEchoes) rFile.Seek(0x4, SEEK_CUR);
|
||||
if (mGame >= EGame::Echoes) rFile.Seek(0x4, SEEK_CUR);
|
||||
}
|
||||
|
||||
void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
|
||||
@@ -379,7 +379,7 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
|
||||
|
||||
// Skipping MP1 ANIM asset list
|
||||
// Events
|
||||
if (mGame >= eEchoesDemo)
|
||||
if (mGame >= EGame::EchoesDemo)
|
||||
{
|
||||
u32 EventDataCount = rANCS.ReadLong();
|
||||
pSet->mAnimEvents.reserve(EventDataCount);
|
||||
@@ -410,7 +410,7 @@ void CAnimSetLoader::ProcessPrimitives()
|
||||
for (u32 iTrans = 0; iTrans < pSet->mHalfTransitions.size(); iTrans++)
|
||||
pSet->mHalfTransitions[iTrans].pMetaTrans->GetUniquePrimitives(UniquePrimitives);
|
||||
|
||||
if (mGame == eCorruptionProto || mGame == eCorruption)
|
||||
if (mGame == EGame::CorruptionProto || mGame == EGame::Corruption)
|
||||
{
|
||||
CSourceAnimData *pAnimData = gpResourceStore->LoadResource<CSourceAnimData>( pSet->mCharacters[0].AnimDataID );
|
||||
|
||||
@@ -431,7 +431,7 @@ void CAnimSetLoader::ProcessPrimitives()
|
||||
}
|
||||
|
||||
// Add used animation indices from the animset to the character's list
|
||||
if (mGame <= eEchoes)
|
||||
if (mGame <= EGame::Echoes)
|
||||
{
|
||||
// Add animations referenced by default transition
|
||||
if (pSet->mpDefaultTransition)
|
||||
@@ -537,9 +537,9 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
|
||||
|
||||
pChar->ID = rANCS.ReadLong();
|
||||
u16 CharVersion = rANCS.ReadShort();
|
||||
if (iNode == 0 && Loader.mGame == eUnknownGame)
|
||||
if (iNode == 0 && Loader.mGame == EGame::Invalid)
|
||||
{
|
||||
Loader.mGame = (CharVersion == 0xA) ? eEchoes : ePrime;
|
||||
Loader.mGame = (CharVersion == 0xA) ? EGame::Echoes : EGame::Prime;
|
||||
}
|
||||
pChar->Name = rANCS.ReadString();
|
||||
pChar->pModel = gpResourceStore->LoadResource<CModel>(rANCS.ReadLong());
|
||||
@@ -554,7 +554,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
|
||||
for (u32 iAnim = 0; iAnim < AnimCount; iAnim++)
|
||||
{
|
||||
rANCS.Seek(0x4, SEEK_CUR);
|
||||
if (Loader.mGame == ePrime) rANCS.Seek(0x1, SEEK_CUR);
|
||||
if (Loader.mGame == EGame::Prime) rANCS.Seek(0x1, SEEK_CUR);
|
||||
rANCS.ReadString();
|
||||
}
|
||||
|
||||
@@ -584,8 +584,8 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
|
||||
CAssetID ParticleID(rANCS, e32Bit);
|
||||
if (ParticleID.IsValid()) pChar->EffectParticles.push_back(ParticleID);
|
||||
|
||||
if (Loader.mGame == ePrime) rANCS.ReadString();
|
||||
if (Loader.mGame == eEchoes) rANCS.Seek(0x4, SEEK_CUR);
|
||||
if (Loader.mGame == EGame::Prime) rANCS.ReadString();
|
||||
if (Loader.mGame == EGame::Echoes) rANCS.Seek(0x4, SEEK_CUR);
|
||||
rANCS.Seek(0xC, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
@@ -604,7 +604,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
|
||||
pChar->UsedAnimationIndices.insert(AnimIndex);
|
||||
}
|
||||
|
||||
if (Loader.mGame == eEchoes)
|
||||
if (Loader.mGame == EGame::Echoes)
|
||||
{
|
||||
pChar->SpatialPrimitives = rANCS.ReadLong();
|
||||
rANCS.Seek(0x1, SEEK_CUR);
|
||||
@@ -629,14 +629,14 @@ CAnimSet* CAnimSetLoader::LoadCHAR(IInputStream& rCHAR, CResourceEntry *pEntry)
|
||||
|
||||
if (Check == 0x5 || Check == 0x3)
|
||||
{
|
||||
Loader.mGame = eCorruption;
|
||||
Loader.mGame = EGame::Corruption;
|
||||
Loader.pSet = new CAnimSet(pEntry);
|
||||
return Loader.LoadCorruptionCHAR(rCHAR);
|
||||
}
|
||||
|
||||
if (Check == 0x59)
|
||||
{
|
||||
Loader.mGame = eReturns;
|
||||
Loader.mGame = EGame::DKCReturns;
|
||||
Loader.pSet = new CAnimSet(pEntry);
|
||||
return Loader.LoadReturnsCHAR(rCHAR);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ EGame CAnimationLoader::UncompressedCheckVersion()
|
||||
u32 Start = mpInput->Tell();
|
||||
bool Echoes = UncompressedCheckEchoes();
|
||||
mpInput->Seek(Start, SEEK_SET);
|
||||
return (Echoes ? eEchoes : ePrime);
|
||||
return (Echoes ? EGame::Echoes : EGame::Prime);
|
||||
}
|
||||
|
||||
void CAnimationLoader::ReadUncompressedANIM()
|
||||
@@ -75,13 +75,13 @@ void CAnimationLoader::ReadUncompressedANIM()
|
||||
NumBoneChannels++;
|
||||
}
|
||||
|
||||
if (mGame == eUnknownGame)
|
||||
if (mGame == EGame::Invalid)
|
||||
mGame = UncompressedCheckVersion();
|
||||
|
||||
// Echoes only - rotation channel indices
|
||||
std::vector<u8> RotationIndices;
|
||||
|
||||
if (mGame == eEchoes)
|
||||
if (mGame == EGame::Echoes)
|
||||
{
|
||||
u32 NumRotationIndices = mpInput->ReadLong();
|
||||
RotationIndices.resize(NumRotationIndices);
|
||||
@@ -125,7 +125,7 @@ void CAnimationLoader::ReadUncompressedANIM()
|
||||
// Echoes only - scale channel indices
|
||||
std::vector<u8> ScaleIndices;
|
||||
|
||||
if (mGame == eEchoes)
|
||||
if (mGame == EGame::Echoes)
|
||||
{
|
||||
u32 NumScaleIndices = mpInput->ReadLong();
|
||||
ScaleIndices.resize(NumScaleIndices);
|
||||
@@ -161,7 +161,7 @@ void CAnimationLoader::ReadUncompressedANIM()
|
||||
}
|
||||
|
||||
// Read bone transforms
|
||||
if (mGame == eEchoes)
|
||||
if (mGame == EGame::Echoes)
|
||||
{
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skipping scale key count
|
||||
mpAnim->mScaleChannels.resize(NumScaleChannels);
|
||||
@@ -197,7 +197,7 @@ void CAnimationLoader::ReadUncompressedANIM()
|
||||
mpAnim->mTranslationChannels[iTrans][iKey] = CVector3f(*mpInput);
|
||||
}
|
||||
|
||||
if (mGame == ePrime)
|
||||
if (mGame == EGame::Prime)
|
||||
{
|
||||
mpAnim->mpEventData = gpResourceStore->LoadResource<CAnimEventData>(mpInput->ReadLong());
|
||||
}
|
||||
@@ -208,10 +208,10 @@ void CAnimationLoader::ReadCompressedANIM()
|
||||
// Header
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip alloc size
|
||||
|
||||
if (mGame == eUnknownGame)
|
||||
mGame = (mpInput->PeekShort() == 0x0101 ? eEchoes : ePrime);
|
||||
if (mGame == EGame::Invalid)
|
||||
mGame = (mpInput->PeekShort() == 0x0101 ? EGame::Echoes : EGame::Prime);
|
||||
|
||||
if (mGame == ePrime)
|
||||
if (mGame == EGame::Prime)
|
||||
{
|
||||
mpAnim->mpEventData = gpResourceStore->LoadResource<CAnimEventData>(mpInput->ReadLong());
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip unknown
|
||||
@@ -224,7 +224,7 @@ void CAnimationLoader::ReadCompressedANIM()
|
||||
|
||||
mRotationDivisor = mpInput->ReadLong();
|
||||
mTranslationMultiplier = mpInput->ReadFloat();
|
||||
if (mGame == eEchoes) mScaleMultiplier = mpInput->ReadFloat();
|
||||
if (mGame == EGame::Echoes) mScaleMultiplier = mpInput->ReadFloat();
|
||||
u32 NumBoneChannels = mpInput->ReadLong();
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip unknown value
|
||||
|
||||
@@ -238,7 +238,7 @@ void CAnimationLoader::ReadCompressedANIM()
|
||||
for (u32 iBit = 0; iBit < NumKeys; iBit++)
|
||||
mKeyFlags[iBit] = BitStream.ReadBit();
|
||||
}
|
||||
mpInput->Seek(mGame == ePrime ? 0x8 : 0x4, SEEK_CUR);
|
||||
mpInput->Seek(mGame == EGame::Prime ? 0x8 : 0x4, SEEK_CUR);
|
||||
|
||||
// Read bone channel descriptors
|
||||
mCompressedChannels.resize(NumBoneChannels);
|
||||
@@ -249,7 +249,7 @@ void CAnimationLoader::ReadCompressedANIM()
|
||||
for (u32 iChan = 0; iChan < NumBoneChannels; iChan++)
|
||||
{
|
||||
SCompressedChannel& rChan = mCompressedChannels[iChan];
|
||||
rChan.BoneID = (mGame == ePrime ? mpInput->ReadLong() : mpInput->ReadByte());
|
||||
rChan.BoneID = (mGame == EGame::Prime ? mpInput->ReadLong() : mpInput->ReadByte());
|
||||
|
||||
// Read rotation parameters
|
||||
rChan.NumRotationKeys = mpInput->ReadShort();
|
||||
@@ -284,7 +284,7 @@ void CAnimationLoader::ReadCompressedANIM()
|
||||
// Read scale parameters
|
||||
u8 ScaleIdx = 0xFF;
|
||||
|
||||
if (mGame == eEchoes)
|
||||
if (mGame == EGame::Echoes)
|
||||
{
|
||||
rChan.NumScaleKeys = mpInput->ReadShort();
|
||||
|
||||
@@ -465,7 +465,7 @@ CQuaternion CAnimationLoader::DequantizeRotation(bool Sign, s16 X, s16 Y, s16 Z)
|
||||
CAnimation* CAnimationLoader::LoadANIM(IInputStream& rANIM, CResourceEntry *pEntry)
|
||||
{
|
||||
// MP3/DKCR unsupported
|
||||
if (pEntry->Game() > eEchoes)
|
||||
if (pEntry->Game() > EGame::Echoes)
|
||||
return new CAnimation(pEntry);
|
||||
|
||||
u32 CompressionType = rANIM.ReadLong();
|
||||
|
||||
@@ -81,7 +81,7 @@ void CAreaLoader::ReadGeometryPrime()
|
||||
CModel *pModel = CModelLoader::LoadWorldModel(*mpMREA, *mpSectionMgr, *mpArea->mpMaterialSet, mVersion);
|
||||
FileModels.push_back(pModel);
|
||||
|
||||
if (mVersion <= ePrime)
|
||||
if (mVersion <= EGame::Prime)
|
||||
mpArea->AddWorldModel(pModel);
|
||||
|
||||
// For Echoes+, load surface mesh IDs, then skip to the start of the next mesh
|
||||
@@ -101,7 +101,7 @@ void CAreaLoader::ReadGeometryPrime()
|
||||
}
|
||||
|
||||
// Split meshes
|
||||
if (mVersion >= eEchoesDemo)
|
||||
if (mVersion >= EGame::EchoesDemo)
|
||||
{
|
||||
std::vector<CModel*> SplitModels;
|
||||
CModelLoader::BuildWorldMeshes(FileModels, SplitModels, true);
|
||||
@@ -124,7 +124,7 @@ void CAreaLoader::ReadSCLYPrime()
|
||||
Log::FileError(mpMREA->GetSourceString(), mpMREA->Tell() - 4, "Invalid SCLY magic: " + SCLY.ToString());
|
||||
return;
|
||||
}
|
||||
mpMREA->Seek(mVersion <= ePrime ? 4 : 1, SEEK_CUR); // Skipping unknown value which is always 1
|
||||
mpMREA->Seek(mVersion <= EGame::Prime ? 4 : 1, SEEK_CUR); // Skipping unknown value which is always 1
|
||||
|
||||
// Read layer sizes
|
||||
mNumLayers = mpMREA->ReadLong();
|
||||
@@ -145,7 +145,7 @@ void CAreaLoader::ReadSCLYPrime()
|
||||
// SCGN
|
||||
CScriptLayer *pGenLayer = nullptr;
|
||||
|
||||
if (mVersion >= eEchoesDemo)
|
||||
if (mVersion >= EGame::EchoesDemo)
|
||||
{
|
||||
mpSectionMgr->ToSection(mScriptGeneratorBlockNum);
|
||||
CFourCC SCGN = mpMREA->ReadFourCC();
|
||||
@@ -252,7 +252,7 @@ void CAreaLoader::ReadHeaderEchoes()
|
||||
// This function reads the header for Echoes and the Echoes demo disc
|
||||
mpArea->mTransform = CTransform4f(*mpMREA);
|
||||
mNumMeshes = mpMREA->ReadLong();
|
||||
if (mVersion == eEchoes) mNumLayers = mpMREA->ReadLong();
|
||||
if (mVersion == EGame::Echoes) mNumLayers = mpMREA->ReadLong();
|
||||
u32 numBlocks = mpMREA->ReadLong();
|
||||
|
||||
mGeometryBlockNum = mpMREA->ReadLong();
|
||||
@@ -266,13 +266,13 @@ void CAreaLoader::ReadHeaderEchoes()
|
||||
mFFFFBlockNum = mpMREA->ReadLong();
|
||||
mPTLABlockNum = mpMREA->ReadLong();
|
||||
mEGMCBlockNum = mpMREA->ReadLong();
|
||||
if (mVersion == eEchoes) mClusters.resize(mpMREA->ReadLong());
|
||||
if (mVersion == EGame::Echoes) mClusters.resize(mpMREA->ReadLong());
|
||||
mpMREA->SeekToBoundary(32);
|
||||
|
||||
mpSectionMgr = new CSectionMgrIn(numBlocks, mpMREA);
|
||||
mpMREA->SeekToBoundary(32);
|
||||
|
||||
if (mVersion == eEchoes)
|
||||
if (mVersion == EGame::Echoes)
|
||||
{
|
||||
ReadCompressedBlocks();
|
||||
Decompress();
|
||||
@@ -440,7 +440,7 @@ void CAreaLoader::ReadDependenciesCorruption()
|
||||
|
||||
for (u32 DepIdx = 0; DepIdx < NumLayerDeps; DepIdx++)
|
||||
{
|
||||
CAssetID AssetID(*mpMREA, eCorruption);
|
||||
CAssetID AssetID(*mpMREA, EGame::Corruption);
|
||||
mpMREA->Skip(4);
|
||||
mpArea->mExtraLayerDeps[LayerIdx].push_back(AssetID);
|
||||
}
|
||||
@@ -452,7 +452,7 @@ void CAreaLoader::ReadDependenciesCorruption()
|
||||
|
||||
for (u32 DepIdx = 0; DepIdx < NumAreaDeps; DepIdx++)
|
||||
{
|
||||
CAssetID AssetID(*mpMREA, eCorruption);
|
||||
CAssetID AssetID(*mpMREA, EGame::Corruption);
|
||||
mpMREA->Skip(4);
|
||||
mpArea->mExtraAreaDeps.push_back(AssetID);
|
||||
}
|
||||
@@ -562,7 +562,7 @@ void CAreaLoader::Decompress()
|
||||
{
|
||||
// This function decompresses compressed clusters into a buffer.
|
||||
// It should be called at the beginning of the first compressed cluster.
|
||||
if (mVersion < eEchoes) return;
|
||||
if (mVersion < EGame::Echoes) return;
|
||||
|
||||
// Decompress clusters
|
||||
mpDecmpBuffer = new u8[mTotalDecmpSize];
|
||||
@@ -699,7 +699,7 @@ void CAreaLoader::SetUpObjects(CScriptLayer *pGenLayer)
|
||||
}
|
||||
|
||||
// Remove "-component" garbage from MP1 instance names
|
||||
if (mVersion <= ePrime)
|
||||
if (mVersion <= EGame::Prime)
|
||||
{
|
||||
TString InstanceName = pInst->InstanceName();
|
||||
|
||||
@@ -747,8 +747,8 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
|
||||
|
||||
switch (Loader.mVersion)
|
||||
{
|
||||
case ePrimeDemo:
|
||||
case ePrime:
|
||||
case EGame::PrimeDemo:
|
||||
case EGame::Prime:
|
||||
Loader.ReadHeaderPrime();
|
||||
Loader.ReadGeometryPrime();
|
||||
Loader.ReadSCLYPrime();
|
||||
@@ -756,7 +756,7 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
|
||||
Loader.ReadLightsPrime();
|
||||
Loader.ReadPATH();
|
||||
break;
|
||||
case eEchoesDemo:
|
||||
case EGame::EchoesDemo:
|
||||
Loader.ReadHeaderEchoes();
|
||||
Loader.ReadGeometryPrime();
|
||||
Loader.ReadSCLYPrime();
|
||||
@@ -766,7 +766,7 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
|
||||
Loader.ReadPTLA();
|
||||
Loader.ReadEGMC();
|
||||
break;
|
||||
case eEchoes:
|
||||
case EGame::Echoes:
|
||||
Loader.ReadHeaderEchoes();
|
||||
Loader.ReadGeometryPrime();
|
||||
Loader.ReadSCLYEchoes();
|
||||
@@ -776,7 +776,7 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
|
||||
Loader.ReadPTLA();
|
||||
Loader.ReadEGMC();
|
||||
break;
|
||||
case eCorruptionProto:
|
||||
case EGame::CorruptionProto:
|
||||
Loader.ReadHeaderCorruption();
|
||||
Loader.ReadGeometryPrime();
|
||||
Loader.ReadDependenciesCorruption();
|
||||
@@ -787,14 +787,14 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
|
||||
Loader.ReadPTLA();
|
||||
Loader.ReadEGMC();
|
||||
break;
|
||||
case eCorruption:
|
||||
case eReturns:
|
||||
case EGame::Corruption:
|
||||
case EGame::DKCReturns:
|
||||
Loader.ReadHeaderCorruption();
|
||||
Loader.ReadGeometryCorruption();
|
||||
Loader.ReadDependenciesCorruption();
|
||||
Loader.ReadSCLYEchoes();
|
||||
Loader.ReadCollision();
|
||||
if (Loader.mVersion == eCorruption)
|
||||
if (Loader.mVersion == EGame::Corruption)
|
||||
{
|
||||
Loader.ReadLightsCorruption();
|
||||
Loader.ReadPATH();
|
||||
@@ -817,13 +817,13 @@ EGame CAreaLoader::GetFormatVersion(u32 Version)
|
||||
{
|
||||
switch (Version)
|
||||
{
|
||||
case 0xC: return ePrimeDemo;
|
||||
case 0xF: return ePrime;
|
||||
case 0x15: return eEchoesDemo;
|
||||
case 0x19: return eEchoes;
|
||||
case 0x1D: return eCorruptionProto;
|
||||
case 0x1E: return eCorruption;
|
||||
case 0x20: return eReturns;
|
||||
default: return eUnknownGame;
|
||||
case 0xC: return EGame::PrimeDemo;
|
||||
case 0xF: return EGame::Prime;
|
||||
case 0x15: return EGame::EchoesDemo;
|
||||
case 0x19: return EGame::Echoes;
|
||||
case 0x1D: return EGame::CorruptionProto;
|
||||
case 0x1E: return EGame::Corruption;
|
||||
case 0x20: return EGame::DKCReturns;
|
||||
default: return EGame::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ CAudioGroup* CAudioGroupLoader::LoadAGSC(IInputStream& rAGSC, CResourceEntry *pE
|
||||
// For now we only load sound define IDs and the group ID!
|
||||
// Version check
|
||||
u32 Check = rAGSC.PeekLong();
|
||||
EGame Game = (Check == 0x1 ? eEchoes : ePrime);
|
||||
EGame Game = (Check == 0x1 ? EGame::Echoes : EGame::Prime);
|
||||
CAudioGroup *pOut = new CAudioGroup(pEntry);
|
||||
|
||||
// Read header, navigate to Proj chunk
|
||||
if (Game == ePrime)
|
||||
if (Game == EGame::Prime)
|
||||
{
|
||||
rAGSC.ReadString();
|
||||
pOut->mGroupName = rAGSC.ReadString();
|
||||
@@ -38,7 +38,7 @@ CAudioGroup* CAudioGroupLoader::LoadAGSC(IInputStream& rAGSC, CResourceEntry *pE
|
||||
rAGSC.Seek(0x14, SEEK_CUR);
|
||||
u32 SfxTableStart = rAGSC.ReadLong();
|
||||
|
||||
if (Game == ePrime)
|
||||
if (Game == EGame::Prime)
|
||||
pOut->mGroupID = GroupID;
|
||||
else
|
||||
ASSERT(pOut->mGroupID == GroupID);
|
||||
|
||||
@@ -39,10 +39,10 @@ void CCollisionLoader::ParseOBBNode(IInputStream& rDCLN)
|
||||
void CCollisionLoader::ReadPropertyFlags(IInputStream& rSrc)
|
||||
{
|
||||
CCollisionMaterial Material;
|
||||
u64 RawFlags = (mVersion <= ePrime ? rSrc.ReadLong() : rSrc.ReadLongLong());
|
||||
u64 RawFlags = (mVersion <= EGame::Prime ? rSrc.ReadLong() : rSrc.ReadLongLong());
|
||||
Material.mRawFlags = RawFlags;
|
||||
|
||||
if (mVersion <= ePrime)
|
||||
if (mVersion <= EGame::Prime)
|
||||
{
|
||||
if (RawFlags & 0x00000001) Material |= eCF_Unknown;
|
||||
if (RawFlags & 0x00000002) Material |= eCF_Stone;
|
||||
@@ -71,7 +71,7 @@ void CCollisionLoader::ReadPropertyFlags(IInputStream& rSrc)
|
||||
if (RawFlags & 0x80000000) Material |= eCF_Floor;
|
||||
}
|
||||
|
||||
else if (mVersion <= eCorruption)
|
||||
else if (mVersion <= EGame::Corruption)
|
||||
{
|
||||
if (RawFlags & 0x00000001) Material |= eCF_Unknown;
|
||||
if (RawFlags & 0x00000002) Material |= eCF_Stone;
|
||||
@@ -105,7 +105,7 @@ void CCollisionLoader::ReadPropertyFlags(IInputStream& rSrc)
|
||||
if (RawFlags & 0x0400000000000000) Material |= eCF_JumpNotAllowed;
|
||||
}
|
||||
|
||||
else if (mVersion == eReturns)
|
||||
else if (mVersion == EGame::DKCReturns)
|
||||
{
|
||||
if (RawFlags & 0x10000000) Material |= eCF_FlippedTri;
|
||||
}
|
||||
@@ -158,7 +158,7 @@ void CCollisionLoader::LoadCollisionIndices(IInputStream &rFile, bool BuildAABox
|
||||
}
|
||||
|
||||
// Echoes introduces a new data chunk; don't know what it is yet, skipping for now
|
||||
if (mVersion >= eEchoes)
|
||||
if (mVersion >= EGame::Echoes)
|
||||
{
|
||||
u32 UnknownCount = rFile.ReadLong();
|
||||
rFile.Seek(UnknownCount * 2, SEEK_CUR);
|
||||
@@ -236,12 +236,12 @@ CCollisionMeshGroup* CCollisionLoader::LoadDCLN(IInputStream& rDCLN, CResourceEn
|
||||
Loader.mpMesh = new CCollisionMesh;
|
||||
Loader.mpMesh->mOctreeLoaded = false;
|
||||
|
||||
if (Loader.mVersion == eReturns)
|
||||
if (Loader.mVersion == EGame::DKCReturns)
|
||||
Loader.mpMesh->mAABox = CAABox(rDCLN);
|
||||
|
||||
// Read indices and return
|
||||
rDCLN.Seek(0x4, SEEK_CUR);
|
||||
Loader.LoadCollisionIndices(rDCLN, Loader.mVersion != eReturns);
|
||||
Loader.LoadCollisionIndices(rDCLN, Loader.mVersion != EGame::DKCReturns);
|
||||
Loader.mpGroup->AddMesh(Loader.mpMesh);
|
||||
|
||||
// Parse OBB tree
|
||||
@@ -254,10 +254,10 @@ EGame CCollisionLoader::GetFormatVersion(u32 Version)
|
||||
{
|
||||
switch (Version)
|
||||
{
|
||||
case 0x2: return ePrime;
|
||||
case 0x3: return ePrime;
|
||||
case 0x4: return eEchoes;
|
||||
case 0x5: return eReturns;
|
||||
default: return eUnknownGame;
|
||||
case 0x2: return EGame::Prime;
|
||||
case 0x3: return EGame::Prime;
|
||||
case 0x4: return EGame::Echoes;
|
||||
case 0x5: return EGame::DKCReturns;
|
||||
default: return EGame::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ EGame CDependencyGroupLoader::VersionTest(IInputStream& rDGRP, u32 DepCount)
|
||||
rDGRP.Seek(DepCount * 8, SEEK_CUR);
|
||||
u32 Remaining = rDGRP.Size() - rDGRP.Tell();
|
||||
|
||||
EGame Game = eCorruptionProto;
|
||||
EGame Game = EGame::CorruptionProto;
|
||||
|
||||
if (Remaining < 32)
|
||||
{
|
||||
@@ -25,7 +25,7 @@ EGame CDependencyGroupLoader::VersionTest(IInputStream& rDGRP, u32 DepCount)
|
||||
}
|
||||
}
|
||||
|
||||
if (IsEOF) Game = ePrimeDemo;
|
||||
if (IsEOF) Game = EGame::PrimeDemo;
|
||||
}
|
||||
|
||||
rDGRP.Seek(Start, SEEK_SET);
|
||||
|
||||
@@ -13,12 +13,12 @@ CFont* CFontLoader::LoadFont(IInputStream& rFONT)
|
||||
mpFont->mLineHeight = rFONT.ReadLong();
|
||||
mpFont->mVerticalOffset = rFONT.ReadLong();
|
||||
mpFont->mLineMargin = rFONT.ReadLong();
|
||||
if (mVersion > ePrimeDemo) rFONT.Seek(0x4, SEEK_CUR);
|
||||
if (mVersion > EGame::PrimeDemo) rFONT.Seek(0x4, SEEK_CUR);
|
||||
rFONT.Seek(0x2, SEEK_CUR);
|
||||
mpFont->mDefaultSize = rFONT.ReadLong();
|
||||
mpFont->mFontName = rFONT.ReadString();
|
||||
|
||||
if (mVersion <= eEchoes) mpFont->mpFontTexture = gpResourceStore->LoadResource(rFONT.ReadLong(), eTexture);
|
||||
if (mVersion <= EGame::Echoes) mpFont->mpFontTexture = gpResourceStore->LoadResource(rFONT.ReadLong(), eTexture);
|
||||
else mpFont->mpFontTexture = gpResourceStore->LoadResource(rFONT.ReadLongLong(), eTexture);
|
||||
|
||||
mpFont->mTextureFormat = rFONT.ReadLong();
|
||||
@@ -39,7 +39,7 @@ CFont* CFontLoader::LoadFont(IInputStream& rFONT)
|
||||
Glyph.TexCoords[2] = CVector2f(TexCoordL, TexCoordD); // Lower-left
|
||||
Glyph.TexCoords[3] = CVector2f(TexCoordR, TexCoordD); // Lower-right
|
||||
|
||||
if (mVersion <= ePrime)
|
||||
if (mVersion <= EGame::Prime)
|
||||
{
|
||||
Glyph.RGBAChannel = 0;
|
||||
Glyph.LeftPadding = rFONT.ReadLong();
|
||||
@@ -50,7 +50,7 @@ CFont* CFontLoader::LoadFont(IInputStream& rFONT)
|
||||
Glyph.BaseOffset = rFONT.ReadLong();
|
||||
Glyph.KerningIndex = rFONT.ReadLong();
|
||||
}
|
||||
else if (mVersion >= eEchoes)
|
||||
else if (mVersion >= EGame::Echoes)
|
||||
{
|
||||
Glyph.RGBAChannel = rFONT.ReadByte();
|
||||
Glyph.LeftPadding = rFONT.ReadByte();
|
||||
@@ -92,7 +92,7 @@ CFont* CFontLoader::LoadFONT(IInputStream& rFONT, CResourceEntry *pEntry)
|
||||
|
||||
u32 FileVersion = rFONT.ReadLong();
|
||||
EGame Version = GetFormatVersion(FileVersion);
|
||||
if (Version == eUnknownGame)
|
||||
if (Version == EGame::Invalid)
|
||||
{
|
||||
Log::FileError(rFONT.GetSourceString(), "Unsupported FONT version: " + TString::HexString(FileVersion, 0));
|
||||
return nullptr;
|
||||
@@ -108,10 +108,10 @@ EGame CFontLoader::GetFormatVersion(u32 Version)
|
||||
{
|
||||
switch (Version)
|
||||
{
|
||||
case 1: return ePrimeDemo;
|
||||
case 2: return ePrime;
|
||||
case 4: return eEchoes;
|
||||
case 5: return eCorruption;
|
||||
default: return eUnknownGame;
|
||||
case 1: return EGame::PrimeDemo;
|
||||
case 2: return EGame::Prime;
|
||||
case 4: return EGame::Echoes;
|
||||
case 5: return EGame::Corruption;
|
||||
default: return EGame::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ CMaterial* CMaterialLoader::ReadPrimeMaterial()
|
||||
pMat->mVtxDesc = ConvertToVertexDescription( mpFile->ReadLong() );
|
||||
|
||||
// Unknowns
|
||||
if (mVersion >= eEchoesDemo)
|
||||
if (mVersion >= EGame::EchoesDemo)
|
||||
{
|
||||
pMat->mEchoesUnknownA = mpFile->ReadLong();
|
||||
pMat->mEchoesUnknownB = mpFile->ReadLong();
|
||||
@@ -648,7 +648,7 @@ CMaterialSet* CMaterialLoader::LoadMaterialSet(IInputStream& rMat, EGame Version
|
||||
Loader.mpFile = &rMat;
|
||||
Loader.mVersion = Version;
|
||||
|
||||
if ((Version >= ePrimeDemo) && (Version <= eEchoes))
|
||||
if ((Version >= EGame::PrimeDemo) && (Version <= EGame::Echoes))
|
||||
Loader.ReadPrimeMatSet();
|
||||
else
|
||||
Loader.ReadCorruptionMatSet();
|
||||
|
||||
@@ -52,7 +52,7 @@ void CModelLoader::LoadAttribArrays(IInputStream& rModel)
|
||||
if (mFlags & eShortNormals) // Shorts
|
||||
{
|
||||
mNormals.resize(mpSectionMgr->CurrentSectionSize() / 0x6);
|
||||
float Divisor = (mVersion < eReturns) ? 32768.f : 16384.f;
|
||||
float Divisor = (mVersion < EGame::DKCReturns) ? 32768.f : 16384.f;
|
||||
|
||||
for (u32 iVtx = 0; iVtx < mNormals.size(); iVtx++)
|
||||
{
|
||||
@@ -93,7 +93,7 @@ void CModelLoader::LoadAttribArrays(IInputStream& rModel)
|
||||
if (mFlags & eHasTex1)
|
||||
{
|
||||
mTex1.resize(mpSectionMgr->CurrentSectionSize() / 0x4);
|
||||
float Divisor = (mVersion < eReturns) ? 32768.f : 8192.f;
|
||||
float Divisor = (mVersion < EGame::DKCReturns) ? 32768.f : 8192.f;
|
||||
|
||||
for (u32 iVtx = 0; iVtx < mTex1.size(); iVtx++)
|
||||
{
|
||||
@@ -122,7 +122,7 @@ SSurface* CModelLoader::LoadSurface(IInputStream& rModel)
|
||||
SSurface *pSurf = new SSurface;
|
||||
|
||||
// Surface header
|
||||
if (mVersion < eReturns)
|
||||
if (mVersion < EGame::DKCReturns)
|
||||
LoadSurfaceHeaderPrime(rModel, pSurf);
|
||||
else
|
||||
LoadSurfaceHeaderDKCR(rModel, pSurf);
|
||||
@@ -172,7 +172,7 @@ SSurface* CModelLoader::LoadSurface(IInputStream& rModel)
|
||||
Vtx.Color[iClr] = mColors[rModel.ReadShort() & 0xFFFF];
|
||||
|
||||
// Tex Coords - these are done a bit differently in DKCR than in the Prime series
|
||||
if (mVersion < eReturns)
|
||||
if (mVersion < EGame::DKCReturns)
|
||||
{
|
||||
// Tex0
|
||||
if (VtxDesc & eTex0)
|
||||
@@ -238,7 +238,7 @@ void CModelLoader::LoadSurfaceHeaderPrime(IInputStream& rModel, SSurface *pSurf)
|
||||
u32 ExtraSize = rModel.ReadLong();
|
||||
pSurf->ReflectionDirection = CVector3f(rModel);
|
||||
|
||||
if (mVersion >= eEchoesDemo)
|
||||
if (mVersion >= EGame::EchoesDemo)
|
||||
rModel.Seek(0x4, SEEK_CUR); // Skipping unknown values
|
||||
|
||||
bool HasAABox = (ExtraSize >= 0x18); // MREAs have a set of bounding box coordinates here.
|
||||
@@ -446,7 +446,7 @@ CModel* CModelLoader::LoadCMDL(IInputStream& rCMDL, CResourceEntry *pEntry)
|
||||
// The rest is common to all CMDL versions
|
||||
Loader.mVersion = GetFormatVersion(Version);
|
||||
|
||||
if (Loader.mVersion == eUnknownGame)
|
||||
if (Loader.mVersion == EGame::Invalid)
|
||||
{
|
||||
Log::FileError(rCMDL.GetSourceString(), "Unsupported CMDL version: " + TString::HexString(Magic, 0));
|
||||
return nullptr;
|
||||
@@ -464,13 +464,13 @@ CModel* CModelLoader::LoadCMDL(IInputStream& rCMDL, CResourceEntry *pEntry)
|
||||
{
|
||||
Loader.mMaterials[iSet] = CMaterialLoader::LoadMaterialSet(rCMDL, Loader.mVersion);
|
||||
|
||||
if (Loader.mVersion < eCorruptionProto)
|
||||
if (Loader.mVersion < EGame::CorruptionProto)
|
||||
Loader.mpSectionMgr->ToNextSection();
|
||||
}
|
||||
|
||||
pModel->mMaterialSets = Loader.mMaterials;
|
||||
pModel->mHasOwnMaterials = true;
|
||||
if (Loader.mVersion >= eCorruptionProto) Loader.mpSectionMgr->ToNextSection();
|
||||
if (Loader.mVersion >= EGame::CorruptionProto) Loader.mpSectionMgr->ToNextSection();
|
||||
|
||||
// Mesh
|
||||
Loader.LoadAttribArrays(rCMDL);
|
||||
@@ -499,7 +499,7 @@ CModel* CModelLoader::LoadWorldModel(IInputStream& rMREA, CSectionMgrIn& rBlockM
|
||||
Loader.mpSectionMgr = &rBlockMgr;
|
||||
Loader.mVersion = Version;
|
||||
Loader.mFlags = eShortNormals;
|
||||
if (Version != eCorruptionProto) Loader.mFlags |= eHasTex1;
|
||||
if (Version != EGame::CorruptionProto) Loader.mFlags |= eHasTex1;
|
||||
Loader.mMaterials.resize(1);
|
||||
Loader.mMaterials[0] = &rMatSet;
|
||||
|
||||
@@ -534,7 +534,7 @@ CModel* CModelLoader::LoadCorruptionWorldModel(IInputStream& rMREA, CSectionMgrI
|
||||
Loader.mFlags = eShortNormals;
|
||||
Loader.mMaterials.resize(1);
|
||||
Loader.mMaterials[0] = &rMatSet;
|
||||
if (Version == eReturns) Loader.mFlags |= eHasTex1;
|
||||
if (Version == EGame::DKCReturns) Loader.mFlags |= eHasTex1;
|
||||
|
||||
// Corruption/DKCR MREAs split the mesh header and surface offsets away from the actual geometry data so I need two section numbers to read it
|
||||
rBlockMgr.ToSection(HeaderSecNum);
|
||||
@@ -638,11 +638,11 @@ EGame CModelLoader::GetFormatVersion(u32 Version)
|
||||
{
|
||||
switch (Version)
|
||||
{
|
||||
case 0x2: return ePrime;
|
||||
case 0x3: return eEchoesDemo;
|
||||
case 0x4: return eEchoes;
|
||||
case 0x5: return eCorruption;
|
||||
case 0xA: return eReturns;
|
||||
default: return eUnknownGame;
|
||||
case 0x2: return EGame::Prime;
|
||||
case 0x3: return EGame::EchoesDemo;
|
||||
case 0x4: return EGame::Echoes;
|
||||
case 0x5: return EGame::Corruption;
|
||||
case 0xA: return EGame::DKCReturns;
|
||||
default: return EGame::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,11 +101,11 @@ public:
|
||||
|
||||
case eStateMachine:
|
||||
// AFSM currently unsupported
|
||||
if (pEntry->Game() <= eEchoes)
|
||||
if (pEntry->Game() <= EGame::Echoes)
|
||||
pRes = new CDependencyGroup(pEntry);
|
||||
else if (pEntry->Game() <= eCorruption)
|
||||
else if (pEntry->Game() <= EGame::Corruption)
|
||||
pRes = CUnsupportedFormatLoader::LoadFSM2(rInput, pEntry);
|
||||
else if (pEntry->Game() == eReturns)
|
||||
else if (pEntry->Game() == EGame::DKCReturns)
|
||||
pRes = CUnsupportedFormatLoader::LoadFSMC(rInput, pEntry);
|
||||
break;
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ CScan* CScanLoader::LoadScanMP2(IInputStream& rSCAN)
|
||||
}
|
||||
|
||||
// Load MP3 dependency list
|
||||
if (mpScan->Game() == eCorruption)
|
||||
if (mpScan->Game() == EGame::Corruption)
|
||||
{
|
||||
rSCAN.GoTo(InstanceEnd);
|
||||
u32 NumDeps = rSCAN.ReadLong();
|
||||
@@ -275,7 +275,7 @@ CScan* CScanLoader::LoadSCAN(IInputStream& rSCAN, CResourceEntry *pEntry)
|
||||
{
|
||||
// The MP2 load function will check for MP3
|
||||
CScanLoader Loader;
|
||||
Loader.mVersion = eEchoes;
|
||||
Loader.mVersion = EGame::Echoes;
|
||||
Loader.mpEntry = pEntry;
|
||||
if (Magic == 0x01000000) rSCAN.Seek(-4, SEEK_CUR); // The version number isn't present in the Echoes demo
|
||||
return Loader.LoadScanMP2(rSCAN);
|
||||
@@ -295,7 +295,7 @@ CScan* CScanLoader::LoadSCAN(IInputStream& rSCAN, CResourceEntry *pEntry)
|
||||
|
||||
// MP1 SCAN - read the file!
|
||||
CScanLoader Loader;
|
||||
Loader.mVersion = ePrime;
|
||||
Loader.mVersion = EGame::Prime;
|
||||
Loader.mpScan = new CScan(pEntry);
|
||||
Loader.mpEntry = pEntry;
|
||||
return Loader.LoadScanMP1(rSCAN);
|
||||
|
||||
@@ -1,257 +1,295 @@
|
||||
#include "CScriptLoader.h"
|
||||
#include "CTemplateLoader.h"
|
||||
#include "Core/GameProject/CResourceStore.h"
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include "Core/Resource/Script/CGameTemplate.h"
|
||||
#include "Core/Resource/Script/NGameList.h"
|
||||
#include "Core/Resource/Script/Property/CArrayProperty.h"
|
||||
#include "Core/Resource/Script/Property/CAssetProperty.h"
|
||||
#include "Core/Resource/Script/Property/CEnumProperty.h"
|
||||
#include "Core/Resource/Script/Property/CFlagsProperty.h"
|
||||
#include <Common/Log.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
// Whether to ensure the values of enum/flag properties are valid
|
||||
#define VALIDATE_PROPERTY_VALUES 1
|
||||
|
||||
CScriptLoader::CScriptLoader()
|
||||
: mpObj(nullptr)
|
||||
, mpArrayItemData(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& rSCLY)
|
||||
{
|
||||
IPropertyTemplate *pTemp = pProp->Template();
|
||||
void* pData = (mpArrayItemData ? mpArrayItemData : mpObj->mPropertyData.data());
|
||||
|
||||
switch (pTemp->Type())
|
||||
switch (pProp->Type())
|
||||
{
|
||||
|
||||
case eBoolProperty:
|
||||
case EPropertyType::Bool:
|
||||
{
|
||||
TBoolProperty *pBoolCast = static_cast<TBoolProperty*>(pProp);
|
||||
pBoolCast->Set( (rSCLY.ReadByte() != 0) );
|
||||
CBoolProperty* pBool = TPropCast<CBoolProperty>(pProp);
|
||||
pBool->ValueRef(pData) = rSCLY.ReadBool();
|
||||
break;
|
||||
}
|
||||
|
||||
case eByteProperty:
|
||||
case EPropertyType::Byte:
|
||||
{
|
||||
TByteProperty *pByteCast = static_cast<TByteProperty*>(pProp);
|
||||
pByteCast->Set(rSCLY.ReadByte());
|
||||
CByteProperty* pByte = TPropCast<CByteProperty>(pProp);
|
||||
pByte->ValueRef(pData) = rSCLY.ReadByte();
|
||||
break;
|
||||
}
|
||||
|
||||
case eShortProperty:
|
||||
case EPropertyType::Short:
|
||||
{
|
||||
TShortProperty *pShortCast = static_cast<TShortProperty*>(pProp);
|
||||
pShortCast->Set(rSCLY.ReadShort());
|
||||
CShortProperty* pShort = TPropCast<CShortProperty>(pProp);
|
||||
pShort->ValueRef(pData) = rSCLY.ReadShort();
|
||||
break;
|
||||
}
|
||||
|
||||
case eLongProperty:
|
||||
case EPropertyType::Int:
|
||||
{
|
||||
TLongProperty *pLongCast = static_cast<TLongProperty*>(pProp);
|
||||
pLongCast->Set(rSCLY.ReadLong());
|
||||
CIntProperty* pInt = TPropCast<CIntProperty>(pProp);
|
||||
pInt->ValueRef(pData) = rSCLY.ReadLong();
|
||||
break;
|
||||
}
|
||||
|
||||
case eBitfieldProperty:
|
||||
case EPropertyType::Float:
|
||||
{
|
||||
TBitfieldProperty *pBitfieldCast = static_cast<TBitfieldProperty*>(pProp);
|
||||
pBitfieldCast->Set(rSCLY.ReadLong());
|
||||
|
||||
// Validate
|
||||
u32 Mask = 0;
|
||||
CBitfieldTemplate *pBitfieldTemp = static_cast<CBitfieldTemplate*>(pTemp);
|
||||
for (u32 iMask = 0; iMask < pBitfieldTemp->NumFlags(); iMask++)
|
||||
Mask |= pBitfieldTemp->FlagMask(iMask);
|
||||
|
||||
u32 Check = pBitfieldCast->Get() & ~Mask;
|
||||
if (Check != 0)
|
||||
Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Bitfield property \"" + pBitfieldTemp->FullName() + "\" + (" + pBitfieldTemp->IDString(true) + ") has flags set that aren't in the template: " + TString::HexString(Check));
|
||||
|
||||
CFloatProperty* pFloat = TPropCast<CFloatProperty>(pProp);
|
||||
pFloat->ValueRef(pData) = rSCLY.ReadFloat();
|
||||
break;
|
||||
}
|
||||
|
||||
case eEnumProperty:
|
||||
case EPropertyType::Choice:
|
||||
{
|
||||
TEnumProperty *pEnumCast = static_cast<TEnumProperty*>(pProp);
|
||||
CEnumTemplate *pEnumTemp = static_cast<CEnumTemplate*>(pTemp);
|
||||
u32 ID = rSCLY.ReadLong();
|
||||
CChoiceProperty* pChoice = TPropCast<CChoiceProperty>(pProp);
|
||||
pChoice->ValueRef(pData) = rSCLY.ReadLong();
|
||||
|
||||
// Validate
|
||||
u32 Index = pEnumTemp->EnumeratorIndex(ID);
|
||||
if (Index == -1) Log::FileError(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Enum property \"" + pEnumTemp->FullName() + "\" (" + pEnumTemp->IDString(true) + ") has invalid enumerator value: " + TString::HexString(ID));
|
||||
|
||||
pEnumCast->Set(ID);
|
||||
#if VALIDATE_PROPERTY_VALUES
|
||||
if (!pChoice->HasValidValue(pData))
|
||||
{
|
||||
u32 Value = pChoice->ValueRef(pData);
|
||||
Log::FileError(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Choice property \"" + pChoice->Name() + "\" (" + pChoice->IDString(true) + ") has unrecognized value: " + TString::HexString(Value));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case eFloatProperty:
|
||||
case EPropertyType::Enum:
|
||||
{
|
||||
TFloatProperty *pFloatCast = static_cast<TFloatProperty*>(pProp);
|
||||
pFloatCast->Set(rSCLY.ReadFloat());
|
||||
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProp);
|
||||
pEnum->ValueRef(pData) = rSCLY.ReadLong();
|
||||
|
||||
#if VALIDATE_PROPERTY_VALUES
|
||||
if (!pEnum->HasValidValue(pData))
|
||||
{
|
||||
u32 Value = pEnum->ValueRef(pData);
|
||||
Log::FileError(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Enum property \"" + pEnum->Name() + "\" (" + pEnum->IDString(true) + ") has unrecognized value: " + TString::HexString(Value));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case eStringProperty:
|
||||
case EPropertyType::Flags:
|
||||
{
|
||||
TStringProperty *pStringCast = static_cast<TStringProperty*>(pProp);
|
||||
pStringCast->Set(rSCLY.ReadString());
|
||||
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
|
||||
pFlags->ValueRef(pData) = rSCLY.ReadLong();
|
||||
|
||||
#if VALIDATE_PROPERTY_VALUES
|
||||
u32 InvalidBits = pFlags->HasValidValue(pData);
|
||||
|
||||
if (InvalidBits)
|
||||
{
|
||||
Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Flags property \"" + pFlags->Name() + "\" + (" + pFlags->IDString(true) + ") has unrecognized flags set: " + TString::HexString(InvalidBits));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case eVector3Property:
|
||||
case EPropertyType::String:
|
||||
{
|
||||
TVector3Property *pVector3Cast = static_cast<TVector3Property*>(pProp);
|
||||
pVector3Cast->Set(CVector3f(rSCLY));
|
||||
CStringProperty* pString = TPropCast<CStringProperty>(pProp);
|
||||
pString->ValueRef(pData) = rSCLY.ReadString();
|
||||
break;
|
||||
}
|
||||
|
||||
case eColorProperty:
|
||||
case EPropertyType::Vector:
|
||||
{
|
||||
TColorProperty *pColorCast = static_cast<TColorProperty*>(pProp);
|
||||
pColorCast->Set(CColor(rSCLY));
|
||||
CVectorProperty* pVector = TPropCast<CVectorProperty>(pProp);
|
||||
pVector->ValueRef(pData) = CVector3f(rSCLY);
|
||||
break;
|
||||
}
|
||||
|
||||
case eSoundProperty:
|
||||
case EPropertyType::Color:
|
||||
{
|
||||
TSoundProperty *pSoundCast = static_cast<TSoundProperty*>(pProp);
|
||||
pSoundCast->Set(rSCLY.ReadLong());
|
||||
CColorProperty* pColor = TPropCast<CColorProperty>(pProp);
|
||||
pColor->ValueRef(pData) = CColor(rSCLY);
|
||||
break;
|
||||
}
|
||||
|
||||
case eAssetProperty:
|
||||
case EPropertyType::Asset:
|
||||
{
|
||||
TAssetProperty *pAssetCast = static_cast<TAssetProperty*>(pProp);
|
||||
CAssetProperty* pAsset = TPropCast<CAssetProperty>(pProp);
|
||||
pAsset->ValueRef(pData) = CAssetID(rSCLY, mpGameTemplate->Game());
|
||||
|
||||
// quick hacky fix - all games set version to DKCR for copy/paste
|
||||
CAssetID ID;
|
||||
if (mVersion == eReturns)
|
||||
ID = CAssetID(rSCLY, (EIDLength) Size);
|
||||
else
|
||||
ID = CAssetID(rSCLY, mVersion);
|
||||
#if VALIDATE_PROPERTY_VALUES
|
||||
CAssetID ID = pAsset->ValueRef(pData);
|
||||
|
||||
pAssetCast->Set(ID);
|
||||
|
||||
// Verify this is a valid resource type for this property
|
||||
if (ID.IsValid())
|
||||
{
|
||||
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
|
||||
|
||||
if (pEntry)
|
||||
{
|
||||
const CResTypeFilter& rkFilter = static_cast<CAssetTemplate*>(pTemp)->TypeFilter();
|
||||
const CResTypeFilter& rkFilter = pAsset->GetTypeFilter();
|
||||
bool Valid = rkFilter.Accepts(pEntry->ResourceType());
|
||||
|
||||
if (!Valid)
|
||||
Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - ID.Length(), "Asset property \"" + pTemp->FullName() + "\" (" + pTemp->IDString(true) + ") has a reference to an illegal asset type: " + pEntry->CookedExtension());
|
||||
Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - ID.Length(), "Asset property \"" + pAsset->Name() + "\" (" + pAsset->IDString(true) + ") has a reference to an illegal asset type: " + pEntry->CookedExtension());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case eStructProperty:
|
||||
case EPropertyType::Sound:
|
||||
{
|
||||
CPropertyStruct *pStructCast = static_cast<CPropertyStruct*>(pProp);
|
||||
CSoundProperty* pSound = TPropCast<CSoundProperty>(pProp);
|
||||
pSound->ValueRef(pData) = rSCLY.ReadLong();
|
||||
break;
|
||||
}
|
||||
|
||||
if (mVersion < eEchoesDemo)
|
||||
LoadStructMP1(rSCLY, pStructCast, static_cast<CStructTemplate*>(pStructCast->Template()));
|
||||
case EPropertyType::Animation:
|
||||
{
|
||||
CAnimationProperty* pAnim = TPropCast<CAnimationProperty>(pProp);
|
||||
pAnim->ValueRef(pData) = rSCLY.ReadLong();
|
||||
break;
|
||||
}
|
||||
|
||||
case EPropertyType::AnimationSet:
|
||||
{
|
||||
CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(pProp);
|
||||
pAnimSet->ValueRef(pData) = CAnimationParameters(rSCLY, mpGameTemplate->Game());
|
||||
break;
|
||||
}
|
||||
|
||||
case EPropertyType::Sequence:
|
||||
{
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
|
||||
case EPropertyType::Spline:
|
||||
{
|
||||
CSplineProperty* pSpline = TPropCast<CSplineProperty>(pProp);
|
||||
std::vector<char>& Buffer = pSpline->ValueRef(pData);
|
||||
Buffer.resize(Size);
|
||||
rSCLY.ReadBytes(Buffer.data(), Buffer.size());
|
||||
break;
|
||||
}
|
||||
|
||||
case EPropertyType::Guid:
|
||||
{
|
||||
ASSERT(Size == 16);
|
||||
CGuidProperty* pGuid = TPropCast<CGuidProperty>(pProp);
|
||||
pGuid->ValueRef(pData).resize(16);
|
||||
rSCLY.ReadBytes(pGuid->ValueRef(pData).data(), 16);
|
||||
break;
|
||||
}
|
||||
|
||||
case EPropertyType::Struct:
|
||||
{
|
||||
CStructProperty* pStruct = TPropCast<CStructProperty>(pProp);
|
||||
|
||||
if (mVersion < EGame::EchoesDemo)
|
||||
LoadStructMP1(rSCLY, pStruct);
|
||||
else
|
||||
LoadStructMP2(rSCLY, pStructCast, static_cast<CStructTemplate*>(pTemp));
|
||||
LoadStructMP2(rSCLY, pStruct);
|
||||
break;
|
||||
}
|
||||
|
||||
case eArrayProperty:
|
||||
case EPropertyType::Array:
|
||||
{
|
||||
CArrayProperty *pArrayCast = static_cast<CArrayProperty*>(pProp);
|
||||
CArrayProperty *pArray = TPropCast<CArrayProperty>(pProp);
|
||||
int Count = rSCLY.ReadLong();
|
||||
|
||||
pArrayCast->Resize(Count);
|
||||
pArray->Resize(pData, Count);
|
||||
void* pOldArrayItemData = mpArrayItemData;
|
||||
|
||||
for (int iElem = 0; iElem < Count; iElem++)
|
||||
// Make sure the array archetype is atomic... non-atomic array archetypes is not supported
|
||||
// because arrays can only have one possible archetype so having property IDs here wouldn't make sense
|
||||
ASSERT(pArray->ItemArchetype()->IsAtomic());
|
||||
|
||||
for (int ElementIdx = 0; ElementIdx < Count; ElementIdx++)
|
||||
{
|
||||
if (mVersion < eEchoesDemo)
|
||||
LoadStructMP1(rSCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate());
|
||||
else
|
||||
LoadStructMP2(rSCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate());
|
||||
/**
|
||||
* so this is kind of annoying, there isn't really any good way to cleanly integrate arrays into the property system
|
||||
* because calculating the pointer to an item requires knowing the array index, which the property itself can't store
|
||||
* because the same property object is used for every array element; and we can't dynamically add children to the array
|
||||
* based on its size either, because the same array property is shared between multiple script instances. so, instead,
|
||||
* we determine the item pointer ourselves and the array archetype property will respect it.
|
||||
*
|
||||
* arrays are an edge case anyway - they only really appear in Prime 1 and there are only a couple array properties in
|
||||
* the game. the only situation where an array property appears in other games is SequenceTimer, and that's going to be
|
||||
* migrated to Sequence properties eventually, so there isn't really any good reason to spend a lot of effort refactoring
|
||||
* things to make this cleaner
|
||||
*/
|
||||
mpArrayItemData = pArray->ItemPointer(pData, ElementIdx);
|
||||
ReadProperty(pArray->ItemArchetype(), 0, rSCLY);
|
||||
}
|
||||
|
||||
mpArrayItemData = pOldArrayItemData;
|
||||
break;
|
||||
}
|
||||
|
||||
case eCharacterProperty:
|
||||
{
|
||||
TCharacterProperty *pAnimCast = static_cast<TCharacterProperty*>(pProp);
|
||||
pAnimCast->Set(CAnimationParameters(rSCLY, mpMaster->Game()));
|
||||
break;
|
||||
}
|
||||
|
||||
case eMayaSplineProperty:
|
||||
{
|
||||
TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp);
|
||||
std::vector<u8> Buffer(Size);
|
||||
rSCLY.ReadBytes(Buffer.data(), Buffer.size());
|
||||
pSplineCast->Set(Buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case eUnknownProperty:
|
||||
{
|
||||
TUnknownProperty *pUnknownCast = static_cast<TUnknownProperty*>(pProp);
|
||||
std::vector<u8> Buffer(Size);
|
||||
rSCLY.ReadBytes(Buffer.data(), Buffer.size());
|
||||
pUnknownCast->Set(Buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CScriptLoader::LoadStructMP1(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp)
|
||||
void CScriptLoader::LoadStructMP1(IInputStream& rSCLY, CStructProperty* pStruct)
|
||||
{
|
||||
u32 StructStart = rSCLY.Tell();
|
||||
|
||||
// Verify property count
|
||||
u32 PropCount = pTemp->Count();
|
||||
u32 PropertyCount = pStruct->NumChildren();
|
||||
u32 Version = 0;
|
||||
|
||||
if (!pTemp->IsSingleProperty())
|
||||
if (!pStruct->IsAtomic())
|
||||
{
|
||||
u32 FilePropCount = rSCLY.ReadLong();
|
||||
Version = pTemp->VersionForPropertyCount(FilePropCount);
|
||||
|
||||
if (Version == -1)
|
||||
{
|
||||
TIDString IDString = pTemp->IDString(true);
|
||||
if (!IDString.IsEmpty()) IDString = " (" + IDString + ")";
|
||||
|
||||
Log::FileWarning(rSCLY.GetSourceString(), StructStart, "Struct \"" + pTemp->FullName() + "\" (" + IDString + ") template prop count doesn't match file; template is " + TString::HexString(PropCount, 2) + ", file is " + TString::HexString(FilePropCount, 2));
|
||||
Version = 0;
|
||||
}
|
||||
//@todo version checking
|
||||
}
|
||||
|
||||
// Parse properties
|
||||
for (u32 iProp = 0; iProp < PropCount; iProp++)
|
||||
for (u32 ChildIndex = 0; ChildIndex < PropertyCount; ChildIndex++)
|
||||
{
|
||||
IPropertyTemplate *pPropTemp = pTemp->PropertyByIndex(iProp);
|
||||
IProperty *pProp = pStruct->PropertyByIndex(iProp);
|
||||
IProperty *pProperty = pStruct->ChildByIndex(ChildIndex);
|
||||
|
||||
if (pPropTemp->CookPreference() != eNeverCook && pPropTemp->IsInVersion(Version))
|
||||
ReadProperty(pProp, 0, rSCLY);
|
||||
//@todo version check
|
||||
if (pProperty->CookPreference() != ECookPreference::Never)
|
||||
ReadProperty(pProperty, 0, rSCLY);
|
||||
}
|
||||
}
|
||||
|
||||
CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& rSCLY)
|
||||
{
|
||||
u32 ObjStart = rSCLY.Tell();
|
||||
u32 StartOffset = rSCLY.Tell();
|
||||
u8 Type = rSCLY.ReadByte();
|
||||
u32 Size = rSCLY.ReadLong();
|
||||
u32 End = rSCLY.Tell() + Size;
|
||||
|
||||
CScriptTemplate *pTemp = mpMaster->TemplateByID((u32) Type);
|
||||
if (!pTemp)
|
||||
CScriptTemplate *pTemplate = mpGameTemplate->TemplateByID((u32) Type);
|
||||
if (!pTemplate)
|
||||
{
|
||||
// No valid template for this object; can't load
|
||||
Log::FileError(rSCLY.GetSourceString(), ObjStart, "Unknown object ID encountered: " + TString::HexString(Type, 2));
|
||||
Log::FileError(rSCLY.GetSourceString(), StartOffset, "Unknown object ID encountered: " + TString::HexString(Type, 2));
|
||||
rSCLY.Seek(End, SEEK_SET);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u32 InstanceID = rSCLY.ReadLong() & 0x03FFFFFF;
|
||||
if (InstanceID == 0x03FFFFFF) InstanceID = mpArea->FindUnusedInstanceID();
|
||||
mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemp);
|
||||
mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemplate);
|
||||
|
||||
// Load connections
|
||||
u32 NumLinks = rSCLY.ReadLong();
|
||||
@@ -268,8 +306,8 @@ CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& rSCLY)
|
||||
}
|
||||
|
||||
// Load object...
|
||||
CPropertyStruct *pBase = mpObj->mpProperties;
|
||||
LoadStructMP1(rSCLY, pBase, static_cast<CStructTemplate*>(pBase->Template()));
|
||||
CStructProperty* pProperties = pTemplate->Properties();
|
||||
LoadStructMP1(rSCLY, pProperties);
|
||||
|
||||
// Cleanup and return
|
||||
rSCLY.Seek(End, SEEK_SET);
|
||||
@@ -288,11 +326,11 @@ CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream& rSCLY)
|
||||
mpLayer = new CScriptLayer(mpArea);
|
||||
mpLayer->Reserve(NumObjects);
|
||||
|
||||
for (u32 iObj = 0; iObj < NumObjects; iObj++)
|
||||
for (u32 ObjectIndex = 0; ObjectIndex < NumObjects; ObjectIndex++)
|
||||
{
|
||||
CScriptObject *pObj = LoadObjectMP1(rSCLY);
|
||||
if (pObj)
|
||||
mpLayer->AddInstance(pObj);
|
||||
CScriptObject *pObject = LoadObjectMP1(rSCLY);
|
||||
if (pObject)
|
||||
mpLayer->AddInstance(pObject);
|
||||
}
|
||||
|
||||
// Layer sizes are always a multiple of 32 - skip end padding before returning
|
||||
@@ -301,46 +339,39 @@ CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream& rSCLY)
|
||||
return mpLayer;
|
||||
}
|
||||
|
||||
void CScriptLoader::LoadStructMP2(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp)
|
||||
void CScriptLoader::LoadStructMP2(IInputStream& rSCLY, CStructProperty* pStruct)
|
||||
{
|
||||
// Verify property count
|
||||
u32 StructStart = rSCLY.Tell();
|
||||
StructStart += 0;
|
||||
u32 PropCount = pTemp->Count();
|
||||
u32 ChildCount = pStruct->NumChildren();
|
||||
|
||||
if (!pTemp->IsSingleProperty())
|
||||
PropCount = rSCLY.ReadShort();
|
||||
if (!pStruct->IsAtomic())
|
||||
ChildCount = rSCLY.ReadShort();
|
||||
|
||||
// Parse properties
|
||||
for (u32 iProp = 0; iProp < PropCount; iProp++)
|
||||
for (u32 ChildIdx = 0; ChildIdx < ChildCount; ChildIdx++)
|
||||
{
|
||||
IProperty *pProp;
|
||||
IPropertyTemplate *pPropTemp;
|
||||
IProperty* pProperty = nullptr;
|
||||
u32 PropertyStart = rSCLY.Tell();
|
||||
u32 PropertyID = -1;
|
||||
u16 PropertyLength = 0;
|
||||
u16 PropertySize = 0;
|
||||
u32 NextProperty = 0;
|
||||
|
||||
if (pTemp->IsSingleProperty())
|
||||
if (pStruct->IsAtomic())
|
||||
{
|
||||
pProp = pStruct->PropertyByIndex(iProp);
|
||||
pPropTemp = pTemp->PropertyByIndex(iProp);
|
||||
pProperty = pStruct->ChildByIndex(ChildIdx);
|
||||
}
|
||||
else
|
||||
{
|
||||
PropertyID = rSCLY.ReadLong();
|
||||
PropertyLength = rSCLY.ReadShort();
|
||||
NextProperty = rSCLY.Tell() + PropertyLength;
|
||||
|
||||
pProp = pStruct->PropertyByID(PropertyID);
|
||||
pPropTemp = pTemp->PropertyByID(PropertyID);
|
||||
PropertySize = rSCLY.ReadShort();
|
||||
NextProperty = rSCLY.Tell() + PropertySize;
|
||||
pProperty = pStruct->ChildByID(PropertyID);
|
||||
}
|
||||
|
||||
if (!pPropTemp)
|
||||
if (!pProperty)
|
||||
Log::FileError(rSCLY.GetSourceString(), PropertyStart, "Can't find template for property " + TString::HexString(PropertyID) + " - skipping");
|
||||
|
||||
else
|
||||
ReadProperty(pProp, PropertyLength, rSCLY);
|
||||
ReadProperty(pProperty, PropertySize, rSCLY);
|
||||
|
||||
if (NextProperty > 0)
|
||||
rSCLY.Seek(NextProperty, SEEK_SET);
|
||||
@@ -354,7 +385,7 @@ CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& rSCLY)
|
||||
u16 ObjectSize = rSCLY.ReadShort();
|
||||
u32 ObjEnd = rSCLY.Tell() + ObjectSize;
|
||||
|
||||
CScriptTemplate *pTemplate = mpMaster->TemplateByID(ObjectID);
|
||||
CScriptTemplate* pTemplate = mpGameTemplate->TemplateByID(ObjectID);
|
||||
|
||||
if (!pTemplate)
|
||||
{
|
||||
@@ -371,19 +402,19 @@ CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& rSCLY)
|
||||
u32 NumConnections = rSCLY.ReadShort();
|
||||
mpObj->mOutLinks.reserve(NumConnections);
|
||||
|
||||
for (u32 iCon = 0; iCon < NumConnections; iCon++)
|
||||
for (u32 LinkIdx = 0; LinkIdx < NumConnections; LinkIdx++)
|
||||
{
|
||||
u32 State = rSCLY.ReadLong();
|
||||
u32 Message = rSCLY.ReadLong();
|
||||
u32 ReceiverID = rSCLY.ReadLong() & 0x03FFFFFF;
|
||||
|
||||
CLink *pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID);
|
||||
CLink* pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID);
|
||||
mpObj->mOutLinks.push_back(pLink);
|
||||
}
|
||||
|
||||
// Load object
|
||||
rSCLY.Seek(0x6, SEEK_CUR); // Skip base struct ID + size
|
||||
LoadStructMP2(rSCLY, mpObj->mpProperties, mpObj->mpTemplate->BaseStruct());
|
||||
LoadStructMP2(rSCLY, pTemplate->Properties());
|
||||
|
||||
// Cleanup and return
|
||||
rSCLY.Seek(ObjEnd, SEEK_SET);
|
||||
@@ -399,11 +430,11 @@ CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& rSCLY)
|
||||
mpLayer = new CScriptLayer(mpArea);
|
||||
mpLayer->Reserve(NumObjects);
|
||||
|
||||
for (u32 iObj = 0; iObj < NumObjects; iObj++)
|
||||
for (u32 ObjectIdx = 0; ObjectIdx < NumObjects; ObjectIdx++)
|
||||
{
|
||||
CScriptObject *pObj = LoadObjectMP2(rSCLY);
|
||||
if (pObj)
|
||||
mpLayer->AddInstance(pObj);
|
||||
CScriptObject* pObject = LoadObjectMP2(rSCLY);
|
||||
if (pObject)
|
||||
mpLayer->AddInstance(pObject);
|
||||
}
|
||||
|
||||
return mpLayer;
|
||||
@@ -416,19 +447,16 @@ CScriptLayer* CScriptLoader::LoadLayer(IInputStream& rSCLY, CGameArea *pArea, EG
|
||||
|
||||
CScriptLoader Loader;
|
||||
Loader.mVersion = Version;
|
||||
Loader.mpMaster = CMasterTemplate::MasterForGame(Version);
|
||||
Loader.mpGameTemplate = NGameList::GetGameTemplate(Version);
|
||||
Loader.mpArea = pArea;
|
||||
|
||||
if (!Loader.mpMaster)
|
||||
if (!Loader.mpGameTemplate)
|
||||
{
|
||||
Log::Write("This game doesn't have a master template; couldn't load script layer");
|
||||
Log::Write("This game doesn't have a game template; couldn't load script layer");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!Loader.mpMaster->IsLoadedSuccessfully())
|
||||
CTemplateLoader::LoadGameTemplates(Version);
|
||||
|
||||
if (Version <= ePrime)
|
||||
if (Version <= EGame::Prime)
|
||||
return Loader.LoadLayerMP1(rSCLY);
|
||||
else
|
||||
return Loader.LoadLayerMP2(rSCLY);
|
||||
@@ -439,21 +467,18 @@ CScriptObject* CScriptLoader::LoadInstance(IInputStream& rSCLY, CGameArea *pArea
|
||||
if (!rSCLY.IsValid()) return nullptr;
|
||||
|
||||
CScriptLoader Loader;
|
||||
Loader.mVersion = (ForceReturnsFormat ? eReturns : Version);
|
||||
Loader.mpMaster = CMasterTemplate::MasterForGame(Version);
|
||||
Loader.mVersion = (ForceReturnsFormat ? EGame::DKCReturns : Version);
|
||||
Loader.mpGameTemplate = NGameList::GetGameTemplate(Version);
|
||||
Loader.mpArea = pArea;
|
||||
Loader.mpLayer = pLayer;
|
||||
|
||||
if (!Loader.mpMaster)
|
||||
if (!Loader.mpGameTemplate)
|
||||
{
|
||||
Log::Write("This game doesn't have a master template; couldn't load script instance");
|
||||
Log::Write("This game doesn't have a game template; couldn't load script instance");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!Loader.mpMaster->IsLoadedSuccessfully())
|
||||
CTemplateLoader::LoadGameTemplates(Version);
|
||||
|
||||
if (Loader.mVersion <= ePrime)
|
||||
if (Loader.mVersion <= EGame::Prime)
|
||||
return Loader.LoadObjectMP1(rSCLY);
|
||||
else
|
||||
return Loader.LoadObjectMP2(rSCLY);
|
||||
|
||||
@@ -5,24 +5,27 @@
|
||||
#include "Core/Resource/Area/CGameArea.h"
|
||||
#include "Core/Resource/Script/CScriptObject.h"
|
||||
#include "Core/Resource/Script/CScriptLayer.h"
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include "Core/Resource/Script/CGameTemplate.h"
|
||||
|
||||
class CScriptLoader
|
||||
{
|
||||
EGame mVersion;
|
||||
CScriptObject *mpObj;
|
||||
CScriptLayer *mpLayer;
|
||||
CGameArea *mpArea;
|
||||
CMasterTemplate *mpMaster;
|
||||
CScriptObject* mpObj;
|
||||
CScriptLayer* mpLayer;
|
||||
CGameArea* mpArea;
|
||||
CGameTemplate *mpGameTemplate;
|
||||
|
||||
// Current array item pointer
|
||||
void* mpArrayItemData;
|
||||
|
||||
CScriptLoader();
|
||||
void ReadProperty(IProperty *pProp, u32 Size, IInputStream& rSCLY);
|
||||
void ReadProperty(IProperty* pProp, u32 Size, IInputStream& rSCLY);
|
||||
|
||||
void LoadStructMP1(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp);
|
||||
void LoadStructMP1(IInputStream& rSCLY, CStructProperty* pStruct);
|
||||
CScriptObject* LoadObjectMP1(IInputStream& rSCLY);
|
||||
CScriptLayer* LoadLayerMP1(IInputStream& rSCLY);
|
||||
|
||||
void LoadStructMP2(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp);
|
||||
void LoadStructMP2(IInputStream& rSCLY, CStructProperty* pStruct);
|
||||
CScriptObject* LoadObjectMP2(IInputStream& rSCLY);
|
||||
CScriptLayer* LoadLayerMP2(IInputStream& rSCLY);
|
||||
|
||||
|
||||
@@ -60,12 +60,12 @@ CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF, CResourceEntry *pEntry
|
||||
// rotation value in MP2. The max bone count is 100 so the linked bone count will not be higher
|
||||
// than that. Additionally, every bone links to its parent at least and every skeleton (as far as I
|
||||
// know) has at least two bones so the linked bone count will never be 0.
|
||||
if (Game == eUnknownGame)
|
||||
if (Game == EGame::Invalid)
|
||||
{
|
||||
u32 Check = rCINF.PeekLong();
|
||||
Game = ((Check > 100 || Check == 0) ? eEchoes : ePrime);
|
||||
Game = ((Check > 100 || Check == 0) ? EGame::Echoes : EGame::Prime);
|
||||
}
|
||||
if (Game >= eEchoes)
|
||||
if (Game >= EGame::Echoes)
|
||||
{
|
||||
pBone->mRotation = CQuaternion(rCINF);
|
||||
pBone->mLocalRotation = CQuaternion(rCINF);
|
||||
|
||||
@@ -44,11 +44,11 @@ void CStringLoader::LoadPrimeSTRG(IInputStream& rSTRG)
|
||||
{
|
||||
mpStringTable->mLangTables[iLang].Language = CFourCC(rSTRG);
|
||||
LangOffsets[iLang] = rSTRG.ReadLong();
|
||||
if (mVersion == eEchoes) rSTRG.Seek(0x4, SEEK_CUR); // Skipping strings size
|
||||
if (mVersion == EGame::Echoes) rSTRG.Seek(0x4, SEEK_CUR); // Skipping strings size
|
||||
}
|
||||
|
||||
// String names
|
||||
if (mVersion == eEchoes)
|
||||
if (mVersion == EGame::Echoes)
|
||||
LoadNameTable(rSTRG);
|
||||
|
||||
// Strings
|
||||
@@ -56,7 +56,7 @@ void CStringLoader::LoadPrimeSTRG(IInputStream& rSTRG)
|
||||
for (u32 iLang = 0; iLang < NumLanguages; iLang++)
|
||||
{
|
||||
rSTRG.Seek(StringsStart + LangOffsets[iLang], SEEK_SET);
|
||||
if (mVersion == ePrime) rSTRG.Seek(0x4, SEEK_CUR); // Skipping strings size
|
||||
if (mVersion == EGame::Prime) rSTRG.Seek(0x4, SEEK_CUR); // Skipping strings size
|
||||
|
||||
u32 LangStart = rSTRG.Tell();
|
||||
CStringTable::SLangTable* pLang = &mpStringTable->mLangTables[iLang];
|
||||
@@ -160,7 +160,7 @@ CStringTable* CStringLoader::LoadSTRG(IInputStream& rSTRG, CResourceEntry *pEntr
|
||||
if (!rSTRG.IsValid()) return nullptr;
|
||||
|
||||
u32 Magic = rSTRG.ReadLong();
|
||||
EGame Version = eUnknownGame;
|
||||
EGame Version = EGame::Invalid;
|
||||
|
||||
if (Magic != 0x87654321)
|
||||
{
|
||||
@@ -170,10 +170,10 @@ CStringTable* CStringLoader::LoadSTRG(IInputStream& rSTRG, CResourceEntry *pEntr
|
||||
{
|
||||
rSTRG.Seek(Magic, SEEK_SET);
|
||||
if ((rSTRG.EoF()) || (rSTRG.ReadShort() == 0xFFFF))
|
||||
Version = ePrimeDemo;
|
||||
Version = EGame::PrimeDemo;
|
||||
}
|
||||
|
||||
if (Version != ePrimeDemo)
|
||||
if (Version != EGame::PrimeDemo)
|
||||
{
|
||||
Log::FileError(rSTRG.GetSourceString(), "Invalid STRG magic: " + TString::HexString(Magic));
|
||||
return nullptr;
|
||||
@@ -185,7 +185,7 @@ CStringTable* CStringLoader::LoadSTRG(IInputStream& rSTRG, CResourceEntry *pEntr
|
||||
u32 FileVersion = rSTRG.ReadLong();
|
||||
Version = GetFormatVersion(FileVersion);
|
||||
|
||||
if (FileVersion == eUnknownGame)
|
||||
if (Version == EGame::Invalid)
|
||||
{
|
||||
Log::FileError(rSTRG.GetSourceString(), "Unsupported STRG version: " + TString::HexString(FileVersion, 0));
|
||||
return nullptr;
|
||||
@@ -197,8 +197,8 @@ CStringTable* CStringLoader::LoadSTRG(IInputStream& rSTRG, CResourceEntry *pEntr
|
||||
Loader.mpStringTable = new CStringTable(pEntry);
|
||||
Loader.mVersion = Version;
|
||||
|
||||
if (Version == ePrimeDemo) Loader.LoadPrimeDemoSTRG(rSTRG);
|
||||
else if (Version < eCorruption) Loader.LoadPrimeSTRG(rSTRG);
|
||||
if (Version == EGame::PrimeDemo) Loader.LoadPrimeDemoSTRG(rSTRG);
|
||||
else if (Version < EGame::Corruption) Loader.LoadPrimeSTRG(rSTRG);
|
||||
else Loader.LoadCorruptionSTRG(rSTRG);
|
||||
|
||||
return Loader.mpStringTable;
|
||||
@@ -208,9 +208,9 @@ EGame CStringLoader::GetFormatVersion(u32 Version)
|
||||
{
|
||||
switch (Version)
|
||||
{
|
||||
case 0x0: return ePrime;
|
||||
case 0x1: return eEchoes;
|
||||
case 0x3: return eCorruption;
|
||||
default: return eUnknownGame;
|
||||
case 0x0: return EGame::Prime;
|
||||
case 0x1: return EGame::Echoes;
|
||||
case 0x3: return EGame::Corruption;
|
||||
default: return EGame::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,52 +0,0 @@
|
||||
#ifndef CTEMPLATELOADER_H
|
||||
#define CTEMPLATELOADER_H
|
||||
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include "Core/Resource/Script/CScriptTemplate.h"
|
||||
#include <tinyxml2.h>
|
||||
|
||||
class CTemplateLoader
|
||||
{
|
||||
static const TString mskTemplatesDir;
|
||||
static const TString mskGameListPath;
|
||||
|
||||
CMasterTemplate *mpMaster;
|
||||
EGame mGame;
|
||||
TString mTemplatesDir;
|
||||
TString mMasterDir;
|
||||
|
||||
// Constructor
|
||||
CTemplateLoader(const TString& rkTemplatesDir)
|
||||
: mTemplatesDir(rkTemplatesDir) {}
|
||||
|
||||
// Load Property
|
||||
IPropertyTemplate* LoadProperty(tinyxml2::XMLElement *pElem, CScriptTemplate *pScript, CStructTemplate *pParentStruct, const TString& rkTemplateName);
|
||||
IPropertyTemplate* CreateProperty(u32 ID, EPropertyType Type, const TString& rkName, CScriptTemplate *pScript, CStructTemplate *pStruct);
|
||||
|
||||
void LoadStructTemplate(const TString& rkTemplateFileName, CStructTemplate *pStruct);
|
||||
void LoadEnumTemplate(const TString& rkTemplateFileName, CEnumTemplate *pEnum);
|
||||
void LoadBitfieldTemplate(const TString& rkTemplateFileName, CBitfieldTemplate *pBitfield);
|
||||
|
||||
void LoadProperties(tinyxml2::XMLElement *pPropertiesElem, CScriptTemplate *pScript, CStructTemplate *pStruct, const TString& rkTemplateName);
|
||||
void LoadEnumerators(tinyxml2::XMLElement *pEnumeratorsElem, CEnumTemplate *pEnum, const TString& rkTemplateName);
|
||||
void LoadBitFlags(tinyxml2::XMLElement *pFlagsElem, CBitfieldTemplate *pBitfield, const TString& rkTemplateName);
|
||||
|
||||
// Load Script Object
|
||||
CScriptTemplate* LoadScriptTemplate(tinyxml2::XMLDocument *pDoc, const TString& rkTemplateName, u32 ObjectID);
|
||||
|
||||
// Load Master
|
||||
CMasterTemplate* LoadGameInfo(tinyxml2::XMLNode *pNode);
|
||||
void LoadMasterTemplate(tinyxml2::XMLDocument *pDoc, CMasterTemplate *pMaster);
|
||||
|
||||
// Utility
|
||||
static void OpenXML(const TString& rkPath, tinyxml2::XMLDocument& rDoc);
|
||||
static TString ErrorName(tinyxml2::XMLError Error);
|
||||
|
||||
public:
|
||||
static void LoadGameList();
|
||||
static void LoadGameTemplates(EGame Game);
|
||||
static void LoadAllGames();
|
||||
static void LoadPropertyList(tinyxml2::XMLDocument *pDoc, const TString& rkListName);
|
||||
};
|
||||
|
||||
#endif // CTEMPLATELOADER_H
|
||||
@@ -9,12 +9,12 @@ void CUnsupportedFormatLoader::PerformCheating(IInputStream& rFile, EGame Game,
|
||||
std::vector<u8> Data(rFile.Size() - rFile.Tell());
|
||||
rFile.ReadBytes(Data.data(), Data.size());
|
||||
|
||||
u32 MaxIndex = (Game <= eEchoes ? Data.size() - 3 : Data.size() - 7);
|
||||
u32 MaxIndex = (Game <= EGame::Echoes ? Data.size() - 3 : Data.size() - 7);
|
||||
CAssetID ID;
|
||||
|
||||
for (u32 iByte = 0; iByte < MaxIndex; iByte++)
|
||||
{
|
||||
if (Game <= eEchoes)
|
||||
if (Game <= EGame::Echoes)
|
||||
{
|
||||
ID = ( (Data[iByte+0] << 24) |
|
||||
(Data[iByte+1] << 16) |
|
||||
@@ -44,17 +44,17 @@ CAudioMacro* CUnsupportedFormatLoader::LoadCAUD(IInputStream& rCAUD, CResourceEn
|
||||
ASSERT(Magic == FOURCC('CAUD'));
|
||||
|
||||
u32 Version = rCAUD.ReadLong();
|
||||
EGame Game = (Version == 0x2 ? eCorruptionProto :
|
||||
Version == 0x9 ? eCorruption :
|
||||
Version == 0xE ? eReturns :
|
||||
eUnknownGame);
|
||||
ASSERT(Game != eUnknownGame && Game == pEntry->Game());
|
||||
EGame Game = (Version == 0x2 ? EGame::CorruptionProto :
|
||||
Version == 0x9 ? EGame::Corruption :
|
||||
Version == 0xE ? EGame::DKCReturns :
|
||||
EGame::Invalid);
|
||||
ASSERT(Game != EGame::Invalid && Game == pEntry->Game());
|
||||
|
||||
CAudioMacro *pMacro = new CAudioMacro(pEntry);
|
||||
pMacro->mMacroName = rCAUD.ReadString();
|
||||
|
||||
// DKCR is missing the sample data size value, and the bulk of the format isn't well understood, unfortunately
|
||||
if (Game == eReturns)
|
||||
if (Game == EGame::DKCReturns)
|
||||
{
|
||||
std::list<CAssetID> AssetList;
|
||||
PerformCheating(rCAUD, pEntry->Game(), AssetList);
|
||||
@@ -71,7 +71,7 @@ CAudioMacro* CUnsupportedFormatLoader::LoadCAUD(IInputStream& rCAUD, CResourceEn
|
||||
for (u32 iVol = 0; iVol < NumVolGroups; iVol++)
|
||||
rCAUD.ReadString();
|
||||
|
||||
u32 SkipAmt = (Game == eCorruptionProto ? 0x10 : 0x14);
|
||||
u32 SkipAmt = (Game == EGame::CorruptionProto ? 0x10 : 0x14);
|
||||
rCAUD.Seek(SkipAmt, SEEK_CUR);
|
||||
u32 NumSamples = rCAUD.ReadLong();
|
||||
|
||||
@@ -237,9 +237,9 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadFRME(IInputStream& rFRME, CResou
|
||||
else if (Version == 4 || Version == 5 || Version == 0xD || Version == 0xE || Version == 0x10)
|
||||
{
|
||||
EGame Game;
|
||||
if (Version == 4) Game = eEchoes;
|
||||
else if (Version == 0x10) Game = eReturns;
|
||||
else Game = eCorruption;
|
||||
if (Version == 4) Game = EGame::Echoes;
|
||||
else if (Version == 0x10) Game = EGame::DKCReturns;
|
||||
else Game = EGame::Corruption;
|
||||
|
||||
u32 NumDependencies = rFRME.ReadLong();
|
||||
|
||||
@@ -359,7 +359,7 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadHIER(IInputStream& rHIER, CResou
|
||||
|
||||
// Note: For some reason this file still exists in MP3 and it's identical to MP2, including with 32-bit asset IDs.
|
||||
// Obviously we can't read 32-bit asset IDs in MP3, so this file should just be ignored.
|
||||
if (pEntry->Game() > eEchoes)
|
||||
if (pEntry->Game() > EGame::Echoes)
|
||||
return pOut;
|
||||
|
||||
for (u32 iNode = 0; iNode < NumNodes; iNode++)
|
||||
@@ -382,8 +382,8 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadHINT(IInputStream& rHINT, CResou
|
||||
u32 Version = rHINT.ReadLong();
|
||||
EGame Game;
|
||||
|
||||
if (Version == 0x1) Game = ePrime;
|
||||
else if (Version == 0x3) Game = eCorruption;
|
||||
if (Version == 0x1) Game = EGame::Prime;
|
||||
else if (Version == 0x3) Game = EGame::Corruption;
|
||||
|
||||
else
|
||||
{
|
||||
@@ -402,7 +402,7 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadHINT(IInputStream& rHINT, CResou
|
||||
pGroup->AddDependency( CAssetID(rHINT, Game) ); // Pop-up STRG
|
||||
rHINT.Seek(0x4, SEEK_CUR); // Skip unknowns
|
||||
|
||||
if (Game <= eEchoes)
|
||||
if (Game <= EGame::Echoes)
|
||||
{
|
||||
rHINT.Seek(0x4, SEEK_CUR);
|
||||
pGroup->AddDependency( CAssetID(rHINT, Game) ); // Target MLVL
|
||||
|
||||
@@ -1226,7 +1226,7 @@ void CUnsupportedParticleLoader::ParseFloatFunction(IInputStream& rFile)
|
||||
|
||||
case FOURCC('CEXT'):
|
||||
ParseIntFunction(rFile);
|
||||
if (mpGroup->Game() >= eReturns) ParseFloatFunction(rFile);
|
||||
if (mpGroup->Game() >= EGame::DKCReturns) ParseFloatFunction(rFile);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1791,7 +1791,7 @@ CDependencyGroup* CUnsupportedParticleLoader::LoadParticle(IInputStream& rFile,
|
||||
Loader.mpGroup = new CDependencyGroup(pEntry);
|
||||
|
||||
// Validate DKCR asset header
|
||||
if (pEntry->Game() == eReturns)
|
||||
if (pEntry->Game() == EGame::DKCReturns)
|
||||
{
|
||||
u32 AssetHeader = rFile.ReadLong();
|
||||
|
||||
|
||||
@@ -14,12 +14,12 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
|
||||
* We start immediately after the "version" value (0x8 in the file)
|
||||
*/
|
||||
// Header
|
||||
if (mVersion < eCorruptionProto)
|
||||
if (mVersion < EGame::CorruptionProto)
|
||||
{
|
||||
mpWorld->mpWorldName = gpResourceStore->LoadResource(rMLVL.ReadLong(), eStringTable);
|
||||
if (mVersion == eEchoes) mpWorld->mpDarkWorldName = gpResourceStore->LoadResource(rMLVL.ReadLong(), eStringTable);
|
||||
if (mVersion >= eEchoes) mpWorld->mTempleKeyWorldIndex = rMLVL.ReadLong();
|
||||
if (mVersion >= ePrime) mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadLong(), eSaveWorld);
|
||||
if (mVersion == EGame::Echoes) mpWorld->mpDarkWorldName = gpResourceStore->LoadResource(rMLVL.ReadLong(), eStringTable);
|
||||
if (mVersion >= EGame::Echoes) mpWorld->mTempleKeyWorldIndex = rMLVL.ReadLong();
|
||||
if (mVersion >= EGame::Prime) mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadLong(), eSaveWorld);
|
||||
mpWorld->mpDefaultSkybox = gpResourceStore->LoadResource(rMLVL.ReadLong(), eModel);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
|
||||
}
|
||||
|
||||
// Memory relays - only in MP1
|
||||
if (mVersion == ePrime)
|
||||
if (mVersion == EGame::Prime)
|
||||
{
|
||||
u32 NumMemoryRelays = rMLVL.ReadLong();
|
||||
mpWorld->mMemoryRelays.reserve(NumMemoryRelays);
|
||||
@@ -50,7 +50,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
|
||||
|
||||
// Areas - here's the real meat of the file
|
||||
u32 NumAreas = rMLVL.ReadLong();
|
||||
if (mVersion == ePrime) rMLVL.Seek(0x4, SEEK_CUR);
|
||||
if (mVersion == EGame::Prime) rMLVL.Seek(0x4, SEEK_CUR);
|
||||
mpWorld->mAreas.resize(NumAreas);
|
||||
|
||||
for (u32 iArea = 0; iArea < NumAreas; iArea++)
|
||||
@@ -70,7 +70,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
|
||||
pArea->AttachedAreaIDs.push_back( rMLVL.ReadShort() );
|
||||
|
||||
// Skip dependency list - this is very fast to regenerate so there's no use in caching it
|
||||
if (mVersion < eCorruptionProto)
|
||||
if (mVersion < EGame::CorruptionProto)
|
||||
{
|
||||
rMLVL.Seek(0x4, SEEK_CUR);
|
||||
u32 NumDependencies = rMLVL.ReadLong();
|
||||
@@ -108,7 +108,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
|
||||
}
|
||||
|
||||
// Rels
|
||||
if ( (mVersion == eEchoesDemo) || (mVersion == eEchoes) )
|
||||
if ( (mVersion == EGame::EchoesDemo) || (mVersion == EGame::Echoes) )
|
||||
{
|
||||
u32 NumRels = rMLVL.ReadLong();
|
||||
pArea->RelFilenames.resize(NumRels);
|
||||
@@ -116,7 +116,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
|
||||
for (u32 iRel = 0; iRel < NumRels; iRel++)
|
||||
pArea->RelFilenames[iRel] = rMLVL.ReadString();
|
||||
|
||||
if (mVersion == eEchoes)
|
||||
if (mVersion == EGame::Echoes)
|
||||
{
|
||||
u32 NumRelOffsets = rMLVL.ReadLong(); // Don't know what these offsets correspond to
|
||||
pArea->RelOffsets.resize(NumRelOffsets);
|
||||
@@ -127,7 +127,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
|
||||
}
|
||||
|
||||
// Internal name - MP1 doesn't have this, we'll get it from the GameInfo file later
|
||||
if (mVersion >= eEchoesDemo)
|
||||
if (mVersion >= EGame::EchoesDemo)
|
||||
pArea->InternalName = rMLVL.ReadString();
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
|
||||
rMLVL.Seek(0x5, SEEK_CUR); // Unknown values which are always 0
|
||||
|
||||
// Audio Groups - we don't need this info as we regenerate it on cook
|
||||
if (mVersion == ePrime)
|
||||
if (mVersion == EGame::Prime)
|
||||
{
|
||||
u32 NumAudioGrps = rMLVL.ReadLong();
|
||||
rMLVL.Seek(0x8 * NumAudioGrps, SEEK_CUR);
|
||||
@@ -168,7 +168,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
|
||||
}
|
||||
|
||||
// Layer state IDs
|
||||
if (mVersion >= eCorruption)
|
||||
if (mVersion >= EGame::Corruption)
|
||||
{
|
||||
rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant layer count
|
||||
for (u32 iArea = 0; iArea < NumAreas; iArea++)
|
||||
@@ -265,7 +265,7 @@ void CWorldLoader::GenerateEditorData()
|
||||
{
|
||||
CGameInfo *pGameInfo = mpWorld->Entry()->ResourceStore()->Project()->GameInfo();
|
||||
|
||||
if (mVersion <= ePrime)
|
||||
if (mVersion <= EGame::Prime)
|
||||
{
|
||||
for (u32 iArea = 0; iArea < mpWorld->NumAreas(); iArea++)
|
||||
{
|
||||
@@ -289,7 +289,7 @@ CWorld* CWorldLoader::LoadMLVL(IInputStream& rMLVL, CResourceEntry *pEntry)
|
||||
|
||||
u32 FileVersion = rMLVL.ReadLong();
|
||||
EGame Version = GetFormatVersion(FileVersion);
|
||||
if (Version == eUnknownGame)
|
||||
if (Version == EGame::Invalid)
|
||||
{
|
||||
Log::FileError(rMLVL.GetSourceString(), "Unsupported MLVL version: " + TString::HexString(FileVersion, 2));
|
||||
return nullptr;
|
||||
@@ -300,7 +300,7 @@ CWorld* CWorldLoader::LoadMLVL(IInputStream& rMLVL, CResourceEntry *pEntry)
|
||||
Loader.mpWorld = new CWorld(pEntry);
|
||||
Loader.mVersion = Version;
|
||||
|
||||
if (Version != eReturns)
|
||||
if (Version != EGame::DKCReturns)
|
||||
Loader.LoadPrimeMLVL(rMLVL);
|
||||
else
|
||||
Loader.LoadReturnsMLVL(rMLVL);
|
||||
@@ -313,12 +313,12 @@ EGame CWorldLoader::GetFormatVersion(u32 Version)
|
||||
{
|
||||
switch (Version)
|
||||
{
|
||||
case 0xD: return ePrimeDemo;
|
||||
case 0x11: return ePrime;
|
||||
case 0x14: return eEchoesDemo;
|
||||
case 0x17: return eEchoes;
|
||||
case 0x19: return eCorruption;
|
||||
case 0x1B: return eReturns;
|
||||
default: return eUnknownGame;
|
||||
case 0xD: return EGame::PrimeDemo;
|
||||
case 0x11: return EGame::Prime;
|
||||
case 0x14: return EGame::EchoesDemo;
|
||||
case 0x17: return EGame::Echoes;
|
||||
case 0x19: return EGame::Corruption;
|
||||
case 0x1B: return EGame::DKCReturns;
|
||||
default: return EGame::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
|
||||
CVertex() {}
|
||||
|
||||
CVertex(CVector3f& rPos)
|
||||
CVertex(const CVector3f& rPos)
|
||||
{
|
||||
Position = rPos;
|
||||
}
|
||||
|
||||
292
src/Core/Resource/Script/CGameTemplate.cpp
Normal file
292
src/Core/Resource/Script/CGameTemplate.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
#include "CGameTemplate.h"
|
||||
#include "NPropertyMap.h"
|
||||
#include "Core/Resource/Factory/CWorldLoader.h"
|
||||
#include <Common/Log.h>
|
||||
|
||||
CGameTemplate::CGameTemplate()
|
||||
: mFullyLoaded(false)
|
||||
, mDirty(false)
|
||||
{
|
||||
}
|
||||
|
||||
void CGameTemplate::Serialize(IArchive& Arc)
|
||||
{
|
||||
Arc << SerialParameter("ScriptObjects", mScriptTemplates)
|
||||
<< SerialParameter("PropertyArchetypes", mPropertyTemplates)
|
||||
<< SerialParameter("States", mStates)
|
||||
<< SerialParameter("Messages", mMessages);
|
||||
}
|
||||
|
||||
void CGameTemplate::Load(const TString& kFilePath)
|
||||
{
|
||||
CXMLReader Reader(kFilePath);
|
||||
ASSERT(Reader.IsValid());
|
||||
|
||||
mGame = Reader.Game();
|
||||
Serialize(Reader);
|
||||
|
||||
mSourceFile = kFilePath;
|
||||
mFullyLoaded = true;
|
||||
|
||||
// Load all sub-templates
|
||||
const TString gkGameRoot = GetGameDirectory();
|
||||
|
||||
for (auto Iter = mScriptTemplates.begin(); Iter != mScriptTemplates.end(); Iter++)
|
||||
{
|
||||
SScriptTemplatePath& ScriptPath = Iter->second;
|
||||
TString AbsPath = gkGameRoot + ScriptPath.Path;
|
||||
ScriptPath.pTemplate = std::make_shared<CScriptTemplate>(this, Iter->first, AbsPath);
|
||||
}
|
||||
|
||||
for (auto Iter = mPropertyTemplates.begin(); Iter != mPropertyTemplates.end(); Iter++)
|
||||
{
|
||||
// For properties, remember that property archetypes can reference other archetypes which
|
||||
// may not be loaded yet.. so if this happens, the referenced property will be loaded,
|
||||
// meaning property templates can be loaded out of order, so we need to make sure
|
||||
// that we don't load any template more than once.
|
||||
SPropertyTemplatePath& PropertyPath = Iter->second;
|
||||
|
||||
if (!PropertyPath.pTemplate)
|
||||
{
|
||||
Internal_LoadPropertyTemplate(Iter->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameTemplate::Save()
|
||||
{
|
||||
Log::Write("Saving game template: " + mSourceFile);
|
||||
CXMLWriter Writer(mSourceFile, "Game", 0, mGame);
|
||||
ASSERT(Writer.IsValid());
|
||||
Serialize(Writer);
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
/** Internal function for loading a property template from a file. */
|
||||
void CGameTemplate::Internal_LoadPropertyTemplate(SPropertyTemplatePath& Path)
|
||||
{
|
||||
if (Path.pTemplate != nullptr) // don't load twice
|
||||
return;
|
||||
|
||||
const TString kGameDir = GetGameDirectory();
|
||||
const TString kTemplateFilePath = kGameDir + Path.Path;
|
||||
CXMLReader Reader(kTemplateFilePath);
|
||||
ASSERT(Reader.IsValid());
|
||||
|
||||
Reader << SerialParameter("PropertyArchetype", Path.pTemplate);
|
||||
ASSERT(Path.pTemplate != nullptr);
|
||||
|
||||
Path.pTemplate->Initialize(nullptr, nullptr, 0);
|
||||
}
|
||||
|
||||
void CGameTemplate::SaveGameTemplates(bool ForceAll /*= false*/)
|
||||
{
|
||||
const TString kGameDir = GetGameDirectory();
|
||||
|
||||
if (mDirty || ForceAll)
|
||||
{
|
||||
Save();
|
||||
}
|
||||
|
||||
for (auto Iter = mScriptTemplates.begin(); Iter != mScriptTemplates.end(); Iter++)
|
||||
{
|
||||
SScriptTemplatePath& Path = Iter->second;
|
||||
|
||||
if( Path.pTemplate )
|
||||
{
|
||||
Path.pTemplate->Save(ForceAll);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto Iter = mPropertyTemplates.begin(); Iter != mPropertyTemplates.end(); Iter++)
|
||||
{
|
||||
SPropertyTemplatePath& Path = Iter->second;
|
||||
|
||||
if( Path.pTemplate )
|
||||
{
|
||||
if( ForceAll || Path.pTemplate->IsDirty() )
|
||||
{
|
||||
const TString kOutPath = kGameDir + Path.Path;
|
||||
FileUtil::MakeDirectory( kOutPath.GetFileDirectory() );
|
||||
|
||||
Log::Write("Saving property template: " + kOutPath);
|
||||
CXMLWriter Writer(kOutPath, "PropertyTemplate", 0, Game());
|
||||
ASSERT(Writer.IsValid());
|
||||
|
||||
Writer << SerialParameter("PropertyArchetype", Path.pTemplate);
|
||||
Path.pTemplate->ClearDirtyFlag();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 CGameTemplate::GameVersion(TString VersionName)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
CScriptTemplate* CGameTemplate::TemplateByID(u32 ObjectID)
|
||||
{
|
||||
auto it = mScriptTemplates.find(ObjectID);
|
||||
|
||||
if (it != mScriptTemplates.end())
|
||||
return it->second.pTemplate.get();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CScriptTemplate* CGameTemplate::TemplateByID(const CFourCC& ObjectID)
|
||||
{
|
||||
return TemplateByID(ObjectID.ToLong());
|
||||
}
|
||||
|
||||
CScriptTemplate* CGameTemplate::TemplateByIndex(u32 Index)
|
||||
{
|
||||
auto it = mScriptTemplates.begin();
|
||||
return (std::next(it, Index))->second.pTemplate.get();
|
||||
}
|
||||
|
||||
SState CGameTemplate::StateByID(u32 StateID)
|
||||
{
|
||||
auto Iter = mStates.find(StateID);
|
||||
|
||||
if (Iter != mStates.end())
|
||||
return SState(Iter->first, Iter->second);
|
||||
else
|
||||
return SState(-1, "Invalid");
|
||||
}
|
||||
|
||||
SState CGameTemplate::StateByID(const CFourCC& State)
|
||||
{
|
||||
return StateByID(State.ToLong());
|
||||
}
|
||||
|
||||
SState CGameTemplate::StateByIndex(u32 Index)
|
||||
{
|
||||
auto Iter = mStates.begin();
|
||||
Iter = std::next(Iter, Index);
|
||||
return SState(Iter->first, Iter->second);
|
||||
}
|
||||
|
||||
SMessage CGameTemplate::MessageByID(u32 MessageID)
|
||||
{
|
||||
auto Iter = mMessages.find(MessageID);
|
||||
|
||||
if (Iter != mMessages.end())
|
||||
return SMessage(Iter->first, Iter->second);
|
||||
else
|
||||
return SMessage(-1, "Invalid");
|
||||
}
|
||||
|
||||
SMessage CGameTemplate::MessageByID(const CFourCC& MessageID)
|
||||
{
|
||||
return MessageByID(MessageID.ToLong());
|
||||
}
|
||||
|
||||
SMessage CGameTemplate::MessageByIndex(u32 Index)
|
||||
{
|
||||
auto Iter = mMessages.begin();
|
||||
Iter = std::next(Iter, Index);
|
||||
return SMessage(Iter->first, Iter->second);
|
||||
}
|
||||
|
||||
IProperty* CGameTemplate::FindPropertyArchetype(const TString& kTypeName)
|
||||
{
|
||||
auto Iter = mPropertyTemplates.find(kTypeName);
|
||||
|
||||
if (Iter == mPropertyTemplates.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If the template isn't loaded yet, then load it.
|
||||
// This has to be done here to allow recursion while loading other property archetypes, because some properties may
|
||||
// request archetypes of other properties that haven't been loaded yet during their load.
|
||||
SPropertyTemplatePath& Path = Iter->second;
|
||||
if (!Path.pTemplate)
|
||||
{
|
||||
Internal_LoadPropertyTemplate(Path);
|
||||
ASSERT(Path.pTemplate != nullptr); // Load failed; missing or malformed template
|
||||
}
|
||||
|
||||
return Path.pTemplate.get();
|
||||
}
|
||||
|
||||
TString CGameTemplate::GetPropertyArchetypeFilePath(const TString& kTypeName)
|
||||
{
|
||||
auto Iter = mPropertyTemplates.find(kTypeName);
|
||||
ASSERT(Iter != mPropertyTemplates.end());
|
||||
return GetGameDirectory() + Iter->second.Path;
|
||||
}
|
||||
|
||||
bool CGameTemplate::RenamePropertyArchetype(const TString& kTypeName, const TString& kNewTypeName)
|
||||
{
|
||||
if( kTypeName != kNewTypeName )
|
||||
{
|
||||
// Fetch the property that we are going to be renaming.
|
||||
// Validate type, too, because we only support renaming struct archetypes at the moment
|
||||
auto Iter = mPropertyTemplates.find(kTypeName);
|
||||
|
||||
if( Iter != mPropertyTemplates.end() )
|
||||
{
|
||||
SPropertyTemplatePath& Path = Iter->second;
|
||||
IProperty* pArchetype = Path.pTemplate.get();
|
||||
|
||||
if( pArchetype )
|
||||
{
|
||||
// Attempt to move the XML to the new location.
|
||||
TString OldPath = GetGameDirectory() + Path.Path;
|
||||
TString NewPath = OldPath.GetFileDirectory() + kNewTypeName + ".xml";
|
||||
|
||||
if( FileUtil::MoveFile(OldPath, NewPath) )
|
||||
{
|
||||
// Update the name in the game template's internal mapping
|
||||
TString RelativePath = FileUtil::MakeRelative( NewPath, GetGameDirectory() );
|
||||
auto MapNode = mPropertyTemplates.extract(Iter);
|
||||
MapNode.key() = kNewTypeName;
|
||||
MapNode.mapped().Path = RelativePath;
|
||||
mPropertyTemplates.insert( std::move(MapNode) );
|
||||
mDirty = true;
|
||||
|
||||
// Renaming the archetype will handle updating the actual type name, and
|
||||
// dirtying/invalidating property sub-instances.
|
||||
TString OldTypeName = pArchetype->HashableTypeName();
|
||||
pArchetype->SetName(kNewTypeName);
|
||||
|
||||
// For MP2 and up, we also need to update the type names stored in the property map.
|
||||
if (pArchetype->Game() >= EGame::EchoesDemo)
|
||||
{
|
||||
NPropertyMap::ChangeTypeName(pArchetype, *OldTypeName, *kNewTypeName);
|
||||
}
|
||||
|
||||
// MP1 has a lot of unnamed properties that just use the type name as their name.
|
||||
// Update these properties so their name now refers to the updated type name.
|
||||
else
|
||||
{
|
||||
std::list<IProperty*> SubInstances;
|
||||
pArchetype->GatherAllSubInstances(SubInstances, true);
|
||||
|
||||
for (auto Iter = SubInstances.begin(); Iter != SubInstances.end(); Iter++)
|
||||
{
|
||||
IProperty* pProperty = *Iter;
|
||||
|
||||
if (pProperty->Name() == kTypeName)
|
||||
{
|
||||
pProperty->SetName(kNewTypeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TString CGameTemplate::GetGameDirectory() const
|
||||
{
|
||||
return mSourceFile.GetFileDirectory();
|
||||
}
|
||||
143
src/Core/Resource/Script/CGameTemplate.h
Normal file
143
src/Core/Resource/Script/CGameTemplate.h
Normal file
@@ -0,0 +1,143 @@
|
||||
#ifndef CGAMETEMPLATE_H
|
||||
#define CGAMETEMPLATE_H
|
||||
|
||||
#include "CLink.h"
|
||||
#include "CScriptTemplate.h"
|
||||
#include "Core/Resource/Script/Property/Properties.h"
|
||||
#include <Common/EGame.h>
|
||||
#include <Common/types.h>
|
||||
#include <map>
|
||||
|
||||
/** Serialization aid
|
||||
* Retro switched from using integers to fourCCs to represent IDs in several cases (states/messages, object IDs).
|
||||
* This struct is functionally an integer but it serializes as an int for MP1 and a fourCC for MP2 and on.
|
||||
*/
|
||||
struct SObjId
|
||||
{
|
||||
union {
|
||||
u32 ID;
|
||||
CFourCC ID_4CC;
|
||||
};
|
||||
|
||||
inline SObjId() {}
|
||||
inline SObjId(u32 InID) : ID(InID) {}
|
||||
inline SObjId(CFourCC InID) : ID_4CC(InID) {}
|
||||
|
||||
inline operator u32() const { return ID; }
|
||||
inline operator CFourCC() const { return ID_4CC; }
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
if (Arc.Game() <= EGame::Prime)
|
||||
Arc.SerializePrimitive(ID, SH_HexDisplay);
|
||||
else
|
||||
Arc.SerializePrimitive(ID_4CC, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/** Struct holding a reference to a script object template */
|
||||
struct SScriptTemplatePath
|
||||
{
|
||||
/** File path to the template file, relative to the game directory */
|
||||
TString Path;
|
||||
|
||||
/** Template in memory */
|
||||
std::shared_ptr<CScriptTemplate> pTemplate;
|
||||
|
||||
/** Constructor */
|
||||
SScriptTemplatePath()
|
||||
{}
|
||||
|
||||
SScriptTemplatePath(const TString& kInPath, CScriptTemplate* pInTemplate)
|
||||
: Path(kInPath)
|
||||
, pTemplate( std::shared_ptr<CScriptTemplate>(pInTemplate) )
|
||||
{}
|
||||
|
||||
/** Serializer */
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
if (Arc.FileVersion() == 0)
|
||||
{
|
||||
Arc << SerialParameter("Path", Path, SH_Attribute);
|
||||
}
|
||||
else
|
||||
{
|
||||
Arc.SerializePrimitive(Path, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Struct holding a reference to a property template */
|
||||
struct SPropertyTemplatePath
|
||||
{
|
||||
/** File path to the template file, relative to the game directory */
|
||||
TString Path;
|
||||
|
||||
/** Template in memory */
|
||||
std::shared_ptr<IProperty> pTemplate;
|
||||
|
||||
/** Constructor */
|
||||
SPropertyTemplatePath()
|
||||
{}
|
||||
|
||||
SPropertyTemplatePath(const TString& kInPath, IProperty* pInTemplate)
|
||||
: Path(kInPath)
|
||||
, pTemplate( std::shared_ptr<IProperty>(pInTemplate) )
|
||||
{}
|
||||
|
||||
/** Serializer */
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
Arc << SerialParameter("Path", Path, SH_Attribute);
|
||||
}
|
||||
};
|
||||
|
||||
/** CGameTemplate - Per-game template data */
|
||||
class CGameTemplate
|
||||
{
|
||||
EGame mGame;
|
||||
TString mSourceFile;
|
||||
bool mFullyLoaded;
|
||||
bool mDirty;
|
||||
|
||||
/** Template arrays */
|
||||
std::map<SObjId, SScriptTemplatePath> mScriptTemplates;
|
||||
std::map<TString, SPropertyTemplatePath> mPropertyTemplates;
|
||||
|
||||
std::map<SObjId, TString> mStates;
|
||||
std::map<SObjId, TString> mMessages;
|
||||
|
||||
/** Internal function for loading a property template from a file. */
|
||||
void Internal_LoadPropertyTemplate(SPropertyTemplatePath& Path);
|
||||
|
||||
public:
|
||||
CGameTemplate();
|
||||
void Serialize(IArchive& Arc);
|
||||
void Load(const TString& kFilePath);
|
||||
void Save();
|
||||
void SaveGameTemplates(bool ForceAll = false);
|
||||
|
||||
u32 GameVersion(TString VersionName);
|
||||
CScriptTemplate* TemplateByID(u32 ObjectID);
|
||||
CScriptTemplate* TemplateByID(const CFourCC& ObjectID);
|
||||
CScriptTemplate* TemplateByIndex(u32 Index);
|
||||
SState StateByID(u32 StateID);
|
||||
SState StateByID(const CFourCC& StateID);
|
||||
SState StateByIndex(u32 Index);
|
||||
SMessage MessageByID(u32 MessageID);
|
||||
SMessage MessageByID(const CFourCC& MessageID);
|
||||
SMessage MessageByIndex(u32 Index);
|
||||
IProperty* FindPropertyArchetype(const TString& kTypeName);
|
||||
TString GetPropertyArchetypeFilePath(const TString& kTypeName);
|
||||
bool RenamePropertyArchetype(const TString& kTypeName, const TString& kNewTypeName);
|
||||
TString GetGameDirectory() const;
|
||||
|
||||
// Inline Accessors
|
||||
inline EGame Game() const { return mGame; }
|
||||
inline u32 NumScriptTemplates() const { return mScriptTemplates.size(); }
|
||||
inline u32 NumStates() const { return mStates.size(); }
|
||||
inline u32 NumMessages() const { return mMessages.size(); }
|
||||
inline bool IsLoadedSuccessfully() { return mFullyLoaded; }
|
||||
};
|
||||
|
||||
#endif // CGAMETEMPLATE_H
|
||||
@@ -8,20 +8,56 @@
|
||||
|
||||
struct SState
|
||||
{
|
||||
u32 ID;
|
||||
union {
|
||||
u32 ID;
|
||||
CFourCC ID_4CC;
|
||||
};
|
||||
TString Name;
|
||||
|
||||
SState() {}
|
||||
SState(u32 _ID, const TString& rkName) : ID(_ID), Name(rkName) {}
|
||||
SState()
|
||||
{}
|
||||
|
||||
SState(u32 InID, const TString& kInName)
|
||||
: ID(InID)
|
||||
, Name(kInName)
|
||||
{}
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
if (Arc.Game() <= EGame::Prime)
|
||||
Arc << SerialParameter("ID", ID, SH_Attribute | SH_HexDisplay);
|
||||
else
|
||||
Arc << SerialParameter("ID", ID_4CC, SH_Attribute);
|
||||
|
||||
Arc << SerialParameter("Name", Name, SH_Attribute);
|
||||
}
|
||||
};
|
||||
|
||||
struct SMessage
|
||||
{
|
||||
u32 ID;
|
||||
union {
|
||||
u32 ID;
|
||||
CFourCC ID_4CC;
|
||||
};
|
||||
TString Name;
|
||||
|
||||
SMessage() {}
|
||||
SMessage(u32 _ID, const TString& rkName) : ID(_ID), Name(rkName) {}
|
||||
SMessage()
|
||||
{}
|
||||
|
||||
SMessage(u32 InID, const TString& kInName)
|
||||
: ID(InID)
|
||||
, Name(kInName)
|
||||
{}
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
if (Arc.Game() <= EGame::Prime)
|
||||
Arc << SerialParameter("ID", ID, SH_Attribute | SH_HexDisplay);
|
||||
else
|
||||
Arc << SerialParameter("ID", ID_4CC, SH_Attribute);
|
||||
|
||||
Arc << SerialParameter("Name", Name, SH_Attribute);
|
||||
}
|
||||
};
|
||||
|
||||
class CLink
|
||||
|
||||
@@ -1,283 +0,0 @@
|
||||
#include "CMasterTemplate.h"
|
||||
#include "Core/Resource/Factory/CWorldLoader.h"
|
||||
#include <Common/Log.h>
|
||||
|
||||
CMasterTemplate::CMasterTemplate()
|
||||
: mVersion(0)
|
||||
, mFullyLoaded(false)
|
||||
{
|
||||
}
|
||||
|
||||
CMasterTemplate::~CMasterTemplate()
|
||||
{
|
||||
for (auto it = mTemplates.begin(); it != mTemplates.end(); it++)
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
u32 CMasterTemplate::GameVersion(TString VersionName)
|
||||
{
|
||||
VersionName = VersionName.ToLower();
|
||||
|
||||
for (u32 iVer = 0; iVer < mGameVersions.size(); iVer++)
|
||||
if (mGameVersions[iVer].ToLower() == VersionName)
|
||||
return iVer;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
CScriptTemplate* CMasterTemplate::TemplateByID(u32 ObjectID)
|
||||
{
|
||||
auto it = mTemplates.find(ObjectID);
|
||||
|
||||
if (it != mTemplates.end())
|
||||
return it->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CScriptTemplate* CMasterTemplate::TemplateByID(const CFourCC& ObjectID)
|
||||
{
|
||||
return TemplateByID(ObjectID.ToLong());
|
||||
}
|
||||
|
||||
CScriptTemplate* CMasterTemplate::TemplateByIndex(u32 Index)
|
||||
{
|
||||
auto it = mTemplates.begin();
|
||||
return (std::next(it, Index))->second;
|
||||
}
|
||||
|
||||
SState CMasterTemplate::StateByID(u32 StateID)
|
||||
{
|
||||
auto it = mStates.find(StateID);
|
||||
|
||||
if (it != mStates.end())
|
||||
return it->second;
|
||||
else
|
||||
return SState(-1, "Invalid");
|
||||
}
|
||||
|
||||
SState CMasterTemplate::StateByID(const CFourCC& State)
|
||||
{
|
||||
return StateByID(State.ToLong());
|
||||
}
|
||||
|
||||
SState CMasterTemplate::StateByIndex(u32 Index)
|
||||
{
|
||||
auto it = mStates.begin();
|
||||
return (std::next(it, Index))->second;
|
||||
}
|
||||
|
||||
SMessage CMasterTemplate::MessageByID(u32 MessageID)
|
||||
{
|
||||
auto it = mMessages.find(MessageID);
|
||||
|
||||
if (it != mMessages.end())
|
||||
return it->second;
|
||||
else
|
||||
return SMessage(-1, "Invalid");
|
||||
}
|
||||
|
||||
SMessage CMasterTemplate::MessageByID(const CFourCC& MessageID)
|
||||
{
|
||||
return MessageByID(MessageID.ToLong());
|
||||
}
|
||||
|
||||
SMessage CMasterTemplate::MessageByIndex(u32 Index)
|
||||
{
|
||||
auto it = mMessages.begin();
|
||||
return (std::next(it, Index))->second;
|
||||
}
|
||||
|
||||
CStructTemplate* CMasterTemplate::StructAtSource(const TString& rkSource)
|
||||
{
|
||||
auto InfoIt = mStructTemplates.find(rkSource);
|
||||
|
||||
if (InfoIt != mStructTemplates.end())
|
||||
return InfoIt->second;
|
||||
|
||||
else return nullptr;
|
||||
}
|
||||
|
||||
// ************ STATIC ************
|
||||
CMasterTemplate* CMasterTemplate::MasterForGame(EGame Game)
|
||||
{
|
||||
auto it = smMasterMap.find(Game);
|
||||
|
||||
if (it != smMasterMap.end())
|
||||
return it->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::list<CMasterTemplate*> CMasterTemplate::MasterList()
|
||||
{
|
||||
std::list<CMasterTemplate*> list;
|
||||
|
||||
for (auto it = smMasterMap.begin(); it != smMasterMap.end(); it++)
|
||||
list.push_back(it->second);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
TString CMasterTemplate::FindGameName(EGame Game)
|
||||
{
|
||||
CMasterTemplate *pMaster = MasterForGame(Game);
|
||||
return pMaster ? pMaster->GameName() : "Unknown Game";
|
||||
}
|
||||
|
||||
EGame CMasterTemplate::FindGameForName(const TString& rkName)
|
||||
{
|
||||
std::list<CMasterTemplate*> Masters = MasterList();
|
||||
|
||||
for (auto It = Masters.begin(); It != Masters.end(); It++)
|
||||
{
|
||||
CMasterTemplate *pMaster = *It;
|
||||
if (pMaster->GameName() == rkName)
|
||||
return pMaster->Game();
|
||||
}
|
||||
|
||||
return eUnknownGame;
|
||||
}
|
||||
|
||||
TString CMasterTemplate::PropertyName(u32 PropertyID)
|
||||
{
|
||||
auto it = smPropertyNames.find(PropertyID);
|
||||
|
||||
if (it != smPropertyNames.end())
|
||||
return it->second;
|
||||
else
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
u32 CMasterTemplate::CreatePropertyID(IPropertyTemplate *pTemp)
|
||||
{
|
||||
// MP1 properties don't have IDs so we can use this function to create one to track instances of a particular property.
|
||||
// To ensure the IDs are unique we'll create a hash using two things: the struct source file and the ID string (relative to the struct).
|
||||
TString IDString = pTemp->IDString(false);
|
||||
TString Source;
|
||||
CStructTemplate *pStruct = pTemp->Parent();
|
||||
|
||||
while (pStruct)
|
||||
{
|
||||
Source = pStruct->SourceFile();
|
||||
if (!Source.IsEmpty()) break;
|
||||
IDString.Prepend(pStruct->IDString(false) + ":");
|
||||
pStruct = pStruct->Parent();
|
||||
}
|
||||
|
||||
return IDString.Hash32() * Source.Hash32();
|
||||
}
|
||||
|
||||
void CMasterTemplate::AddProperty(IPropertyTemplate *pTemp, const TString& rkTemplateName /*= ""*/)
|
||||
{
|
||||
u32 ID;
|
||||
|
||||
if (pTemp->Game() >= eEchoesDemo)
|
||||
ID = pTemp->PropertyID();
|
||||
|
||||
// Use a different ID for MP1
|
||||
else
|
||||
{
|
||||
// For MP1 we only really need to track properties that come from struct templates.
|
||||
if (!pTemp->IsFromStructTemplate()) return;
|
||||
else ID = CreatePropertyID(pTemp);
|
||||
}
|
||||
|
||||
auto it = smIDMap.find(ID);
|
||||
|
||||
// Add this property/template to existing ID info
|
||||
if (it != smIDMap.end())
|
||||
{
|
||||
SPropIDInfo& rInfo = it->second;
|
||||
rInfo.PropertyList.push_back(pTemp);
|
||||
|
||||
if (!rkTemplateName.IsEmpty())
|
||||
{
|
||||
bool NewTemplate = true;
|
||||
|
||||
for (u32 iTemp = 0; iTemp < rInfo.XMLList.size(); iTemp++)
|
||||
{
|
||||
if (rInfo.XMLList[iTemp] == rkTemplateName)
|
||||
{
|
||||
NewTemplate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NewTemplate)
|
||||
rInfo.XMLList.push_back(rkTemplateName);
|
||||
}
|
||||
}
|
||||
|
||||
// Create new ID info
|
||||
else
|
||||
{
|
||||
SPropIDInfo Info;
|
||||
if (!rkTemplateName.IsEmpty()) Info.XMLList.push_back(rkTemplateName);
|
||||
Info.PropertyList.push_back(pTemp);
|
||||
smIDMap[ID] = Info;
|
||||
}
|
||||
}
|
||||
|
||||
void CMasterTemplate::RenameProperty(IPropertyTemplate *pTemp, const TString& rkNewName)
|
||||
{
|
||||
u32 ID = pTemp->PropertyID();
|
||||
if (ID <= 0xFF) ID = CreatePropertyID(pTemp);
|
||||
|
||||
// Master name list
|
||||
auto NameIt = smPropertyNames.find(ID);
|
||||
TString Original;
|
||||
|
||||
if (NameIt != smPropertyNames.end())
|
||||
{
|
||||
Original = NameIt->second;
|
||||
smPropertyNames[ID] = rkNewName;
|
||||
}
|
||||
|
||||
// Properties
|
||||
auto InfoIt = smIDMap.find(ID);
|
||||
|
||||
if (InfoIt != smIDMap.end())
|
||||
{
|
||||
const SPropIDInfo& rkInfo = InfoIt->second;
|
||||
|
||||
for (u32 iTemp = 0; iTemp < rkInfo.PropertyList.size(); iTemp++)
|
||||
{
|
||||
if (Original.IsEmpty() || rkInfo.PropertyList[iTemp]->Name() == Original)
|
||||
rkInfo.PropertyList[iTemp]->SetName(rkNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TString> CMasterTemplate::XMLsUsingID(u32 ID)
|
||||
{
|
||||
auto InfoIt = smIDMap.find(ID);
|
||||
|
||||
if (InfoIt != smIDMap.end())
|
||||
{
|
||||
const SPropIDInfo& rkInfo = InfoIt->second;
|
||||
return rkInfo.XMLList;
|
||||
}
|
||||
else
|
||||
return std::vector<TString>();
|
||||
}
|
||||
|
||||
const std::vector<IPropertyTemplate*>* CMasterTemplate::TemplatesWithMatchingID(IPropertyTemplate *pTemp)
|
||||
{
|
||||
u32 ID = pTemp->PropertyID();
|
||||
if (ID <= 0xFF) ID = CreatePropertyID(pTemp);
|
||||
|
||||
auto InfoIt = smIDMap.find(ID);
|
||||
|
||||
if (InfoIt != smIDMap.end())
|
||||
{
|
||||
const SPropIDInfo& rkInfo = InfoIt->second;
|
||||
return &rkInfo.PropertyList;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::map<u32, CMasterTemplate::SPropIDInfo> CMasterTemplate::smIDMap;
|
||||
std::map<EGame, CMasterTemplate*> CMasterTemplate::smMasterMap;
|
||||
std::map<u32, TString> CMasterTemplate::smPropertyNames;
|
||||
u32 CMasterTemplate::smGameListVersion;
|
||||
@@ -1,76 +0,0 @@
|
||||
#ifndef CMASTERTEMPLATE_H
|
||||
#define CMASTERTEMPLATE_H
|
||||
|
||||
#include "CLink.h"
|
||||
#include "CScriptTemplate.h"
|
||||
#include <Common/EGame.h>
|
||||
#include <Common/types.h>
|
||||
#include <map>
|
||||
|
||||
class CMasterTemplate
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
EGame mGame;
|
||||
TString mGameName;
|
||||
TString mSourceFile;
|
||||
u32 mVersion;
|
||||
bool mFullyLoaded;
|
||||
|
||||
std::vector<TString> mGameVersions;
|
||||
std::map<TString, CStructTemplate*> mStructTemplates;
|
||||
|
||||
std::map<u32, CScriptTemplate*> mTemplates;
|
||||
std::map<u32, SState> mStates;
|
||||
std::map<u32, SMessage> mMessages;
|
||||
|
||||
struct SPropIDInfo
|
||||
{
|
||||
std::vector<TString> XMLList; // List of script/struct templates that use this ID
|
||||
std::vector<IPropertyTemplate*> PropertyList; // List of all properties that use this ID
|
||||
};
|
||||
static std::map<u32, SPropIDInfo> smIDMap;
|
||||
static std::map<EGame, CMasterTemplate*> smMasterMap;
|
||||
static std::map<u32, TString> smPropertyNames;
|
||||
static u32 smGameListVersion;
|
||||
|
||||
public:
|
||||
CMasterTemplate();
|
||||
~CMasterTemplate();
|
||||
u32 GameVersion(TString VersionName);
|
||||
CScriptTemplate* TemplateByID(u32 ObjectID);
|
||||
CScriptTemplate* TemplateByID(const CFourCC& ObjectID);
|
||||
CScriptTemplate* TemplateByIndex(u32 Index);
|
||||
SState StateByID(u32 StateID);
|
||||
SState StateByID(const CFourCC& StateID);
|
||||
SState StateByIndex(u32 Index);
|
||||
SMessage MessageByID(u32 MessageID);
|
||||
SMessage MessageByID(const CFourCC& MessageID);
|
||||
SMessage MessageByIndex(u32 Index);
|
||||
CStructTemplate* StructAtSource(const TString& rkSource);
|
||||
|
||||
// Inline Accessors
|
||||
inline EGame Game() const { return mGame; }
|
||||
inline TString GameName() const { return mGameName; }
|
||||
inline u32 NumGameVersions() const { return mGameVersions.empty() ? 1 : mGameVersions.size(); }
|
||||
inline u32 NumScriptTemplates() const { return mTemplates.size(); }
|
||||
inline u32 NumStates() const { return mStates.size(); }
|
||||
inline u32 NumMessages() const { return mMessages.size(); }
|
||||
inline bool IsLoadedSuccessfully() { return mFullyLoaded; }
|
||||
inline TString GetDirectory() const { return mSourceFile.GetFileDirectory(); }
|
||||
|
||||
// Static
|
||||
static CMasterTemplate* MasterForGame(EGame Game);
|
||||
static std::list<CMasterTemplate*> MasterList();
|
||||
static TString FindGameName(EGame Game);
|
||||
static EGame FindGameForName(const TString& rkName);
|
||||
static TString PropertyName(u32 PropertyID);
|
||||
static u32 CreatePropertyID(IPropertyTemplate *pTemp);
|
||||
static void AddProperty(IPropertyTemplate *pTemp, const TString& rkTemplateName = "");
|
||||
static void RenameProperty(IPropertyTemplate *pTemp, const TString& rkNewName);
|
||||
static std::vector<TString> XMLsUsingID(u32 ID);
|
||||
static const std::vector<IPropertyTemplate*>* TemplatesWithMatchingID(IPropertyTemplate *pTemp);
|
||||
};
|
||||
|
||||
#endif // CMASTERTEMPLATE_H
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "CScriptObject.h"
|
||||
#include "CScriptLayer.h"
|
||||
#include "CMasterTemplate.h"
|
||||
#include "CGameTemplate.h"
|
||||
#include "Core/Resource/Animation/CAnimSet.h"
|
||||
|
||||
CScriptObject::CScriptObject(u32 InstanceID, CGameArea *pArea, CScriptLayer *pLayer, CScriptTemplate *pTemplate)
|
||||
@@ -13,19 +13,31 @@ CScriptObject::CScriptObject(u32 InstanceID, CGameArea *pArea, CScriptLayer *pLa
|
||||
, mIsCheckingNearVisibleActivation(false)
|
||||
{
|
||||
mpTemplate->AddObject(this);
|
||||
mpProperties = (CPropertyStruct*) pTemplate->BaseStruct()->InstantiateProperty(this, nullptr);
|
||||
|
||||
mpInstanceName = mpTemplate->FindInstanceName(mpProperties);
|
||||
mpPosition = mpTemplate->FindPosition(mpProperties);
|
||||
mpRotation = mpTemplate->FindRotation(mpProperties);
|
||||
mpScale = mpTemplate->FindScale(mpProperties);
|
||||
mpActive = mpTemplate->FindActive(mpProperties);
|
||||
mpLightParameters = mpTemplate->FindLightParameters(mpProperties);
|
||||
// Init properties
|
||||
CStructProperty* pProperties = pTemplate->Properties();
|
||||
u32 PropertiesSize = pProperties->DataSize();
|
||||
|
||||
mPropertyData.resize( PropertiesSize );
|
||||
void* pData = mPropertyData.data();
|
||||
pProperties->Construct( pData );
|
||||
|
||||
mInstanceName = CStringRef(pData, pTemplate->NameProperty());
|
||||
mPosition = CVectorRef(pData, pTemplate->PositionProperty());
|
||||
mRotation = CVectorRef(pData, pTemplate->RotationProperty());
|
||||
mScale = CVectorRef(pData, pTemplate->ScaleProperty());
|
||||
mActive = CBoolRef(pData, pTemplate->ActiveProperty());
|
||||
mLightParameters = CStructRef(pData, pTemplate->LightParametersProperty());
|
||||
}
|
||||
|
||||
CScriptObject::~CScriptObject()
|
||||
{
|
||||
if (mpProperties) delete mpProperties;
|
||||
if (!mPropertyData.empty())
|
||||
{
|
||||
mpTemplate->Properties()->Destruct( mPropertyData.data() );
|
||||
mPropertyData.clear();
|
||||
}
|
||||
|
||||
mpTemplate->RemoveObject(this);
|
||||
|
||||
// Note: Incoming links will be deleted by the sender.
|
||||
@@ -34,6 +46,19 @@ CScriptObject::~CScriptObject()
|
||||
}
|
||||
|
||||
// ************ DATA MANIPULATION ************
|
||||
void CScriptObject::CopyProperties(CScriptObject* pObject)
|
||||
{
|
||||
ASSERT(pObject->Template() == Template());
|
||||
CSerialVersion Version(0, IArchive::skCurrentArchiveVersion, Template()->Game());
|
||||
|
||||
CVectorOutStream DataStream;
|
||||
CBasicBinaryWriter DataWriter(&DataStream, Version);
|
||||
Template()->Properties()->SerializeValue( pObject->PropertyData(), DataWriter );
|
||||
|
||||
CBasicBinaryReader DataReader(DataStream.Data(), DataStream.Size(), Version);
|
||||
Template()->Properties()->SerializeValue( PropertyData(), DataReader );
|
||||
}
|
||||
|
||||
void CScriptObject::EvaluateProperties()
|
||||
{
|
||||
EvaluateDisplayAsset();
|
||||
@@ -43,12 +68,12 @@ CScriptObject::~CScriptObject()
|
||||
|
||||
void CScriptObject::EvaluateDisplayAsset()
|
||||
{
|
||||
mpDisplayAsset = mpTemplate->FindDisplayAsset(mpProperties, mActiveCharIndex, mActiveAnimIndex, mHasInGameModel);
|
||||
mpDisplayAsset = mpTemplate->FindDisplayAsset(PropertyData(), mActiveCharIndex, mActiveAnimIndex, mHasInGameModel);
|
||||
}
|
||||
|
||||
void CScriptObject::EvaluateCollisionModel()
|
||||
{
|
||||
mpCollision = mpTemplate->FindCollision(mpProperties);
|
||||
mpCollision = mpTemplate->FindCollision(PropertyData());
|
||||
}
|
||||
|
||||
void CScriptObject::EvaluateVolume()
|
||||
@@ -59,13 +84,16 @@ void CScriptObject::EvaluateVolume()
|
||||
|
||||
bool CScriptObject::IsEditorProperty(IProperty *pProp)
|
||||
{
|
||||
return ( (pProp == mpInstanceName) ||
|
||||
(pProp == mpPosition) ||
|
||||
(pProp == mpRotation) ||
|
||||
(pProp == mpScale) ||
|
||||
(pProp == mpActive) ||
|
||||
(pProp == mpLightParameters) ||
|
||||
(pProp->Parent() == mpLightParameters)
|
||||
return ( (pProp == mInstanceName.Property()) ||
|
||||
(pProp == mPosition.Property()) ||
|
||||
(pProp == mRotation.Property()) ||
|
||||
(pProp == mScale.Property()) ||
|
||||
(pProp == mActive.Property()) ||
|
||||
(pProp == mLightParameters.Property()) ||
|
||||
(pProp->Parent() == mPosition.Property()) ||
|
||||
(pProp->Parent() == mRotation.Property()) ||
|
||||
(pProp->Parent() == mScale.Property()) ||
|
||||
(pProp->Parent() == mLightParameters.Property())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#ifndef CSCRIPTOBJECT_H
|
||||
#define CSCRIPTOBJECT_H
|
||||
|
||||
#include "IProperty.h"
|
||||
#include "IPropertyTemplate.h"
|
||||
#include "CScriptTemplate.h"
|
||||
#include "Core/Resource/Area/CGameArea.h"
|
||||
#include "Core/Resource/Model/CModel.h"
|
||||
#include "Core/Resource/CCollisionMeshGroup.h"
|
||||
#include "Core/Resource/Script/Property/Properties.h"
|
||||
|
||||
class CScriptLayer;
|
||||
class CLink;
|
||||
@@ -30,14 +29,15 @@ class CScriptObject
|
||||
u32 mInstanceID;
|
||||
std::vector<CLink*> mOutLinks;
|
||||
std::vector<CLink*> mInLinks;
|
||||
CPropertyStruct *mpProperties;
|
||||
std::vector<char> mPropertyData;
|
||||
|
||||
CStringRef mInstanceName;
|
||||
CVectorRef mPosition;
|
||||
CVectorRef mRotation;
|
||||
CVectorRef mScale;
|
||||
CBoolRef mActive;
|
||||
CStructRef mLightParameters;
|
||||
|
||||
TStringProperty *mpInstanceName;
|
||||
TVector3Property *mpPosition;
|
||||
TVector3Property *mpRotation;
|
||||
TVector3Property *mpScale;
|
||||
TBoolProperty *mpActive;
|
||||
CPropertyStruct *mpLightParameters;
|
||||
TResPtr<CResource> mpDisplayAsset;
|
||||
TResPtr<CCollisionMeshGroup> mpCollision;
|
||||
u32 mActiveCharIndex;
|
||||
@@ -54,6 +54,7 @@ public:
|
||||
CScriptObject(u32 InstanceID, CGameArea *pArea, CScriptLayer *pLayer, CScriptTemplate *pTemplate);
|
||||
~CScriptObject();
|
||||
|
||||
void CopyProperties(CScriptObject* pObject);
|
||||
void EvaluateProperties();
|
||||
void EvaluateDisplayAsset();
|
||||
void EvaluateCollisionModel();
|
||||
@@ -69,43 +70,41 @@ public:
|
||||
|
||||
// Accessors
|
||||
CScriptTemplate* Template() const { return mpTemplate; }
|
||||
CMasterTemplate* MasterTemplate() const { return mpTemplate->MasterTemplate(); }
|
||||
CGameTemplate* GameTemplate() const { return mpTemplate->GameTemplate(); }
|
||||
CGameArea* Area() const { return mpArea; }
|
||||
CScriptLayer* Layer() const { return mpLayer; }
|
||||
u32 Version() const { return mVersion; }
|
||||
CPropertyStruct* Properties() const { return mpProperties; }
|
||||
u32 NumProperties() const { return mpProperties->Count(); }
|
||||
IProperty* PropertyByIndex(u32 Index) const { return mpProperties->PropertyByIndex(Index); }
|
||||
IProperty* PropertyByIDString(const TIDString& rkStr) const { return mpProperties->PropertyByIDString(rkStr); }
|
||||
u32 ObjectTypeID() const { return mpTemplate->ObjectID(); }
|
||||
u32 InstanceID() const { return mInstanceID; }
|
||||
u32 NumLinks(ELinkType Type) const { return (Type == eIncoming ? mInLinks.size() : mOutLinks.size()); }
|
||||
CLink* Link(ELinkType Type, u32 Index) const { return (Type == eIncoming ? mInLinks[Index] : mOutLinks[Index]); }
|
||||
void* PropertyData() const { return (void*) mPropertyData.data(); }
|
||||
|
||||
CVector3f Position() const { return mpPosition ? mpPosition->Get() : CVector3f::skZero; }
|
||||
CVector3f Rotation() const { return mpRotation ? mpRotation->Get() : CVector3f::skZero; }
|
||||
CVector3f Scale() const { return mpScale ? mpScale->Get() : CVector3f::skOne; }
|
||||
TString InstanceName() const { return mpInstanceName ? mpInstanceName->Get() : ""; }
|
||||
bool IsActive() const { return mpActive ? mpActive->Get() : false; }
|
||||
CVector3f Position() const { return mPosition.IsValid() ? mPosition.Get() : CVector3f::skZero; }
|
||||
CVector3f Rotation() const { return mRotation.IsValid() ? mRotation.Get() : CVector3f::skZero; }
|
||||
CVector3f Scale() const { return mScale.IsValid() ? mScale.Get() : CVector3f::skOne; }
|
||||
TString InstanceName() const { return mInstanceName.IsValid() ? mInstanceName.Get() : ""; }
|
||||
bool IsActive() const { return mActive.IsValid() ? mActive.Get() : false; }
|
||||
bool HasInGameModel() const { return mHasInGameModel; }
|
||||
CPropertyStruct* LightParameters() const { return mpLightParameters; }
|
||||
CStructRef LightParameters() const { return mLightParameters; }
|
||||
CResource* DisplayAsset() const { return mpDisplayAsset; }
|
||||
u32 ActiveCharIndex() const { return mActiveCharIndex; }
|
||||
u32 ActiveAnimIndex() const { return mActiveAnimIndex; }
|
||||
CCollisionMeshGroup* Collision() const { return mpCollision; }
|
||||
EVolumeShape VolumeShape() const { return mVolumeShape; }
|
||||
float VolumeScale() const { return mVolumeScale; }
|
||||
void SetPosition(const CVector3f& rkNewPos) { if (mpPosition) mpPosition->Set(rkNewPos); }
|
||||
void SetRotation(const CVector3f& rkNewRot) { if (mpRotation) mpRotation->Set(rkNewRot); }
|
||||
void SetScale(const CVector3f& rkNewScale) { if (mpScale) mpScale->Set(rkNewScale); }
|
||||
void SetName(const TString& rkNewName) { if (mpInstanceName) mpInstanceName->Set(rkNewName); }
|
||||
void SetActive(bool Active) { if (mpActive) mpActive->Set(Active); }
|
||||
void SetPosition(const CVector3f& rkNewPos) { mPosition.Set(rkNewPos); }
|
||||
void SetRotation(const CVector3f& rkNewRot) { mRotation.Set(rkNewRot); }
|
||||
void SetScale(const CVector3f& rkNewScale) { mScale.Set(rkNewScale); }
|
||||
void SetName(const TString& rkNewName) { mInstanceName.Set(rkNewName); }
|
||||
void SetActive(bool Active) { mActive.Set(Active); }
|
||||
|
||||
TVector3Property* PositionProperty() const { return mpPosition; }
|
||||
TVector3Property* RotationProperty() const { return mpRotation; }
|
||||
TVector3Property* ScaleProperty() const { return mpScale; }
|
||||
TStringProperty* InstanceNameProperty() const { return mpInstanceName; }
|
||||
TBoolProperty* ActiveProperty() const { return mpActive; }
|
||||
bool HasPosition() const { return mPosition.IsValid(); }
|
||||
bool HasRotation() const { return mRotation.IsValid(); }
|
||||
bool HasScale() const { return mScale.IsValid(); }
|
||||
bool HasInstanceName() const { return mInstanceName.IsValid(); }
|
||||
bool HasActive() const { return mActive.IsValid(); }
|
||||
bool HasLightParameters() const { return mLightParameters.IsValid(); }
|
||||
};
|
||||
|
||||
#endif // CSCRIPTOBJECT_H
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "CScriptTemplate.h"
|
||||
#include "CScriptObject.h"
|
||||
#include "CMasterTemplate.h"
|
||||
#include "CGameTemplate.h"
|
||||
#include "Core/GameProject/CResourceStore.h"
|
||||
#include "Core/Resource/Animation/CAnimSet.h"
|
||||
#include <Common/Log.h>
|
||||
@@ -8,35 +8,118 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
CScriptTemplate::CScriptTemplate(CMasterTemplate *pMaster)
|
||||
: mpMaster(pMaster)
|
||||
, mpBaseStruct(nullptr)
|
||||
// Old constructor
|
||||
CScriptTemplate::CScriptTemplate(CGameTemplate *pGame)
|
||||
: mpGame(pGame)
|
||||
, mpProperties(nullptr)
|
||||
, mVisible(true)
|
||||
, mDirty(false)
|
||||
, mpNameProperty(nullptr)
|
||||
, mpPositionProperty(nullptr)
|
||||
, mpRotationProperty(nullptr)
|
||||
, mpScaleProperty(nullptr)
|
||||
, mpActiveProperty(nullptr)
|
||||
, mpLightParametersProperty(nullptr)
|
||||
, mPreviewScale(1.f)
|
||||
, mVolumeShape(eNoShape)
|
||||
, mVolumeScale(1.f)
|
||||
{
|
||||
}
|
||||
|
||||
// New constructor
|
||||
CScriptTemplate::CScriptTemplate(CGameTemplate* pInGame, u32 InObjectID, const TString& kInFilePath)
|
||||
: mRotationType(eRotationEnabled)
|
||||
, mScaleType(eScaleEnabled)
|
||||
, mPreviewScale(1.f)
|
||||
, mVolumeShape(eNoShape)
|
||||
, mVolumeScale(1.f)
|
||||
, mSourceFile(kInFilePath)
|
||||
, mObjectID(InObjectID)
|
||||
, mpGame(pInGame)
|
||||
, mpNameProperty(nullptr)
|
||||
, mpPositionProperty(nullptr)
|
||||
, mpRotationProperty(nullptr)
|
||||
, mpScaleProperty(nullptr)
|
||||
, mpActiveProperty(nullptr)
|
||||
, mpLightParametersProperty(nullptr)
|
||||
, mVisible(true)
|
||||
, mDirty(false)
|
||||
{
|
||||
// Load
|
||||
CXMLReader Reader(kInFilePath);
|
||||
ASSERT(Reader.IsValid());
|
||||
Serialize(Reader);
|
||||
|
||||
// Post load initialization
|
||||
mSourceFile = kInFilePath;
|
||||
mpProperties->Initialize(nullptr, this, 0);
|
||||
|
||||
if (!mNameIDString.IsEmpty()) mpNameProperty = TPropCast<CStringProperty>( mpProperties->ChildByIDString(mNameIDString) );
|
||||
if (!mPositionIDString.IsEmpty()) mpPositionProperty = TPropCast<CVectorProperty>( mpProperties->ChildByIDString(mPositionIDString) );
|
||||
if (!mRotationIDString.IsEmpty()) mpRotationProperty = TPropCast<CVectorProperty>( mpProperties->ChildByIDString(mRotationIDString) );
|
||||
if (!mScaleIDString.IsEmpty()) mpScaleProperty = TPropCast<CVectorProperty>( mpProperties->ChildByIDString(mScaleIDString) );
|
||||
if (!mActiveIDString.IsEmpty()) mpActiveProperty = TPropCast<CBoolProperty>( mpProperties->ChildByIDString(mActiveIDString) );
|
||||
if (!mLightParametersIDString.IsEmpty()) mpLightParametersProperty = TPropCast<CStructProperty>( mpProperties->ChildByIDString(mLightParametersIDString) );
|
||||
}
|
||||
|
||||
CScriptTemplate::~CScriptTemplate()
|
||||
{
|
||||
delete mpBaseStruct;
|
||||
}
|
||||
|
||||
void CScriptTemplate::Serialize(IArchive& Arc)
|
||||
{
|
||||
Arc << SerialParameter("Modules", mModules, SH_Optional)
|
||||
<< SerialParameter("Properties", mpProperties);
|
||||
|
||||
if (Arc.ParamBegin("EditorProperties", 0))
|
||||
{
|
||||
Arc << SerialParameter("NameProperty", mNameIDString, SH_Optional)
|
||||
<< SerialParameter("PositionProperty", mPositionIDString, SH_Optional)
|
||||
<< SerialParameter("RotationProperty", mRotationIDString, SH_Optional)
|
||||
<< SerialParameter("ScaleProperty", mScaleIDString, SH_Optional)
|
||||
<< SerialParameter("ActiveProperty", mActiveIDString, SH_Optional)
|
||||
<< SerialParameter("LightParametersProperty", mLightParametersIDString, SH_Optional);
|
||||
|
||||
Arc.ParamEnd();
|
||||
}
|
||||
|
||||
Arc << SerialParameter("Assets", mAssets, SH_Optional)
|
||||
<< SerialParameter("Attachments", mAttachments, SH_Optional)
|
||||
<< SerialParameter("RotationType", mRotationType, SH_Optional, eRotationEnabled)
|
||||
<< SerialParameter("ScaleType", mScaleType, SH_Optional, eScaleEnabled)
|
||||
<< SerialParameter("PreviewScale", mPreviewScale, SH_Optional, 1.0f)
|
||||
<< SerialParameter("VolumeShape", mVolumeShape, SH_Optional, eNoShape)
|
||||
<< SerialParameter("VolumeScale", mVolumeScale, SH_Optional, 1.0f)
|
||||
<< SerialParameter("VolumeConditionProperty", mVolumeConditionIDString, SH_Optional)
|
||||
<< SerialParameter("VolumeConditions", mVolumeConditions, SH_Optional);
|
||||
}
|
||||
|
||||
void CScriptTemplate::Save(bool Force)
|
||||
{
|
||||
if (IsDirty() || Force)
|
||||
{
|
||||
Log::Write("Saving script template: " + mSourceFile);
|
||||
CXMLWriter Writer(mSourceFile, "ScriptObject", 0, mpGame->Game());
|
||||
ASSERT(Writer.IsValid());
|
||||
Serialize(Writer);
|
||||
mDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
EGame CScriptTemplate::Game() const
|
||||
{
|
||||
return mpMaster->Game();
|
||||
return mpGame->Game();
|
||||
}
|
||||
|
||||
// ************ PROPERTY FETCHING ************
|
||||
template<typename PropType, EPropertyType PropEnum>
|
||||
PropType TFetchProperty(CPropertyStruct *pProperties, const TIDString& rkID)
|
||||
template<class PropType>
|
||||
PropType* TFetchProperty(CStructProperty* pProperties, const TIDString& rkID)
|
||||
{
|
||||
if (rkID.IsEmpty()) return nullptr;
|
||||
IProperty *pProp = pProperties->PropertyByIDString(rkID);
|
||||
IProperty *pProp = pProperties->ChildByIDString(rkID);
|
||||
|
||||
if (pProp && (pProp->Type() == PropEnum))
|
||||
return static_cast<PropType>(pProp);
|
||||
return static_cast<PropType*>(pProp)->ValuePtr();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
@@ -80,39 +163,42 @@ s32 CScriptTemplate::CheckVolumeConditions(CScriptObject *pObj, bool LogErrors)
|
||||
// Private function
|
||||
if (mVolumeShape == eConditionalShape)
|
||||
{
|
||||
IProperty *pProp = pObj->Properties()->PropertyByIDString(mVolumeConditionIDString);
|
||||
TIDString PropID = mVolumeConditionIDString;
|
||||
IProperty* pProp = pObj->Template()->Properties()->ChildByIDString( PropID );
|
||||
|
||||
// Get value of the condition test property (only boolean, integral, and enum types supported)
|
||||
void* pData = pObj->PropertyData();
|
||||
int Val;
|
||||
|
||||
switch (pProp->Type())
|
||||
{
|
||||
case eBoolProperty:
|
||||
Val = (static_cast<TBoolProperty*>(pProp)->Get() ? 1 : 0);
|
||||
case EPropertyType::Bool:
|
||||
Val = TPropCast<CBoolProperty>(pProp)->Value(pData) ? 1 : 0;
|
||||
break;
|
||||
|
||||
case eByteProperty:
|
||||
Val = (int) static_cast<TByteProperty*>(pProp)->Get();
|
||||
case EPropertyType::Byte:
|
||||
Val = (int) TPropCast<CByteProperty>(pProp)->Value(pData);
|
||||
break;
|
||||
|
||||
case eShortProperty:
|
||||
Val = (int) static_cast<TShortProperty*>(pProp)->Get();
|
||||
case EPropertyType::Short:
|
||||
Val = (int) TPropCast<CShortProperty>(pProp)->Value(pData);
|
||||
break;
|
||||
|
||||
case eLongProperty:
|
||||
Val = (int) static_cast<TLongProperty*>(pProp)->Get();
|
||||
case EPropertyType::Int:
|
||||
Val = TPropCast<CIntProperty>(pProp)->Value(pData);
|
||||
break;
|
||||
|
||||
case eEnumProperty:
|
||||
Val = (int) static_cast<TEnumProperty*>(pProp)->Get();
|
||||
case EPropertyType::Enum:
|
||||
case EPropertyType::Choice:
|
||||
Val = TPropCast<CEnumProperty>(pProp)->Value(pData);
|
||||
break;
|
||||
}
|
||||
|
||||
// Test and check whether any of the conditions are true
|
||||
for (u32 iCon = 0; iCon < mVolumeConditions.size(); iCon++)
|
||||
for (u32 LinkIdx = 0; LinkIdx < mVolumeConditions.size(); LinkIdx++)
|
||||
{
|
||||
if (mVolumeConditions[iCon].Value == Val)
|
||||
return iCon;
|
||||
if (mVolumeConditions[LinkIdx].Value == Val)
|
||||
return LinkIdx;
|
||||
}
|
||||
|
||||
if (LogErrors)
|
||||
@@ -122,37 +208,7 @@ s32 CScriptTemplate::CheckVolumeConditions(CScriptObject *pObj, bool LogErrors)
|
||||
return -1;
|
||||
}
|
||||
|
||||
TStringProperty* CScriptTemplate::FindInstanceName(CPropertyStruct *pProperties)
|
||||
{
|
||||
return TFetchProperty<TStringProperty*, eStringProperty>(pProperties, mNameIDString);
|
||||
}
|
||||
|
||||
TVector3Property* CScriptTemplate::FindPosition(CPropertyStruct *pProperties)
|
||||
{
|
||||
return TFetchProperty<TVector3Property*, eVector3Property>(pProperties, mPositionIDString);
|
||||
}
|
||||
|
||||
TVector3Property* CScriptTemplate::FindRotation(CPropertyStruct *pProperties)
|
||||
{
|
||||
return TFetchProperty<TVector3Property*, eVector3Property>(pProperties, mRotationIDString);
|
||||
}
|
||||
|
||||
TVector3Property* CScriptTemplate::FindScale(CPropertyStruct *pProperties)
|
||||
{
|
||||
return TFetchProperty<TVector3Property*, eVector3Property>(pProperties, mScaleIDString);
|
||||
}
|
||||
|
||||
TBoolProperty* CScriptTemplate::FindActive(CPropertyStruct *pProperties)
|
||||
{
|
||||
return TFetchProperty<TBoolProperty*, eBoolProperty>(pProperties, mActiveIDString);
|
||||
}
|
||||
|
||||
CPropertyStruct* CScriptTemplate::FindLightParameters(CPropertyStruct *pProperties)
|
||||
{
|
||||
return TFetchProperty<CPropertyStruct*, eStructProperty>(pProperties, mLightParametersIDString);
|
||||
}
|
||||
|
||||
CResource* CScriptTemplate::FindDisplayAsset(CPropertyStruct *pProperties, u32& rOutCharIndex, u32& rOutAnimIndex, bool& rOutIsInGame)
|
||||
CResource* CScriptTemplate::FindDisplayAsset(void* pPropertyData, u32& rOutCharIndex, u32& rOutAnimIndex, bool& rOutIsInGame)
|
||||
{
|
||||
rOutCharIndex = -1;
|
||||
rOutAnimIndex = -1;
|
||||
@@ -170,25 +226,28 @@ CResource* CScriptTemplate::FindDisplayAsset(CPropertyStruct *pProperties, u32&
|
||||
// Property
|
||||
else
|
||||
{
|
||||
IProperty *pProp = pProperties->PropertyByIDString(it->AssetLocation);
|
||||
IProperty* pProp = mpProperties->ChildByIDString(it->AssetLocation);
|
||||
|
||||
if (it->AssetType == SEditorAsset::eAnimParams && pProp->Type() == eCharacterProperty)
|
||||
if (it->AssetType == SEditorAsset::eAnimParams && pProp->Type() == EPropertyType::AnimationSet)
|
||||
{
|
||||
TCharacterProperty *pChar = static_cast<TCharacterProperty*>(pProp);
|
||||
pRes = pChar->Get().AnimSet();
|
||||
CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(pProp);
|
||||
CAnimationParameters Params = pAnimSet->Value(pPropertyData);
|
||||
pRes = Params.AnimSet();
|
||||
|
||||
if (pRes)
|
||||
{
|
||||
u32 MaxNumChars = static_cast<CAnimSet*>(pRes)->NumCharacters();
|
||||
rOutCharIndex = (it->ForceNodeIndex >= 0 && it->ForceNodeIndex < (s32) MaxNumChars ? it->ForceNodeIndex : pChar->Get().CharacterIndex());
|
||||
rOutAnimIndex = pChar->Get().AnimIndex();
|
||||
rOutCharIndex = (it->ForceNodeIndex >= 0 && it->ForceNodeIndex < (s32) MaxNumChars ? it->ForceNodeIndex : Params.CharacterIndex());
|
||||
rOutAnimIndex = Params.AnimIndex();
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
TAssetProperty *pAsset = static_cast<TAssetProperty*>(pProp);
|
||||
CResourceEntry *pEntry = gpResourceStore->FindEntry(pAsset->Get());
|
||||
ASSERT(pProp->Type() == EPropertyType::Asset);
|
||||
CAssetProperty* pAsset = TPropCast<CAssetProperty>(pProp);
|
||||
CAssetID ID = pAsset->Value(pPropertyData);
|
||||
CResourceEntry *pEntry = gpResourceStore->FindEntry( ID );
|
||||
if (pEntry) pRes = pEntry->Load();
|
||||
}
|
||||
}
|
||||
@@ -205,7 +264,7 @@ CResource* CScriptTemplate::FindDisplayAsset(CPropertyStruct *pProperties, u32&
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CCollisionMeshGroup* CScriptTemplate::FindCollision(CPropertyStruct *pProperties)
|
||||
CCollisionMeshGroup* CScriptTemplate::FindCollision(void* pPropertyData)
|
||||
{
|
||||
for (auto it = mAssets.begin(); it != mAssets.end(); it++)
|
||||
{
|
||||
@@ -219,12 +278,12 @@ CCollisionMeshGroup* CScriptTemplate::FindCollision(CPropertyStruct *pProperties
|
||||
// Property
|
||||
else
|
||||
{
|
||||
IProperty *pProp = pProperties->PropertyByIDString(it->AssetLocation);
|
||||
IProperty* pProp = mpProperties->ChildByIDString(it->AssetLocation);
|
||||
|
||||
if (pProp->Type() == eAssetProperty)
|
||||
if (pProp->Type() == EPropertyType::Asset)
|
||||
{
|
||||
TAssetProperty *pAsset = static_cast<TAssetProperty*>(pProp);
|
||||
pRes = gpResourceStore->LoadResource( pAsset->Get(), eDynamicCollision );
|
||||
CAssetProperty* pAsset = TPropCast<CAssetProperty>(pProp);
|
||||
pRes = gpResourceStore->LoadResource( pAsset->Value(pPropertyData), eDynamicCollision );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#ifndef CSCRIPTTEMPLATE_H
|
||||
#define CSCRIPTTEMPLATE_H
|
||||
|
||||
#include "IPropertyTemplate.h"
|
||||
#include "IProperty.h"
|
||||
#include "EPropertyType.h"
|
||||
#include "Core/Resource/Script/Property/Properties.h"
|
||||
#include "EVolumeShape.h"
|
||||
#include "Core/Resource/Model/CModel.h"
|
||||
#include "Core/Resource/CCollisionMeshGroup.h"
|
||||
@@ -12,6 +10,7 @@
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
class CGameTemplate;
|
||||
class CScriptObject;
|
||||
typedef TString TIDString;
|
||||
|
||||
@@ -26,6 +25,13 @@ struct SAttachment
|
||||
TIDString AttachProperty; // Must point to a CMDL!
|
||||
TString LocatorName;
|
||||
EAttachType AttachType;
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
Arc << SerialParameter("AttachProperty", AttachProperty, SH_Attribute)
|
||||
<< SerialParameter("LocatorName", LocatorName, SH_Attribute)
|
||||
<< SerialParameter("AttachType", AttachType, SH_Attribute);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -37,9 +43,6 @@ struct SAttachment
|
||||
*/
|
||||
class CScriptTemplate
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
public:
|
||||
enum ERotationType {
|
||||
eRotationEnabled, eRotationDisabled
|
||||
@@ -52,34 +55,28 @@ public:
|
||||
private:
|
||||
struct SEditorAsset
|
||||
{
|
||||
enum {
|
||||
enum EAssetType {
|
||||
eModel, eAnimParams, eBillboard, eCollision
|
||||
} AssetType;
|
||||
|
||||
enum {
|
||||
enum EAssetSource {
|
||||
eProperty, eFile
|
||||
} AssetSource;
|
||||
|
||||
TIDString AssetLocation;
|
||||
s32 ForceNodeIndex; // Force animsets to use specific node instead of one from property
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
Arc << SerialParameter("Type", AssetType, SH_Attribute)
|
||||
<< SerialParameter("Source", AssetSource, SH_Attribute)
|
||||
<< SerialParameter("Location", AssetLocation, SH_Attribute)
|
||||
<< SerialParameter("ForceCharacterIndex", ForceNodeIndex, SH_Attribute | SH_Optional, (s32) -1);
|
||||
}
|
||||
};
|
||||
|
||||
CMasterTemplate *mpMaster;
|
||||
CStructTemplate *mpBaseStruct;
|
||||
std::list<CScriptObject*> mObjectList;
|
||||
TString mTemplateName;
|
||||
std::vector<TString> mModules;
|
||||
TString mSourceFile;
|
||||
u32 mObjectID;
|
||||
bool mVisible;
|
||||
|
||||
// Editor Properties
|
||||
TIDString mNameIDString;
|
||||
TIDString mPositionIDString;
|
||||
TIDString mRotationIDString;
|
||||
TIDString mScaleIDString;
|
||||
TIDString mActiveIDString;
|
||||
TIDString mLightParametersIDString;
|
||||
std::unique_ptr<CStructProperty> mpProperties;
|
||||
std::vector<SEditorAsset> mAssets;
|
||||
std::vector<SAttachment> mAttachments;
|
||||
|
||||
@@ -92,53 +89,85 @@ private:
|
||||
float mVolumeScale;
|
||||
TIDString mVolumeConditionIDString;
|
||||
|
||||
TString mSourceFile;
|
||||
u32 mObjectID;
|
||||
|
||||
// Editor Properties
|
||||
TIDString mNameIDString;
|
||||
TIDString mPositionIDString;
|
||||
TIDString mRotationIDString;
|
||||
TIDString mScaleIDString;
|
||||
TIDString mActiveIDString;
|
||||
TIDString mLightParametersIDString;
|
||||
|
||||
CGameTemplate* mpGame;
|
||||
std::list<CScriptObject*> mObjectList;
|
||||
|
||||
CStringProperty* mpNameProperty;
|
||||
CVectorProperty* mpPositionProperty;
|
||||
CVectorProperty* mpRotationProperty;
|
||||
CVectorProperty* mpScaleProperty;
|
||||
CBoolProperty* mpActiveProperty;
|
||||
CStructProperty* mpLightParametersProperty;
|
||||
|
||||
struct SVolumeCondition {
|
||||
int Value;
|
||||
u32 Value;
|
||||
EVolumeShape Shape;
|
||||
float Scale;
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
Arc << SerialParameter("Value", Value)
|
||||
<< SerialParameter("Shape", Shape)
|
||||
<< SerialParameter("Scale", Scale, SH_Optional, 1.0f);
|
||||
}
|
||||
};
|
||||
std::vector<SVolumeCondition> mVolumeConditions;
|
||||
bool mVisible;
|
||||
bool mDirty;
|
||||
|
||||
public:
|
||||
CScriptTemplate(CMasterTemplate *pMaster);
|
||||
// Default constructor. Don't use. This is only here so the serializer doesn't complain
|
||||
CScriptTemplate() { ASSERT(false); }
|
||||
// Old constructor
|
||||
CScriptTemplate(CGameTemplate *pGame);
|
||||
// New constructor
|
||||
CScriptTemplate(CGameTemplate* pGame, u32 ObjectID, const TString& kFilePath);
|
||||
~CScriptTemplate();
|
||||
void Serialize(IArchive& rArc);
|
||||
void Save(bool Force = false);
|
||||
EGame Game() const;
|
||||
|
||||
// Property Fetching
|
||||
EVolumeShape VolumeShape(CScriptObject *pObj);
|
||||
float VolumeScale(CScriptObject *pObj);
|
||||
TStringProperty* FindInstanceName(CPropertyStruct *pProperties);
|
||||
TVector3Property* FindPosition(CPropertyStruct *pProperties);
|
||||
TVector3Property* FindRotation(CPropertyStruct *pProperties);
|
||||
TVector3Property* FindScale(CPropertyStruct *pProperties);
|
||||
TBoolProperty* FindActive(CPropertyStruct *pProperties);
|
||||
CPropertyStruct* FindLightParameters(CPropertyStruct *pProperties);
|
||||
CResource* FindDisplayAsset(CPropertyStruct *pProperties, u32& rOutCharIndex, u32& rOutAnimIndex, bool& rOutIsInGame);
|
||||
CCollisionMeshGroup* FindCollision(CPropertyStruct *pProperties);
|
||||
CResource* FindDisplayAsset(void* pPropertyData, u32& rOutCharIndex, u32& rOutAnimIndex, bool& rOutIsInGame);
|
||||
CCollisionMeshGroup* FindCollision(void* pPropertyData);
|
||||
|
||||
// Accessors
|
||||
inline CMasterTemplate* MasterTemplate() const { return mpMaster; }
|
||||
inline TString Name() const { return mTemplateName; }
|
||||
inline CGameTemplate* GameTemplate() const { return mpGame; }
|
||||
inline TString Name() const { return mpProperties->Name(); }
|
||||
inline ERotationType RotationType() const { return mRotationType; }
|
||||
inline EScaleType ScaleType() const { return mScaleType; }
|
||||
inline float PreviewScale() const { return mPreviewScale; }
|
||||
inline u32 ObjectID() const { return mObjectID; }
|
||||
inline bool IsVisible() const { return mVisible; }
|
||||
inline TString SourceFile() const { return mSourceFile; }
|
||||
inline CStructTemplate* BaseStruct() const { return mpBaseStruct; }
|
||||
inline CStructProperty* Properties() const { return mpProperties.get(); }
|
||||
inline u32 NumAttachments() const { return mAttachments.size(); }
|
||||
const SAttachment& Attachment(u32 Index) const { return mAttachments[Index]; }
|
||||
const std::vector<TString>& RequiredModules() const { return mModules; }
|
||||
|
||||
inline bool HasName() const { return !mNameIDString.IsEmpty(); }
|
||||
inline bool HasPosition() const { return !mPositionIDString.IsEmpty(); }
|
||||
inline bool HasRotation() const { return !mRotationIDString.IsEmpty(); }
|
||||
inline bool HasScale() const { return !mScaleIDString.IsEmpty(); }
|
||||
inline bool HasActive() const { return !mActiveIDString.IsEmpty(); }
|
||||
inline CStringProperty* NameProperty() const { return mpNameProperty; }
|
||||
inline CVectorProperty* PositionProperty() const { return mpPositionProperty; }
|
||||
inline CVectorProperty* RotationProperty() const { return mpRotationProperty; }
|
||||
inline CVectorProperty* ScaleProperty() const { return mpScaleProperty; }
|
||||
inline CBoolProperty* ActiveProperty() const { return mpActiveProperty; }
|
||||
inline CStructProperty* LightParametersProperty() const { return mpLightParametersProperty; }
|
||||
|
||||
inline void SetVisible(bool Visible) { mVisible = Visible; }
|
||||
|
||||
inline void DebugPrintProperties() { mpBaseStruct->DebugPrintProperties(""); }
|
||||
inline void MarkDirty() { mDirty = true; }
|
||||
inline bool IsDirty() const { return mDirty || mpProperties->IsDirty(); }
|
||||
|
||||
// Object Tracking
|
||||
u32 NumObjects() const;
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef EPROPERTYTYPE
|
||||
#define EPROPERTYTYPE
|
||||
|
||||
#include <Common/TString.h>
|
||||
|
||||
enum EPropertyType
|
||||
{
|
||||
eBoolProperty,
|
||||
eByteProperty,
|
||||
eShortProperty,
|
||||
eLongProperty,
|
||||
eEnumProperty,
|
||||
eBitfieldProperty,
|
||||
eFloatProperty,
|
||||
eStringProperty,
|
||||
eVector3Property,
|
||||
eColorProperty,
|
||||
eSoundProperty,
|
||||
eAssetProperty,
|
||||
eStructProperty,
|
||||
eArrayProperty,
|
||||
eCharacterProperty,
|
||||
eMayaSplineProperty,
|
||||
eUnknownProperty,
|
||||
eInvalidProperty
|
||||
};
|
||||
|
||||
// functions defined in IPropertyTemplate.cpp
|
||||
EPropertyType PropStringToPropEnum(TString Prop);
|
||||
TString PropEnumToPropString(EPropertyType Prop);
|
||||
|
||||
#endif // EPROPERTYTYPE
|
||||
|
||||
@@ -1,243 +0,0 @@
|
||||
#include "IProperty.h"
|
||||
#include "IPropertyTemplate.h"
|
||||
|
||||
// ************ IProperty ************
|
||||
bool IProperty::IsInArray() const
|
||||
{
|
||||
CPropertyStruct *pParent = mpParent;
|
||||
|
||||
while (pParent)
|
||||
{
|
||||
if (pParent->Type() == eArrayProperty) return true;
|
||||
pParent = pParent->Parent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CPropertyStruct* IProperty::RootStruct()
|
||||
{
|
||||
return (mpParent ? mpParent->RootStruct() : Type() == eStructProperty ? static_cast<CPropertyStruct*>(this) : nullptr);
|
||||
}
|
||||
|
||||
IPropertyTemplate* IProperty::Template() const
|
||||
{
|
||||
return mpTemplate;
|
||||
}
|
||||
|
||||
TString IProperty::Name() const
|
||||
{
|
||||
return mpTemplate->Name();
|
||||
}
|
||||
|
||||
u32 IProperty::ID() const
|
||||
{
|
||||
if (mpParent && mpParent->Type() == eArrayProperty)
|
||||
return ArrayIndex();
|
||||
else
|
||||
return mpTemplate->PropertyID();
|
||||
}
|
||||
|
||||
TIDString IProperty::IDString(bool FullPath) const
|
||||
{
|
||||
TIDString Out;
|
||||
|
||||
if (ID() != 0xFFFFFFFF)
|
||||
{
|
||||
if (mpParent && FullPath)
|
||||
{
|
||||
Out = mpParent->IDString(true);
|
||||
if (!Out.IsEmpty()) Out += ":";
|
||||
}
|
||||
|
||||
Out += TString::HexString(ID());
|
||||
}
|
||||
|
||||
return Out;
|
||||
}
|
||||
|
||||
u32 IProperty::ArrayIndex() const
|
||||
{
|
||||
CArrayProperty *pArray = TPropCast<CArrayProperty>(mpParent);
|
||||
|
||||
if (pArray)
|
||||
{
|
||||
for (u32 iSub = 0; iSub < pArray->Count(); iSub++)
|
||||
{
|
||||
if (pArray->PropertyByIndex(iSub) == this)
|
||||
return iSub;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool IProperty::ShouldCook()
|
||||
{
|
||||
if (mpTemplate->CookPreference() == eNeverCook) return false;
|
||||
else if (mpTemplate->CookPreference() == eAlwaysCook) return true;
|
||||
|
||||
else
|
||||
{
|
||||
if (mpTemplate->Game() == eReturns)
|
||||
return !MatchesDefault();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool IProperty::MatchesDefault()
|
||||
{
|
||||
const IPropertyValue *pkValue = RawValue();
|
||||
const IPropertyValue *pkDefault = mpTemplate->RawDefaultValue();
|
||||
if (!pkValue || !pkDefault) return false;
|
||||
else return pkValue->Matches(pkDefault);
|
||||
}
|
||||
|
||||
// ************ TAssetProperty ************
|
||||
TAssetProperty::TAssetProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
: TTypedProperty(pTemp, pInstance, pParent, CAssetID::InvalidID( pTemp->Game() ))
|
||||
{
|
||||
}
|
||||
|
||||
// ************ CPropertyStruct ************
|
||||
void CPropertyStruct::Copy(const IProperty *pkProp)
|
||||
{
|
||||
const CPropertyStruct *pkSource = static_cast<const CPropertyStruct*>(pkProp);
|
||||
|
||||
for (u32 iSub = 0; iSub < mProperties.size(); iSub++)
|
||||
mProperties[iSub]->Copy(pkSource->mProperties[iSub]);
|
||||
}
|
||||
|
||||
bool CPropertyStruct::ShouldCook()
|
||||
{
|
||||
if (mpTemplate->CookPreference() == eNeverCook) return false;
|
||||
|
||||
for (u32 iProp = 0; iProp < mProperties.size(); iProp++)
|
||||
{
|
||||
if (mProperties[iProp]->ShouldCook())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IProperty* CPropertyStruct::PropertyByIndex(u32 index) const
|
||||
{
|
||||
return mProperties[index];
|
||||
}
|
||||
|
||||
IProperty* CPropertyStruct::PropertyByID(u32 ID) const
|
||||
{
|
||||
for (auto it = mProperties.begin(); it != mProperties.end(); it++)
|
||||
{
|
||||
if ((*it)->ID() == ID)
|
||||
return *it;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IProperty* CPropertyStruct::PropertyByIDString(const TIDString& rkStr) const
|
||||
{
|
||||
// Resolve namespace
|
||||
u32 NSStart = rkStr.IndexOf(":");
|
||||
|
||||
// String has namespace; the requested property is within a struct
|
||||
if (NSStart != -1)
|
||||
{
|
||||
TString StrStructID = rkStr.Truncate(NSStart);
|
||||
if (!StrStructID.IsHexString()) return nullptr;
|
||||
|
||||
u32 StructID = StrStructID.ToInt32();
|
||||
TString PropName = rkStr.ChopFront(NSStart + 1);
|
||||
|
||||
CPropertyStruct *pStruct = StructByID(StructID);
|
||||
if (!pStruct) return nullptr;
|
||||
else return pStruct->PropertyByIDString(PropName);
|
||||
}
|
||||
|
||||
// No namespace; fetch the property from this struct
|
||||
else
|
||||
{
|
||||
if (rkStr.IsHexString())
|
||||
return PropertyByID(rkStr.ToInt32());
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CPropertyStruct* CPropertyStruct::StructByIndex(u32 index) const
|
||||
{
|
||||
IProperty *pProp = PropertyByIndex(index);
|
||||
|
||||
if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty)
|
||||
return static_cast<CPropertyStruct*>(pProp);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CPropertyStruct* CPropertyStruct::StructByID(u32 ID) const
|
||||
{
|
||||
IProperty *pProp = PropertyByID(ID);
|
||||
|
||||
if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty)
|
||||
return static_cast<CPropertyStruct*>(pProp);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CPropertyStruct* CPropertyStruct::StructByIDString(const TIDString& rkStr) const
|
||||
{
|
||||
IProperty *pProp = PropertyByIDString(rkStr);
|
||||
|
||||
if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty)
|
||||
return static_cast<CPropertyStruct*>(pProp);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ************ CArrayProperty ************
|
||||
void CArrayProperty::Copy(const IProperty *pkProp)
|
||||
{
|
||||
const CArrayProperty *pkSource = static_cast<const CArrayProperty*>(pkProp);
|
||||
Resize(pkSource->Count());
|
||||
|
||||
for (u32 iSub = 0; iSub < mProperties.size(); iSub++)
|
||||
mProperties[iSub]->Copy(pkSource->mProperties[iSub]);
|
||||
}
|
||||
|
||||
bool CArrayProperty::ShouldCook()
|
||||
{
|
||||
return (mpTemplate->CookPreference() == eNeverCook ? false : true);
|
||||
}
|
||||
|
||||
void CArrayProperty::Resize(int Size)
|
||||
{
|
||||
int OldSize = mProperties.size();
|
||||
if (OldSize == Size) return;
|
||||
|
||||
if (Size < OldSize)
|
||||
{
|
||||
for (int iProp = mProperties.size() - 1; iProp >= Size; iProp--)
|
||||
delete mProperties[iProp];
|
||||
}
|
||||
|
||||
mProperties.resize(Size);
|
||||
|
||||
if (Size > OldSize)
|
||||
{
|
||||
for (int iProp = OldSize; iProp < Size; iProp++)
|
||||
mProperties[iProp] = static_cast<CArrayTemplate*>(mpTemplate)->CreateSubStruct(Instance(), this);
|
||||
}
|
||||
}
|
||||
|
||||
CStructTemplate* CArrayProperty::SubStructTemplate() const
|
||||
{
|
||||
// CArrayTemplate inherits from CStructTemplate. The template defines the substruct structure.
|
||||
return static_cast<CStructTemplate*>(Template());
|
||||
}
|
||||
|
||||
TString CArrayProperty::ElementName() const
|
||||
{
|
||||
return static_cast<CArrayTemplate*>(Template())->ElementName();
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
#ifndef IPROPERTY
|
||||
#define IPROPERTY
|
||||
|
||||
#include "EPropertyType.h"
|
||||
#include "IPropertyValue.h"
|
||||
#include "Core/Resource/CResource.h"
|
||||
#include "Core/Resource/TResPtr.h"
|
||||
#include "Core/Resource/Animation/CAnimationParameters.h"
|
||||
#include <Common/CColor.h>
|
||||
#include <Common/TString.h>
|
||||
#include <Math/CVector3f.h>
|
||||
#include <list>
|
||||
|
||||
class CScriptObject;
|
||||
class CScriptTemplate;
|
||||
class CStructTemplate;
|
||||
class IPropertyTemplate;
|
||||
typedef TString TIDString;
|
||||
|
||||
/*
|
||||
* IProperty is the base class, containing just some virtual function definitions
|
||||
*/
|
||||
class IProperty
|
||||
{
|
||||
protected:
|
||||
class CPropertyStruct *mpParent;
|
||||
CScriptObject *mpInstance;
|
||||
IPropertyTemplate *mpTemplate;
|
||||
|
||||
public:
|
||||
IProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
: mpParent(pParent)
|
||||
, mpInstance(pInstance)
|
||||
, mpTemplate(pTemp)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~IProperty() {}
|
||||
virtual EPropertyType Type() const = 0;
|
||||
virtual TString ToString() const { return ""; }
|
||||
virtual IPropertyValue* RawValue() { return nullptr; }
|
||||
virtual void Copy(const IProperty *pkProp) = 0;
|
||||
virtual IProperty* Clone(CScriptObject *pInstance, CPropertyStruct *pParent = 0) const = 0;
|
||||
virtual bool Matches(const IProperty *pkProp) const = 0;
|
||||
|
||||
virtual bool ShouldCook(); // Can't be const because it calls MatchesDefault()
|
||||
virtual bool MatchesDefault(); // Can't be const because RawValue() isn't const
|
||||
|
||||
inline CScriptObject* Instance() const { return mpInstance; }
|
||||
inline CPropertyStruct* Parent() const { return mpParent; }
|
||||
inline void SetParent(CPropertyStruct *pParent) { mpParent = pParent; }
|
||||
|
||||
bool IsInArray() const;
|
||||
CPropertyStruct* RootStruct();
|
||||
|
||||
// These functions can't be in the header to avoid circular includes with IPropertyTemplate.h
|
||||
IPropertyTemplate* Template() const;
|
||||
TString Name() const;
|
||||
u32 ID() const;
|
||||
TIDString IDString(bool FullPath) const;
|
||||
u32 ArrayIndex() const;
|
||||
};
|
||||
|
||||
/*
|
||||
* TTypedProperty is a template subclass for actual properties.
|
||||
*/
|
||||
#define IMPLEMENT_PROPERTY_CLONE(ClassName) \
|
||||
virtual IProperty* Clone(CScriptObject *pInstance, CPropertyStruct *pParent) const \
|
||||
{ \
|
||||
if (!pParent) pParent = mpParent; \
|
||||
ClassName *pOut = new ClassName(mpTemplate, pInstance, pParent); \
|
||||
pOut->Copy(this); \
|
||||
return pOut; \
|
||||
}
|
||||
|
||||
template <typename ValueType, EPropertyType TypeEnum, class ValueClass>
|
||||
class TTypedProperty : public IProperty
|
||||
{
|
||||
ValueClass mValue;
|
||||
public:
|
||||
TTypedProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
: IProperty(pTemp, pInstance, pParent) {}
|
||||
|
||||
TTypedProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent, ValueType v)
|
||||
: IProperty(pTemp, pInstance, pParent), mValue(v) {}
|
||||
|
||||
~TTypedProperty() {}
|
||||
virtual EPropertyType Type() const { return TypeEnum; }
|
||||
static inline EPropertyType StaticType() { return TypeEnum; }
|
||||
|
||||
virtual TString ToString() const { return mValue.ToString(); }
|
||||
virtual IPropertyValue* RawValue() { return &mValue; }
|
||||
|
||||
virtual void Copy(const IProperty *pkProp)
|
||||
{
|
||||
const TTypedProperty *pkCast = static_cast<const TTypedProperty*>(pkProp);
|
||||
mValue.Set(pkCast->mValue.Get());
|
||||
}
|
||||
|
||||
IMPLEMENT_PROPERTY_CLONE(TTypedProperty)
|
||||
|
||||
virtual bool Matches(const IProperty *pkProp) const
|
||||
{
|
||||
const TTypedProperty *pkTyped = static_cast<const TTypedProperty*>(pkProp);
|
||||
return ( (Type() == pkTyped->Type()) &&
|
||||
mValue.Matches(&pkTyped->mValue) );
|
||||
}
|
||||
|
||||
inline ValueType Get() const { return mValue.Get(); }
|
||||
inline void Set(ValueType v) { mValue.Set(v); }
|
||||
};
|
||||
typedef TTypedProperty<bool, eBoolProperty, CBoolValue> TBoolProperty;
|
||||
typedef TTypedProperty<char, eByteProperty, CByteValue> TByteProperty;
|
||||
typedef TTypedProperty<short, eShortProperty, CShortValue> TShortProperty;
|
||||
typedef TTypedProperty<long, eLongProperty, CLongValue> TLongProperty;
|
||||
typedef TTypedProperty<long, eEnumProperty, CLongValue> TEnumProperty;
|
||||
typedef TTypedProperty<long, eBitfieldProperty, CHexLongValue> TBitfieldProperty;
|
||||
typedef TTypedProperty<float, eFloatProperty, CFloatValue> TFloatProperty;
|
||||
typedef TTypedProperty<CVector3f, eVector3Property, CVector3Value> TVector3Property;
|
||||
typedef TTypedProperty<CColor, eColorProperty, CColorValue> TColorProperty;
|
||||
typedef TTypedProperty<std::vector<u8>, eUnknownProperty, CUnknownValue> TUnknownProperty;
|
||||
|
||||
/*
|
||||
* TStringProperty, TSoundProperty, TAssetProperty, and TCharacterProperty get little subclasses in order to override some virtual functions.
|
||||
*/
|
||||
#define IMPLEMENT_PROPERTY_CTORS(ClassName, ValueType) \
|
||||
ClassName(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent) \
|
||||
: TTypedProperty(pTemp, pInstance, pParent) {} \
|
||||
\
|
||||
ClassName(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent, ValueType v) \
|
||||
: TTypedProperty(pTemp, pInstance, pParent, v) {}
|
||||
|
||||
class TStringProperty : public TTypedProperty<TString, eStringProperty, CStringValue>
|
||||
{
|
||||
public:
|
||||
IMPLEMENT_PROPERTY_CTORS(TStringProperty, TString)
|
||||
IMPLEMENT_PROPERTY_CLONE(TStringProperty)
|
||||
virtual bool MatchesDefault() { return Get().IsEmpty(); }
|
||||
virtual bool ShouldCook() { return true; }
|
||||
};
|
||||
|
||||
class TSoundProperty : public TTypedProperty<u32, eSoundProperty, CSoundValue>
|
||||
{
|
||||
public:
|
||||
IMPLEMENT_PROPERTY_CTORS(TSoundProperty, u32)
|
||||
IMPLEMENT_PROPERTY_CLONE(TSoundProperty)
|
||||
virtual bool MatchesDefault() { return Get() == 0xFFFFFFFF; }
|
||||
};
|
||||
|
||||
class TAssetProperty : public TTypedProperty<CAssetID, eAssetProperty, CAssetValue>
|
||||
{
|
||||
public:
|
||||
TAssetProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent); // Can't be in the header because needs to check the template to set the correct ID length
|
||||
TAssetProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent, CAssetID v)
|
||||
: TTypedProperty(pTemp, pInstance, pParent, v) {}
|
||||
|
||||
IMPLEMENT_PROPERTY_CLONE(TAssetProperty)
|
||||
virtual bool MatchesDefault() { return !Get().IsValid(); }
|
||||
virtual bool ShouldCook() { return true; }
|
||||
};
|
||||
|
||||
class TCharacterProperty : public TTypedProperty<CAnimationParameters, eCharacterProperty, CCharacterValue>
|
||||
{
|
||||
public:
|
||||
IMPLEMENT_PROPERTY_CTORS(TCharacterProperty, CAnimationParameters)
|
||||
IMPLEMENT_PROPERTY_CLONE(TCharacterProperty)
|
||||
virtual bool MatchesDefault() { return Get().AnimSet() == nullptr; }
|
||||
virtual bool ShouldCook() { return true; }
|
||||
};
|
||||
|
||||
class TMayaSplineProperty : public TTypedProperty<std::vector<u8>, eMayaSplineProperty, CMayaSplineValue>
|
||||
{
|
||||
public:
|
||||
IMPLEMENT_PROPERTY_CTORS(TMayaSplineProperty, std::vector<u8>)
|
||||
IMPLEMENT_PROPERTY_CLONE(TMayaSplineProperty)
|
||||
virtual bool MatchesDefault() { return Get().empty(); }
|
||||
};
|
||||
|
||||
/*
|
||||
* CPropertyStruct is for defining structs of properties.
|
||||
*/
|
||||
class CPropertyStruct : public IProperty
|
||||
{
|
||||
friend class CScriptLoader;
|
||||
protected:
|
||||
std::vector<IProperty*> mProperties;
|
||||
public:
|
||||
CPropertyStruct(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
: IProperty(pTemp, pInstance, pParent) {}
|
||||
|
||||
~CPropertyStruct()
|
||||
{
|
||||
for (auto it = mProperties.begin(); it != mProperties.end(); it++)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
EPropertyType Type() const { return eStructProperty; }
|
||||
static inline EPropertyType StaticType() { return eStructProperty; }
|
||||
|
||||
virtual void Copy(const IProperty *pkProp);
|
||||
|
||||
virtual IProperty* Clone(CScriptObject *pInstance, CPropertyStruct *pParent) const
|
||||
{
|
||||
if (!pParent) pParent = mpParent;
|
||||
CPropertyStruct *pOut = new CPropertyStruct(mpTemplate, pInstance, pParent);
|
||||
pOut->Copy(this);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
virtual bool Matches(const IProperty *pkProp) const
|
||||
{
|
||||
const CPropertyStruct *pkStruct = static_cast<const CPropertyStruct*>(pkProp);
|
||||
|
||||
if ( (Type() == pkStruct->Type()) &&
|
||||
(mProperties.size() == pkStruct->mProperties.size()) )
|
||||
{
|
||||
for (u32 iProp = 0; iProp < mProperties.size(); iProp++)
|
||||
{
|
||||
if (!mProperties[iProp]->Matches(pkStruct->mProperties[iProp]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool MatchesDefault()
|
||||
{
|
||||
for (u32 iProp = 0; iProp < mProperties.size(); iProp++)
|
||||
{
|
||||
if (!mProperties[iProp]->MatchesDefault())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool ShouldCook();
|
||||
|
||||
// Inline
|
||||
inline u32 Count() const { return mProperties.size(); }
|
||||
inline void AddSubProperty(IProperty *pProp) { mProperties.push_back(pProp); }
|
||||
inline IProperty* operator[](u32 index) { return mProperties[index]; }
|
||||
|
||||
// Functions
|
||||
IProperty* PropertyByIndex(u32 index) const;
|
||||
IProperty* PropertyByID(u32 ID) const;
|
||||
IProperty* PropertyByIDString(const TIDString& rkStr) const;
|
||||
CPropertyStruct* StructByIndex(u32 index) const;
|
||||
CPropertyStruct* StructByID(u32 ID) const;
|
||||
CPropertyStruct* StructByIDString(const TIDString& rkStr) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* CArrayProperty stores a repeated property struct.
|
||||
*/
|
||||
class CArrayProperty : public CPropertyStruct
|
||||
{
|
||||
friend class CScriptLoader;
|
||||
|
||||
public:
|
||||
CArrayProperty(IPropertyTemplate *pTemp, CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
: CPropertyStruct(pTemp, pInstance, pParent) {}
|
||||
|
||||
EPropertyType Type() const { return eArrayProperty; }
|
||||
static inline EPropertyType StaticType() { return eArrayProperty; }
|
||||
|
||||
virtual void Copy(const IProperty *pkProp);
|
||||
|
||||
virtual IProperty* Clone(CScriptObject *pInstance, CPropertyStruct *pParent) const
|
||||
{
|
||||
if (!pParent) pParent = mpParent;
|
||||
CArrayProperty *pOut = new CArrayProperty(mpTemplate, pInstance, pParent);
|
||||
pOut->Copy(this);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
virtual bool MatchesDefault() { return mProperties.empty(); }
|
||||
virtual bool ShouldCook();
|
||||
|
||||
// Inline
|
||||
inline void Reserve(u32 amount) { mProperties.reserve(amount); }
|
||||
|
||||
// Functions
|
||||
void Resize(int Size);
|
||||
CStructTemplate* SubStructTemplate() const;
|
||||
TString ElementName() const;
|
||||
};
|
||||
|
||||
/*
|
||||
* Function for casting properties. Returns null if the property is not actually the requested type.
|
||||
*/
|
||||
template <class PropertyClass>
|
||||
PropertyClass* TPropCast(IProperty *pProp)
|
||||
{
|
||||
return (pProp && pProp->Type() == PropertyClass::StaticType() ? static_cast<PropertyClass*>(pProp) : nullptr);
|
||||
}
|
||||
|
||||
#endif // IPROPERTY
|
||||
|
||||
@@ -1,289 +0,0 @@
|
||||
#include "IPropertyTemplate.h"
|
||||
#include "CMasterTemplate.h"
|
||||
#include <iostream>
|
||||
|
||||
// ************ IPropertyTemplate ************
|
||||
EGame IPropertyTemplate::Game() const
|
||||
{
|
||||
return (mpMasterTemplate ? mpMasterTemplate->Game() : eUnknownGame);
|
||||
}
|
||||
|
||||
bool IPropertyTemplate::IsInVersion(u32 Version) const
|
||||
{
|
||||
if (mAllowedVersions.empty())
|
||||
return true;
|
||||
|
||||
for (u32 iVer = 0; iVer < mAllowedVersions.size(); iVer++)
|
||||
if (mAllowedVersions[iVer] == Version)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TString IPropertyTemplate::FullName() const
|
||||
{
|
||||
return mpParent ? mpParent->FullName() + "::" + Name() : Name();
|
||||
}
|
||||
|
||||
TIDString IPropertyTemplate::IDString(bool FullPath) const
|
||||
{
|
||||
if (mID != 0xFFFFFFFF)
|
||||
{
|
||||
TIDString Out;
|
||||
|
||||
if (mpParent && FullPath)
|
||||
{
|
||||
Out = mpParent->IDString(true);
|
||||
if (!Out.IsEmpty()) Out += ":";
|
||||
}
|
||||
|
||||
Out += TIDString::HexString(mID);
|
||||
return Out;
|
||||
}
|
||||
else return "";
|
||||
}
|
||||
|
||||
bool IPropertyTemplate::IsDescendantOf(const CStructTemplate *pStruct) const
|
||||
{
|
||||
CStructTemplate *pParent = mpParent;
|
||||
|
||||
while (pParent)
|
||||
{
|
||||
if (pParent == pStruct) return true;
|
||||
pParent = pParent->Parent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IPropertyTemplate::IsFromStructTemplate() const
|
||||
{
|
||||
const CStructTemplate *pParent = Parent();
|
||||
|
||||
while (pParent)
|
||||
{
|
||||
if (!pParent->SourceFile().IsEmpty()) return true;
|
||||
pParent = pParent->Parent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TString IPropertyTemplate::FindStructSource() const
|
||||
{
|
||||
const CStructTemplate *pkStruct = mpParent;
|
||||
|
||||
while (pkStruct)
|
||||
{
|
||||
if (!pkStruct->SourceFile().IsEmpty()) return pkStruct->SourceFile();
|
||||
pkStruct = pkStruct->Parent();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
CStructTemplate* IPropertyTemplate::RootStruct()
|
||||
{
|
||||
if (mpParent) return mpParent->RootStruct();
|
||||
else if (Type() == eStructProperty) return static_cast<CStructTemplate*>(this);
|
||||
else return nullptr;
|
||||
}
|
||||
|
||||
// ************ CStructTemplate ************
|
||||
void CStructTemplate::CopyStructData(const CStructTemplate *pkStruct)
|
||||
{
|
||||
mVersionPropertyCounts = pkStruct->mVersionPropertyCounts;
|
||||
mIsSingleProperty = pkStruct->mIsSingleProperty;
|
||||
mSourceFile = pkStruct->mSourceFile;
|
||||
|
||||
mSubProperties.resize(pkStruct->mSubProperties.size());
|
||||
|
||||
for (u32 iSub = 0; iSub < pkStruct->mSubProperties.size(); iSub++)
|
||||
{
|
||||
mSubProperties[iSub] = pkStruct->mSubProperties[iSub]->Clone(mpScriptTemplate, this);
|
||||
CMasterTemplate::AddProperty(mSubProperties[iSub]);
|
||||
}
|
||||
}
|
||||
|
||||
u32 CStructTemplate::PropertyCountForVersion(u32 Version)
|
||||
{
|
||||
if (Version == -1) Version = 0;
|
||||
return mVersionPropertyCounts[Version];
|
||||
}
|
||||
|
||||
u32 CStructTemplate::VersionForPropertyCount(u32 PropCount)
|
||||
{
|
||||
for (u32 iVer = 0; iVer < NumVersions(); iVer++)
|
||||
if (mVersionPropertyCounts[iVer] == PropCount)
|
||||
return iVer;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
IPropertyTemplate* CStructTemplate::PropertyByIndex(u32 index)
|
||||
{
|
||||
if (mSubProperties.size() > index)
|
||||
return mSubProperties[index];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IPropertyTemplate* CStructTemplate::PropertyByID(u32 ID)
|
||||
{
|
||||
for (auto it = mSubProperties.begin(); it != mSubProperties.end(); it++)
|
||||
{
|
||||
if ((*it)->PropertyID() == ID)
|
||||
return *it;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IPropertyTemplate* CStructTemplate::PropertyByIDString(const TIDString& str)
|
||||
{
|
||||
// Resolve namespace
|
||||
u32 nsStart = str.IndexOf(":");
|
||||
u32 propStart = nsStart + 1;
|
||||
|
||||
// String has namespace; the requested property is within a struct
|
||||
if (nsStart != -1)
|
||||
{
|
||||
TString strStructID = str.SubString(0, nsStart);
|
||||
if (!strStructID.IsHexString()) return nullptr;
|
||||
|
||||
u32 structID = strStructID.ToInt32();
|
||||
TString propName = str.SubString(propStart, str.Length() - propStart);
|
||||
|
||||
CStructTemplate *pStruct = StructByID(structID);
|
||||
if (!pStruct) return nullptr;
|
||||
else return pStruct->PropertyByIDString(propName);
|
||||
}
|
||||
|
||||
// No namespace; fetch the property from this struct
|
||||
else
|
||||
{
|
||||
// ID string lookup
|
||||
if (str.IsHexString())
|
||||
return PropertyByID(str.ToInt32());
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CStructTemplate* CStructTemplate::StructByIndex(u32 index)
|
||||
{
|
||||
IPropertyTemplate *pProp = PropertyByIndex(index);
|
||||
|
||||
if (pProp->Type() == eStructProperty)
|
||||
return static_cast<CStructTemplate*>(pProp);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CStructTemplate* CStructTemplate::StructByID(u32 ID)
|
||||
{
|
||||
IPropertyTemplate *pProp = PropertyByID(ID);
|
||||
|
||||
if (pProp && pProp->Type() == eStructProperty)
|
||||
return static_cast<CStructTemplate*>(pProp);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CStructTemplate* CStructTemplate::StructByIDString(const TString& str)
|
||||
{
|
||||
IPropertyTemplate *pProp = PropertyByIDString(str);
|
||||
|
||||
if (pProp && pProp->Type() == eStructProperty)
|
||||
return static_cast<CStructTemplate*>(pProp);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CStructTemplate::HasProperty(const TIDString& rkIdString)
|
||||
{
|
||||
IPropertyTemplate *pProperty = PropertyByIDString(rkIdString);
|
||||
return (pProperty != nullptr);
|
||||
}
|
||||
|
||||
void CStructTemplate::DetermineVersionPropertyCounts()
|
||||
{
|
||||
for (u32 iVer = 0; iVer < mVersionPropertyCounts.size(); iVer++)
|
||||
{
|
||||
mVersionPropertyCounts[iVer] = 0;
|
||||
|
||||
for (u32 iProp = 0; iProp < mSubProperties.size(); iProp++)
|
||||
{
|
||||
if (mSubProperties[iProp]->IsInVersion(iVer) && mSubProperties[iProp]->CookPreference() != eNeverCook)
|
||||
mVersionPropertyCounts[iVer]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ************ GLOBAL FUNCTIONS ************
|
||||
TString PropEnumToPropString(EPropertyType Prop)
|
||||
{
|
||||
switch (Prop)
|
||||
{
|
||||
case eBoolProperty: return "bool";
|
||||
case eByteProperty: return "byte";
|
||||
case eShortProperty: return "short";
|
||||
case eLongProperty: return "long";
|
||||
case eEnumProperty: return "enum";
|
||||
case eBitfieldProperty: return "bitfield";
|
||||
case eFloatProperty: return "float";
|
||||
case eStringProperty: return "string";
|
||||
case eColorProperty: return "color";
|
||||
case eVector3Property: return "vector3f";
|
||||
case eSoundProperty: return "sound";
|
||||
case eAssetProperty: return "asset";
|
||||
case eStructProperty: return "struct";
|
||||
case eArrayProperty: return "array";
|
||||
case eCharacterProperty: return "character";
|
||||
case eMayaSplineProperty: return "MayaSpline";
|
||||
case eUnknownProperty: return "unknown";
|
||||
|
||||
case eInvalidProperty:
|
||||
default:
|
||||
return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
EPropertyType PropStringToPropEnum(TString Prop)
|
||||
{
|
||||
Prop = Prop.ToLower();
|
||||
if (Prop == "bool") return eBoolProperty;
|
||||
if (Prop == "byte") return eByteProperty;
|
||||
if (Prop == "short") return eShortProperty;
|
||||
if (Prop == "long") return eLongProperty;
|
||||
if (Prop == "enum") return eEnumProperty;
|
||||
if (Prop == "bitfield") return eBitfieldProperty;
|
||||
if (Prop == "float") return eFloatProperty;
|
||||
if (Prop == "string") return eStringProperty;
|
||||
if (Prop == "color") return eColorProperty;
|
||||
if (Prop == "vector3f") return eVector3Property;
|
||||
if (Prop == "sound") return eSoundProperty;
|
||||
if (Prop == "asset") return eAssetProperty;
|
||||
if (Prop == "struct") return eStructProperty;
|
||||
if (Prop == "array") return eArrayProperty;
|
||||
if (Prop == "character") return eCharacterProperty;
|
||||
if (Prop == "mayaspline") return eMayaSplineProperty;
|
||||
if (Prop == "unknown") return eUnknownProperty;
|
||||
return eInvalidProperty;
|
||||
}
|
||||
|
||||
// ************ DEBUG ************
|
||||
void CStructTemplate::DebugPrintProperties(TString base)
|
||||
{
|
||||
base = base + Name() + "::";
|
||||
for (auto it = mSubProperties.begin(); it != mSubProperties.end(); it++)
|
||||
{
|
||||
IPropertyTemplate *tmp = *it;
|
||||
if (tmp->Type() == eStructProperty)
|
||||
{
|
||||
CStructTemplate *tmp2 = static_cast<CStructTemplate*>(tmp);
|
||||
tmp2->DebugPrintProperties(base);
|
||||
}
|
||||
else
|
||||
Log::Write(base + tmp->Name());
|
||||
}
|
||||
}
|
||||
@@ -1,763 +0,0 @@
|
||||
#ifndef IPROPERTYTEMPLATE
|
||||
#define IPROPERTYTEMPLATE
|
||||
|
||||
#include "EPropertyType.h"
|
||||
#include "IProperty.h"
|
||||
#include "IPropertyValue.h"
|
||||
#include "Core/Resource/CResTypeFilter.h"
|
||||
#include "Core/Resource/Animation/CAnimationParameters.h"
|
||||
#include <Common/CColor.h>
|
||||
#include <Common/TString.h>
|
||||
#include <Common/types.h>
|
||||
#include <Math/CVector3f.h>
|
||||
#include <vector>
|
||||
|
||||
typedef TString TIDString;
|
||||
class CMasterTemplate;
|
||||
class CStructTemplate;
|
||||
class IProperty;
|
||||
|
||||
enum ECookPreference
|
||||
{
|
||||
eNoCookPreference,
|
||||
eAlwaysCook,
|
||||
eNeverCook
|
||||
};
|
||||
|
||||
// IPropertyTemplate - Base class. Contains basic info that every property has,
|
||||
// plus virtual functions for determining more specific property type.
|
||||
class IPropertyTemplate
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
protected:
|
||||
CStructTemplate *mpParent;
|
||||
CScriptTemplate *mpScriptTemplate;
|
||||
CMasterTemplate *mpMasterTemplate;
|
||||
TString mName;
|
||||
TString mDescription;
|
||||
u32 mID;
|
||||
ECookPreference mCookPreference;
|
||||
std::vector<u32> mAllowedVersions;
|
||||
|
||||
public:
|
||||
IPropertyTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: mID(ID)
|
||||
, mpParent(pParent)
|
||||
, mpScriptTemplate(pScript)
|
||||
, mpMasterTemplate(pMaster)
|
||||
, mName("UNSET PROPERTY NAME")
|
||||
, mCookPreference(eNoCookPreference)
|
||||
{
|
||||
}
|
||||
|
||||
IPropertyTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: mID(ID)
|
||||
, mpParent(pParent)
|
||||
, mpScriptTemplate(pScript)
|
||||
, mpMasterTemplate(pMaster)
|
||||
, mName(rkName)
|
||||
, mCookPreference(CookPreference)
|
||||
{
|
||||
}
|
||||
|
||||
virtual EPropertyType Type() const = 0;
|
||||
virtual bool CanHaveDefault() const = 0;
|
||||
virtual bool IsNumerical() const = 0;
|
||||
virtual IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent) = 0;
|
||||
virtual IPropertyTemplate* Clone(CScriptTemplate *pScript, CStructTemplate *pParent = 0) const = 0;
|
||||
|
||||
virtual void Copy(const IPropertyTemplate *pkTemp)
|
||||
{
|
||||
mName = pkTemp->mName;
|
||||
mDescription = pkTemp->mDescription;
|
||||
mID = pkTemp->mID;
|
||||
mCookPreference = pkTemp->mCookPreference;
|
||||
mAllowedVersions = pkTemp->mAllowedVersions;
|
||||
}
|
||||
|
||||
virtual bool Matches(const IPropertyTemplate *pkTemp) const
|
||||
{
|
||||
return ( (pkTemp != nullptr) &&
|
||||
(mName == pkTemp->mName) &&
|
||||
(mDescription == pkTemp->mDescription) &&
|
||||
(mID == pkTemp->mID) &&
|
||||
(mCookPreference == pkTemp->mCookPreference) &&
|
||||
(mAllowedVersions == pkTemp->mAllowedVersions) &&
|
||||
(Type() == pkTemp->Type()) );
|
||||
}
|
||||
|
||||
virtual TString DefaultToString() const { return ""; }
|
||||
virtual const IPropertyValue* RawDefaultValue() const { return nullptr; }
|
||||
virtual bool HasValidRange() const { return false; }
|
||||
virtual TString RangeToString() const { return ""; }
|
||||
virtual TString Suffix() const { return ""; }
|
||||
|
||||
virtual void SetParam(const TString& rkParamName, const TString& rkValue)
|
||||
{
|
||||
if (rkParamName == "cook_pref")
|
||||
{
|
||||
TString lValue = rkValue.ToLower();
|
||||
|
||||
if (lValue == "always")
|
||||
mCookPreference = eAlwaysCook;
|
||||
else if (lValue == "never")
|
||||
mCookPreference = eNeverCook;
|
||||
else
|
||||
mCookPreference = eNoCookPreference;
|
||||
}
|
||||
|
||||
else if (rkParamName == "description")
|
||||
mDescription = rkValue;
|
||||
}
|
||||
|
||||
EGame Game() const;
|
||||
bool IsInVersion(u32 Version) const;
|
||||
TString FullName() const;
|
||||
TIDString IDString(bool FullPath) const;
|
||||
bool IsDescendantOf(const CStructTemplate *pStruct) const;
|
||||
bool IsFromStructTemplate() const;
|
||||
TString FindStructSource() const;
|
||||
CStructTemplate* RootStruct();
|
||||
|
||||
// Inline Accessors
|
||||
inline TString Name() const { return mName; }
|
||||
inline TString Description() const { return mDescription; }
|
||||
inline u32 PropertyID() const { return mID; }
|
||||
inline ECookPreference CookPreference() const { return mCookPreference; }
|
||||
inline CStructTemplate* Parent() const { return mpParent; }
|
||||
inline CScriptTemplate* ScriptTemplate() const { return mpScriptTemplate; }
|
||||
inline CMasterTemplate* MasterTemplate() const { return mpMasterTemplate; }
|
||||
inline void SetName(const TString& rkName) { mName = rkName; }
|
||||
inline void SetDescription(const TString& rkDesc) { mDescription = rkDesc; }
|
||||
};
|
||||
|
||||
// Macro for defining reimplementations of IPropertyTemplate::Clone(), which are usually identical to each other aside from the class being instantiated
|
||||
#define IMPLEMENT_TEMPLATE_CLONE(ClassName) \
|
||||
virtual IPropertyTemplate* Clone(CScriptTemplate *pScript, CStructTemplate *pParent = 0) const \
|
||||
{ \
|
||||
if (!pParent) pParent = mpParent; \
|
||||
if (!pScript) pScript = mpScriptTemplate; \
|
||||
ClassName *pTemp = new ClassName(mID, pScript, mpMasterTemplate, pParent); \
|
||||
pTemp->Copy(this); \
|
||||
return pTemp; \
|
||||
}
|
||||
|
||||
// TTypedPropertyTemplate - Template property class that allows for tracking
|
||||
// a default value. Typedefs are set up for a bunch of property types.
|
||||
template<typename PropType, EPropertyType PropTypeEnum, class ValueClass, bool CanHaveDefaultValue>
|
||||
class TTypedPropertyTemplate : public IPropertyTemplate
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
protected:
|
||||
ValueClass mDefaultValue;
|
||||
|
||||
public:
|
||||
TTypedPropertyTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: IPropertyTemplate(ID, pScript, pMaster, pParent) {}
|
||||
|
||||
TTypedPropertyTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: IPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {}
|
||||
|
||||
virtual EPropertyType Type() const { return PropTypeEnum; }
|
||||
virtual bool CanHaveDefault() const { return CanHaveDefaultValue; }
|
||||
virtual bool IsNumerical() const { return false; }
|
||||
|
||||
virtual IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
{
|
||||
typedef TTypedProperty<PropType, PropTypeEnum, ValueClass> TPropertyType;
|
||||
TPropertyType *pOut = new TPropertyType(this, pInstance, pParent, GetDefaultValue());
|
||||
return pOut;
|
||||
}
|
||||
|
||||
IMPLEMENT_TEMPLATE_CLONE(TTypedPropertyTemplate)
|
||||
|
||||
virtual void Copy(const IPropertyTemplate *pkTemp)
|
||||
{
|
||||
IPropertyTemplate::Copy(pkTemp);
|
||||
mDefaultValue.Copy(&static_cast<const TTypedPropertyTemplate*>(pkTemp)->mDefaultValue);
|
||||
}
|
||||
|
||||
virtual bool Matches(const IPropertyTemplate *pkTemp) const
|
||||
{
|
||||
const TTypedPropertyTemplate *pkTyped = static_cast<const TTypedPropertyTemplate*>(pkTemp);
|
||||
|
||||
return ( (IPropertyTemplate::Matches(pkTemp)) &&
|
||||
(mDefaultValue.Matches(&pkTyped->mDefaultValue)) );
|
||||
}
|
||||
|
||||
virtual TString DefaultToString() const
|
||||
{
|
||||
return mDefaultValue.ToString();
|
||||
}
|
||||
|
||||
virtual const IPropertyValue* RawDefaultValue() const
|
||||
{
|
||||
return &mDefaultValue;
|
||||
}
|
||||
|
||||
virtual void SetParam(const TString& rkParamName, const TString& rkValue)
|
||||
{
|
||||
IPropertyTemplate::SetParam(rkParamName, rkValue);
|
||||
|
||||
if (rkParamName == "default")
|
||||
mDefaultValue.FromString(rkValue.ToLower());
|
||||
}
|
||||
|
||||
inline PropType GetDefaultValue() const { return mDefaultValue.Get(); }
|
||||
inline void SetDefaultValue(const PropType& rkIn) { mDefaultValue.Set(rkIn); }
|
||||
};
|
||||
|
||||
// TNumericalPropertyTemplate - Subclass of TTypedPropertyTemplate for numerical
|
||||
// property types, and allows a min/max value and a suffix to be tracked.
|
||||
template<typename PropType, EPropertyType PropTypeEnum, class ValueClass>
|
||||
class TNumericalPropertyTemplate : public TTypedPropertyTemplate<PropType,PropTypeEnum,ValueClass,true>
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
ValueClass mMin;
|
||||
ValueClass mMax;
|
||||
TString mSuffix;
|
||||
|
||||
public:
|
||||
TNumericalPropertyTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, pScript, pMaster, pParent)
|
||||
{}
|
||||
|
||||
TNumericalPropertyTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent)
|
||||
, mMin(0)
|
||||
, mMax(0)
|
||||
{}
|
||||
|
||||
virtual bool IsNumerical() const { return true; }
|
||||
virtual bool HasValidRange() const { return (mMin != 0 || mMax != 0); }
|
||||
|
||||
IMPLEMENT_TEMPLATE_CLONE(TNumericalPropertyTemplate)
|
||||
|
||||
virtual void Copy(const IPropertyTemplate *pkTemp)
|
||||
{
|
||||
TTypedPropertyTemplate::Copy(pkTemp);
|
||||
|
||||
const TNumericalPropertyTemplate *pkNumerical = static_cast<const TNumericalPropertyTemplate*>(pkTemp);
|
||||
mMin.Copy(&pkNumerical->mMin);
|
||||
mMax.Copy(&pkNumerical->mMax);
|
||||
mSuffix = pkNumerical->mSuffix;
|
||||
}
|
||||
|
||||
virtual bool Matches(const IPropertyTemplate *pkTemp) const
|
||||
{
|
||||
const TNumericalPropertyTemplate *pkNumerical = static_cast<const TNumericalPropertyTemplate*>(pkTemp);
|
||||
|
||||
return ( (TTypedPropertyTemplate::Matches(pkTemp)) &&
|
||||
(mMin.Matches(&pkNumerical->mMin)) &&
|
||||
(mMax.Matches(&pkNumerical->mMax)) &&
|
||||
(mSuffix == pkNumerical->mSuffix) );
|
||||
}
|
||||
|
||||
virtual TString RangeToString() const
|
||||
{
|
||||
return mMin.ToString() + "," + mMax.ToString();
|
||||
}
|
||||
|
||||
virtual void SetParam(const TString& rkParamName, const TString& rkValue)
|
||||
{
|
||||
TTypedPropertyTemplate::SetParam(rkParamName, rkValue);
|
||||
|
||||
if (rkParamName == "range")
|
||||
{
|
||||
TStringList Components = rkValue.ToLower().Split(", ");
|
||||
|
||||
if (Components.size() == 2)
|
||||
{
|
||||
mMin.FromString(Components.front());
|
||||
mMax.FromString(Components.back());
|
||||
}
|
||||
}
|
||||
|
||||
else if (rkParamName == "suffix")
|
||||
{
|
||||
mSuffix = rkValue;
|
||||
}
|
||||
}
|
||||
|
||||
virtual TString Suffix() const { return mSuffix; }
|
||||
inline PropType GetMin() const { return mMin.Get(); }
|
||||
inline PropType GetMax() const { return mMax.Get(); }
|
||||
|
||||
inline void SetRange(const PropType& rkMin, const PropType& rkMax)
|
||||
{
|
||||
mMin.Set(rkMin);
|
||||
mMax.Set(rkMax);
|
||||
}
|
||||
|
||||
inline void SetSuffix(const TString& rkSuffix)
|
||||
{
|
||||
mSuffix = rkSuffix;
|
||||
}
|
||||
};
|
||||
|
||||
// Typedefs for all property types that don't need further functionality.
|
||||
typedef TTypedPropertyTemplate<bool, eBoolProperty, CBoolValue, true> TBoolTemplate;
|
||||
typedef TNumericalPropertyTemplate<s8, eByteProperty, CByteValue> TByteTemplate;
|
||||
typedef TNumericalPropertyTemplate<s16, eShortProperty, CShortValue> TShortTemplate;
|
||||
typedef TNumericalPropertyTemplate<s32, eLongProperty, CLongValue> TLongTemplate;
|
||||
typedef TNumericalPropertyTemplate<float, eFloatProperty, CFloatValue> TFloatTemplate;
|
||||
typedef TTypedPropertyTemplate<CVector3f, eVector3Property, CVector3Value, true> TVector3Template;
|
||||
typedef TTypedPropertyTemplate<CColor, eColorProperty, CColorValue, true> TColorTemplate;
|
||||
|
||||
// TCharacterTemplate, TSoundTemplate, TStringTemplate, and TMayaSplineTemplate get their own subclasses so they can reimplement a couple functions
|
||||
class TCharacterTemplate : public TTypedPropertyTemplate<CAnimationParameters, eCharacterProperty, CCharacterValue, false>
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
public:
|
||||
TCharacterTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, pScript, pMaster, pParent) {}
|
||||
|
||||
TCharacterTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {}
|
||||
|
||||
IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
{
|
||||
return new TCharacterProperty(this, pInstance, pParent, CAnimationParameters(Game()));
|
||||
}
|
||||
};
|
||||
|
||||
class TSoundTemplate : public TTypedPropertyTemplate<u32, eSoundProperty, CSoundValue, false>
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
public:
|
||||
TSoundTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, pScript, pMaster, pParent) {}
|
||||
|
||||
TSoundTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {}
|
||||
|
||||
IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
{
|
||||
return new TSoundProperty(this, pInstance, pParent, -1);
|
||||
}
|
||||
};
|
||||
|
||||
class TStringTemplate : public TTypedPropertyTemplate<TString, eStringProperty, CStringValue, false>
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
public:
|
||||
TStringTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, pScript, pMaster, pParent) {}
|
||||
|
||||
TStringTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {}
|
||||
|
||||
IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
{
|
||||
return new TStringProperty(this, pInstance, pParent);
|
||||
}
|
||||
};
|
||||
|
||||
class TMayaSplineTemplate : public TTypedPropertyTemplate<std::vector<u8>, eMayaSplineProperty, CMayaSplineValue, false>
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
public:
|
||||
TMayaSplineTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, pScript, pMaster, pParent) {}
|
||||
|
||||
TMayaSplineTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {}
|
||||
|
||||
IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
{
|
||||
return new TMayaSplineProperty(this, pInstance, pParent);
|
||||
}
|
||||
};
|
||||
|
||||
// CAssetTemplate - Property template for assets. Tracks a list of resource types that
|
||||
// the property is allowed to accept.
|
||||
class CAssetTemplate : public IPropertyTemplate
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
CResTypeFilter mTypeFilter;
|
||||
public:
|
||||
CAssetTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: IPropertyTemplate(ID, pScript, pMaster, pParent) {}
|
||||
|
||||
CAssetTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: IPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) {}
|
||||
|
||||
virtual EPropertyType Type() const { return eAssetProperty; }
|
||||
virtual bool CanHaveDefault() const { return false; }
|
||||
virtual bool IsNumerical() const { return false; }
|
||||
|
||||
IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
{
|
||||
return new TAssetProperty(this, pInstance, pParent);
|
||||
}
|
||||
|
||||
IMPLEMENT_TEMPLATE_CLONE(CAssetTemplate)
|
||||
|
||||
virtual void Copy(const IPropertyTemplate *pkTemp)
|
||||
{
|
||||
IPropertyTemplate::Copy(pkTemp);
|
||||
mTypeFilter = static_cast<const CAssetTemplate*>(pkTemp)->mTypeFilter;
|
||||
}
|
||||
|
||||
virtual bool Matches(const IPropertyTemplate *pkTemp) const
|
||||
{
|
||||
const CAssetTemplate *pkAsset = static_cast<const CAssetTemplate*>(pkTemp);
|
||||
|
||||
return ( (IPropertyTemplate::Matches(pkTemp)) &&
|
||||
(mTypeFilter == pkAsset->mTypeFilter) );
|
||||
}
|
||||
|
||||
void SetTypeFilter(const TStringList& rkExtensions) { mTypeFilter.SetAcceptedTypes(Game(), rkExtensions); }
|
||||
const CResTypeFilter& TypeFilter() const { return mTypeFilter; }
|
||||
};
|
||||
|
||||
// CEnumTemplate - Property template for enums. Tracks a list of possible values (enumerators).
|
||||
class CEnumTemplate : public TTypedPropertyTemplate<s32, eEnumProperty, CHexLongValue, true>
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
struct SEnumerator
|
||||
{
|
||||
TString Name;
|
||||
u32 ID;
|
||||
|
||||
SEnumerator(const TString& rkName, u32 _ID)
|
||||
: Name(rkName), ID(_ID) {}
|
||||
|
||||
bool operator==(const SEnumerator& rkOther) const
|
||||
{
|
||||
return ( (Name == rkOther.Name) && (ID == rkOther.ID) );
|
||||
}
|
||||
};
|
||||
std::vector<SEnumerator> mEnumerators;
|
||||
TString mSourceFile;
|
||||
|
||||
public:
|
||||
CEnumTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, pScript, pMaster, pParent)
|
||||
{
|
||||
}
|
||||
|
||||
CEnumTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent)
|
||||
{
|
||||
}
|
||||
|
||||
virtual EPropertyType Type() const { return eEnumProperty; }
|
||||
virtual bool CanHaveDefault() const { return true; }
|
||||
virtual bool IsNumerical() const { return false; }
|
||||
|
||||
virtual IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
{
|
||||
TEnumProperty *pEnum = new TEnumProperty(this, pInstance, pParent);
|
||||
pEnum->Set(GetDefaultValue());
|
||||
return pEnum;
|
||||
}
|
||||
|
||||
IMPLEMENT_TEMPLATE_CLONE(CEnumTemplate)
|
||||
|
||||
virtual void Copy(const IPropertyTemplate *pkTemp)
|
||||
{
|
||||
TTypedPropertyTemplate::Copy(pkTemp);
|
||||
|
||||
const CEnumTemplate *pkEnum = static_cast<const CEnumTemplate*>(pkTemp);
|
||||
mEnumerators = pkEnum->mEnumerators;
|
||||
mSourceFile = pkEnum->mSourceFile;
|
||||
}
|
||||
|
||||
virtual bool Matches(const IPropertyTemplate *pkTemp) const
|
||||
{
|
||||
const CEnumTemplate *pkEnum = static_cast<const CEnumTemplate*>(pkTemp);
|
||||
|
||||
return ( (TTypedPropertyTemplate::Matches(pkTemp)) &&
|
||||
(mEnumerators == pkEnum->mEnumerators) &&
|
||||
(mSourceFile == pkEnum->mSourceFile) );
|
||||
}
|
||||
|
||||
inline TString SourceFile() const { return mSourceFile; }
|
||||
inline u32 NumEnumerators() const { return mEnumerators.size(); }
|
||||
|
||||
u32 EnumeratorIndex(u32 enumID) const
|
||||
{
|
||||
for (u32 iEnum = 0; iEnum < mEnumerators.size(); iEnum++)
|
||||
{
|
||||
if (mEnumerators[iEnum].ID == enumID)
|
||||
return iEnum;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
u32 EnumeratorID(u32 enumIndex) const
|
||||
{
|
||||
if (mEnumerators.size() > enumIndex)
|
||||
return mEnumerators[enumIndex].ID;
|
||||
|
||||
else return -1;
|
||||
}
|
||||
|
||||
TString EnumeratorName(u32 enumIndex) const
|
||||
{
|
||||
if (mEnumerators.size() > enumIndex)
|
||||
return mEnumerators[enumIndex].Name;
|
||||
|
||||
else return "INVALID ENUM INDEX";
|
||||
}
|
||||
};
|
||||
|
||||
// CBitfieldTemplate - Property template for bitfields, which can have multiple
|
||||
// distinct boolean parameters packed into one property.
|
||||
class CBitfieldTemplate : public TTypedPropertyTemplate<u32, eBitfieldProperty, CHexLongValue, true>
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
struct SBitFlag
|
||||
{
|
||||
TString Name;
|
||||
u32 Mask;
|
||||
|
||||
SBitFlag(const TString& _name, u32 _mask)
|
||||
: Name(_name), Mask(_mask) {}
|
||||
|
||||
bool operator==(const SBitFlag& rkOther) const
|
||||
{
|
||||
return ( (Name == rkOther.Name) && (Mask == rkOther.Mask) );
|
||||
}
|
||||
};
|
||||
std::vector<SBitFlag> mBitFlags;
|
||||
TString mSourceFile;
|
||||
|
||||
public:
|
||||
CBitfieldTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, pScript, pMaster, pParent)
|
||||
{
|
||||
}
|
||||
|
||||
CBitfieldTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent)
|
||||
{
|
||||
}
|
||||
|
||||
virtual EPropertyType Type() const { return eBitfieldProperty; }
|
||||
virtual bool CanHaveDefault() const { return true; }
|
||||
virtual bool IsNumerical() const { return false; }
|
||||
|
||||
virtual IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
{
|
||||
TBitfieldProperty *pBitfield = new TBitfieldProperty(this, pInstance, pParent);
|
||||
pBitfield->Set(GetDefaultValue());
|
||||
return pBitfield;
|
||||
}
|
||||
|
||||
IMPLEMENT_TEMPLATE_CLONE(CBitfieldTemplate)
|
||||
|
||||
virtual void Copy(const IPropertyTemplate *pkTemp)
|
||||
{
|
||||
TTypedPropertyTemplate::Copy(pkTemp);
|
||||
|
||||
const CBitfieldTemplate *pkBitfield = static_cast<const CBitfieldTemplate*>(pkTemp);
|
||||
mBitFlags = pkBitfield->mBitFlags;
|
||||
mSourceFile = pkBitfield->mSourceFile;
|
||||
}
|
||||
|
||||
virtual bool Matches(const IPropertyTemplate *pkTemp) const
|
||||
{
|
||||
const CBitfieldTemplate *pkBitfield = static_cast<const CBitfieldTemplate*>(pkTemp);
|
||||
|
||||
return ( (TTypedPropertyTemplate::Matches(pkTemp)) &&
|
||||
(mBitFlags == pkBitfield->mBitFlags) &&
|
||||
(mSourceFile == pkBitfield->mSourceFile) );
|
||||
}
|
||||
|
||||
inline TString SourceFile() const { return mSourceFile; }
|
||||
inline u32 NumFlags() const { return mBitFlags.size(); }
|
||||
inline TString FlagName(u32 index) const { return mBitFlags[index].Name; }
|
||||
inline u32 FlagMask(u32 index) const { return mBitFlags[index].Mask; }
|
||||
};
|
||||
|
||||
// CStructTemplate - Defines structs composed of multiple sub-properties.
|
||||
class CStructTemplate : public IPropertyTemplate
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
|
||||
protected:
|
||||
std::vector<IPropertyTemplate*> mSubProperties;
|
||||
std::vector<u32> mVersionPropertyCounts;
|
||||
bool mIsSingleProperty;
|
||||
TString mSourceFile;
|
||||
|
||||
void DetermineVersionPropertyCounts();
|
||||
public:
|
||||
CStructTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: IPropertyTemplate(ID, pScript, pMaster, pParent)
|
||||
, mIsSingleProperty(false) {}
|
||||
|
||||
CStructTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: IPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent)
|
||||
, mIsSingleProperty(false) {}
|
||||
|
||||
~CStructTemplate()
|
||||
{
|
||||
for (auto it = mSubProperties.begin(); it != mSubProperties.end(); it++)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
EPropertyType Type() const { return eStructProperty; }
|
||||
bool CanHaveDefault() const { return false; }
|
||||
bool IsNumerical() const { return false; }
|
||||
|
||||
IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
{
|
||||
CPropertyStruct *pStruct = new CPropertyStruct(this, pInstance, pParent);
|
||||
|
||||
for (u32 iSub = 0; iSub < mSubProperties.size(); iSub++)
|
||||
{
|
||||
IProperty *pSubProp = mSubProperties[iSub]->InstantiateProperty(pInstance, pStruct);
|
||||
pStruct->AddSubProperty(pSubProp);
|
||||
}
|
||||
|
||||
return pStruct;
|
||||
}
|
||||
|
||||
IMPLEMENT_TEMPLATE_CLONE(CStructTemplate)
|
||||
|
||||
virtual void Copy(const IPropertyTemplate *pkTemp)
|
||||
{
|
||||
IPropertyTemplate::Copy(pkTemp);
|
||||
|
||||
const CStructTemplate *pkStruct = static_cast<const CStructTemplate*>(pkTemp);
|
||||
CopyStructData(pkStruct);
|
||||
}
|
||||
|
||||
void CopyStructData(const CStructTemplate *pkStruct);
|
||||
|
||||
virtual bool Matches(const IPropertyTemplate *pkTemp) const
|
||||
{
|
||||
const CStructTemplate *pkStruct = static_cast<const CStructTemplate*>(pkTemp);
|
||||
|
||||
if ( (IPropertyTemplate::Matches(pkTemp)) &&
|
||||
(mVersionPropertyCounts == pkStruct->mVersionPropertyCounts) &&
|
||||
(mIsSingleProperty == pkStruct->mIsSingleProperty) &&
|
||||
(mSourceFile == pkStruct->mSourceFile) )
|
||||
{
|
||||
return StructDataMatches(pkStruct);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StructDataMatches(const CStructTemplate *pkStruct) const
|
||||
{
|
||||
if ( (mIsSingleProperty == pkStruct->mIsSingleProperty) &&
|
||||
(mSubProperties.size() == pkStruct->mSubProperties.size()) )
|
||||
{
|
||||
for (u32 iSub = 0; iSub < mSubProperties.size(); iSub++)
|
||||
{
|
||||
if (!mSubProperties[iSub]->Matches(pkStruct->mSubProperties[iSub]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline TString SourceFile() const { return mSourceFile; }
|
||||
inline bool IsSingleProperty() const { return mIsSingleProperty; }
|
||||
inline u32 Count() const { return mSubProperties.size(); }
|
||||
inline u32 NumVersions() const { return mVersionPropertyCounts.size(); }
|
||||
|
||||
u32 PropertyCountForVersion(u32 Version);
|
||||
u32 VersionForPropertyCount(u32 PropCount);
|
||||
IPropertyTemplate* PropertyByIndex(u32 index);
|
||||
IPropertyTemplate* PropertyByID(u32 ID);
|
||||
IPropertyTemplate* PropertyByIDString(const TIDString& str);
|
||||
CStructTemplate* StructByIndex(u32 index);
|
||||
CStructTemplate* StructByID(u32 ID);
|
||||
CStructTemplate* StructByIDString(const TIDString& str);
|
||||
bool HasProperty(const TIDString& rkIdString);
|
||||
void DebugPrintProperties(TString base);
|
||||
};
|
||||
|
||||
// CArrayTemplate - Defines a repeating struct composed of multiple sub-properties.
|
||||
// Similar to CStructTemplate, but with new implementations of Type() and InstantiateProperty().
|
||||
class CArrayTemplate : public CStructTemplate
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class CTemplateWriter;
|
||||
TString mElementName;
|
||||
|
||||
public:
|
||||
CArrayTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: CStructTemplate(ID, pScript, pMaster, pParent)
|
||||
{
|
||||
mIsSingleProperty = true;
|
||||
}
|
||||
|
||||
CArrayTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0)
|
||||
: CStructTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent)
|
||||
{
|
||||
mIsSingleProperty = true;
|
||||
}
|
||||
|
||||
EPropertyType Type() const { return eArrayProperty; }
|
||||
|
||||
IProperty* InstantiateProperty(CScriptObject *pInstance, CPropertyStruct *pParent)
|
||||
{
|
||||
return new CArrayProperty(this, pInstance, pParent);
|
||||
}
|
||||
|
||||
IMPLEMENT_TEMPLATE_CLONE(CArrayTemplate)
|
||||
|
||||
virtual void Copy(const IPropertyTemplate *pkTemp)
|
||||
{
|
||||
CStructTemplate::Copy(pkTemp);
|
||||
mElementName = static_cast<const CArrayTemplate*>(pkTemp)->mElementName;
|
||||
}
|
||||
|
||||
virtual bool Matches(const IPropertyTemplate *pkTemp) const
|
||||
{
|
||||
const CArrayTemplate *pkArray = static_cast<const CArrayTemplate*>(pkTemp);
|
||||
|
||||
return ( (mElementName == pkArray->mElementName) &
|
||||
(CStructTemplate::Matches(pkTemp)) );
|
||||
}
|
||||
|
||||
void SetParam(const TString& rkParamName, const TString& rkValue)
|
||||
{
|
||||
if (rkParamName == "element_name")
|
||||
mElementName = rkValue;
|
||||
else
|
||||
CStructTemplate::SetParam(rkParamName, rkValue);
|
||||
}
|
||||
|
||||
TString ElementName() const { return mElementName; }
|
||||
void SetElementName(const TString& rkName) { mElementName = rkName; }
|
||||
|
||||
CPropertyStruct* CreateSubStruct(CScriptObject *pInstance, CArrayProperty *pArray)
|
||||
{
|
||||
return (CPropertyStruct*) CStructTemplate::InstantiateProperty(pInstance, pArray);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // IPROPERTYTEMPLATE
|
||||
|
||||
@@ -1,390 +0,0 @@
|
||||
#ifndef IPROPERTYVALUE_H
|
||||
#define IPROPERTYVALUE_H
|
||||
|
||||
#include "EPropertyType.h"
|
||||
#include <Common/CAssetID.h>
|
||||
#include <Common/Log.h>
|
||||
#include "Core/Resource/Animation/CAnimationParameters.h"
|
||||
#include "Core/Resource/CResource.h"
|
||||
#include "Core/Resource/TResPtr.h"
|
||||
|
||||
#include <Common/CColor.h>
|
||||
#include <Common/TString.h>
|
||||
#include <Math/CVector3f.h>
|
||||
|
||||
class IPropertyValue
|
||||
{
|
||||
public:
|
||||
virtual TString ToString() const = 0;
|
||||
virtual void FromString(const TString& rkString) = 0;
|
||||
virtual IPropertyValue* Clone() const = 0;
|
||||
virtual void Copy(const IPropertyValue *pkValue) = 0;
|
||||
virtual bool Matches(const IPropertyValue *pkValue) const = 0;
|
||||
};
|
||||
|
||||
template<typename PropType>
|
||||
class TTypedPropertyValue : public IPropertyValue
|
||||
{
|
||||
protected:
|
||||
PropType mValue;
|
||||
|
||||
public:
|
||||
TTypedPropertyValue() {}
|
||||
|
||||
TTypedPropertyValue(PropType rkVal)
|
||||
: mValue(rkVal) {}
|
||||
|
||||
virtual void Copy(const IPropertyValue *pkValue)
|
||||
{
|
||||
const TTypedPropertyValue *pkOther = static_cast<const TTypedPropertyValue*>(pkValue);
|
||||
mValue = pkOther->mValue;
|
||||
}
|
||||
|
||||
virtual bool Matches(const IPropertyValue *pkValue) const
|
||||
{
|
||||
const TTypedPropertyValue *pkOther = static_cast<const TTypedPropertyValue*>(pkValue);
|
||||
return ((pkValue != nullptr) && (mValue == pkOther->mValue));
|
||||
}
|
||||
|
||||
PropType Get() const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
void Set(const PropType& rkIn)
|
||||
{
|
||||
mValue = rkIn;
|
||||
}
|
||||
|
||||
bool operator==(const TTypedPropertyValue& rkOther) const
|
||||
{
|
||||
return (mValue == rkOther.mValue);
|
||||
}
|
||||
|
||||
bool operator==(const PropType& rkOther) const { return (mValue == rkOther); }
|
||||
bool operator!=(const PropType& rkOther) const { return (mValue != rkOther); }
|
||||
bool operator< (const PropType& rkOther) const { return (mValue < rkOther); }
|
||||
bool operator<=(const PropType& rkOther) const { return (mValue <= rkOther); }
|
||||
bool operator> (const PropType& rkOther) const { return (mValue > rkOther); }
|
||||
bool operator>=(const PropType& rkOther) const { return (mValue >= rkOther); }
|
||||
};
|
||||
|
||||
class CBoolValue : public TTypedPropertyValue<bool>
|
||||
{
|
||||
public:
|
||||
CBoolValue() { mValue = false; }
|
||||
CBoolValue(bool Val) { mValue = Val; }
|
||||
|
||||
TString ToString() const
|
||||
{
|
||||
return (!mValue ? "false" : "true");
|
||||
}
|
||||
|
||||
void FromString(const TString& rkString)
|
||||
{
|
||||
mValue = (rkString == "true");
|
||||
}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CBoolValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CByteValue : public TTypedPropertyValue<s8>
|
||||
{
|
||||
public:
|
||||
CByteValue() { mValue = 0; }
|
||||
CByteValue(s8 Val) { mValue = Val; }
|
||||
|
||||
TString ToString() const
|
||||
{
|
||||
return TString::FromInt32(mValue, 0, 10);
|
||||
}
|
||||
|
||||
void FromString(const TString& rkString)
|
||||
{
|
||||
u32 base = (rkString.StartsWith("0x") ? 16 : 10);
|
||||
mValue = (s8) rkString.ToInt32(base);
|
||||
}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CByteValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CShortValue : public TTypedPropertyValue<s16>
|
||||
{
|
||||
public:
|
||||
CShortValue() { mValue = 0; }
|
||||
CShortValue(s16 Val) { mValue = Val; }
|
||||
|
||||
TString ToString() const
|
||||
{
|
||||
return TString::FromInt32((s32) mValue, 0, 10);
|
||||
}
|
||||
|
||||
void FromString(const TString& rkString)
|
||||
{
|
||||
u32 base = (rkString.StartsWith("0x") ? 16 : 10);
|
||||
mValue = (s16) rkString.ToInt32(base);
|
||||
}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CShortValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CLongValue : public TTypedPropertyValue<s32>
|
||||
{
|
||||
public:
|
||||
CLongValue() { mValue = 0; }
|
||||
CLongValue(s32 Val) { mValue = Val; }
|
||||
|
||||
TString ToString() const
|
||||
{
|
||||
return TString::FromInt32(mValue, 0, 10);
|
||||
}
|
||||
|
||||
void FromString(const TString& rkString)
|
||||
{
|
||||
u32 base = (rkString.StartsWith("0x") ? 16 : 10);
|
||||
mValue = (s32) rkString.ToInt32(base);
|
||||
}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CLongValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CHexLongValue : public TTypedPropertyValue<u32>
|
||||
{
|
||||
public:
|
||||
CHexLongValue() { mValue = 0; }
|
||||
CHexLongValue(u32 Val) { mValue = Val; }
|
||||
|
||||
TString ToString() const
|
||||
{
|
||||
return TString::HexString(mValue, 8);
|
||||
}
|
||||
|
||||
void FromString(const TString& rkString)
|
||||
{
|
||||
u32 Base = (rkString.StartsWith("0x") ? 16 : 10);
|
||||
mValue = (s32) rkString.ToInt32(Base);
|
||||
}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CHexLongValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CFloatValue : public TTypedPropertyValue<float>
|
||||
{
|
||||
public:
|
||||
CFloatValue() { mValue = 0.0f; }
|
||||
CFloatValue(float Val) { mValue = Val; }
|
||||
|
||||
TString ToString() const
|
||||
{
|
||||
return TString::FromFloat(mValue);
|
||||
}
|
||||
|
||||
void FromString(const TString& rkString)
|
||||
{
|
||||
mValue = rkString.ToFloat();
|
||||
}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CFloatValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CStringValue : public TTypedPropertyValue<TString>
|
||||
{
|
||||
public:
|
||||
CStringValue() {}
|
||||
CStringValue(const TString& rkVal) { mValue = rkVal; }
|
||||
|
||||
// These functions are extremely complicated, but try to follow along
|
||||
TString ToString() const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
void FromString(const TString& rkString)
|
||||
{
|
||||
mValue = rkString;
|
||||
}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CStringValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CColorValue : public TTypedPropertyValue<CColor>
|
||||
{
|
||||
public:
|
||||
CColorValue() {}
|
||||
CColorValue(const CColor& rkVal) { mValue = rkVal; }
|
||||
|
||||
TString ToString() const
|
||||
{
|
||||
TString out;
|
||||
out += TString::FromFloat(mValue.R) + ", ";
|
||||
out += TString::FromFloat(mValue.G) + ", ";
|
||||
out += TString::FromFloat(mValue.B) + ", ";
|
||||
out += TString::FromFloat(mValue.A);
|
||||
return out;
|
||||
}
|
||||
|
||||
void FromString(const TString& rkString)
|
||||
{
|
||||
TStringList Components = rkString.Split(", ");
|
||||
|
||||
if (Components.size() < 3 || Components.size() > 4)
|
||||
{
|
||||
Log::Error("CColorValue::FromString was passed a string with an invalid number of components");
|
||||
mValue = CColor::skTransparentBlack;
|
||||
return;
|
||||
}
|
||||
|
||||
float *pPtr = &mValue.R;
|
||||
mValue.A = 1.0f;
|
||||
|
||||
for (auto it = Components.begin(); it != Components.end(); it++)
|
||||
{
|
||||
*pPtr = it->ToFloat();
|
||||
pPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CColorValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CVector3Value : public TTypedPropertyValue<CVector3f>
|
||||
{
|
||||
public:
|
||||
CVector3Value() {}
|
||||
CVector3Value(const CVector3f& rkVal) { mValue = rkVal; }
|
||||
|
||||
TString ToString() const
|
||||
{
|
||||
TString out;
|
||||
out += TString::FromFloat(mValue.X) + ", ";
|
||||
out += TString::FromFloat(mValue.Y) + ", ";
|
||||
out += TString::FromFloat(mValue.Z);
|
||||
return out;
|
||||
}
|
||||
|
||||
void FromString(const TString& rkString)
|
||||
{
|
||||
TStringList Components = rkString.Split(", ");
|
||||
|
||||
if (Components.size() != 3)
|
||||
{
|
||||
Log::Error("CVector3Value::FromString was passed a string with an invalid number of components");
|
||||
mValue = CVector3f::skInfinite;
|
||||
return;
|
||||
}
|
||||
|
||||
float *pPtr = &mValue.X;
|
||||
|
||||
for (auto it = Components.begin(); it != Components.end(); it++)
|
||||
{
|
||||
*pPtr = it->ToFloat();
|
||||
pPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CVector3Value(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CCharacterValue : public TTypedPropertyValue<CAnimationParameters>
|
||||
{
|
||||
public:
|
||||
CCharacterValue() {}
|
||||
CCharacterValue(const CAnimationParameters& rkParams) { mValue = rkParams; }
|
||||
|
||||
TString ToString() const { return ""; }
|
||||
void FromString(const TString&) { }
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CCharacterValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CMayaSplineValue : public TTypedPropertyValue<std::vector<u8>>
|
||||
{
|
||||
public:
|
||||
CMayaSplineValue() {}
|
||||
CMayaSplineValue(const std::vector<u8>& rkData) { mValue = rkData; }
|
||||
|
||||
TString ToString() const { return "[MayaSpline]"; }
|
||||
void FromString(const TString&) {}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CMayaSplineValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CSoundValue : public TTypedPropertyValue<u32>
|
||||
{
|
||||
public:
|
||||
CSoundValue() {}
|
||||
CSoundValue(u32 SoundID) { mValue = SoundID; }
|
||||
|
||||
TString ToString() const { return TString::FromInt32(mValue, 0, 10); }
|
||||
void FromString(const TString& rkString) { mValue = rkString.ToInt32(10); }
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CSoundValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CAssetValue : public TTypedPropertyValue<CAssetID>
|
||||
{
|
||||
public:
|
||||
CAssetValue() {}
|
||||
CAssetValue(const CAssetID& rkID) { mValue = rkID; }
|
||||
|
||||
TString ToString() const { return ""; }
|
||||
void FromString(const TString&) {}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CAssetValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
class CUnknownValue : public TTypedPropertyValue<std::vector<u8>>
|
||||
{
|
||||
public:
|
||||
CUnknownValue();
|
||||
CUnknownValue(const std::vector<u8>& rkVec) { mValue = rkVec; }
|
||||
|
||||
TString ToString() const { return ""; }
|
||||
void FromString(const TString&) {}
|
||||
|
||||
IPropertyValue* Clone() const
|
||||
{
|
||||
return new CUnknownValue(mValue);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // IPROPERTYVALUE_H
|
||||
174
src/Core/Resource/Script/NGameList.cpp
Normal file
174
src/Core/Resource/Script/NGameList.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
#include "NGameList.h"
|
||||
#include <Common/Log.h>
|
||||
|
||||
namespace NGameList
|
||||
{
|
||||
|
||||
/** Path for the templates directory */
|
||||
const TString gkTemplatesDir = "../templates/";
|
||||
|
||||
/** Path to the game list file */
|
||||
const TString gkGameListPath = gkTemplatesDir + "GameList.xml";
|
||||
|
||||
/** Info about a particular game serialized to the list */
|
||||
struct SGameInfo
|
||||
{
|
||||
TString Name;
|
||||
TString TemplatePath;
|
||||
std::unique_ptr<CGameTemplate> pTemplate;
|
||||
bool IsValid;
|
||||
|
||||
SGameInfo()
|
||||
: IsValid(false)
|
||||
{}
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
Arc << SerialParameter("Name", Name)
|
||||
<< SerialParameter("GameTemplate", TemplatePath);
|
||||
|
||||
if (Arc.IsReader())
|
||||
{
|
||||
IsValid = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
SGameInfo gGameList[EGame::Max];
|
||||
|
||||
/** Whether the game list has been loaded */
|
||||
bool gLoadedGameList = false;
|
||||
|
||||
/** Returns whether a game template has been loaded or not */
|
||||
bool IsGameTemplateLoaded(EGame Game)
|
||||
{
|
||||
int GameIdx = (int) Game;
|
||||
const SGameInfo& GameInfo = gGameList[GameIdx];
|
||||
return GameInfo.pTemplate != nullptr;
|
||||
}
|
||||
|
||||
/** Serialize the game list to/from a file */
|
||||
inline void SerializeGameList(IArchive& Arc)
|
||||
{
|
||||
// Serialize the number of games with valid GameInfos.
|
||||
u32 NumGames = 0;
|
||||
|
||||
if (Arc.IsWriter())
|
||||
{
|
||||
for (u32 GameIdx = 0; GameIdx < (u32) EGame::Max; GameIdx++)
|
||||
{
|
||||
if ( gGameList[GameIdx].IsValid )
|
||||
NumGames++;
|
||||
}
|
||||
}
|
||||
|
||||
Arc.SerializeArraySize(NumGames);
|
||||
|
||||
// Serialize the actual game info
|
||||
for (u32 GameIdx = 0; GameIdx < (u32) EGame::Max; GameIdx++)
|
||||
{
|
||||
// Skip games that don't have game templates when writing.
|
||||
if (Arc.IsWriter() && !gGameList[GameIdx].IsValid)
|
||||
continue;
|
||||
|
||||
ENSURE( Arc.ParamBegin("Game", 0) );
|
||||
|
||||
// Determine which game is being serialized
|
||||
EGame Game = (EGame) GameIdx;
|
||||
Arc << SerialParameter("ID", Game, SH_Attribute);
|
||||
ASSERT( Game != EGame::Invalid );
|
||||
|
||||
gGameList[ (u32) Game ].Serialize(Arc);
|
||||
Arc.ParamEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/** Load the game list into memory */
|
||||
void LoadGameList()
|
||||
{
|
||||
ASSERT(!gLoadedGameList);
|
||||
Log::Write("Loading game list");
|
||||
|
||||
CXMLReader Reader(gkGameListPath);
|
||||
ASSERT(Reader.IsValid());
|
||||
|
||||
SerializeGameList(Reader);
|
||||
gLoadedGameList = true;
|
||||
}
|
||||
|
||||
/** Save the game list back out to a file */
|
||||
void SaveGameList()
|
||||
{
|
||||
ASSERT(gLoadedGameList);
|
||||
Log::Write("Saving game list");
|
||||
|
||||
CXMLWriter Writer(gkGameListPath, "GameList");
|
||||
ASSERT(Writer.IsValid());
|
||||
|
||||
SerializeGameList(Writer);
|
||||
}
|
||||
|
||||
/** Load all game templates into memory */
|
||||
void LoadAllGameTemplates()
|
||||
{
|
||||
for (int GameIdx = 0; GameIdx < (int) EGame::Max; GameIdx++)
|
||||
GetGameTemplate( (EGame) GameIdx );
|
||||
}
|
||||
|
||||
/** Resave templates. If ForceAll is false, only saves templates that have been modified. */
|
||||
void SaveTemplates(bool ForceAll /*= false*/)
|
||||
{
|
||||
for (int GameIdx = 0; GameIdx < (int) EGame::Max; GameIdx++)
|
||||
{
|
||||
EGame Game = (EGame) GameIdx;
|
||||
if ( IsGameTemplateLoaded(Game) )
|
||||
{
|
||||
CGameTemplate* pGameTemplate = GetGameTemplate(Game);
|
||||
pGameTemplate->SaveGameTemplates(ForceAll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the game template for a given game */
|
||||
CGameTemplate* GetGameTemplate(EGame Game)
|
||||
{
|
||||
// Game must be valid!
|
||||
if (Game == EGame::Invalid)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ASSERT(Game >= (EGame) 0 && Game < EGame::Max);
|
||||
|
||||
// Initialize the game list, if it hasn't been loaded yet.
|
||||
if (!gLoadedGameList)
|
||||
{
|
||||
LoadGameList();
|
||||
}
|
||||
|
||||
int GameIdx = (int) Game;
|
||||
SGameInfo& GameInfo = gGameList[GameIdx];
|
||||
|
||||
// Load the game template, if it hasn't been loaded yet.
|
||||
if (!GameInfo.pTemplate && !GameInfo.Name.IsEmpty())
|
||||
{
|
||||
TString GamePath = gkTemplatesDir + GameInfo.TemplatePath;
|
||||
GameInfo.pTemplate = std::make_unique<CGameTemplate>();
|
||||
GameInfo.pTemplate->Load(GamePath);
|
||||
}
|
||||
|
||||
return GameInfo.pTemplate.get();
|
||||
}
|
||||
|
||||
/** Clean up game list resources. This needs to be called on app shutdown to ensure things are cleaned up in the right order. */
|
||||
void Shutdown()
|
||||
{
|
||||
for (int GameIdx = 0; GameIdx < (int) EGame::Max; GameIdx++)
|
||||
{
|
||||
gGameList[GameIdx].Name = "";
|
||||
gGameList[GameIdx].TemplatePath = "";
|
||||
gGameList[GameIdx].pTemplate = nullptr;
|
||||
}
|
||||
gLoadedGameList = false;
|
||||
}
|
||||
|
||||
}
|
||||
32
src/Core/Resource/Script/NGameList.h
Normal file
32
src/Core/Resource/Script/NGameList.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef NGAMELIST_H
|
||||
#define NGAMELIST_H
|
||||
|
||||
#include "CGameTemplate.h"
|
||||
|
||||
namespace NGameList
|
||||
{
|
||||
|
||||
/** Load all game templates into memory
|
||||
* This normally isn't necessary to call, as game templates will be lazy-loaded the
|
||||
* first time they are requested.
|
||||
*/
|
||||
void LoadAllGameTemplates();
|
||||
|
||||
/** Load the game list into memory. This is normally not necessary to call. */
|
||||
void LoadGameList();
|
||||
|
||||
/** Save the game list back out to a file */
|
||||
void SaveGameList();
|
||||
|
||||
/** Resave templates. If ForceAll is false, only saves templates that have been modified. */
|
||||
void SaveTemplates(bool ForceAll = false);
|
||||
|
||||
/** Get the game template for a given game */
|
||||
CGameTemplate* GetGameTemplate(EGame Game);
|
||||
|
||||
/** Clean up game list resources. This needs to be called on app shutdown to ensure things are cleaned up in the right order. */
|
||||
void Shutdown();
|
||||
|
||||
}
|
||||
|
||||
#endif // NGAMELIST_H
|
||||
567
src/Core/Resource/Script/NPropertyMap.cpp
Normal file
567
src/Core/Resource/Script/NPropertyMap.cpp
Normal file
@@ -0,0 +1,567 @@
|
||||
#include "NPropertyMap.h"
|
||||
#include "NGameList.h"
|
||||
#include <Common/NBasics.h>
|
||||
#include <Common/Serialization/XML.h>
|
||||
|
||||
/** NPropertyMap: Namespace for property ID -> name mappings */
|
||||
namespace NPropertyMap
|
||||
{
|
||||
|
||||
/** Path to the property map file */
|
||||
const char* gpkLegacyMapPath = "../templates/PropertyMapLegacy.xml";
|
||||
const char* gpkMapPath = "../templates/PropertyMap.xml";
|
||||
|
||||
/** Whether to do name lookups from the legacy map */
|
||||
const bool gkUseLegacyMapForNameLookups = false;
|
||||
|
||||
/** Whether to update names in the legacy map */
|
||||
const bool gkUseLegacyMapForUpdates = false;
|
||||
|
||||
/** Whether the map is dirty (has unsaved changes */
|
||||
bool gMapIsDirty = false;
|
||||
|
||||
/** Whether the map has been loaded */
|
||||
bool gMapIsLoaded = false;
|
||||
|
||||
/** Mapping of typename hashes back to the original string */
|
||||
std::unordered_map<u32, TString> gHashToTypeName;
|
||||
|
||||
/** Register a hash -> name mapping */
|
||||
inline void RegisterTypeName(u32 TypeHash, TString TypeName)
|
||||
{
|
||||
ASSERT( !TypeName.IsEmpty() );
|
||||
ASSERT( TypeName != "Unknown" );
|
||||
gHashToTypeName.emplace( std::make_pair<u32, TString>(std::move(TypeHash), std::move(TypeName)) );
|
||||
}
|
||||
|
||||
/** Key structure for name map lookups */
|
||||
struct SNameKey
|
||||
{
|
||||
union
|
||||
{
|
||||
struct {
|
||||
u32 TypeHash;
|
||||
u32 ID;
|
||||
};
|
||||
struct {
|
||||
u64 Key;
|
||||
};
|
||||
};
|
||||
|
||||
SNameKey()
|
||||
: TypeHash(-1), ID(-1)
|
||||
{}
|
||||
|
||||
SNameKey(u32 InTypeHash, u32 InID)
|
||||
: TypeHash(InTypeHash), ID(InID)
|
||||
{}
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
TString TypeName;
|
||||
|
||||
if (Arc.IsWriter())
|
||||
{
|
||||
TypeName = gHashToTypeName[TypeHash];
|
||||
ASSERT(!TypeName.IsEmpty());
|
||||
}
|
||||
|
||||
Arc << SerialParameter("ID", ID, SH_Attribute | SH_HexDisplay)
|
||||
<< SerialParameter("Type", TypeName, SH_Attribute);
|
||||
|
||||
if (Arc.IsReader())
|
||||
{
|
||||
TypeHash = TypeName.Hash32();
|
||||
RegisterTypeName(TypeHash, TypeName);
|
||||
}
|
||||
}
|
||||
|
||||
friend bool operator==(const SNameKey& kLHS, const SNameKey& kRHS)
|
||||
{
|
||||
return kLHS.Key == kRHS.Key;
|
||||
}
|
||||
|
||||
friend bool operator<(const SNameKey& kLHS, const SNameKey& kRHS)
|
||||
{
|
||||
return kLHS.Key < kRHS.Key;
|
||||
}
|
||||
};
|
||||
|
||||
/** Hasher for name keys for use in std::unordered_map */
|
||||
struct KeyHash
|
||||
{
|
||||
inline size_t operator()(const SNameKey& kKey) const
|
||||
{
|
||||
return std::hash<u64>()(kKey.Key);
|
||||
}
|
||||
};
|
||||
|
||||
/** Value structure for name map lookups */
|
||||
struct SNameValue
|
||||
{
|
||||
/** Name of the property */
|
||||
TString Name;
|
||||
|
||||
/** Whether this name is valid */
|
||||
bool IsValid;
|
||||
|
||||
/** List of all properties using this ID */
|
||||
std::list<IProperty*> PropertyList;
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
Arc << SerialParameter("Name", Name, SH_Attribute);
|
||||
}
|
||||
|
||||
friend bool operator==(const SNameValue& kLHS, const SNameValue& kRHS)
|
||||
{
|
||||
return kLHS.Name == kRHS.Name;
|
||||
}
|
||||
};
|
||||
|
||||
/** Mapping of property IDs to names. In the key, the upper 32 bits
|
||||
* are the type, and the lower 32 bits are the ID.
|
||||
*/
|
||||
std::map<SNameKey, SNameValue> gNameMap;
|
||||
|
||||
/** Legacy map that only includes the ID in the key */
|
||||
std::map<u32, TString> gLegacyNameMap;
|
||||
|
||||
/** Internal: Creates a name key for the given property. */
|
||||
SNameKey CreateKey(IProperty* pProperty)
|
||||
{
|
||||
SNameKey Key;
|
||||
Key.ID = pProperty->ID();
|
||||
Key.TypeHash = CCRC32::StaticHashString( pProperty->HashableTypeName() );
|
||||
return Key;
|
||||
}
|
||||
|
||||
SNameKey CreateKey(u32 ID, const char* pkTypeName)
|
||||
{
|
||||
return SNameKey( CCRC32::StaticHashString(pkTypeName), ID );
|
||||
}
|
||||
|
||||
/** Loads property names into memory */
|
||||
void LoadMap()
|
||||
{
|
||||
ASSERT( !gMapIsLoaded );
|
||||
Log::Write("Loading property map");
|
||||
|
||||
if ( gkUseLegacyMapForNameLookups )
|
||||
{
|
||||
CXMLReader Reader(gpkLegacyMapPath);
|
||||
ASSERT(Reader.IsValid());
|
||||
Reader << SerialParameter("PropertyMap", gLegacyNameMap, SH_HexDisplay);
|
||||
}
|
||||
else
|
||||
{
|
||||
CXMLReader Reader(gpkMapPath);
|
||||
ASSERT(Reader.IsValid());
|
||||
Reader << SerialParameter("PropertyMap", gNameMap, SH_HexDisplay);
|
||||
|
||||
// Iterate over the map and set up the valid flags
|
||||
for (auto Iter = gNameMap.begin(); Iter != gNameMap.end(); Iter++)
|
||||
{
|
||||
const SNameKey& kKey = Iter->first;
|
||||
SNameValue& Value = Iter->second;
|
||||
Value.IsValid = (CalculatePropertyID(*Value.Name, *gHashToTypeName[kKey.TypeHash]) == kKey.ID);
|
||||
}
|
||||
}
|
||||
|
||||
gMapIsLoaded = true;
|
||||
}
|
||||
|
||||
inline void ConditionalLoadMap()
|
||||
{
|
||||
if( !gMapIsLoaded )
|
||||
{
|
||||
LoadMap();
|
||||
}
|
||||
}
|
||||
|
||||
/** Saves property names back out to the template file */
|
||||
void SaveMap(bool Force /*= false*/)
|
||||
{
|
||||
if( !gMapIsLoaded )
|
||||
{
|
||||
if (Force)
|
||||
{
|
||||
LoadMap();
|
||||
}
|
||||
else return;
|
||||
}
|
||||
|
||||
Log::Write("Saving property map");
|
||||
|
||||
if( gMapIsDirty || Force )
|
||||
{
|
||||
if( gkUseLegacyMapForUpdates )
|
||||
{
|
||||
CXMLWriter Writer(gpkLegacyMapPath, "PropertyMap");
|
||||
ASSERT(Writer.IsValid());
|
||||
Writer << SerialParameter("PropertyMap", gLegacyNameMap, SH_HexDisplay);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure all game templates are loaded and clear out ID-type pairs that aren't used
|
||||
// This mostly occurs when type names are changed - unneeded pairings with the old type can be left in the map
|
||||
NGameList::LoadAllGameTemplates();
|
||||
|
||||
for (auto Iter = gNameMap.begin(); Iter != gNameMap.end(); Iter++)
|
||||
{
|
||||
SNameValue& Value = Iter->second;
|
||||
|
||||
if (Value.PropertyList.empty())
|
||||
{
|
||||
Iter = gNameMap.erase(Iter);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the actual save
|
||||
CXMLWriter Writer(gpkMapPath, "PropertyMap");
|
||||
ASSERT(Writer.IsValid());
|
||||
Writer << SerialParameter("PropertyMap", gNameMap, SH_HexDisplay);
|
||||
}
|
||||
gMapIsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Given a property ID and type, returns the name of the property */
|
||||
const char* GetPropertyName(IProperty* pInProperty)
|
||||
{
|
||||
ConditionalLoadMap();
|
||||
|
||||
if (gkUseLegacyMapForNameLookups)
|
||||
{
|
||||
auto MapFind = gLegacyNameMap.find( pInProperty->ID() );
|
||||
return (MapFind == gLegacyNameMap.end() ? "Unknown" : *MapFind->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
SNameKey Key = CreateKey(pInProperty);
|
||||
auto MapFind = gNameMap.find(Key);
|
||||
return (MapFind == gNameMap.end() ? "Unknown" : *MapFind->second.Name);
|
||||
}
|
||||
}
|
||||
|
||||
/** Given a property name and type, returns the name of the property.
|
||||
* This requires you to provide the exact type string used in the hash.
|
||||
*/
|
||||
const char* GetPropertyName(u32 ID, const char* pkTypeName)
|
||||
{
|
||||
// Does not support legacy map
|
||||
ConditionalLoadMap();
|
||||
|
||||
SNameKey Key = CreateKey(ID, pkTypeName);
|
||||
auto MapFind = gNameMap.find(Key);
|
||||
return MapFind == gNameMap.end() ? "Unknown" : *MapFind->second.Name;
|
||||
}
|
||||
|
||||
/** Calculate the property ID of a given name/type. */
|
||||
u32 CalculatePropertyID(const char* pkName, const char* pkTypeName)
|
||||
{
|
||||
CCRC32 CRC;
|
||||
CRC.Hash(pkName);
|
||||
CRC.Hash(pkTypeName);
|
||||
return CRC.Digest();
|
||||
}
|
||||
|
||||
/** Returns whether the specified ID is in the map. */
|
||||
bool IsValidPropertyID(u32 ID, const char* pkTypeName, bool* pOutIsValid /*= nullptr*/)
|
||||
{
|
||||
SNameKey Key = CreateKey(ID, pkTypeName);
|
||||
auto MapFind = gNameMap.find(Key);
|
||||
|
||||
if (MapFind != gNameMap.end())
|
||||
{
|
||||
if (pOutIsValid != nullptr)
|
||||
{
|
||||
SNameValue& Value = MapFind->second;
|
||||
*pOutIsValid = Value.IsValid;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
/** Retrieves a list of all properties that match the requested property ID. */
|
||||
void RetrievePropertiesWithID(u32 ID, const char* pkTypeName, std::list<IProperty*>& OutList)
|
||||
{
|
||||
SNameKey Key = CreateKey(ID, pkTypeName);
|
||||
auto MapFind = gNameMap.find(Key);
|
||||
|
||||
if (MapFind != gNameMap.end())
|
||||
{
|
||||
SNameValue& Value = MapFind->second;
|
||||
OutList = Value.PropertyList;
|
||||
}
|
||||
}
|
||||
|
||||
/** Retrieves a list of all XML templates that contain a given property ID. */
|
||||
void RetrieveXMLsWithProperty(u32 ID, const char* pkTypeName, std::set<TString>& OutSet)
|
||||
{
|
||||
SNameKey Key = CreateKey(ID, pkTypeName);
|
||||
auto MapFind = gNameMap.find(Key);
|
||||
|
||||
if (MapFind != gNameMap.end())
|
||||
{
|
||||
SNameValue& NameValue = MapFind->second;
|
||||
|
||||
for (auto ListIter = NameValue.PropertyList.begin(); ListIter != NameValue.PropertyList.end(); ListIter++)
|
||||
{
|
||||
IProperty* pProperty = *ListIter;
|
||||
OutSet.insert( pProperty->GetTemplateFileName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Updates the name of a given property in the map */
|
||||
void SetPropertyName(u32 ID, const char* pkTypeName, const char* pkNewName)
|
||||
{
|
||||
if( gkUseLegacyMapForUpdates )
|
||||
{
|
||||
auto Iter = gLegacyNameMap.find(ID);
|
||||
|
||||
if (Iter == gLegacyNameMap.end() || Iter->second != pkNewName)
|
||||
{
|
||||
Iter->second = pkNewName;
|
||||
gMapIsDirty = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SNameKey Key = CreateKey(ID, pkTypeName);
|
||||
auto MapFind = gNameMap.find(Key);
|
||||
|
||||
if (MapFind != gNameMap.end())
|
||||
{
|
||||
SNameValue& Value = MapFind->second;
|
||||
|
||||
if (Value.Name != pkNewName)
|
||||
{
|
||||
TString OldName = Value.Name;
|
||||
Value.Name = pkNewName;
|
||||
gMapIsDirty = true;
|
||||
|
||||
// Update all properties with this ID with the new name
|
||||
for (auto Iter = Value.PropertyList.begin(); Iter != Value.PropertyList.end(); Iter++)
|
||||
{
|
||||
// If the property overrides the name, then don't change it.
|
||||
IProperty* pIterProperty = *Iter;
|
||||
|
||||
if (pIterProperty->Name() == OldName)
|
||||
{
|
||||
pIterProperty->SetName(Value.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Change a type name of a property. */
|
||||
void ChangeTypeName(IProperty* pProperty, const char* pkOldTypeName, const char* pkNewTypeName)
|
||||
{
|
||||
u32 OldTypeHash = CCRC32::StaticHashString(pkOldTypeName);
|
||||
u32 NewTypeHash = CCRC32::StaticHashString(pkNewTypeName);
|
||||
|
||||
if (OldTypeHash == NewTypeHash)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Start off with a ist of all properties in the same inheritance chain as this one.
|
||||
std::list<IProperty*> Properties;
|
||||
IProperty* pArchetype = pProperty->RootArchetype();
|
||||
pArchetype->GatherAllSubInstances(Properties, true);
|
||||
|
||||
for (auto Iter = Properties.begin(); Iter != Properties.end(); Iter++)
|
||||
{
|
||||
pProperty = *Iter;
|
||||
|
||||
if (pProperty->UsesNameMap())
|
||||
{
|
||||
SNameKey OldKey(OldTypeHash, pProperty->ID());
|
||||
SNameKey NewKey(NewTypeHash, pProperty->ID());
|
||||
|
||||
// Disassociate this property from the old mapping.
|
||||
bool WasRegistered = false;
|
||||
auto Find = gNameMap.find(OldKey);
|
||||
|
||||
if (Find != gNameMap.end())
|
||||
{
|
||||
SNameValue& Value = Find->second;
|
||||
WasRegistered = NBasics::ListRemoveOne(Value.PropertyList, pProperty);
|
||||
}
|
||||
|
||||
// Create a key for the new property and add it to the list.
|
||||
Find = gNameMap.find(NewKey);
|
||||
|
||||
if (Find == gNameMap.end())
|
||||
{
|
||||
SNameValue Value;
|
||||
Value.Name = pProperty->Name();
|
||||
Value.IsValid = ( CalculatePropertyID(*Value.Name, pkNewTypeName) == pProperty->ID() );
|
||||
gNameMap[NewKey] = Value;
|
||||
Find = gNameMap.find(NewKey);
|
||||
}
|
||||
ASSERT(Find != gNameMap.end());
|
||||
|
||||
if (WasRegistered)
|
||||
{
|
||||
Find->second.PropertyList.push_back(pProperty);
|
||||
}
|
||||
|
||||
gMapIsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
RegisterTypeName(NewTypeHash, pkNewTypeName);
|
||||
}
|
||||
|
||||
/** Change a type name. */
|
||||
void ChangeTypeNameGlobally(const char* pkOldTypeName, const char* pkNewTypeName)
|
||||
{
|
||||
u32 OldTypeHash = CCRC32::StaticHashString(pkOldTypeName);
|
||||
u32 NewTypeHash = CCRC32::StaticHashString(pkNewTypeName);
|
||||
|
||||
if (OldTypeHash == NewTypeHash)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// The process here is basically to find all properties with a matching typename
|
||||
// hash and update the hashes to the new type. Not 100% sure if this is the best
|
||||
// way to go about doing it. From what I understand, insert() does not invalidate
|
||||
// iterators, and extract() only invalidates the iterator being extracted. So this
|
||||
// implementation should work correctly.
|
||||
for (auto MapIter = gNameMap.begin(); MapIter != gNameMap.end(); MapIter++)
|
||||
{
|
||||
if (MapIter->first.TypeHash == OldTypeHash)
|
||||
{
|
||||
auto PrevIter = MapIter;
|
||||
PrevIter--;
|
||||
|
||||
auto MapNode = gNameMap.extract(MapIter);
|
||||
MapIter = PrevIter;
|
||||
|
||||
SNameKey& Key = MapNode.key();
|
||||
Key.TypeHash = NewTypeHash;
|
||||
gNameMap.insert( std::move(MapNode) );
|
||||
gMapIsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
RegisterTypeName(NewTypeHash, pkNewTypeName);
|
||||
gHashToTypeName[NewTypeHash] = pkNewTypeName;
|
||||
}
|
||||
|
||||
/** Registers a property in the name map. Should be called on all properties that use the map */
|
||||
void RegisterProperty(IProperty* pProperty)
|
||||
{
|
||||
ConditionalLoadMap();
|
||||
|
||||
// Sanity checks to make sure we don't accidentally add non-hash property IDs to the map.
|
||||
ASSERT( pProperty->UsesNameMap() );
|
||||
ASSERT( pProperty->ID() > 0xFF && pProperty->ID() != 0xFFFFFFFF );
|
||||
|
||||
// Just need to register the property in the list.
|
||||
SNameKey Key = CreateKey(pProperty);
|
||||
auto MapFind = gNameMap.find(Key);
|
||||
|
||||
if( gkUseLegacyMapForNameLookups )
|
||||
{
|
||||
// If we are using the legacy map, gNameMap may be empty. We need to retrieve the name
|
||||
// from the legacy map, and create an entry in gNameMap with it.
|
||||
|
||||
//@todo this prob isn't the most efficient way to do this
|
||||
if (MapFind == gNameMap.end())
|
||||
{
|
||||
auto LegacyMapFind = gLegacyNameMap.find( pProperty->ID() );
|
||||
ASSERT( LegacyMapFind != gLegacyNameMap.end() );
|
||||
|
||||
SNameValue Value;
|
||||
Value.Name = LegacyMapFind->second;
|
||||
Value.IsValid = ( CalculatePropertyID(*Value.Name, pProperty->HashableTypeName()) == pProperty->ID() );
|
||||
pProperty->SetName(Value.Name);
|
||||
|
||||
gNameMap[Key] = Value;
|
||||
MapFind = gNameMap.find(Key);
|
||||
ASSERT(MapFind != gNameMap.end());
|
||||
|
||||
RegisterTypeName(Key.TypeHash, pProperty->HashableTypeName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(MapFind != gNameMap.end());
|
||||
pProperty->SetName( MapFind->second.Name );
|
||||
}
|
||||
|
||||
MapFind->second.PropertyList.push_back(pProperty);
|
||||
|
||||
// Update the property's Name field to match the mapped name.
|
||||
pProperty->SetName( MapFind->second.Name );
|
||||
}
|
||||
|
||||
/** Unregisters a property from the name map. Should be called on all properties that use the map on destruction. */
|
||||
void UnregisterProperty(IProperty* pProperty)
|
||||
{
|
||||
SNameKey Key = CreateKey(pProperty);
|
||||
auto Iter = gNameMap.find(Key);
|
||||
|
||||
if (Iter != gNameMap.end())
|
||||
{
|
||||
// Found the value, now remove the element from the list.
|
||||
SNameValue& Value = Iter->second;
|
||||
NBasics::ListRemoveOne(Value.PropertyList, pProperty);
|
||||
}
|
||||
}
|
||||
|
||||
/** Class for iterating through the map */
|
||||
class CIteratorImpl
|
||||
{
|
||||
public:
|
||||
std::map<SNameKey, SNameValue>::const_iterator mIter;
|
||||
};
|
||||
|
||||
CIterator::CIterator()
|
||||
{
|
||||
mpImpl = new CIteratorImpl;
|
||||
mpImpl->mIter = gNameMap.begin();
|
||||
}
|
||||
|
||||
CIterator::~CIterator()
|
||||
{
|
||||
delete mpImpl;
|
||||
}
|
||||
|
||||
u32 CIterator::ID() const
|
||||
{
|
||||
return mpImpl->mIter->first.ID;
|
||||
}
|
||||
|
||||
const char* CIterator::Name() const
|
||||
{
|
||||
return *mpImpl->mIter->second.Name;
|
||||
}
|
||||
|
||||
const char* CIterator::TypeName() const
|
||||
{
|
||||
u32 TypeHash = mpImpl->mIter->first.TypeHash;
|
||||
auto Find = gHashToTypeName.find(TypeHash);
|
||||
ASSERT(Find != gHashToTypeName.end());
|
||||
return *Find->second;
|
||||
}
|
||||
|
||||
CIterator::operator bool() const
|
||||
{
|
||||
return mpImpl->mIter != gNameMap.end();
|
||||
}
|
||||
|
||||
void CIterator::operator++()
|
||||
{
|
||||
mpImpl->mIter++;
|
||||
}
|
||||
|
||||
}
|
||||
75
src/Core/Resource/Script/NPropertyMap.h
Normal file
75
src/Core/Resource/Script/NPropertyMap.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef NPROPERTYMAP_H
|
||||
#define NPROPERTYMAP_H
|
||||
|
||||
#include <Common/types.h>
|
||||
#include "Core/Resource/Script/Property/IProperty.h"
|
||||
|
||||
/** NPropertyMap: Namespace for property ID -> name mappings */
|
||||
namespace NPropertyMap
|
||||
{
|
||||
|
||||
/** Loads property names into memory */
|
||||
void LoadMap();
|
||||
|
||||
/** Saves property names back out to the template file */
|
||||
void SaveMap(bool Force = false);
|
||||
|
||||
/** Returns the name of the property */
|
||||
const char* GetPropertyName(IProperty* pProperty);
|
||||
|
||||
/** Given a property name and type, returns the name of the property.
|
||||
* This requires you to provide the exact type string used in the hash.
|
||||
*/
|
||||
const char* GetPropertyName(u32 ID, const char* pkTypeName);
|
||||
|
||||
/** Calculate the property ID of a given name/type. */
|
||||
u32 CalculatePropertyID(const char* pkName, const char* pkTypeName);
|
||||
|
||||
/**
|
||||
* Returns whether the specified name is in the map.
|
||||
* If the ID is valid and pOutIsValid is non-null, it will return whether the current name is correct.
|
||||
*/
|
||||
bool IsValidPropertyID(u32 ID, const char* pkTypeName, bool* pOutIsValid = nullptr);
|
||||
|
||||
/** Retrieves a list of all properties that match the requested property ID. */
|
||||
void RetrievePropertiesWithID(u32 ID, const char* pkTypeName, std::list<IProperty*>& OutList);
|
||||
|
||||
/** Retrieves a list of all XML templates that contain a given property ID. */
|
||||
void RetrieveXMLsWithProperty(u32 ID, const char* pkTypeName, std::set<TString>& OutSet);
|
||||
|
||||
/** Updates the name of a given property in the map */
|
||||
void SetPropertyName(u32 ID, const char* pkTypeName, const char* pkNewName);
|
||||
|
||||
/** Change a type name of a property. */
|
||||
void ChangeTypeName(IProperty* pProperty, const char* pkOldTypeName, const char* pkNewTypeName);
|
||||
|
||||
/** Change a type name. */
|
||||
void ChangeTypeNameGlobally(const char* pkOldTypeName, const char* pkNewTypeName);
|
||||
|
||||
/** Registers a property in the name map. Should be called on all properties that use the map */
|
||||
void RegisterProperty(IProperty* pProperty);
|
||||
|
||||
/** Unregisters a property from the name map. Should be called on all properties that use the map on destruction. */
|
||||
void UnregisterProperty(IProperty* pProperty);
|
||||
|
||||
/** Class that allows for iteration through the name map */
|
||||
class CIterator
|
||||
{
|
||||
/** Private implementation */
|
||||
class CIteratorImpl* mpImpl;
|
||||
|
||||
public:
|
||||
CIterator();
|
||||
~CIterator();
|
||||
|
||||
u32 ID() const;
|
||||
const char* Name() const;
|
||||
const char* TypeName() const;
|
||||
|
||||
operator bool() const;
|
||||
void operator ++();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // NPROPERTYMAP_H
|
||||
27
src/Core/Resource/Script/Property/CAnimationProperty.h
Normal file
27
src/Core/Resource/Script/Property/CAnimationProperty.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef CANIMATIONPROPERTY_H
|
||||
#define CANIMATIONPROPERTY_H
|
||||
|
||||
#include "IProperty.h"
|
||||
|
||||
class CAnimationProperty : public TSerializeableTypedProperty< u32, EPropertyType::Animation >
|
||||
{
|
||||
friend class IProperty;
|
||||
|
||||
protected:
|
||||
CAnimationProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual void SerializeValue(void* pData, IArchive& rArc) const
|
||||
{
|
||||
rArc.SerializePrimitive( (u32&) ValueRef(pData), SH_HexDisplay );
|
||||
}
|
||||
|
||||
virtual TString ValueAsString(void* pData) const
|
||||
{
|
||||
return TString::HexString( (u32) Value(pData) );
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CANIMATIONPROPERTY_H
|
||||
34
src/Core/Resource/Script/Property/CAnimationSetProperty.h
Normal file
34
src/Core/Resource/Script/Property/CAnimationSetProperty.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef CANIMATIONSETPROPERTY_H
|
||||
#define CANIMATIONSETPROPERTY_H
|
||||
|
||||
#include "IProperty.h"
|
||||
|
||||
class CAnimationSetProperty : public TSerializeableTypedProperty< CAnimationParameters, EPropertyType::AnimationSet >
|
||||
{
|
||||
friend class IProperty;
|
||||
|
||||
protected:
|
||||
CAnimationSetProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{
|
||||
mDefaultValue.SetGame(Game);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
{
|
||||
Value(pData).Serialize(Arc);
|
||||
}
|
||||
|
||||
virtual const char* HashableTypeName() const
|
||||
{
|
||||
return (Game() <= EGame::Echoes ? "AnimationSet" : "CharacterAnimationSet");
|
||||
}
|
||||
|
||||
virtual CAnimationParameters GetSerializationDefaultValue()
|
||||
{
|
||||
return CAnimationParameters( Game() );
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CANIMATIONSETPROPERTY_H
|
||||
204
src/Core/Resource/Script/Property/CArrayProperty.h
Normal file
204
src/Core/Resource/Script/Property/CArrayProperty.h
Normal file
@@ -0,0 +1,204 @@
|
||||
#ifndef CARRAYPROPERTY_H
|
||||
#define CARRAYPROPERTY_H
|
||||
|
||||
#include "IProperty.h"
|
||||
|
||||
struct SScriptArray
|
||||
{
|
||||
int Count;
|
||||
std::vector<char> Array;
|
||||
|
||||
SScriptArray()
|
||||
: Count(0)
|
||||
{}
|
||||
|
||||
inline bool operator==(const SScriptArray& rkOther) const
|
||||
{
|
||||
return( Count == rkOther.Count && Array == rkOther.Array );
|
||||
}
|
||||
};
|
||||
|
||||
/** You probably shouldn't use this on intrinsic classes; script only */
|
||||
/** @todo proper support of default values for arrays (this would be used for prefabs) */
|
||||
class CArrayProperty : public TTypedProperty<u32, EPropertyType::Array>
|
||||
{
|
||||
friend class IProperty;
|
||||
|
||||
/** This class inherits from TTypedPropertyNew<int> in order to expose the array
|
||||
* count value (the first member of SScriptArray). Outside users can edit this
|
||||
* value and we respond by updating the allocated space, handling item destruction
|
||||
* and construction, etc.
|
||||
*/
|
||||
IProperty* mpItemArchetype;
|
||||
|
||||
/** Internal functions */
|
||||
SScriptArray& _GetInternalArray(void* pData) const
|
||||
{
|
||||
return *( (SScriptArray*) RawValuePtr(pData) );
|
||||
}
|
||||
|
||||
u32 _InternalArrayCount(void* pPropertyData) const
|
||||
{
|
||||
std::vector<char>& rArray = _GetInternalArray(pPropertyData).Array;
|
||||
return rArray.size() / ItemSize();
|
||||
}
|
||||
|
||||
protected:
|
||||
CArrayProperty(EGame Game)
|
||||
: TTypedProperty(Game)
|
||||
, mpItemArchetype(nullptr)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual u32 DataSize() const
|
||||
{
|
||||
return sizeof(SScriptArray);
|
||||
}
|
||||
|
||||
virtual u32 DataAlignment() const
|
||||
{
|
||||
return alignof(SScriptArray);
|
||||
}
|
||||
|
||||
virtual void Construct(void* pData) const
|
||||
{
|
||||
new(ValuePtr(pData)) SScriptArray;
|
||||
}
|
||||
|
||||
virtual void Destruct(void* pData) const
|
||||
{
|
||||
RevertToDefault(pData);
|
||||
TTypedProperty::Destruct(pData);
|
||||
}
|
||||
|
||||
virtual bool MatchesDefault(void* pData) const
|
||||
{
|
||||
return ArrayCount(pData) == 0;
|
||||
}
|
||||
|
||||
virtual void RevertToDefault(void* pData) const
|
||||
{
|
||||
Resize(pData, 0);
|
||||
ValueRef(pData) = 0;
|
||||
}
|
||||
|
||||
virtual bool CanHaveDefault() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool IsPointerType() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void* GetChildDataPointer(void* pPropertyData) const
|
||||
{
|
||||
return _GetInternalArray(pPropertyData).Array.data();
|
||||
}
|
||||
|
||||
virtual void PropertyValueChanged(void* pPropertyData)
|
||||
{
|
||||
SScriptArray& rArray = _GetInternalArray(pPropertyData);
|
||||
rArray.Count = Math::Max(rArray.Count, 0);
|
||||
Resize(pPropertyData, rArray.Count);
|
||||
}
|
||||
|
||||
virtual void Serialize(IArchive& rArc)
|
||||
{
|
||||
TTypedProperty::Serialize(rArc);
|
||||
rArc << SerialParameter("ItemArchetype", mpItemArchetype);
|
||||
}
|
||||
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
{
|
||||
u32 Count = ArrayCount(pData);
|
||||
Arc.SerializeArraySize(Count);
|
||||
|
||||
if (Arc.IsReader())
|
||||
Resize(pData, Count);
|
||||
|
||||
for (u32 ItemIdx = 0; ItemIdx < Count; ItemIdx++)
|
||||
{
|
||||
if (Arc.ParamBegin("ArrayElement", 0))
|
||||
{
|
||||
void* pItemData = ItemPointer(pData, ItemIdx);
|
||||
mpItemArchetype->SerializeValue(pItemData, Arc);
|
||||
Arc.ParamEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void InitFromArchetype(IProperty* pOther)
|
||||
{
|
||||
TTypedProperty::InitFromArchetype(pOther);
|
||||
CArrayProperty* pOtherArray = static_cast<CArrayProperty*>(pOther);
|
||||
mpItemArchetype = IProperty::CreateCopy(pOtherArray->mpItemArchetype);
|
||||
}
|
||||
|
||||
virtual void PostInitialize()
|
||||
{
|
||||
TTypedProperty::PostInitialize();
|
||||
mpItemArchetype->Initialize(this, mpScriptTemplate, 0);
|
||||
}
|
||||
|
||||
u32 ArrayCount(void* pPropertyData) const
|
||||
{
|
||||
return ValueRef(pPropertyData);
|
||||
}
|
||||
|
||||
void Resize(void* pPropertyData, u32 NewCount) const
|
||||
{
|
||||
u32 OldCount = _InternalArrayCount(pPropertyData);
|
||||
|
||||
if (OldCount != NewCount)
|
||||
{
|
||||
SScriptArray& rArray = _GetInternalArray(pPropertyData);
|
||||
|
||||
// Handle destruction of old elements
|
||||
if (OldCount > NewCount)
|
||||
{
|
||||
for (u32 ItemIdx = NewCount; ItemIdx < OldCount; ItemIdx++)
|
||||
{
|
||||
void* pItemPtr = ItemPointer(pPropertyData, ItemIdx);
|
||||
mpItemArchetype->Destruct(pItemPtr);
|
||||
}
|
||||
}
|
||||
|
||||
u32 NewSize = NewCount * ItemSize();
|
||||
rArray.Array.resize(NewSize);
|
||||
rArray.Count = NewCount;
|
||||
|
||||
// Handle construction of new elements
|
||||
if (NewCount > OldCount)
|
||||
{
|
||||
for (u32 ItemIdx = OldCount; ItemIdx < NewCount; ItemIdx++)
|
||||
{
|
||||
void* pItemPtr = ItemPointer(pPropertyData, ItemIdx);
|
||||
mpItemArchetype->Construct(pItemPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* ItemPointer(void* pPropertyData, u32 ItemIndex) const
|
||||
{
|
||||
ASSERT(_InternalArrayCount(pPropertyData) > ItemIndex);
|
||||
std::vector<char>& rArray = _GetInternalArray(pPropertyData).Array;
|
||||
u32 MyItemSize = ItemSize();
|
||||
ASSERT(rArray.size() >= (MyItemSize * (ItemIndex+1)));
|
||||
return rArray.data() + (MyItemSize * ItemIndex);
|
||||
}
|
||||
|
||||
u32 ItemSize() const
|
||||
{
|
||||
u32 ItemAlign = mpItemArchetype->DataAlignment();
|
||||
u32 ItemSize = ALIGN(mpItemArchetype->DataSize(), ItemAlign);
|
||||
return ItemSize;
|
||||
}
|
||||
|
||||
/** Accessors */
|
||||
IProperty* ItemArchetype() const { return mpItemArchetype; }
|
||||
};
|
||||
|
||||
#endif // CARRAYPROPERTY_H
|
||||
67
src/Core/Resource/Script/Property/CAssetProperty.h
Normal file
67
src/Core/Resource/Script/Property/CAssetProperty.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef CASSETPROPERTY_H
|
||||
#define CASSETPROPERTY_H
|
||||
|
||||
#include "IProperty.h"
|
||||
#include "Core/Resource/CResTypeFilter.h"
|
||||
|
||||
class CAssetProperty : public TSerializeableTypedProperty<CAssetID, EPropertyType::Asset>
|
||||
{
|
||||
friend class IProperty;
|
||||
|
||||
CResTypeFilter mTypeFilter;
|
||||
|
||||
protected:
|
||||
CAssetProperty::CAssetProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{
|
||||
mDefaultValue = CAssetID::InvalidID( mGame );
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void Serialize(IArchive& rArc)
|
||||
{
|
||||
TSerializeableTypedProperty::Serialize(rArc);
|
||||
CAssetProperty* pArchetype = static_cast<CAssetProperty*>(mpArchetype);
|
||||
rArc << SerialParameter("TypeFilter", mTypeFilter, pArchetype ? SH_Optional : 0, pArchetype ? pArchetype->mTypeFilter : CResTypeFilter());
|
||||
}
|
||||
|
||||
virtual bool ShouldSerialize() const
|
||||
{
|
||||
CAssetProperty* pArchetype = static_cast<CAssetProperty*>(mpArchetype);
|
||||
return TSerializeableTypedProperty::ShouldSerialize() ||
|
||||
mTypeFilter != pArchetype->mTypeFilter;
|
||||
}
|
||||
|
||||
virtual void InitFromArchetype(IProperty* pOther)
|
||||
{
|
||||
TTypedProperty::InitFromArchetype(pOther);
|
||||
mTypeFilter = static_cast<CAssetProperty*>(pOther)->mTypeFilter;
|
||||
}
|
||||
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
{
|
||||
Arc.SerializePrimitive( ValueRef(pData), 0 );
|
||||
}
|
||||
|
||||
virtual TString ValueAsString(void* pData) const
|
||||
{
|
||||
return Value(pData).ToString();
|
||||
}
|
||||
|
||||
virtual CAssetID GetSerializationDefaultValue()
|
||||
{
|
||||
return CAssetID::InvalidID(Game());
|
||||
}
|
||||
|
||||
void SetTypeFilter(const TStringList& rkExtensions)
|
||||
{
|
||||
mTypeFilter.SetAcceptedTypes(Game(), rkExtensions);
|
||||
}
|
||||
|
||||
const CResTypeFilter& GetTypeFilter() const
|
||||
{
|
||||
return mTypeFilter;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CASSETPROPERTY_H
|
||||
27
src/Core/Resource/Script/Property/CBoolProperty.h
Normal file
27
src/Core/Resource/Script/Property/CBoolProperty.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef CBOOLPROPERTY_H
|
||||
#define CBOOLPROPERTY_H
|
||||
|
||||
#include "IProperty.h"
|
||||
|
||||
class CBoolProperty : public TSerializeableTypedProperty< bool, EPropertyType::Bool >
|
||||
{
|
||||
friend class IProperty;
|
||||
|
||||
protected:
|
||||
CBoolProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
{
|
||||
Arc.SerializePrimitive( ValueRef(pData), 0 );
|
||||
}
|
||||
|
||||
virtual TString ValueAsString(void* pData)
|
||||
{
|
||||
return Value(pData) ? "true" : "false";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CBOOLPROPERTY_H
|
||||
27
src/Core/Resource/Script/Property/CByteProperty.h
Normal file
27
src/Core/Resource/Script/Property/CByteProperty.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef CBYTEPROPERTY_H
|
||||
#define CBYTEPROPERTY_H
|
||||
|
||||
#include "IProperty.h"
|
||||
|
||||
class CByteProperty : public TNumericalProperty< s8, EPropertyType::Byte >
|
||||
{
|
||||
friend class IProperty;
|
||||
|
||||
protected:
|
||||
CByteProperty(EGame Game)
|
||||
: TNumericalProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
{
|
||||
Arc.SerializePrimitive( (u8&) ValueRef(pData), 0 );
|
||||
}
|
||||
|
||||
virtual TString ValueAsString(void* pData) const
|
||||
{
|
||||
return TString::FromInt32( (s32) Value(pData), 0, 10 );
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CBYTEPROPERTY_H
|
||||
32
src/Core/Resource/Script/Property/CColorProperty.h
Normal file
32
src/Core/Resource/Script/Property/CColorProperty.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef CCOLORPROPERTY_H
|
||||
#define CCOLORPROPERTY_H
|
||||
|
||||
#include "IProperty.h"
|
||||
#include "CFloatProperty.h"
|
||||
|
||||
class CColorProperty : public TSerializeableTypedProperty< CColor, EPropertyType::Color >
|
||||
{
|
||||
friend class IProperty;
|
||||
|
||||
protected:
|
||||
CColorProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual void PostInitialize()
|
||||
{
|
||||
CreateIntrinsic(EPropertyType::Float, this, mOffset + 0, "R");
|
||||
CreateIntrinsic(EPropertyType::Float, this, mOffset + 4, "G");
|
||||
CreateIntrinsic(EPropertyType::Float, this, mOffset + 8, "B");
|
||||
CreateIntrinsic(EPropertyType::Float, this, mOffset + 12, "A");
|
||||
TPropCast<CFloatProperty>( mChildren.back() )->SetDefaultValue(1.0f);
|
||||
}
|
||||
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
{
|
||||
Value(pData).Serialize(Arc);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CVECTORPROPERTY_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user