diff --git a/Common/CUniqueID.cpp b/Common/CUniqueID.cpp index 77e0fa4c..1aafc29a 100644 --- a/Common/CUniqueID.cpp +++ b/Common/CUniqueID.cpp @@ -237,7 +237,7 @@ CUniqueID CUniqueID::FromString(std::string String) CUniqueID ID; ID.mLength = e32Bit; - u32 LongID = StringUtil::StrToRes32(Name); + u32 LongID = StringUtil::ToInt32(Name); if (SystemEndianness == LittleEndian) memcpy(ID.mID, &LongID, 4); @@ -252,7 +252,7 @@ CUniqueID CUniqueID::FromString(std::string String) CUniqueID ID; ID.mLength = e64Bit; - u64 LongID = StringUtil::StrToRes64(Name); + u64 LongID = StringUtil::ToInt64(Name); if (SystemEndianness == LittleEndian) memcpy(ID.mID, &LongID, 8); @@ -266,7 +266,7 @@ CUniqueID CUniqueID::FromString(std::string String) { CUniqueID ID; ID.mLength = e128Bit; - StringUtil::StrToRes128(Name, (char*) ID.mID); + StringUtil::ToInt128(Name, (char*) ID.mID); return ID; } } diff --git a/Common/StringUtil.cpp b/Common/StringUtil.cpp index c91d76c9..1f978ccf 100644 --- a/Common/StringUtil.cpp +++ b/Common/StringUtil.cpp @@ -39,22 +39,6 @@ namespace StringUtil return path.substr(endname + 1, path.size() - endname); } - - // Not convinced stringstream is the best way to do string conversions of asset IDs - don't know of a better way tho - std::string ResToStr(unsigned long assetID) - { - std::stringstream sstream; - sstream << std::hex << std::setw(8) << std::setfill('0') << assetID << std::dec; - return sstream.str(); - } - - std::string ResToStr(unsigned long long assetID) - { - std::stringstream sstream; - sstream << std::hex << std::setw(16) << std::setfill('0') << assetID << std::dec; - return sstream.str(); - } - std::string ToUpper(std::string str) { for (unsigned int i = 0; i < str.length(); i++) @@ -77,22 +61,25 @@ namespace StringUtil return str; } - std::string ToHexString(unsigned char num, bool addPrefix, int width) + std::string ToHexString(unsigned char num, bool addPrefix, bool uppercase, int width) { - return ToHexString((unsigned long) num, addPrefix, width); + return ToHexString((unsigned long) num, addPrefix, uppercase, width); } - std::string ToHexString(unsigned short num, bool addPrefix, int width) + std::string ToHexString(unsigned short num, bool addPrefix, bool uppercase, int width) { - return ToHexString((unsigned long) num, addPrefix, width); + return ToHexString((unsigned long) num, addPrefix, uppercase, width); } - std::string ToHexString(unsigned long num, bool addPrefix, int width) + std::string ToHexString(unsigned long num, bool addPrefix, bool uppercase, int width) { - std::stringstream str; - if (addPrefix) str << "0x"; - str << std::hex << std::setw(width) << std::setfill('0') << num; - return str.str(); + std::stringstream stream; + stream << std::hex << std::setw(width) << std::setfill('0') << num; + + std::string str = stream.str(); + if (uppercase) str = ToUpper(str); + if (addPrefix) str = std::string("0x") + str; + return str; } long Hash32(std::string str) @@ -119,15 +106,15 @@ namespace StringUtil return hash; } - long StrToRes32(std::string str) { + long ToInt32(std::string str) { return std::stoul(str, nullptr, 16); } - long long StrToRes64(std::string str) { + long long ToInt64(std::string str) { return std::stoull(str, nullptr, 16); } - void StrToRes128(std::string str, char *out) { + void ToInt128(std::string str, char *out) { long long Part1 = std::stoull(str.substr(0, 16), nullptr, 16); long long Part2 = std::stoull(str.substr(16, 16), nullptr, 16); @@ -141,14 +128,18 @@ namespace StringUtil memcpy(out + 8, &Part2, 8); } - long GetResID32(std::string str) + std::string ToString(unsigned long v) { - long resID; - if (IsHexString(str, false, 8)) - resID = StrToRes32(str); - else - resID = Hash32(GetFileName(str)); - return resID; + std::stringstream sstream; + sstream << std::hex << std::setw(8) << std::setfill('0') << v << std::dec; + return sstream.str(); + } + + std::string ToString(unsigned long long v) + { + std::stringstream sstream; + sstream << std::hex << std::setw(16) << std::setfill('0') << v << std::dec; + return sstream.str(); } bool IsHexString(std::string str, bool requirePrefix, long width) diff --git a/Common/StringUtil.h b/Common/StringUtil.h index a756b3ff..b3ea46d1 100644 --- a/Common/StringUtil.h +++ b/Common/StringUtil.h @@ -12,19 +12,18 @@ namespace StringUtil std::string GetFileNameWithExtension(std::string path); std::string GetPathWithoutExtension(std::string path); std::string GetExtension(std::string path); - std::string ResToStr(unsigned long ID); - std::string ResToStr(unsigned long long ID); std::string ToUpper(std::string str); std::string ToLower(std::string str); - std::string ToHexString(unsigned char num, bool addPrefix = true, int width = 0); - std::string ToHexString(unsigned short num, bool addPrefix = true, int width = 0); - std::string ToHexString(unsigned long num, bool addPrefix = true, int width = 0); + std::string ToHexString(unsigned char num, bool addPrefix = true, bool uppercase = false, int width = 0); + std::string ToHexString(unsigned short num, bool addPrefix = true, bool uppercase = false, int width = 0); + std::string ToHexString(unsigned long num, bool addPrefix = true, bool uppercase = false, int width = 0); long Hash32(std::string str); long long Hash64(std::string str); - long StrToRes32(std::string str); - long long StrToRes64(std::string str); - void StrToRes128(std::string str, char *out); - long GetResID32(std::string str); + long ToInt32(std::string str); + long long ToInt64(std::string str); + void ToInt128(std::string str, char *out); + std::string ToString(unsigned long ID); + std::string ToString(unsigned long long ID); bool IsHexString(std::string str, bool requirePrefix = false, long width = -1); std::string AppendSlash(std::string str); CStringList Tokenize(const std::string& str, const char *pTokens); diff --git a/Core/CResCache.cpp b/Core/CResCache.cpp index 3f6866ca..20d72c6e 100644 --- a/Core/CResCache.cpp +++ b/Core/CResCache.cpp @@ -116,11 +116,11 @@ CResource* CResCache::GetResource(CUniqueID ResID, CFourCC type) // Load from folder else { - Source = mResSource.Path + StringUtil::ResToStr(ResID.ToLong()) + "." + type.ToString(); + Source = mResSource.Path + StringUtil::ToString(ResID.ToLong()) + "." + type.ToString(); CFileInStream file(Source, IOUtil::BigEndian); if (!file.IsValid()) { - Source = mResSource.Path + StringUtil::ResToStr(ResID.ToLongLong()) + "." + type.ToString(); + Source = mResSource.Path + StringUtil::ToString(ResID.ToLongLong()) + "." + type.ToString(); file.Open(Source, IOUtil::BigEndian); if (!file.IsValid()) { diff --git a/PrimeWorldEditor.pro b/PrimeWorldEditor.pro index 81923686..2c747a38 100644 --- a/PrimeWorldEditor.pro +++ b/PrimeWorldEditor.pro @@ -144,7 +144,11 @@ SOURCES += \ UI/CSceneViewport.cpp \ UI/undo/CRotateNodeCommand.cpp \ UI/undo/CScaleNodeCommand.cpp \ - UI/CModelEditorViewport.cpp + UI/CModelEditorViewport.cpp \ + Resource/cooker/CTemplateWriter.cpp \ + Resource/cooker/CWorldCooker.cpp \ + Resource/script/CPropertyTemplate.cpp \ + Resource/script/CProperty.cpp HEADERS += \ Common/AnimUtil.h \ @@ -306,7 +310,11 @@ HEADERS += \ UI/CSceneViewport.h \ UI/undo/CRotateNodeCommand.h \ UI/undo/CScaleNodeCommand.h \ - UI/CModelEditorViewport.h + UI/CModelEditorViewport.h \ + Resource/cooker/CTemplateWriter.h \ + Resource/cooker/CWorldCooker.h \ + Resource/script/CPropertyTemplate.h \ + Resource/script/EVolumeShape.h FORMS += \ UI/CWorldEditorWindow.ui \ @@ -374,3 +382,7 @@ else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../Libraries/assimp/ INCLUDEPATH += $$PWD/../../Libraries/assimp/include DEPENDPATH += $$PWD/../../Libraries/assimp/include + +CONFIG(release, debug|release): LIBS += -LE:/C++/Libraries/boost_1_56_0/lib32-msvc-12.0 -llibboost_filesystem-vc120-mt-1_56 +CONFIG(debug, debug|release): LIBS += -LE:/C++/Libraries/boost_1_56_0/lib32-msvc-12.0 -llibboost_filesystem-vc120-mt-gd-1_56 +INCLUDEPATH += E:/C++/Libraries/boost_1_56_0 diff --git a/Resource/CAnimSet.cpp b/Resource/CAnimSet.cpp index 959c141f..2d3cb79b 100644 --- a/Resource/CAnimSet.cpp +++ b/Resource/CAnimSet.cpp @@ -11,7 +11,7 @@ CAnimSet::~CAnimSet() EResType CAnimSet::Type() { - return eCharacter; + return eAnimSet; } u32 CAnimSet::getNodeCount() diff --git a/Resource/cooker/CTemplateWriter.cpp b/Resource/cooker/CTemplateWriter.cpp new file mode 100644 index 00000000..37e1371f --- /dev/null +++ b/Resource/cooker/CTemplateWriter.cpp @@ -0,0 +1,451 @@ +#include "CTemplateWriter.h" +#include "../cooker/CWorldCooker.h" +#include +#include + +using namespace tinyxml2; + +CTemplateWriter::CTemplateWriter() +{ +} + +void CTemplateWriter::SaveAllTemplates() +{ + // Create directory + std::list masterList = CMasterTemplate::GetMasterList(); + std::string out = "../templates/"; + boost::filesystem::create_directory(out); + + // Resave master templates + for (auto it = masterList.begin(); it != masterList.end(); it++) + SaveGameTemplates(*it, out); + + // Resave game list + XMLDocument gameList; + + XMLDeclaration *pDecl = gameList.NewDeclaration(); + gameList.LinkEndChild(pDecl); + + XMLElement *pBase = gameList.NewElement("GameList"); + pBase->SetAttribute("version", 3); + gameList.LinkEndChild(pBase); + + for (auto it = masterList.begin(); it != masterList.end(); it++) + { + CMasterTemplate *pMaster = *it; + + XMLElement *pGame = gameList.NewElement("game"); + + XMLElement *pGameName = gameList.NewElement("name"); + pGameName->SetText(pMaster->mGameName.c_str()); + + XMLElement *pWorldVersion = gameList.NewElement("mlvl"); + u32 versionNumber = CWorldCooker::GetMLVLVersion(pMaster->GetGame()); + pWorldVersion->SetText(StringUtil::ToHexString(versionNumber, true, true, 2).c_str()); + + XMLElement *pTempPath = gameList.NewElement("master"); + pTempPath->SetText(pMaster->mSourceFile.c_str()); + + pGame->LinkEndChild(pGameName); + pGame->LinkEndChild(pWorldVersion); + pGame->LinkEndChild(pTempPath); + pBase->LinkEndChild(pGame); + } + + gameList.SaveFile((out + "GameList.xml").c_str()); +} + +void CTemplateWriter::SaveGameTemplates(CMasterTemplate *pMaster, const std::string& dir) +{ + // Create directory + std::string outFile = dir + pMaster->mSourceFile; + std::string outDir = StringUtil::GetFileDirectory(outFile); + boost::filesystem::create_directory(outDir); + + // Resave script templates + for (auto it = pMaster->mTemplates.begin(); it != pMaster->mTemplates.end(); it++) + SaveScriptTemplate(it->second, outDir); + + // Resave master template + XMLDocument master; + + XMLDeclaration *pDecl = master.NewDeclaration(); + master.LinkEndChild(pDecl); + + XMLElement *pBase = master.NewElement("MasterTemplate"); + pBase->SetAttribute("version", 3); + master.LinkEndChild(pBase); + + // Write property list + if (!pMaster->mPropertyList.empty()) + { + SavePropertyList(pMaster, outDir); + + XMLElement *pPropList = master.NewElement("properties"); + pPropList->SetText("Properties.xml"); + pBase->LinkEndChild(pPropList); + } + + // Write script objects + XMLElement *pObjects = master.NewElement("objects"); + pBase->LinkEndChild(pObjects); + + for (auto it = pMaster->mTemplates.begin(); it != pMaster->mTemplates.end(); it++) + { + std::string objID; + u32 intID = (it->second)->ObjectID(); + if (intID <= 0xFF) objID = StringUtil::ToHexString(intID, true, true, 2); + else objID = CFourCC(intID).ToString(); + + XMLElement *pObj = master.NewElement("object"); + pObj->SetAttribute("ID", objID.c_str()); + pObj->SetAttribute("template", (it->second)->mSourceFile.c_str()); + pObjects->LinkEndChild(pObj); + } + + // Write script states/messages + std::map *pMaps[2] = { &pMaster->mStates, &pMaster->mMessages }; + std::string types[2] = { "state", "message" }; + + for (u32 iScr = 0; iScr < 2; iScr++) + { + XMLElement *pElem = master.NewElement((types[iScr] + "s").c_str()); + pBase->LinkEndChild(pElem); + + for (auto it = pMaps[iScr]->begin(); it != pMaps[iScr]->end(); it++) + { + std::string ID; + if (it->first <= 0xFF) ID = StringUtil::ToHexString(it->first, true, true, 2); + else ID = CFourCC(it->first).ToString(); + + XMLElement *pSubElem = master.NewElement(types[iScr].c_str()); + pSubElem->SetAttribute("ID", ID.c_str()); + pSubElem->SetAttribute("name", (it->second).c_str()); + pElem->LinkEndChild(pSubElem); + } + } + + // Save file + master.SaveFile(outFile.c_str()); +} + +void CTemplateWriter::SavePropertyList(CMasterTemplate *pMaster, const std::string& dir) +{ + // Create XML + XMLDocument list; + + XMLDeclaration *pDecl = list.NewDeclaration(); + list.LinkEndChild(pDecl); + + XMLElement *pBase = list.NewElement("Properties"); + pBase->SetAttribute("version", 3); + list.LinkEndChild(pBase); + + // Write properties + for (auto it = pMaster->mPropertyList.begin(); it != pMaster->mPropertyList.end(); it++) + { + CPropertyTemplate *pTemp = it->second; + + if (pTemp->Type() == eStructProperty) + { + CStructTemplate *pStructTemp = static_cast(pTemp); + + XMLElement *pElem = list.NewElement("struct"); + pElem->SetAttribute("ID", StringUtil::ToHexString(pTemp->PropertyID(), true, true, 8).c_str()); + pElem->SetAttribute("name", pTemp->Name().c_str()); + + if (!pStructTemp->mSourceFile.empty()) + { + SaveStructTemplate(pStructTemp, pMaster, dir); + pElem->SetAttribute("template", pStructTemp->mSourceFile.c_str()); + } + + pBase->LinkEndChild(pElem); + } + + else + { + XMLElement *pElem = list.NewElement("property"); + pElem->SetAttribute("ID", StringUtil::ToHexString(pTemp->PropertyID(), true, true, 8).c_str()); + pElem->SetAttribute("name", pTemp->Name().c_str()); + pElem->SetAttribute("type", PropEnumToPropString(pTemp->Type()).c_str()); + + if (pTemp->Type() == eFileProperty) + { + // Construct extension list string + CFileTemplate *pFileProp = static_cast(pTemp); + const CStringList& extensions = pFileProp->Extensions(); + + std::string strList = ""; + + for (auto it = extensions.begin(); it != extensions.end();) + { + strList += *it; + it++; + if (it != extensions.end()) strList += ","; + } + + pElem->SetAttribute("ext", strList.c_str()); + } + + pBase->LinkEndChild(pElem); + } + } + + list.SaveFile((dir + "Properties.xml").c_str()); +} + +void CTemplateWriter::SaveScriptTemplate(CScriptTemplate *pTemp, const std::string& dir) +{ + // Create directory + std::string outFile = dir + pTemp->mSourceFile; + std::string outDir = StringUtil::GetFileDirectory(outFile); + boost::filesystem::create_directory(outDir); + + // Create new document + XMLDocument scriptXML; + + XMLDeclaration *pDecl = scriptXML.NewDeclaration(); + scriptXML.LinkEndChild(pDecl); + + // Base element + XMLElement *pBase = scriptXML.NewElement("ScriptTemplate"); + pBase->SetAttribute("version", 3.0f); + scriptXML.LinkEndChild(pBase); + + // Write object name + XMLElement *pName = scriptXML.NewElement("name"); + pName->SetText(pTemp->TemplateName().c_str()); + pBase->LinkEndChild(pName); + + // Write properties + for (auto it = pTemp->mPropertySets.begin(); it != pTemp->mPropertySets.end(); it++) + { + XMLElement *pProperties = scriptXML.NewElement("properties"); + pProperties->SetAttribute("version", it->SetName.c_str()); + SaveProperties(&scriptXML, pProperties, it->pBaseStruct, pTemp->MasterTemplate(), dir); + pBase->LinkEndChild(pProperties); + } + + // Write editor properties + XMLElement *pEditor = scriptXML.NewElement("editor"); + pBase->LinkEndChild(pEditor); + + // Editor Properties + XMLElement *pEditorProperties = scriptXML.NewElement("properties"); + pEditor->LinkEndChild(pEditorProperties); + + std::string 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]->empty()) + { + XMLElement *pProperty = scriptXML.NewElement("property"); + pProperty->SetAttribute("name", propNames[iProp].c_str()); + pProperty->SetAttribute("ID", pPropStrings[iProp]->c_str()); + pEditorProperties->LinkEndChild(pProperty); + } + } + + // Editor Assets + XMLElement *pAssets = scriptXML.NewElement("assets"); + pEditor->LinkEndChild(pAssets); + + for (auto it = pTemp->mAssets.begin(); it != pTemp->mAssets.end(); it++) + { + std::string type = (it->AssetType == CScriptTemplate::SEditorAsset::eAnimParams ? "animparams" : "model"); + std::string source = (it->AssetSource == CScriptTemplate::SEditorAsset::eFile ? "file" : "property"); + + s32 force = -1; + if (it->AssetSource == CScriptTemplate::SEditorAsset::eAnimParams) force = it->ForceNodeIndex; + + XMLElement *pAsset = scriptXML.NewElement(type.c_str()); + pAsset->SetAttribute("source", source.c_str()); + if (force >= 0) pAsset->SetAttribute("force", std::to_string(force).c_str()); + pAsset->SetText(it->AssetLocation.c_str()); + pAssets->LinkEndChild(pAsset); + } + + // 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) -> std::string + { + switch (shape) + { + case eBoxShape: return "Box"; + case eAxisAlignedBoxShape: return "AxisAlignedBox"; + case eEllipsoidShape: return "Ellipsoid"; + case eCylinderShape: return "Cylinder"; + case eCylinderLargeShape: return "CylinderLarge"; + case eConditionalShape: return "Conditional"; + default: return "INVALID"; + } + }; + + pVolume->SetAttribute("shape", GetVolumeString(pTemp->mVolumeShape).c_str()); + + if (pTemp->mVolumeShape == eConditionalShape) + { + pVolume->SetAttribute("propertyID", pTemp->mVolumeConditionIDString.c_str()); + + // Find conditional test property + CPropertyTemplate *pProp; + + for (auto it = pTemp->mPropertySets.begin(); it != pTemp->mPropertySets.end(); it++) + { + pProp = it->pBaseStruct->PropertyByIDString(pTemp->mVolumeConditionIDString); + if (pProp) break; + } + + // Write conditions + for (auto it = pTemp->mVolumeConditions.begin(); it != pTemp->mVolumeConditions.end(); it++) + { + // Value should be an integer, or a boolean condition? + std::string strVal; + + if (pProp->Type() == eBoolProperty) + strVal = (it->Value == 1 ? "true" : "false"); + else + strVal = StringUtil::ToHexString((u32) it->Value, true, true, (it->Value > 0xFF ? 8 : 2)); + + XMLElement *pCondition = scriptXML.NewElement("condition"); + pCondition->SetAttribute("value", strVal.c_str()); + pCondition->SetAttribute("shape", GetVolumeString(it->Shape).c_str()); + pVolume->LinkEndChild(pCondition); + } + } + } + + // Write to file + scriptXML.SaveFile(outFile.c_str()); +} + +void CTemplateWriter::SaveStructTemplate(CStructTemplate *pTemp, CMasterTemplate *pMaster, const std::string& dir) +{ + // Create directory + std::string outFile = dir + pTemp->mSourceFile; + std::string outDir = StringUtil::GetFileDirectory(outFile); + std::string name = StringUtil::GetFileName(pTemp->mSourceFile); + boost::filesystem::create_directory(outDir); + + // Create new document and write struct properties to it + XMLDocument structXML; + + XMLDeclaration *pDecl = structXML.NewDeclaration(); + structXML.LinkEndChild(pDecl); + + XMLElement *pBase = structXML.NewElement("struct"); + pBase->SetAttribute("name", name.c_str()); + pBase->SetAttribute("type", (pTemp->IsSingleProperty() ? "single" : "multi")); + SaveProperties(&structXML, pBase, pTemp, pMaster, dir); + structXML.LinkEndChild(pBase); + + structXML.SaveFile(outFile.c_str()); +} + +void CTemplateWriter::SaveProperties(XMLDocument *pDoc, XMLElement *pParent, CStructTemplate *pTemp, CMasterTemplate *pMaster, const std::string& dir) +{ + for (u32 iProp = 0; iProp < pTemp->Count(); iProp++) + { + CPropertyTemplate *pProp = pTemp->PropertyByIndex(iProp); + u32 propID = (pProp->PropertyID() == 0xFFFFFFFF ? iProp : pProp->PropertyID()); + std::string strID = StringUtil::ToHexString(propID, true, true, (propID > 0xFF ? 8 : 2)); + + if (pProp->Type() == eStructProperty) + { + CStructTemplate *pStructTemp = static_cast(pProp); + bool isExternal = (!pStructTemp->mSourceFile.empty()); + + XMLElement *pElem = pDoc->NewElement("struct"); + pElem->SetAttribute("ID", strID.c_str()); + + if ((!pMaster->HasPropertyList()) || (pProp->PropertyID() == -1) || pTemp->IsSingleProperty()) + { + pElem->SetAttribute("name", pProp->Name().c_str()); + } + + if (!isExternal) { + std::string type = pStructTemp->IsSingleProperty() ? "single" : "multi"; + pElem->SetAttribute("type", type.c_str()); + } + + // Only save properties if this is a multi struct, or if there is no master property list + if (!pMaster->HasPropertyList() || !pStructTemp->IsSingleProperty()) + { + // Embed struct or save to external XML? + if (!pStructTemp->mSourceFile.empty()) + { + SaveStructTemplate(pStructTemp, pMaster, dir); + pElem->SetAttribute("template", pStructTemp->mSourceFile.c_str()); + } + + else + { + SaveProperties(pDoc, pElem, pStructTemp, pMaster, dir); + } + } + + pParent->LinkEndChild(pElem); + } + + else + { + XMLElement *pElem = pDoc->NewElement("property"); + pElem->SetAttribute("ID", strID.c_str()); + + if ((!pMaster->HasPropertyList()) || (pProp->PropertyID() == -1) || pTemp->IsSingleProperty()) + { + pElem->SetAttribute("name", pProp->Name().c_str()); + pElem->SetAttribute("type", PropEnumToPropString(pProp->Type()).c_str()); + + if (pProp->Type() == eFileProperty) + { + // Construct extension list string + CFileTemplate *pFileProp = static_cast(pProp); + const CStringList& extensions = pFileProp->Extensions(); + + std::string strList = ""; + + for (auto it = extensions.begin(); it != extensions.end();) + { + strList += *it; + it++; + if (it != extensions.end()) strList += ","; + } + + pElem->SetAttribute("ext", strList.c_str()); + } + } + + pParent->LinkEndChild(pElem); + } + } +} + diff --git a/Resource/cooker/CTemplateWriter.h b/Resource/cooker/CTemplateWriter.h new file mode 100644 index 00000000..7538c1d1 --- /dev/null +++ b/Resource/cooker/CTemplateWriter.h @@ -0,0 +1,21 @@ +#ifndef CTEMPLATEWRITER_H +#define CTEMPLATEWRITER_H + +#include "../script/CMasterTemplate.h" +#include "../script/CScriptTemplate.h" + +class CTemplateWriter +{ + CTemplateWriter(); + +public: + static void SaveAllTemplates(); + static void SaveGameTemplates(CMasterTemplate *pMaster, const std::string& dir); + static void SavePropertyList(CMasterTemplate *pMaster, const std::string& dir); + static void SaveScriptTemplate(CScriptTemplate *pTemp, const std::string& dir); + static void SaveStructTemplate(CStructTemplate *pTemp, CMasterTemplate *pMaster, const std::string& dir); + static void SaveProperties(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CStructTemplate *pTemp, CMasterTemplate *pMaster, const std::string& dir); + // todo: save enum templates +}; + +#endif // CTEMPLATEWRITER_H diff --git a/Resource/cooker/CWorldCooker.cpp b/Resource/cooker/CWorldCooker.cpp new file mode 100644 index 00000000..b42e1681 --- /dev/null +++ b/Resource/cooker/CWorldCooker.cpp @@ -0,0 +1,19 @@ +#include "CWorldCooker.h" + +CWorldCooker::CWorldCooker() +{ +} + +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; + default: return 0; + } +} diff --git a/Resource/cooker/CWorldCooker.h b/Resource/cooker/CWorldCooker.h new file mode 100644 index 00000000..e1b03597 --- /dev/null +++ b/Resource/cooker/CWorldCooker.h @@ -0,0 +1,14 @@ +#ifndef CWORLDCOOKER_H +#define CWORLDCOOKER_H + +#include +#include "../EFormatVersion.h" + +class CWorldCooker +{ + CWorldCooker(); +public: + static u32 GetMLVLVersion(EGame version); +}; + +#endif // CWORLDCOOKER_H diff --git a/Resource/factory/CScriptLoader.cpp b/Resource/factory/CScriptLoader.cpp index 57755076..fd8bd5e5 100644 --- a/Resource/factory/CScriptLoader.cpp +++ b/Resource/factory/CScriptLoader.cpp @@ -10,78 +10,78 @@ CScriptLoader::CScriptLoader() mpObj = nullptr; } -CPropertyStruct* CScriptLoader::LoadStructMP1(CInputStream& SCLY, CStructTemplate *tmp) +CPropertyStruct* CScriptLoader::LoadStructMP1(CInputStream& SCLY, CStructTemplate *pTemp) { - u32 StructStart = SCLY.Tell(); - CPropertyStruct *PropStruct = new CPropertyStruct(); - PropStruct->tmp = tmp; + u32 structStart = SCLY.Tell(); + CPropertyStruct *propStruct = new CPropertyStruct(); + propStruct->mpTemplate = pTemp; // Verify property count - s32 TemplatePropCount = tmp->TemplateCount(); - if (TemplatePropCount >= 0) + u32 propCount = pTemp->Count(); + + if (!pTemp->IsSingleProperty()) { - u32 FilePropCount = SCLY.ReadLong(); - if (TemplatePropCount != FilePropCount) - Log::FileWarning(SCLY.GetSourceString(), StructStart, "Struct \"" + tmp->Name() + "\" template prop count doesn't match file"); + u32 filePropCount = SCLY.ReadLong(); + if (propCount != filePropCount) + Log::FileWarning(SCLY.GetSourceString(), structStart, "Struct \"" + pTemp->Name() + "\" template prop count doesn't match file"); } // Parse properties - u32 PropCount = tmp->Count(); - PropStruct->Reserve(PropCount); + propStruct->Reserve(propCount); - for (u32 p = 0; p < PropCount; p++) + for (u32 iProp = 0; iProp < propCount; iProp++) { - CPropertyBase *prop = nullptr; - CPropertyTemplate *proptmp = tmp->PropertyByIndex(p); - EPropertyType type = proptmp->Type(); + CPropertyBase *pProp = nullptr; + CPropertyTemplate *pPropTmp = pTemp->PropertyByIndex(iProp); + EPropertyType type = pPropTmp->Type(); switch (type) { case eBoolProperty: { bool v = (SCLY.ReadByte() == 1); - prop = new CBoolProperty(v); + pProp = new CBoolProperty(v); break; } case eByteProperty: { char v = SCLY.ReadByte(); - prop = new CByteProperty(v); + pProp = new CByteProperty(v); break; } case eShortProperty: { short v = SCLY.ReadShort(); - prop = new CShortProperty(v); + pProp = new CShortProperty(v); break; } case eLongProperty: { long v = SCLY.ReadLong(); - prop = new CLongProperty(v); + pProp = new CLongProperty(v); break; } case eFloatProperty: { float v = SCLY.ReadFloat(); - prop = new CFloatProperty(v); + pProp = new CFloatProperty(v); break; } case eStringProperty: { std::string v = SCLY.ReadString(); - prop = new CStringProperty(v); + pProp = new CStringProperty(v); break; } case eVector3Property: { CVector3f v(SCLY); - prop = new CVector3Property(v); + pProp = new CVector3Property(v); break; } case eColorProperty: { CVector4f color(SCLY); CColor v(color.x, color.y, color.z, color.w); - prop = new CColorProperty(v); + pProp = new CColorProperty(v); break; } case eFileProperty: { u32 ResID = SCLY.ReadLong(); - const CStringList& Extensions = static_cast(proptmp)->Extensions(); + const CStringList& Extensions = static_cast(pPropTmp)->Extensions(); CResource *pRes = nullptr; @@ -94,65 +94,75 @@ CPropertyStruct* CScriptLoader::LoadStructMP1(CInputStream& SCLY, CStructTemplat if (pRes) break; } - prop = new CFileProperty(pRes); + pProp = new CFileProperty(pRes); break; } case eStructProperty: { - CStructTemplate *StructTmp = tmp->StructByIndex(p); - prop = LoadStructMP1(SCLY, StructTmp); + CStructTemplate *StructTmp = pTemp->StructByIndex(iProp); + pProp = LoadStructMP1(SCLY, StructTmp); break; } + default: + pProp = new CUnknownProperty(); + break; } - if (prop) + if (pProp) { - prop->tmp = proptmp; - PropStruct->Properties.push_back(prop); + pProp->mpTemplate = pPropTmp; + propStruct->mProperties.push_back(pProp); } } - return PropStruct; + return propStruct; } CScriptObject* CScriptLoader::LoadObjectMP1(CInputStream& SCLY) { - u32 ObjStart = SCLY.Tell(); + u32 objStart = SCLY.Tell(); u8 type = SCLY.ReadByte(); u32 size = SCLY.ReadLong(); u32 end = SCLY.Tell() + size; - CScriptTemplate *tmp = mpMaster->TemplateByID((u32) type); - if (!tmp) + CScriptTemplate *pTemp = mpMaster->TemplateByID((u32) type); + if (!pTemp) { // No valid template for this object; can't load - Log::FileError(SCLY.GetSourceString(), ObjStart, "Invalid object ID encountered - " + StringUtil::ToHexString(type)); + Log::FileError(SCLY.GetSourceString(), objStart, "Invalid object ID encountered: " + StringUtil::ToHexString(type)); SCLY.Seek(end, SEEK_SET); return nullptr; } - mpObj = new CScriptObject(mpArea, mpLayer, tmp); + mpObj = new CScriptObject(mpArea, mpLayer, pTemp); mpObj->mInstanceID = SCLY.ReadLong(); // Load connections - u32 numConnections = SCLY.ReadLong(); - mpObj->mOutConnections.reserve(numConnections); + u32 numLinks = SCLY.ReadLong(); + mpObj->mOutConnections.reserve(numLinks); - for (u32 c = 0; c < numConnections; c++) + for (u32 iLink = 0; iLink < numLinks; iLink++) { - SLink con; - con.State = SCLY.ReadLong(); - con.Message = SCLY.ReadLong(); - con.ObjectID = SCLY.ReadLong(); - mpObj->mOutConnections.push_back(con); + SLink link; + link.State = SCLY.ReadLong(); + link.Message = SCLY.ReadLong(); + link.ObjectID = SCLY.ReadLong(); + mpObj->mOutConnections.push_back(link); } // Load object... - CStructTemplate *base = tmp->BaseStruct(); - mpObj->mpProperties = LoadStructMP1(SCLY, base); - SetupAttribs(); + u32 count = SCLY.PeekLong(); + CStructTemplate *pBase = pTemp->BaseStructByCount(count); + + if (!pBase) { + Log::Error(pTemp->TemplateName() + " template doesn't match file property count (" + StringUtil::ToString(count) + ")"); + pBase = pTemp->BaseStructByIndex(0); + } + mpObj->mpProperties = LoadStructMP1(SCLY, pBase); // Cleanup and return SCLY.Seek(end, SEEK_SET); + + mpObj->EvaluateProperties(); return mpObj; } @@ -184,41 +194,41 @@ void CScriptLoader::LoadStructMP2(CInputStream& SCLY, CPropertyStruct *pStruct, // Verify property count if (!pTemp->IsSingleProperty()) { - u16 NumProperties = SCLY.ReadShort(); - if ((pTemp->TemplateCount() >= 0) && (NumProperties != pTemp->TemplateCount())) + u16 numProperties = SCLY.ReadShort(); + if (numProperties != pTemp->Count()) Log::FileWarning(SCLY.GetSourceString(), SCLY.Tell() - 2, "Struct \"" + pTemp->Name() + "\" template property count doesn't match file"); } // Parse properties - u32 PropCount = pTemp->Count(); - pStruct->Reserve(PropCount); + u32 propCount = pTemp->Count(); + pStruct->Reserve(propCount); - for (u32 p = 0; p < PropCount; p++) + for (u32 iProp = 0; iProp < propCount; iProp++) { CPropertyBase *pProp; CPropertyTemplate *pPropTemp; - u32 PropertyStart = SCLY.Tell(); - u32 PropertyID = -1; + u32 propertyStart = SCLY.Tell(); + u32 propertyID = -1; u16 PropertyLength = 0; u32 NextProperty = 0; if (pTemp->IsSingleProperty()) { - pProp = pStruct->PropertyByIndex(p); - pPropTemp = pTemp->PropertyByIndex(p); + pProp = pStruct->PropertyByIndex(iProp); + pPropTemp = pTemp->PropertyByIndex(iProp); } else { - PropertyID = SCLY.ReadLong(); + propertyID = SCLY.ReadLong(); PropertyLength = SCLY.ReadShort(); NextProperty = SCLY.Tell() + PropertyLength; - pProp = pStruct->PropertyByID(PropertyID); - pPropTemp = pTemp->PropertyByID(PropertyID); + pProp = pStruct->PropertyByID(propertyID); + pPropTemp = pTemp->PropertyByID(propertyID); } if (!pPropTemp) - Log::FileError(SCLY.GetSourceString(), PropertyStart, "Can't find template for property " + StringUtil::ToHexString(PropertyID) + " - skipping"); + Log::FileError(SCLY.GetSourceString(), propertyStart, "Can't find template for property " + StringUtil::ToHexString(propertyID) + " - skipping"); else { @@ -312,7 +322,7 @@ void CScriptLoader::LoadStructMP2(CInputStream& SCLY, CPropertyStruct *pStruct, if (it != Extensions.begin()) ExtList += "/"; ExtList += *it; } - Log::FileWarning(SCLY.GetSourceString(), "Incorrect resource type? " + ExtList + " " + StringUtil::ToHexString(PropertyID)); + Log::FileWarning(SCLY.GetSourceString(), "Incorrect resource type? " + ExtList + " " + StringUtil::ToHexString(propertyID)); } pFileCast->Set(pRes); @@ -333,6 +343,14 @@ void CScriptLoader::LoadStructMP2(CInputStream& SCLY, CPropertyStruct *pStruct, break; } + case eArrayProperty: { + CArrayProperty *pArrayCast = static_cast(pProp); + std::vector buf(PropertyLength); + SCLY.ReadBytes(buf.data(), buf.size()); + pArrayCast->Set(buf); + break; + } + } } @@ -357,7 +375,7 @@ CScriptObject* CScriptLoader::LoadObjectMP2(CInputStream& SCLY) return nullptr; } - mpObj = CScriptObject::CopyFromTemplate(pTemplate, mpArea, mpLayer); + mpObj = new CScriptObject(mpArea, mpLayer, pTemplate); mpObj->mpTemplate = pTemplate; mpObj->mInstanceID = SCLY.ReadLong(); @@ -375,12 +393,16 @@ CScriptObject* CScriptLoader::LoadObjectMP2(CInputStream& SCLY) } // Load object - CStructTemplate *pBase = pTemplate->BaseStruct(); SCLY.Seek(0x6, SEEK_CUR); // Skip base struct ID + size - LoadStructMP2(SCLY, mpObj->mpProperties, pBase); - SetupAttribs(); + u16 numProps = SCLY.PeekShort(); + mpObj->CopyFromTemplate(pTemplate, (u32) numProps); + CStructTemplate *pBase = pTemplate->BaseStructByCount(numProps); + LoadStructMP2(SCLY, mpObj->mpProperties, pBase); + + // Cleanup and return SCLY.Seek(ObjEnd, SEEK_SET); + mpObj->EvaluateProperties(); return mpObj; } @@ -416,32 +438,6 @@ CScriptLayer* CScriptLoader::LoadLayerMP2(CInputStream& SCLY) return mpLayer; } -void CScriptLoader::SetupAttribs() -{ - // Add template attributes - u32 numAttribs = mpObj->mpTemplate->AttribCount(); - for (u32 a = 0; a < numAttribs; a++) - { - CAttribTemplate *AttribTmp = mpObj->mpTemplate->Attrib(a); - CPropertyBase *prop = mpObj->PropertyByName( AttribTmp->Target() ); - - // Check for static resource - CResource *res = nullptr; - std::string ResStr = AttribTmp->Resource(); - if (!ResStr.empty()) - res = gResCache.GetResource(ResStr); - - mpObj->mAttribs.emplace_back(CScriptObject::SAttrib(AttribTmp->Type(), res, AttribTmp->Settings(), prop) ); - mpObj->mAttribFlags |= AttribTmp->Type(); - } - - // Initial attribute evaluation - mpObj->EvaluateInstanceName(); - mpObj->EvalutateXForm(); - mpObj->EvaluateTevColor(); - mpObj->EvaluateDisplayModel(); -} - CScriptLayer* CScriptLoader::LoadLayer(CInputStream &SCLY, CGameArea *pArea, EGame version) { if (!SCLY.IsValid()) return nullptr; diff --git a/Resource/factory/CTemplateLoader.cpp b/Resource/factory/CTemplateLoader.cpp index 32521a71..0ffa81be 100644 --- a/Resource/factory/CTemplateLoader.cpp +++ b/Resource/factory/CTemplateLoader.cpp @@ -3,474 +3,408 @@ #include "../script/EAttribType.h" #include -// ************ PROPERTY ************ -CPropertyTemplate* CTemplateLoader::LoadPropertyTemplate(tinyxml2::XMLElement *pElem, const std::string& TemplateName) +void CTemplateLoader::LoadStructProperties(tinyxml2::XMLElement *pElem, CStructTemplate *pTemp, const std::string& templateName) { - const char *pElemName = pElem->Name(); + tinyxml2::XMLElement *pChild = pElem->FirstChildElement(); - // Load multi-property struct - if (strcmp(pElemName, "struct") == 0) + while (pChild) { - CStructTemplate *pStruct = LoadStructTemplate(pElem, TemplateName); + CPropertyTemplate *pProp = LoadPropertyTemplate(pChild, templateName); - if (pStruct) - pStruct->mIsSingleProperty = false; + if (pProp) + pTemp->mProperties.push_back(pProp); - return pStruct; + pChild = pChild->NextSiblingElement(); + } +} + +CPropertyTemplate* CTemplateLoader::LoadPropertyTemplate(tinyxml2::XMLElement *pElem, const std::string& templateName) +{ + const char *kpIDStr = pElem->Attribute("ID"); + const char *kpNameStr = pElem->Attribute("name"); + const char *kpTypeStr = pElem->Attribute("type"); + const char *kpExtensionsStr = pElem->Attribute("ext"); + const char *kpTemplateStr = pElem->Attribute("template"); + + // Get ID + name, find source template if it exists + u32 ID = StringUtil::ToInt32(kpIDStr); + CPropertyTemplate *pSource = nullptr; + std::string name; + + if (mpMaster->HasPropertyList()) + pSource = mpMaster->GetProperty(ID); + + if (kpNameStr) + name = kpNameStr; + else if (pSource) + name = pSource->Name(); + else + name = StringUtil::ToHexString(ID); + + // Load Property + if (strcmp(pElem->Name(), "property") == 0) + { + CPropertyTemplate *pProp; + EPropertyType type = eInvalidProperty; + + // Type + if (kpTypeStr) + type = PropStringToPropEnum(kpTypeStr); + else if (pSource) + type = pSource->Type(); + + // File property + if (type == eFileProperty) + { + CStringList extensions; + if (kpExtensionsStr) + extensions = StringUtil::Tokenize(kpExtensionsStr, ","); + else if (pSource) + extensions = static_cast(pSource)->Extensions(); + + pProp = new CFileTemplate(name, ID, extensions); + } + + // Regular property + else + pProp = new CPropertyTemplate(type, name, ID); + + return pProp; } - else if (strcmp(pElemName, "property") == 0) + // Load Struct + else if (strcmp(pElem->Name(), "struct") == 0) { - // Get name, type, and ID - std::string Name; - EPropertyType Type; - u32 ID; - GetPropertyInfo(pElem, Name, Type, ID); + CStructTemplate *pStruct = new CStructTemplate(); - // Error check - if (Type == eInvalidProperty) + pStruct->mPropID = ID; + + // Read children properties + // Priority: [Embedded] -> [Template] -> [Master] + + // Embedded + if (!pElem->NoChildren()) + LoadStructProperties(pElem, pStruct, templateName); + + // Template + else if (kpTemplateStr) { - const char *pType = pElem->Attribute("type"); + std::string tempPath = mMasterDir + kpTemplateStr; - if (pType) - Log::Error("Invalid property type in " + TemplateName + " template: " + pType); - else - Log::Error("Property " + Name + " in " + TemplateName + " template has no type"); - } + tinyxml2::XMLDocument structXML; + structXML.LoadFile(tempPath.c_str()); - // Load single-property struct - if (Type == eStructProperty) - { - CStructTemplate *pStruct = LoadStructTemplate(pElem, TemplateName); - pStruct->mIsSingleProperty = true; - return pStruct; - } - - // Load file property - else if (Type == eFileProperty) - { - // Fetch file extension - CFileTemplate *pFile = nullptr; - const char *pExt = pElem->Attribute("ext"); - - if (pExt) - pFile = new CFileTemplate(Name, ID, StringUtil::Tokenize(pExt, ",")); + if (structXML.Error()) + Log::Error("Couldn't open struct XML: " + mMasterDir + kpTemplateStr); else { - CFileTemplate *pSrc = (CFileTemplate*) mpMaster->GetProperty(ID); + tinyxml2::XMLElement *pRoot = structXML.FirstChildElement("struct"); + pStruct->mSourceFile = kpTemplateStr; - if (pSrc) - pFile = new CFileTemplate(Name, ID, pSrc->Extensions()); + if (pRoot->Attribute("type")) + pStruct->mIsSingleProperty = (strcmp(pRoot->Attribute("type"), "single") == 0); + + if (pRoot->Attribute("name")) + pStruct->mPropName = pRoot->Attribute("name"); + + LoadStructProperties(pRoot, pStruct, templateName); } - - // Check if extensions are valid - if (!pFile) - { - Log::Error("File property " + Name + " in " + TemplateName + " template has no extension"); - return nullptr; - } - - else - return pFile; } - // Load regular property - else + // Master + else if (pSource) { - CPropertyTemplate *pProperty = new CPropertyTemplate(Type, Name, ID); - return pProperty; + CStructTemplate *pSourceStruct = static_cast(pSource); + + for (u32 iProp = 0; iProp < pSourceStruct->Count(); iProp++) + pStruct->mProperties.push_back(pSourceStruct->PropertyByIndex(iProp)); } + + // If it's none of these, then it probably has no children because it's a property list entry. + + // Single property? + if (kpTypeStr) + pStruct->mIsSingleProperty = (strcmp(kpTypeStr, "single") == 0); + else if (pSource) + pStruct->mIsSingleProperty = static_cast(pSource)->IsSingleProperty(); + + // Name + if (!name.empty()) + pStruct->mPropName = name; + + return pStruct; } return nullptr; } -CStructTemplate* CTemplateLoader::LoadStructTemplate(tinyxml2::XMLElement *pElem, const std::string& TemplateName) +// ************ SCRIPT OBJECT ************ +CScriptTemplate* CTemplateLoader::LoadScriptTemplate(tinyxml2::XMLDocument *pDoc, const std::string& templateName, u32 objectID) { - CStructTemplate *pStruct = new CStructTemplate(); + CScriptTemplate *pScript = new CScriptTemplate(mpMaster); + pScript->mObjectID = objectID; - // Get name, type, and ID - GetPropertyInfo(pElem, pStruct->mPropName, pStruct->mPropType, pStruct->mPropID); - const char *pTemp = pElem->Attribute("template"); - if (!pTemp) pTemp = pElem->Attribute("target"); + tinyxml2::XMLElement *pRoot = pDoc->FirstChildElement("ScriptTemplate"); - // Get source template from the master property list, if it exists - CStructTemplate *pSrc = (CStructTemplate*) mpMaster->GetProperty(pStruct->mPropID); + // Name + tinyxml2::XMLElement *pNameElem = pRoot->FirstChildElement("name"); - // "IsSingleProperty" means, does the struct contain multiple properties, each with separate IDs - // or does the entire struct as a whole count as just one property? - if (pSrc) - pStruct->mIsSingleProperty = pSrc->IsSingleProperty(); - else - pStruct->mIsSingleProperty = (strcmp(pElem->Name(), "property") == 0); + if (pNameElem) + pScript->mTemplateName = pNameElem->GetText(); - // Read struct children. Priority is [Embedded -> Template -> Master]. - // Embedded - if (!pElem->NoChildren()) + // Properties + tinyxml2::XMLElement *pPropsElem = pRoot->FirstChildElement("properties"); + + while (pPropsElem) { - // Get count - const char *pCount = pElem->Attribute("count"); + CScriptTemplate::SPropertySet set; - if (pCount) - pStruct->mPropertyCount = std::stoul(pCount); - - // Parse sub-elements - tinyxml2::XMLElement *pChild = pElem->FirstChildElement(); - - while (pChild) - { - CPropertyTemplate *pProp = LoadPropertyTemplate(pChild, TemplateName); - - if (pProp) - pStruct->mProperties.push_back(pProp); - - pChild = pChild->NextSiblingElement(); - } + const char *kpVersion = pPropsElem->Attribute("version"); + set.SetName = (kpVersion ? kpVersion : ""); + set.pBaseStruct = new CStructTemplate(); + set.pBaseStruct->mIsSingleProperty = false; + set.pBaseStruct->mPropID = -1; + set.pBaseStruct->mPropName = pScript->mTemplateName; + LoadStructProperties(pPropsElem, set.pBaseStruct, pScript->mTemplateName); + pScript->mPropertySets.push_back(set); + pPropsElem = pPropsElem->NextSiblingElement("properties"); } - // Template - else if (pTemp) + // Editor Parameters + tinyxml2::XMLElement *pEditor = pRoot->FirstChildElement("editor"); + + if (pEditor) { - // Get handle for XML - std::string TempPath = mMasterDir + pTemp; + // Editor Properties + tinyxml2::XMLElement *pEdProperties = pEditor->FirstChildElement("properties"); + tinyxml2::XMLElement *pEdProp = pEdProperties->FirstChildElement("property"); - tinyxml2::XMLDocument TempXML; - TempXML.LoadFile(TempPath.c_str()); - - if (TempXML.Error()) - Log::Error("Couldn't open struct template: " + TempPath); - - else + while (pEdProp) { - tinyxml2::XMLElement *pVersionElem = TempXML.FirstChildElement()->FirstChildElement("version"); - tinyxml2::XMLElement *pPropertiesElem = TempXML.FirstChildElement()->FirstChildElement("properties"); + const char *kpName = pEdProp->Attribute("name"); + const char *kpID = pEdProp->Attribute("ID"); - if (!pVersionElem) Log::Error("Struct template has no version element: " + TempPath); - if (!pPropertiesElem) Log::Error("Struct template has no properties element: " + TempPath); - - if (pVersionElem && pPropertiesElem) + if (kpName && kpID) { - // Get version number - u32 VersionNumber = std::stoul(pVersionElem->GetText()); + if (strcmp(kpName, "InstanceName") == 0) + pScript->mNameIDString = kpID; + else if (strcmp(kpName, "Position") == 0) + pScript->mPositionIDString = kpID; + else if (strcmp(kpName, "Rotation") == 0) + pScript->mRotationIDString = kpID; + else if (strcmp(kpName, "Scale") == 0) + pScript->mScaleIDString = kpID; + else if (strcmp(kpName, "Active") == 0) + pScript->mActiveIDString = kpID; + else if (strcmp(kpName, "LightParameters") == 0) + pScript->mLightParametersIDString = kpID; + } - // Get property count - const char *pCount = pPropertiesElem->Attribute("count"); + pEdProp = pEdProp->NextSiblingElement("property"); + } - if (pCount) - pStruct->mPropertyCount = std::stoul(pCount); + // Editor Assets + tinyxml2::XMLElement *pEdAssets = pEditor->FirstChildElement("assets"); + tinyxml2::XMLElement *pAsset = pEdAssets->FirstChildElement(); - // Parse properties - tinyxml2::XMLElement *pPropElem = pPropertiesElem->FirstChildElement(); + while (pAsset) + { + const char *kpSource = pAsset->Attribute("source"); + const char *kpID = pAsset->GetText(); - while (pPropElem) + if (kpSource && kpID) + { + CScriptTemplate::SEditorAsset asset; + + if (strcmp(pAsset->Name(), "animparams") == 0) + asset.AssetType = CScriptTemplate::SEditorAsset::eAnimParams; + else if (strcmp(pAsset->Name(), "model") == 0) + asset.AssetType = CScriptTemplate::SEditorAsset::eModel; + else { - if (!pPropElem) break; + pAsset = pAsset->NextSiblingElement(); + continue; + } - CPropertyTemplate *pProp = LoadPropertyTemplate(pPropElem, TemplateName); + if (strcmp(kpSource, "property") == 0) + asset.AssetSource = CScriptTemplate::SEditorAsset::eProperty; + else if (strcmp(kpSource, "file") == 0) + asset.AssetSource = CScriptTemplate::SEditorAsset::eFile; + else + { + pAsset = pAsset->NextSiblingElement(); + continue; + } - if (pProp) - pStruct->mProperties.push_back(pProp); + const char *kpForce = pAsset->Attribute("force"); + if (kpForce) + asset.ForceNodeIndex = StringUtil::ToInt32(kpForce); + else + asset.ForceNodeIndex = -1; - pPropElem = pPropElem->NextSiblingElement(); + asset.AssetLocation = kpID; + pScript->mAssets.push_back(asset); + } + + pAsset = pAsset->NextSiblingElement(); + } + + // Rotation + tinyxml2::XMLElement *pRotType = pEditor->FirstChildElement("rotation_type"); + + if (pRotType) + { + const char *kpType = pRotType->GetText(); + + if (kpType) + { + if (strcmp(kpType, "disabled") == 0) pScript->mRotationType = CScriptTemplate::eRotationDisabled; + else pScript->mRotationType = CScriptTemplate::eRotationEnabled; + } + } + + // Scale + tinyxml2::XMLElement *pScaleType = pEditor->FirstChildElement("scale_type"); + + if (pScaleType) + { + const char *kpType = pScaleType->GetText(); + + if (kpType) + { + if (strcmp(kpType, "disabled") == 0) pScript->mScaleType = CScriptTemplate::eScaleDisabled; + else if (strcmp(kpType, "volume") == 0) pScript->mScaleType = CScriptTemplate::eScaleVolume; + else pScript->mScaleType = CScriptTemplate::eScaleEnabled; + } + } + + // Preview Volume + if (pScript->mScaleType == CScriptTemplate::eScaleVolume) + { + tinyxml2::XMLElement *pVolume = pEditor->FirstChildElement("preview_volume"); + + // Lambda to avoid duplicating volume shape code + auto GetVolumeType = [](const char *kpType) -> EVolumeShape { + if (strcmp(kpType, "none") == 0) return eNoShape; + if (strcmp(kpType, "Box") == 0) return eBoxShape; + if (strcmp(kpType, "AxisAlignedBox") == 0) return eAxisAlignedBoxShape; + if (strcmp(kpType, "Ellipsoid") == 0) return eEllipsoidShape; + if (strcmp(kpType, "Cylinder") == 0) return eCylinderShape; + if (strcmp(kpType, "CylinderLarge") == 0) return eCylinderLargeShape; + if (strcmp(kpType, "Conditional") == 0) return eConditionalShape; + return eInvalidShape; + }; + + const char *kpShape = pVolume->Attribute("shape"); + + if (kpShape) + pScript->mVolumeShape = GetVolumeType(kpShape); + + // Conditional + if (pScript->mVolumeShape == eConditionalShape) + { + const char *kpID = pVolume->Attribute("propertyID"); + + if (kpID) + { + pScript->mVolumeConditionIDString = kpID; + tinyxml2::XMLElement *pCondition = pVolume->FirstChildElement("condition"); + + while (pCondition) + { + const char *kpConditionValue = pCondition->Attribute("value"); + const char *kpConditionShape = pCondition->Attribute("shape"); + + if (kpConditionValue && kpConditionShape) + { + CScriptTemplate::SVolumeCondition condition; + condition.Shape = GetVolumeType(kpConditionShape); + + if (strcmp(kpConditionValue, "true") == 0) + condition.Value = 1; + else if (strcmp(kpConditionValue, "false") == 0) + condition.Value = 0; + else + condition.Value = StringUtil::ToInt32(kpConditionValue); + + pScript->mVolumeConditions.push_back(condition); + } + + pCondition = pCondition->NextSiblingElement("condition"); + } } } } } - // Master - else if (pSrc) - { - pStruct->mPropertyCount = pSrc->TemplateCount(); - - for (u32 p = 0; p < pSrc->Count(); p++) - pStruct->mProperties.push_back(pSrc->PropertyByIndex(p)); - } - - // If it's none of these things, then it probably has no children because it's a property list entry - return pStruct; -} - -void CTemplateLoader::GetPropertyInfo(tinyxml2::XMLElement *pElem, std::string& Name, EPropertyType& Type, u32& ID) -{ - const char *pNameStr = pElem->Attribute("name"); - const char *pTypeStr = pElem->Attribute("type"); - const char *pIDStr = pElem->Attribute("ID"); - bool IsBaseStruct = (strcmp(pElem->Name(), "properties") == 0); - - // Fetch source template, if available - CPropertyTemplate *pSrcTmp; - - if (pIDStr) - { - ID = std::stoul(pIDStr, 0, 16); - pSrcTmp = mpMaster->GetProperty(ID); - } - else - { - ID = 0xFFFFFFFF; - pSrcTmp = nullptr; - } - - // Get name - if (pNameStr) - Name = pNameStr; - else if (pSrcTmp) - Name = pSrcTmp->Name(); - else if (IsBaseStruct) - Name = "Base"; - else - Name = ""; - - // Get type - if (strcmp(pElem->Name(), "struct") == 0) - Type = eStructProperty; - else if (IsBaseStruct) - Type = eStructProperty; - else if (pTypeStr) - Type = PropStringToPropEnum(pTypeStr); - else if (pSrcTmp) - Type = pSrcTmp->Type(); - else - Type = eInvalidProperty; -} - -// ************ SCRIPT OBJECT ************ -CScriptTemplate* CTemplateLoader::LoadScriptTemplate(tinyxml2::XMLDocument *pDoc, const std::string& TemplateName, u32 ObjectID) -{ - tinyxml2::XMLElement *pBaseElement = pDoc->FirstChildElement(); - - CScriptTemplate *pScript = new CScriptTemplate(mpMaster); - pScript->mObjectID = ObjectID; - pScript->mTemplateName = pBaseElement->Name(); - - // Properties? - tinyxml2::XMLElement *pProperties = pBaseElement->FirstChildElement("properties"); - if (pProperties) - { - pScript->mpBaseStruct = LoadStructTemplate(pBaseElement->FirstChildElement("properties"), TemplateName); - pScript->mpBaseStruct->SetName(pScript->mTemplateName); - } - - // Attribs? - tinyxml2::XMLElement *pAttributes = pBaseElement->FirstChildElement("attributes"); - if (pAttributes) LoadScriptAttribs(pAttributes, pScript); - return pScript; } -void CTemplateLoader::LoadScriptAttribs(tinyxml2::XMLElement *pElem, CScriptTemplate *pScript) -{ - // Parsing attribs - tinyxml2::XMLElement *pAttrib = pElem->FirstChildElement("attrib"); - while (pAttrib) - { - CAttribTemplate Attrib; - Attrib.ExtraSettings = -1; - - const char *pType = pAttrib->Attribute("type"); - if (!pType) - Log::Error("An attrib in " + pScript->TemplateName() + " template has no type set"); - - else - { - // Initialize attrib template values - Attrib.AttribType = AttribStringToAttribEnum(pType); - - if (Attrib.AttribType == eInvalidAttrib) - Log::Error("An attrib in " + pScript->TemplateName() + " template has an invalid type: " + pType); - - else - { - bool NoError = ParseAttribExtra(pAttrib, Attrib, pScript->TemplateName()); - - if (NoError) - { - Attrib.AttribTarget = pAttrib->Attribute("target"); - CPropertyTemplate *pTargetProp = nullptr; - - if (Attrib.ResFile.empty()) - { - pTargetProp = pScript->mpBaseStruct->PropertyByName(Attrib.AttribTarget); // Ensure target is valid if it points to a property - - if (!pTargetProp) - Log::Error("An attrib in " + pScript->TemplateName() + " template of type " + pType + " has an invalid target: " + Attrib.AttribTarget); - } - - if ((pTargetProp) || (!Attrib.ResFile.empty())) - pScript->mAttribs.push_back(Attrib); - } - } - } - - pAttrib = pAttrib->NextSiblingElement("attrib"); - } -} - -bool CTemplateLoader::ParseAttribExtra(tinyxml2::XMLElement *pElem, CAttribTemplate& Attrib, const std::string& TemplateName) -{ - // This function is for parsing extra tags that some attribs have, such as "source" for models or "forcenode" for animsets - - // AnimSet - if (Attrib.Type() == eAnimSetAttrib) - { - // Check res source - const char *pSource = pElem->Attribute("source"); - - if ((pSource) && (strcmp(pSource, "file") == 0)) - { - const char *pFileName = pElem->Attribute("target"); - if (pFileName) - Attrib.ResFile = std::string("../resources/") + pFileName; - else - { - Log::Error("An attrib in " + TemplateName + " template of type animset has an invalid target: \"" + pFileName + "\""); - return false; - } - } - - // Check forcenode - const char *pForceNode = pElem->Attribute("forcenode"); - if (pForceNode) - { - if (!StringUtil::IsHexString(pForceNode)) - { - Log::Error("An animset attrib in " + TemplateName + " has an invalid \"forcenode\" setting: \"" + pForceNode + "\""); - return false; - } - else - Attrib.ExtraSettings = std::stoul(pForceNode); - } - } - - // Model - if (Attrib.Type() == eModelAttrib) - { - // Check res source - const char *pSource = pElem->Attribute("source"); - if ((pSource) && (strcmp(pSource, "file") == 0)) - { - const char *pFileName = pElem->Attribute("target"); - if (pFileName) - Attrib.ResFile = std::string("../resources/") + pFileName; - else - { - Log::Error("An attrib in " + TemplateName + " template of type model has an invalid target: \"" + pFileName + "\""); - return false; - } - } - } - - // Volume - if (Attrib.Type() == eVolumeAttrib) - { - const char *pShape = pElem->Attribute("shape"); - - if (pShape) - { - if (strcmp(pShape, "Box") == 0) - Attrib.ExtraSettings = 0; - else if (strcmp(pShape, "OrientedBox") == 0) - Attrib.ExtraSettings = 1; - else if (strcmp(pShape, "Sphere") == 0) - Attrib.ExtraSettings = 2; - else - { - Log::Error("Volume attrib in " + TemplateName + " template has an invalid shape: " + pShape); - return false; - } - } - else - { - Log::Error("Volume attrib in " + TemplateName + " template has no shape attribute"); - return false; - } - } - - return true; -} - // ************ MASTER ************ void CTemplateLoader::LoadMasterTemplate(tinyxml2::XMLDocument *pDoc) { - tinyxml2::XMLNode *pNode = pDoc->FirstChild()->NextSibling()->FirstChild(); + tinyxml2::XMLElement *pRoot = pDoc->FirstChildElement("MasterTemplate"); + mpMaster->mVersion = StringUtil::ToInt32(pRoot->Attribute("version")); - while (pNode) + tinyxml2::XMLElement *pElem = pRoot->FirstChildElement(); + + while (pElem) { - tinyxml2::XMLElement *pElem = pNode->ToElement(); - - // Version - if (strcmp(pElem->Name(), "version") == 0) - { - u32 Version = std::stoul(pElem->GetText()); - mpMaster->mVersion = Version; - } - // Properties - else if (strcmp(pElem->Name(), "properties") == 0) + if (strcmp(pElem->Name(), "properties") == 0) { - std::string PropListPath = mMasterDir + pElem->GetText(); + std::string propListPath = mMasterDir + pElem->GetText(); - tinyxml2::XMLDocument PropListXML; - PropListXML.LoadFile(PropListPath.c_str()); + tinyxml2::XMLDocument propListXML; + propListXML.LoadFile(propListPath.c_str()); - if (PropListXML.Error()) - Log::Error("Couldn't open property list: " + PropListPath); + if (propListXML.Error()) + Log::Error("Couldn't open property list: " + propListPath); else - LoadPropertyList(&PropListXML, PropListPath); + LoadPropertyList(&propListXML, propListPath); } // Objects else if (strcmp(pElem->Name(), "objects") == 0) { - // Iterate categories - tinyxml2::XMLElement *pCat = pElem->FirstChildElement("category"); + tinyxml2::XMLElement *pObj = pElem->FirstChildElement("object"); - while (pCat) + while (pObj) { - CTemplateCategory Cat(pCat->Attribute("name")); - tinyxml2::XMLElement *pObj = pCat->FirstChildElement("object"); + // ID can either be a hex number or an ASCII fourCC + std::string strID = pObj->Attribute("ID"); + u32 ID; - while (pObj) + if (StringUtil::IsHexString(strID, true)) + ID = StringUtil::ToInt32(strID); + else + ID = CFourCC(strID).ToLong(); + + // Load up the object + std::string templateName = pObj->Attribute("template"); + std::string templatePath = mMasterDir + templateName; + + tinyxml2::XMLDocument scriptXML; + scriptXML.LoadFile(templatePath.c_str()); + + if (scriptXML.Error()) + Log::Error("Couldn't open script template: " + templatePath); + + else { - // ID can either be a hex number or an ASCII fourCC - std::string StrID = pObj->Attribute("ID"); - u32 ID; + CScriptTemplate *pTemp = LoadScriptTemplate(&scriptXML, templateName, ID); - if (StringUtil::IsHexString(StrID, true)) - ID = std::stoul(StrID, 0, 16); - else - ID = CFourCC(StrID).ToLong(); - - // Load up the object - std::string TemplateName = pObj->Attribute("template"); - std::string TemplatePath = mMasterDir + TemplateName; - - tinyxml2::XMLDocument ObjectXML; - ObjectXML.LoadFile(TemplatePath.c_str()); - - if (ObjectXML.Error()) - Log::Error("Couldn't open script template: " + TemplatePath); - - else + if (pTemp) { - CScriptTemplate *pTemp = LoadScriptTemplate(&ObjectXML, TemplateName, ID); - - if (pTemp) - { - mpMaster->mTemplates[ID] = pTemp; - Cat.AddTemplate(pTemp); - } + pTemp->mSourceFile = templateName; + mpMaster->mTemplates[ID] = pTemp; } - - pObj = pObj->NextSiblingElement("object"); } - Cat.Sort(); - mpMaster->mCategories.push_back(Cat); - pCat = pCat->NextSiblingElement("category"); + pObj = pObj->NextSiblingElement("object"); } } @@ -481,16 +415,16 @@ void CTemplateLoader::LoadMasterTemplate(tinyxml2::XMLDocument *pDoc) while (pState) { - std::string StrID = pState->Attribute("ID"); - u32 StateID; + std::string strID = pState->Attribute("ID"); + u32 stateID; - if (StringUtil::IsHexString(StrID, true)) - StateID = std::stoul(StrID, 0, 16); + if (StringUtil::IsHexString(strID, true)) + stateID = StringUtil::ToInt32(strID); else - StateID = CFourCC(StrID).ToLong(); + stateID = CFourCC(strID).ToLong(); - std::string StateName = pState->Attribute("name"); - mpMaster->mStates[StateID] = StateName; + std::string stateName = pState->Attribute("name"); + mpMaster->mStates[stateID] = stateName; pState = pState->NextSiblingElement("state"); } } @@ -502,37 +436,39 @@ void CTemplateLoader::LoadMasterTemplate(tinyxml2::XMLDocument *pDoc) while (pMessage) { - std::string StrID = pMessage->Attribute("ID"); - u32 MessageID; + std::string strID = pMessage->Attribute("ID"); + u32 messageID; - if (StringUtil::IsHexString(StrID, true)) - MessageID = std::stoul(StrID, 0, 16); + if (StringUtil::IsHexString(strID, true)) + messageID = StringUtil::ToInt32(strID); else - MessageID = CFourCC(StrID).ToLong(); + messageID = CFourCC(strID).ToLong(); - std::string MessageName = pMessage->Attribute("name"); - mpMaster->mMessages[MessageID] = MessageName; + std::string messageName = pMessage->Attribute("name"); + mpMaster->mMessages[messageID] = messageName; pMessage = pMessage->NextSiblingElement("message"); } } - pNode = pNode->NextSibling(); + pElem = pElem->NextSiblingElement(); } } -void CTemplateLoader::LoadPropertyList(tinyxml2::XMLDocument *pDoc, const std::string& ListName) +void CTemplateLoader::LoadPropertyList(tinyxml2::XMLDocument *pDoc, const std::string& listName) { tinyxml2::XMLElement *pElem = pDoc->FirstChildElement()->FirstChildElement(); while (pElem) { - CPropertyTemplate *pProp = LoadPropertyTemplate(pElem, ListName); + CPropertyTemplate *pProp = LoadPropertyTemplate(pElem, listName); if (pProp) mpMaster->mPropertyList[pProp->PropertyID()] = pProp; pElem = pElem->NextSiblingElement(); } + + mpMaster->mHasPropList = true; } CMasterTemplate* CTemplateLoader::LoadGame(tinyxml2::XMLNode *pNode) @@ -561,9 +497,15 @@ CMasterTemplate* CTemplateLoader::LoadGame(tinyxml2::XMLNode *pNode) MasterXML.LoadFile(MasterPath.c_str()); if (MasterXML.Error()) + { Log::Error("Couldn't open master template at " + MasterPath + " - error " + std::to_string(MasterXML.ErrorID())); + } + else + { LoadMasterTemplate(&MasterXML); + mpMaster->mSourceFile = pGameElem->GetText(); + } } pGameElem = pGameElem->NextSiblingElement(); } @@ -575,17 +517,17 @@ CMasterTemplate* CTemplateLoader::LoadGame(tinyxml2::XMLNode *pNode) // ************ PUBLIC ************ void CTemplateLoader::LoadGameList() { - static const std::string TemplatesDir = "../templates/"; - static const std::string GameListPath = TemplatesDir + "GameList.xml"; + static const std::string skTemplatesDir = "../templates/"; + static const std::string skGameListPath = skTemplatesDir + "GameList.xml"; Log::Write("Loading game list"); // Load Game List XML tinyxml2::XMLDocument GameListXML; - GameListXML.LoadFile(GameListPath.c_str()); + GameListXML.LoadFile(skGameListPath.c_str()); if (GameListXML.Error()) { - Log::Error("Couldn't open game list at " + GameListPath + " - error " + std::to_string(GameListXML.ErrorID())); + Log::Error("Couldn't open game list at " + skGameListPath + " - error " + std::to_string(GameListXML.ErrorID())); return; } @@ -606,7 +548,7 @@ void CTemplateLoader::LoadGameList() // Games else if (strcmp(pElement->Name(), "game") == 0) { - CTemplateLoader Loader(TemplatesDir); + CTemplateLoader Loader(skTemplatesDir); CMasterTemplate *pMaster = Loader.LoadGame(pNode); if (!pMaster->IsLoadedSuccessfully()) diff --git a/Resource/factory/CTemplateLoader.h b/Resource/factory/CTemplateLoader.h index 5a14f26e..2d45a455 100644 --- a/Resource/factory/CTemplateLoader.h +++ b/Resource/factory/CTemplateLoader.h @@ -12,21 +12,18 @@ class CTemplateLoader std::string mMasterDir; // Constructor - CTemplateLoader(const std::string& TemplatesDir) : mTemplatesDir(TemplatesDir) {} + CTemplateLoader(const std::string& templatesDir) : mTemplatesDir(templatesDir) {} // Load Property - CPropertyTemplate* LoadPropertyTemplate(tinyxml2::XMLElement *pElem, const std::string& TemplateName); - CStructTemplate* LoadStructTemplate(tinyxml2::XMLElement *pElem, const std::string& TemplateName); - void GetPropertyInfo(tinyxml2::XMLElement *pElem, std::string& Name, EPropertyType& Type, u32& ID); + void LoadStructProperties(tinyxml2::XMLElement *pElem, CStructTemplate *pTemp, const std::string& templateName); + CPropertyTemplate* LoadPropertyTemplate(tinyxml2::XMLElement *pElem, const std::string& templateName); // Load Script Object - CScriptTemplate* LoadScriptTemplate(tinyxml2::XMLDocument *pDoc, const std::string& TemplateName, u32 ObjectID); - void LoadScriptAttribs(tinyxml2::XMLElement *pElem, CScriptTemplate *pScript); - bool ParseAttribExtra(tinyxml2::XMLElement *pElem, CAttribTemplate& Attrib, const std::string& TemplateName); + CScriptTemplate* LoadScriptTemplate(tinyxml2::XMLDocument *pDoc, const std::string& templateName, u32 objectID); // Load Master void LoadMasterTemplate(tinyxml2::XMLDocument *pDoc); - void LoadPropertyList(tinyxml2::XMLDocument *pDoc, const std::string& ListName); + void LoadPropertyList(tinyxml2::XMLDocument *pDoc, const std::string& listName); CMasterTemplate* LoadGame(tinyxml2::XMLNode *pNode); public: diff --git a/Resource/script/CMasterTemplate.cpp b/Resource/script/CMasterTemplate.cpp index 8d705990..a9df268f 100644 --- a/Resource/script/CMasterTemplate.cpp +++ b/Resource/script/CMasterTemplate.cpp @@ -6,6 +6,7 @@ CMasterTemplate::CMasterTemplate() { mVersion = 0; mFullyLoaded = false; + mHasPropList = false; } CMasterTemplate::~CMasterTemplate() @@ -92,15 +93,17 @@ CPropertyTemplate* CMasterTemplate::GetProperty(u32 PropertyID) return nullptr; } +bool CMasterTemplate::HasPropertyList() +{ + return mHasPropList; +} + bool CMasterTemplate::IsLoadedSuccessfully() { return mFullyLoaded; } // ************ STATIC ************ -std::unordered_map CMasterTemplate::smMasterMap; -u32 CMasterTemplate::smGameListVersion; - CMasterTemplate* CMasterTemplate::GetMasterForGame(EGame Game) { auto it = smMasterMap.find(Game); @@ -110,3 +113,16 @@ CMasterTemplate* CMasterTemplate::GetMasterForGame(EGame Game) else return nullptr; } + +std::list CMasterTemplate::GetMasterList() +{ + std::list list; + + for (auto it = smMasterMap.begin(); it != smMasterMap.end(); it++) + list.push_back(it->second); + + return list; +} + +std::map CMasterTemplate::smMasterMap; +u32 CMasterTemplate::smGameListVersion; diff --git a/Resource/script/CMasterTemplate.h b/Resource/script/CMasterTemplate.h index 2c7b1325..8a136b01 100644 --- a/Resource/script/CMasterTemplate.h +++ b/Resource/script/CMasterTemplate.h @@ -5,27 +5,29 @@ #include "CTemplateCategory.h" #include "../EFormatVersion.h" #include -#include +#include #include class CMasterTemplate { friend class CTemplateLoader; + friend class CTemplateWriter; EGame mGame; std::string mGameName; + std::string mSourceFile; u32 mVersion; bool mFullyLoaded; - std::unordered_map mTemplates; - std::unordered_map mStates; - std::unordered_map mMessages; + std::map mTemplates; + std::map mStates; + std::map mMessages; std::vector mCategories; bool mHasPropList; - std::unordered_map mPropertyList; + std::map mPropertyList; - static std::unordered_map smMasterMap; + static std::map smMasterMap; static u32 smGameListVersion; public: @@ -45,9 +47,11 @@ public: std::string MessageByID(const CFourCC& MessageID); std::string MessageByIndex(u32 Index); CPropertyTemplate* GetProperty(u32 PropertyID); + bool HasPropertyList(); bool IsLoadedSuccessfully(); static CMasterTemplate* GetMasterForGame(EGame Game); + static std::list GetMasterList(); }; // ************ INLINE ************ diff --git a/Resource/script/CProperty.cpp b/Resource/script/CProperty.cpp new file mode 100644 index 00000000..e18ece39 --- /dev/null +++ b/Resource/script/CProperty.cpp @@ -0,0 +1,121 @@ +#include "CProperty.h" + +// ************ CPropertyStruct ************ +CPropertyStruct::~CPropertyStruct() +{ + for (auto it = mProperties.begin(); it != mProperties.end(); it++) + delete *it; +} + +CPropertyBase* CPropertyStruct::PropertyByIndex(u32 index) +{ + return mProperties[index]; +} + +CPropertyBase* CPropertyStruct::PropertyByID(u32 ID) +{ + for (auto it = mProperties.begin(); it != mProperties.end(); it++) + { + if ((*it)->ID() == ID) + return *it; + } + return nullptr; +} + +CPropertyBase* CPropertyStruct::PropertyByIDString(const TIDString& str) +{ + // Resolve namespace + std::string::size_type nsStart = str.find_first_of(":"); + std::string::size_type propStart = nsStart + 1; + + // String has namespace; the requested property is within a struct + if (nsStart != std::string::npos) + { + std::string strStructID = str.substr(0, nsStart); + if (!StringUtil::IsHexString(strStructID)) return nullptr; + + u32 structID = StringUtil::ToInt32(strStructID); + std::string propName = str.substr(propStart, str.length() - propStart); + + CPropertyStruct *pStruct = StructByID(structID); + if (!pStruct) return nullptr; + else return pStruct->PropertyByIDString(propName); + } + + // No namespace; fetch the property from this struct + else + { + if (StringUtil::IsHexString(str)) + return PropertyByID(StringUtil::ToInt32(str)); + else + return nullptr; + } +} + +CPropertyStruct* CPropertyStruct::StructByIndex(u32 index) +{ + CPropertyBase *pProp = PropertyByIndex(index); + + if (pProp->Type() == eStructProperty) + return static_cast(pProp); + else + return nullptr; +} + +CPropertyStruct* CPropertyStruct::StructByID(u32 ID) +{ + CPropertyBase *pProp = PropertyByID(ID); + + if (pProp->Type() == eStructProperty) + return static_cast(pProp); + else + return nullptr; +} + +CPropertyStruct* CPropertyStruct::StructByIDString(const TIDString& str) +{ + CPropertyBase *pProp = PropertyByIDString(str); + + if (pProp->Type() == eStructProperty) + return static_cast(pProp); + else + return nullptr; +} + +// ************ STATIC ************ +CPropertyStruct* CPropertyStruct::CopyFromTemplate(CStructTemplate *pTemp) +{ + CPropertyStruct *pStruct = new CPropertyStruct(); + pStruct->mpTemplate = pTemp; + pStruct->Reserve(pTemp->Count()); + + for (u32 iProp = 0; iProp < pTemp->Count(); iProp++) + { + CPropertyTemplate *pPropTemp = pTemp->PropertyByIndex(iProp); + CPropertyBase *pProp = nullptr; + + switch (pPropTemp->Type()) + { + case eBoolProperty: pProp = new CBoolProperty(false); break; + case eByteProperty: pProp = new CByteProperty(0); break; + case eShortProperty: pProp = new CShortProperty(0); break; + case eLongProperty: pProp = new CLongProperty(0); break; + case eFloatProperty: pProp = new CFloatProperty(0.f); break; + case eStringProperty: pProp = new CStringProperty(""); break; + case eVector3Property: pProp = new CVector3Property(CVector3f::skZero); break; + case eColorProperty: pProp = new CColorProperty(CColor::skBlack); break; + case eFileProperty: pProp = new CFileProperty(); break; + case eArrayProperty: pProp = new CArrayProperty(); break; + case eUnknownProperty: pProp = new CUnknownProperty(); break; + case eStructProperty: pProp = CPropertyStruct::CopyFromTemplate(static_cast(pPropTemp)); break; + } + + if (pProp) + { + pProp->SetTemplate(pPropTemp); + pStruct->mProperties.push_back(pProp); + } + } + + return pStruct; +} diff --git a/Resource/script/CProperty.h b/Resource/script/CProperty.h index a59201bc..a1fa6339 100644 --- a/Resource/script/CProperty.h +++ b/Resource/script/CProperty.h @@ -7,7 +7,7 @@ * It's a bit hard to read, should be reorganized at some point */ #include "../CResource.h" -#include "CScriptTemplate.h" +#include "CPropertyTemplate.h" #include "EPropertyType.h" #include #include @@ -15,6 +15,10 @@ #include #include +class CScriptTemplate; + +typedef std::string TIDString; + /* * CPropertyBase is the base class, containing just some virtual function definitions * Virtual destructor is mainly there to make cleanup easy; don't need to cast to delete @@ -23,14 +27,14 @@ class CPropertyBase { friend class CScriptLoader; protected: - CPropertyTemplate *tmp; + CPropertyTemplate *mpTemplate; public: virtual ~CPropertyBase() {} - virtual EPropertyType Type() = 0; - CPropertyTemplate *Template() { return tmp; } - void SetTemplate(CPropertyTemplate *_tmp) { tmp = _tmp; } - std::string Name() { return tmp->Name(); } - u32 ID() { return tmp->PropertyID(); } + inline virtual EPropertyType Type() = 0; + inline CPropertyTemplate *Template() { return mpTemplate; } + inline void SetTemplate(CPropertyTemplate *_tmp) { mpTemplate = _tmp; } + inline std::string Name() { return mpTemplate->Name(); } + inline u32 ID() { return mpTemplate->PropertyID(); } }; /* @@ -41,14 +45,14 @@ template class __CProperty : public CPropertyBase { friend class CScriptLoader; - t Value; + t mValue; public: __CProperty() {} __CProperty(t v) { Set(v); } ~__CProperty() {} - EPropertyType Type() { return type; } - t Get() { return Value; } - void Set(t v) { Value = v; } + inline EPropertyType Type() { return type; } + inline t Get() { return mValue; } + inline void Set(t v) { mValue = v; } }; typedef __CProperty CBoolProperty; typedef __CProperty CByteProperty; @@ -59,6 +63,7 @@ typedef __CProperty CStringProperty; typedef __CProperty CVector3Property; typedef __CProperty CColorProperty; typedef __CProperty CFileProperty; +typedef __CProperty, eArrayProperty> CArrayProperty; typedef __CProperty, eUnknownProperty> CUnknownProperty; /* @@ -67,28 +72,28 @@ typedef __CProperty, eUnknownProperty> CUnknownProperty; template <> class __CProperty : public CPropertyBase { - CResource *Value; + CResource *mValue; CToken mToken; public: __CProperty() { - Value = nullptr; + mValue = nullptr; } __CProperty(CResource* v) { - Value = v; + mValue = v; mToken = CToken(v); } ~__CProperty() {} - EPropertyType Type() { return eFileProperty; } - CResource* Get() { return Value; } - void Set(CResource *v) + inline EPropertyType Type() { return eFileProperty; } + inline CResource* Get() { return mValue; } + inline void Set(CResource *v) { - if (Value != v) + if (mValue != v) { - Value = v; + mValue = v; mToken = CToken(v); } } @@ -104,128 +109,27 @@ public: class CPropertyStruct : public CPropertyBase { friend class CScriptLoader; - std::vector Properties; + std::vector mProperties; public: // Destructor simply iterates through the list and deletes them. Nothing complicated. - ~CPropertyStruct() - { - for (auto it = Properties.begin(); it != Properties.end(); it++) - delete *it; - } + ~CPropertyStruct(); + // Inline EPropertyType Type() { return eStructProperty; } - u32 Count() { return Properties.size(); } - void Reserve(u32 amount) { Properties.reserve(amount); } - CPropertyBase* PropertyByIndex(u32 index) { return Properties[index]; } - CPropertyBase* PropertyByName(std::string name) - { - // Resolve namespace - std::string::size_type NsStart = name.find_first_of("::"); - std::string::size_type PropStart = NsStart + 2; + inline u32 Count() { return mProperties.size(); } + inline void Reserve(u32 amount) { mProperties.reserve(amount); } + inline CPropertyBase* operator[](u32 index) { return mProperties[index]; } - // Namespace; the requested property is within a struct - if (NsStart != std::string::npos) - { - std::string StructName = name.substr(0, NsStart); - std::string PropName = name.substr(PropStart, name.length() - PropStart); + // Functions + CPropertyBase* PropertyByIndex(u32 index); + CPropertyBase* PropertyByID(u32 ID); + CPropertyBase* PropertyByIDString(const TIDString& str); + CPropertyStruct* StructByIndex(u32 index); + CPropertyStruct* StructByID(u32 ID); + CPropertyStruct* StructByIDString(const TIDString& str); - CPropertyStruct *Struct = StructByName(StructName); - if (!Struct) return nullptr; - else return Struct->PropertyByName(PropName); - } - - // No namespace; fetch the property from this struct - else - { - // ID string lookup - if (StringUtil::IsHexString(name)) - return PropertyByID(std::stoul(name, 0, 16)); - - // Name lookup - else - { - for (auto it = Properties.begin(); it != Properties.end(); it++) - { - if ((*it)->Name() == name) - return *it; - } - return nullptr; - } - } - } - CPropertyBase* PropertyByID(u32 ID) - { - for (auto it = Properties.begin(); it != Properties.end(); it++) - { - if ((*it)->ID() == ID) - return *it; - } - return nullptr; - } - CPropertyStruct* StructByIndex(u32 index) - { - CPropertyBase *prop = PropertyByIndex(index); - - if (prop->Type() == eStructProperty) - return static_cast(prop); - else - return nullptr; - } - CPropertyStruct* StructByName(std::string name) - { - CPropertyBase *prop = PropertyByName(name); - - if (prop->Type() == eStructProperty) - return static_cast(prop); - else - return nullptr; - } - CPropertyStruct* StructByID(u32 ID) - { - CPropertyBase *prop = PropertyByID(ID); - - if (prop->Type() == eStructProperty) - return static_cast(prop); - else - return nullptr; - } - inline CPropertyBase* operator[](u32 index) { return Properties[index]; } - - static CPropertyStruct* CopyFromTemplate(CStructTemplate *pTemp) - { - CPropertyStruct *pStruct = new CPropertyStruct(); - pStruct->tmp = pTemp; - pStruct->Reserve(pTemp->Count()); - - for (u32 iProp = 0; iProp < pTemp->Count(); iProp++) - { - CPropertyTemplate *pPropTemp = pTemp->PropertyByIndex(iProp); - CPropertyBase *pProp = nullptr; - - switch (pPropTemp->Type()) - { - case eBoolProperty: pProp = new CBoolProperty(false); break; - case eByteProperty: pProp = new CByteProperty(0); break; - case eShortProperty: pProp = new CShortProperty(0); break; - case eLongProperty: pProp = new CLongProperty(0); break; - case eFloatProperty: pProp = new CFloatProperty(0.f); break; - case eStringProperty: pProp = new CStringProperty(""); break; - case eVector3Property: pProp = new CVector3Property(CVector3f::skZero); break; - case eColorProperty: pProp = new CColorProperty(CColor::skBlack); break; - case eFileProperty: pProp = new CFileProperty(); break; - case eUnknownProperty: pProp = new CUnknownProperty(); break; - case eStructProperty: pProp = CPropertyStruct::CopyFromTemplate(static_cast(pPropTemp)); break; - } - - if (pProp) - { - pProp->SetTemplate(pPropTemp); - pStruct->Properties.push_back(pProp); - } - } - - return pStruct; - } + // Static + static CPropertyStruct* CopyFromTemplate(CStructTemplate *pTemp); }; #endif // CPROPERTY diff --git a/Resource/script/CPropertyTemplate.cpp b/Resource/script/CPropertyTemplate.cpp new file mode 100644 index 00000000..4b29dc47 --- /dev/null +++ b/Resource/script/CPropertyTemplate.cpp @@ -0,0 +1,169 @@ +#include "CPropertyTemplate.h" +#include + +EPropertyType PropStringToPropEnum(std::string prop) +{ + if (prop == "bool") return eBoolProperty; + if (prop == "byte") return eByteProperty; + if (prop == "short") return eShortProperty; + if (prop == "long") return eLongProperty; + if (prop == "float") return eFloatProperty; + if (prop == "string") return eStringProperty; + if (prop == "color") return eColorProperty; + if (prop == "vector3f") return eVector3Property; + if (prop == "file") return eFileProperty; + if (prop == "struct") return eStructProperty; + if (prop == "array") return eArrayProperty; + if (prop == "unknown") return eUnknownProperty; + return eInvalidProperty; +} + +std::string PropEnumToPropString(EPropertyType prop) +{ + switch (prop) + { + case eBoolProperty: return "bool"; + case eByteProperty: return "byte"; + case eShortProperty: return "short"; + case eLongProperty: return "long"; + case eFloatProperty: return "float"; + case eStringProperty: return "string"; + case eColorProperty: return "color"; + case eVector3Property: return "vector3f"; + case eFileProperty: return "file"; + case eStructProperty: return "struct"; + case eArrayProperty: return "array"; + case eUnknownProperty: return "unknown"; + + case eInvalidProperty: + default: + return "invalid"; + } +} + +/******************* + * CStructTemplate * + *******************/ +CStructTemplate::CStructTemplate() : CPropertyTemplate(-1) +{ + mIsSingleProperty = false; + mPropType = eStructProperty; +} + +CStructTemplate::~CStructTemplate() +{ + for (auto it = mProperties.begin(); it != mProperties.end(); it++) + delete *it; +} + +// ************ GETTERS ************ +EPropertyType CStructTemplate::Type() const +{ + return eStructProperty; +} + +bool CStructTemplate::IsSingleProperty() const +{ + return mIsSingleProperty; +} + +u32 CStructTemplate::Count() const +{ + return mProperties.size(); +} + +CPropertyTemplate* CStructTemplate::PropertyByIndex(u32 index) +{ + if (mProperties.size() > index) + return mProperties[index]; + else + return nullptr; +} + +CPropertyTemplate* CStructTemplate::PropertyByID(u32 ID) +{ + for (auto it = mProperties.begin(); it != mProperties.end(); it++) + { + if ((*it)->PropertyID() == ID) + return *it; + } + return nullptr; +} + +CPropertyTemplate* CStructTemplate::PropertyByIDString(const std::string& str) +{ + // Resolve namespace + std::string::size_type nsStart = str.find_first_of("::"); + std::string::size_type propStart = nsStart + 2; + + // String has namespace; the requested property is within a struct + if (nsStart != std::string::npos) + { + std::string strStructID = str.substr(0, nsStart); + if (!StringUtil::IsHexString(strStructID)) return nullptr; + + u32 structID = StringUtil::ToInt32(strStructID); + std::string propName = str.substr(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 (StringUtil::IsHexString(str)) + return PropertyByID(std::stoul(str, 0, 16)); + else + return nullptr; + } +} + +CStructTemplate* CStructTemplate::StructByIndex(u32 index) +{ + CPropertyTemplate *pProp = PropertyByIndex(index); + + if (pProp->Type() == eStructProperty) + return static_cast(pProp); + else + return nullptr; +} + +CStructTemplate* CStructTemplate::StructByID(u32 ID) +{ + CPropertyTemplate *pProp = PropertyByID(ID); + + if (pProp && pProp->Type() == eStructProperty) + return static_cast(pProp); + else + return nullptr; +} + +CStructTemplate* CStructTemplate::StructByIDString(const std::string& str) +{ + CPropertyTemplate *pProp = PropertyByIDString(str); + + if (pProp && pProp->Type() == eStructProperty) + return static_cast(pProp); + else + return nullptr; +} + +// ************ DEBUG ************ +void CStructTemplate::DebugPrintProperties(std::string base) +{ + base = base + Name() + "::"; + for (auto it = mProperties.begin(); it != mProperties.end(); it++) + { + CPropertyTemplate *tmp = *it; + if (tmp->Type() == eStructProperty) + { + CStructTemplate *tmp2 = static_cast(tmp); + tmp2->DebugPrintProperties(base); + } + else + std::cout << base << tmp->Name() << "\n"; + } +} diff --git a/Resource/script/CPropertyTemplate.h b/Resource/script/CPropertyTemplate.h new file mode 100644 index 00000000..2904593e --- /dev/null +++ b/Resource/script/CPropertyTemplate.h @@ -0,0 +1,72 @@ +#ifndef CPROPERTYTEMPLATE +#define CPROPERTYTEMPLATE + +#include "EPropertyType.h" +#include +#include +#include +#include + +class CPropertyTemplate +{ + friend class CTemplateLoader; + friend class CTemplateWriter; + +protected: + EPropertyType mPropType; + std::string mPropName; + u32 mPropID; +public: + CPropertyTemplate(u32 ID) { mPropID = ID; } + CPropertyTemplate(EPropertyType type, std::string name, u32 ID) : mPropType(type), mPropName(name), mPropID(ID) {} + + virtual EPropertyType Type() const { return mPropType; } + inline std::string Name() const { return mPropName; } + inline u32 PropertyID() const { return mPropID; } + inline void SetName(const std::string& Name) { mPropName = Name; } +}; + +class CFileTemplate : public CPropertyTemplate +{ + friend class CTemplateLoader; + friend class CTemplateWriter; + + CStringList mAcceptedExtensions; +public: + CFileTemplate(u32 ID) : CPropertyTemplate(ID) { mPropType = eFileProperty; } + + CFileTemplate(std::string name, u32 ID, const CStringList& extensions) + : CPropertyTemplate(ID) { + mPropType = eFileProperty; mPropName = name; mAcceptedExtensions = extensions; + } + + EPropertyType Type() const { return eFileProperty; } + const CStringList& Extensions() const { return mAcceptedExtensions; } +}; + +class CStructTemplate : public CPropertyTemplate +{ + friend class CTemplateLoader; + friend class CTemplateWriter; + + bool mIsSingleProperty; + std::vector mProperties; + std::string mSourceFile; +public: + CStructTemplate(); + ~CStructTemplate(); + + EPropertyType Type() const; + bool IsSingleProperty() const; + u32 Count() const; + CPropertyTemplate* PropertyByIndex(u32 index); + CPropertyTemplate* PropertyByID(u32 ID); + CPropertyTemplate* PropertyByIDString(const std::string& str); + CStructTemplate* StructByIndex(u32 index); + CStructTemplate* StructByID(u32 ID); + CStructTemplate* StructByIDString(const std::string& str); + void DebugPrintProperties(std::string base); +}; + +#endif // CPROPERTYTEMPLATE + diff --git a/Resource/script/CScriptObject.cpp b/Resource/script/CScriptObject.cpp index 996b5127..50f90f0f 100644 --- a/Resource/script/CScriptObject.cpp +++ b/Resource/script/CScriptObject.cpp @@ -4,11 +4,10 @@ CScriptObject::CScriptObject(CGameArea *pArea, CScriptLayer *pLayer, CScriptTemplate *pTemplate) { + mpTemplate = pTemplate; mpArea = pArea; mpLayer = pLayer; - mpTemplate = pTemplate; mpProperties = nullptr; - mAttribFlags = 0; mpTemplate->AddObject(this); } @@ -19,186 +18,72 @@ CScriptObject::~CScriptObject() } // ************ DATA MANIPULATION ************ -void CScriptObject::EvalutateXForm() +void CScriptObject::CopyFromTemplate(CScriptTemplate *pTemp, u32 propCount) { - // Reset XForm values to defaults - mPosition = CVector3f(0); - mRotation = CVector3f(0); - mScale = CVector3f(1); - mVolumeSize = CVector3f(0); - mVolumeShape = -1; - - // Look for PRS attribs - for (u32 a = 0; a < mAttribs.size(); a++) - { - if ((mAttribs[a].Type == ePositionAttrib) || - (mAttribs[a].Type == eRotationAttrib) || - (mAttribs[a].Type == eScaleAttrib) || - (mAttribs[a].Type == eVolumeAttrib)) - { - CVector3Property *attrib = static_cast(mAttribs[a].Prop); - - if (mAttribs[a].Type == ePositionAttrib) - mPosition = attrib->Get(); - else if (mAttribs[a].Type == eRotationAttrib) - mRotation = attrib->Get(); - else if (mAttribs[a].Type == eScaleAttrib) - mScale = attrib->Get(); - else if (mAttribs[a].Type == eVolumeAttrib) { - mVolumeSize = attrib->Get(); - mVolumeShape = mAttribs[a].Settings; - } - } - } + CStructTemplate *pBaseStruct = pTemp->BaseStructByCount(propCount); + delete mpProperties; + mpProperties = CPropertyStruct::CopyFromTemplate(pBaseStruct); } -void CScriptObject::EvaluateInstanceName() +void CScriptObject::EvaluateProperties() { - // Reset instance name to default - mInstanceName = mpTemplate->TemplateName(); - - // Simply look for an instance name - set if we find it - for (u32 a = 0; a < mAttribs.size(); a++) - { - if (mAttribs[a].Type == eNameAttrib) - { - CStringProperty *str = static_cast(mAttribs[a].Prop); - mInstanceName = str->Get(); - return; - } - } -} - -void CScriptObject::EvaluateTevColor() -{ - // Evaluate the TEV color initializer - this is used for beam troopers - mTevColor = CColor::skWhite; // Initialize to white in case there's no vulnerability attrib - - for (u32 a = 0; a < mAttribs.size(); a++) - { - if (mAttribs[a].Type == eVulnerabilityAttrib) - { - CPropertyStruct* vuln = static_cast(mAttribs[a].Prop); - - u32 Power = static_cast(vuln->PropertyByIndex(0))->Get(); - u32 Ice = static_cast(vuln->PropertyByIndex(1))->Get(); - u32 Wave = static_cast(vuln->PropertyByIndex(2))->Get(); - u32 Plasma = static_cast(vuln->PropertyByIndex(3))->Get(); - - if (Plasma != 2) mTevColor = CColor::skRed; - else if (Ice != 2) mTevColor = CColor::skWhite; - else if (Power != 2) mTevColor = CColor::skYellow; - else if (Wave != 2) mTevColor = CColor::skPurple; - else mTevColor = CColor::skWhite; - - break; - } - } + mpInstanceName = mpTemplate->FindInstanceName(mpProperties); + mpPosition = mpTemplate->FindPosition(mpProperties); + mpRotation = mpTemplate->FindRotation(mpProperties); + mpScale = mpTemplate->FindScale(mpProperties); + mpActive = mpTemplate->FindActive(mpProperties); + mpLightParameters = mpTemplate->FindLightParameters(mpProperties); + mVolumeShape = mpTemplate->VolumeShape(this); + EvaluateDisplayModel(); } void CScriptObject::EvaluateDisplayModel() { - // Look for animset or model - for (u32 a = 0; a < mAttribs.size(); a++) - { - // Evaluate AnimSet attrib - if (mAttribs[a].Type == eAnimSetAttrib) - { - // Get the AnimationParameters struct so we can fetch relevant values from it... - SAttrib *Attrib = &mAttribs[a]; - CPropertyStruct *AnimParams = static_cast(Attrib->Prop); - EGame game = mpTemplate->MasterTemplate()->GetGame(); - - CResource *ANCS; - if (Attrib->Res) - ANCS = Attrib->Res; - else if (game <= eCorruption) - ANCS = static_cast( (*AnimParams)[0] )->Get(); - else - ANCS = static_cast( (*AnimParams)[1] )->Get(); - - if ((ANCS) && (ANCS->Type() == eCharacter)) - { - // Get animset + node index and return the relevant model - CAnimSet *set = static_cast(ANCS); - u32 node; - - if (mpTemplate->MasterTemplate()->GetGame() >= eCorruptionProto) - node = 0; - else if (Attrib->Settings == -1) - node = static_cast( (*AnimParams)[1] )->Get(); - else - node = Attrib->Settings; - - CModel *model = set->getNodeModel(node); - if (model && (model->Type() == eModel)) - { - mpDisplayModel = model; - return; - } - } - } - - // Evaluate Model attrib - else if (mAttribs[a].Type == eModelAttrib) - { - SAttrib *Attrib = &mAttribs[a]; - CResource *CMDL; - - if (Attrib->Res) - CMDL = Attrib->Res; - else - CMDL = static_cast(Attrib->Prop)->Get(); - - if (CMDL && (CMDL->Type() == eModel)) - { - mpDisplayModel = static_cast(CMDL); - return; - } - } - } - - // No valid display asset - mpDisplayModel = nullptr; - return; + mpDisplayModel = mpTemplate->FindDisplayModel(mpProperties); + mModelToken = CToken(mpDisplayModel); } // ************ GETTERS ************ -CPropertyBase* CScriptObject::PropertyByIndex(u32 index) +CPropertyBase* CScriptObject::PropertyByIndex(u32 index) const { return mpProperties->PropertyByIndex(index); } -CPropertyBase* CScriptObject::PropertyByName(std::string name) +CPropertyBase* CScriptObject::PropertyByIDString(std::string str) const { - return mpProperties->PropertyByName(name); + return mpProperties->PropertyByIDString(str); } -CScriptTemplate* CScriptObject::Template() +CScriptTemplate* CScriptObject::Template() const { return mpTemplate; } -CMasterTemplate* CScriptObject::MasterTemplate() +CMasterTemplate* CScriptObject::MasterTemplate() const { return mpTemplate->MasterTemplate(); } -CGameArea* CScriptObject::Area() +CGameArea* CScriptObject::Area() const { return mpArea; } -CScriptLayer* CScriptObject::Layer() +CScriptLayer* CScriptObject::Layer() const { return mpLayer; } -CPropertyStruct* CScriptObject::Properties() +CPropertyStruct* CScriptObject::Properties() const { return mpProperties; } +u32 CScriptObject::NumProperties() const +{ + return mpProperties->Count(); +} + u32 CScriptObject::ObjectTypeID() const { return mpTemplate->ObjectID(); @@ -229,40 +114,74 @@ const SLink& CScriptObject::OutLink(u32 index) const return mOutConnections[index]; } -// Attribs -CVector3f CScriptObject::GetPosition() const +std::string CScriptObject::InstanceName() const { - return mPosition; + if (mpInstanceName) + return mpInstanceName->Get(); + else + return ""; } -CVector3f CScriptObject::GetRotation() const +CVector3f CScriptObject::Position() const { - return mRotation; + if (mpPosition) + return mpPosition->Get(); + else + return CVector3f::skZero; } -CVector3f CScriptObject::GetScale() const +CVector3f CScriptObject::Rotation() const { - return mScale; + if (mpRotation) + return mpRotation->Get(); + else + return CVector3f::skZero; } -CVector3f CScriptObject::GetVolume() const +CVector3f CScriptObject::Scale() const { - return mVolumeSize; + if (mpScale) + return mpScale->Get(); + else + return CVector3f::skOne; } -u32 CScriptObject::GetVolumeShape() const +bool CScriptObject::IsActive() const { - return mVolumeShape; + if (mpActive) + return mpActive->Get(); + else + return true; } -std::string CScriptObject::GetInstanceName() const +void CScriptObject::SetPosition(const CVector3f& newPos) { - return mInstanceName; + if (mpPosition) mpPosition->Set(newPos); } -CColor CScriptObject::GetTevColor() const +void CScriptObject::SetRotation(const CVector3f& newRot) { - return mTevColor; + if (mpRotation) mpRotation->Set(newRot); +} + +void CScriptObject::SetScale(const CVector3f& newScale) +{ + if (mpScale) mpScale->Set(newScale); +} + +void CScriptObject::SetName(const std::string& newName) +{ + if (mpInstanceName) mpInstanceName->Set(newName); +} + +void CScriptObject::SetActive(bool isActive) +{ + if (mpActive) mpActive->Set(isActive); +} + +CPropertyStruct* CScriptObject::LightParameters() const +{ + return mpLightParameters; } CModel* CScriptObject::GetDisplayModel() const @@ -270,18 +189,7 @@ CModel* CScriptObject::GetDisplayModel() const return mpDisplayModel; } -int CScriptObject::GetAttribFlags() const +EVolumeShape CScriptObject::VolumeShape() const { - return mAttribFlags; -} - -// ************ STATIC ************ -CScriptObject* CScriptObject::CopyFromTemplate(CScriptTemplate *pTemp, CGameArea *pArea, CScriptLayer *pLayer) -{ - CScriptObject *pObj = new CScriptObject(pArea, pLayer, pTemp); - - CStructTemplate *pBaseStruct = pTemp->BaseStruct(); - pObj->mpProperties = CPropertyStruct::CopyFromTemplate(pBaseStruct); - - return pObj; + return mVolumeShape; } diff --git a/Resource/script/CScriptObject.h b/Resource/script/CScriptObject.h index 22be2623..22e5c270 100644 --- a/Resource/script/CScriptObject.h +++ b/Resource/script/CScriptObject.h @@ -3,6 +3,7 @@ #include "SConnection.h" #include "CProperty.h" +#include "CPropertyTemplate.h" #include "CScriptTemplate.h" #include "EAttribType.h" #include "../model/CModel.h" @@ -24,48 +25,32 @@ class CScriptObject std::vector mInConnections; CPropertyStruct *mpProperties; - CVector3f mPosition, mRotation, mScale; - CVector3f mVolumeSize; - u32 mVolumeShape; - std::string mInstanceName; - CColor mTevColor; - CModel* mpDisplayModel; - - struct SAttrib - { - EAttribType Type; - u32 Settings; - CResource *Res; - CToken ResToken; - CPropertyBase *Prop; - - // Convenience constructor - SAttrib(EAttribType type, CResource *res, u32 settings, CPropertyBase *prop) { - Type = type; - Res = res; - ResToken = CToken(res); - Settings = settings; - Prop = prop; - } - }; - std::vector mAttribs; - - int mAttribFlags; // int container for EAttribType flags + CStringProperty *mpInstanceName; + CVector3Property *mpPosition; + CVector3Property *mpRotation; + CVector3Property *mpScale; + CBoolProperty *mpActive; + CPropertyStruct *mpLightParameters; + CModel *mpDisplayModel; + CToken mModelToken; + EVolumeShape mVolumeShape; public: CScriptObject(CGameArea *pArea, CScriptLayer *pLayer, CScriptTemplate *pTemplate); ~CScriptObject(); + void CopyFromTemplate(CScriptTemplate *pTemp, u32 propCount); + void EvaluateProperties(); void EvaluateDisplayModel(); - void EvaluateInstanceName(); - void EvaluateTevColor(); - void EvalutateXForm(); - CScriptTemplate* Template(); - CMasterTemplate* MasterTemplate(); - CGameArea* Area(); - CScriptLayer* Layer(); - CPropertyStruct* Properties(); + CScriptTemplate* Template() const; + CMasterTemplate* MasterTemplate() const; + CGameArea* Area() const; + CScriptLayer* Layer() const; + CPropertyStruct* Properties() const; + u32 NumProperties() const; + CPropertyBase* PropertyByIndex(u32 index) const; + CPropertyBase* PropertyByIDString(std::string str) const; u32 ObjectTypeID() const; u32 InstanceID() const; u32 NumInLinks() const; @@ -73,21 +58,19 @@ public: const SLink& InLink(u32 index) const; const SLink& OutLink(u32 index) const; - CPropertyBase* PropertyByIndex(u32 index); - CPropertyBase* PropertyByName(std::string name); - - CVector3f GetPosition() const; - CVector3f GetRotation() const; - CVector3f GetScale() const; - CVector3f GetVolume() const; - u32 GetVolumeShape() const; - std::string GetInstanceName() const; - CColor GetTevColor() const; + CVector3f Position() const; + CVector3f Rotation() const; + CVector3f Scale() const; + std::string InstanceName() const; + bool IsActive() const; + void SetPosition(const CVector3f& newPos); + void SetRotation(const CVector3f& newRot); + void SetScale(const CVector3f& newScale); + void SetName(const std::string& newName); + void SetActive(bool isActive); + CPropertyStruct* LightParameters() const; CModel* GetDisplayModel() const; - int GetAttribFlags() const; - - // Static - static CScriptObject* CopyFromTemplate(CScriptTemplate *pTemp, CGameArea *pArea, CScriptLayer *pLayer); + EVolumeShape VolumeShape() const; }; #endif // CSCRIPTOBJECT_H diff --git a/Resource/script/CScriptTemplate.cpp b/Resource/script/CScriptTemplate.cpp index f077290c..e01d43c5 100644 --- a/Resource/script/CScriptTemplate.cpp +++ b/Resource/script/CScriptTemplate.cpp @@ -5,230 +5,19 @@ #include #include #include +#include -EPropertyType PropStringToPropEnum(std::string prop) -{ - if (prop == "bool") return eBoolProperty; - if (prop == "byte") return eByteProperty; - if (prop == "short") return eShortProperty; - if (prop == "long") return eLongProperty; - if (prop == "float") return eFloatProperty; - if (prop == "string") return eStringProperty; - if (prop == "color") return eColorProperty; - if (prop == "vector3f") return eVector3Property; - if (prop == "file") return eFileProperty; - if (prop == "struct") return eStructProperty; - if (prop == "unknown") return eUnknownProperty; - return eInvalidProperty; -} - -std::string PropEnumToPropString(EPropertyType prop) -{ - switch (prop) - { - case eBoolProperty: return "bool"; - case eByteProperty: return "byte"; - case eShortProperty: return "short"; - case eLongProperty: return "long"; - case eFloatProperty: return "float"; - case eStringProperty: return "string"; - case eColorProperty: return "color"; - case eVector3Property: return "vector3f"; - case eFileProperty: return "file"; - case eStructProperty: return "struct"; - case eUnknownProperty: return "unknown"; - - case eInvalidProperty: - default: - return "invalid"; - } -} - -EAttribType AttribStringToAttribEnum(const std::string& Attrib) -{ - if (Attrib == "name") return eNameAttrib; - if (Attrib == "position") return ePositionAttrib; - if (Attrib == "rotation") return eRotationAttrib; - if (Attrib == "scale") return eScaleAttrib; - if (Attrib == "model") return eModelAttrib; - if (Attrib == "animset") return eAnimSetAttrib; - if (Attrib == "volume") return eVolumeAttrib; - if (Attrib == "vulnerability") return eVulnerabilityAttrib; - return eInvalidAttrib; -} - -std::string AttribEnumToAttribString(EAttribType Attrib) -{ - switch (Attrib) - { - case eNameAttrib: return "name"; - case ePositionAttrib: return "position"; - case eRotationAttrib: return "rotation"; - case eScaleAttrib: return "scale"; - case eModelAttrib: return "model"; - case eAnimSetAttrib: return "animset"; - case eVolumeAttrib: return "volume"; - case eVulnerabilityAttrib: return "vulnerability"; - - case eInvalidAttrib: - default: - return "invalid"; - } -} - -/******************* - * CStructTemplate * - *******************/ -CStructTemplate::CStructTemplate() : CPropertyTemplate(-1) -{ - mIsSingleProperty = false; - mPropertyCount = -1; - mPropType = eStructProperty; -} - -CStructTemplate::~CStructTemplate() -{ - for (auto it = mProperties.begin(); it != mProperties.end(); it++) - delete *it; -} - -// ************ GETTERS ************ -EPropertyType CStructTemplate::Type() const -{ - return eStructProperty; -} - -bool CStructTemplate::IsSingleProperty() const -{ - return mIsSingleProperty; -} - -s32 CStructTemplate::TemplateCount() const -{ - return mPropertyCount; -} - -u32 CStructTemplate::Count() const -{ - return mProperties.size(); -} - -CPropertyTemplate* CStructTemplate::PropertyByIndex(u32 index) -{ - if (mProperties.size() > index) - return mProperties[index]; - else - return nullptr; -} - -CPropertyTemplate* CStructTemplate::PropertyByName(std::string name) -{ - // Resolve namespace - std::string::size_type NsStart = name.find_first_of("::"); - std::string::size_type PropStart = NsStart + 2; - - // Namespace; the requested property is within a struct - if (NsStart != std::string::npos) - { - std::string StructName = name.substr(0, NsStart); - std::string PropName = name.substr(PropStart, name.length() - PropStart); - - CStructTemplate *tmp = StructByName(StructName); - if (!tmp) return nullptr; - else return tmp->PropertyByName(PropName); - } - - // No namespace; fetch the property from this struct - else - { - // ID string lookup - if (StringUtil::IsHexString(name)) - return PropertyByID(std::stoul(name, 0, 16)); - - // Name lookup - else - { - for (auto it = mProperties.begin(); it != mProperties.end(); it++) - { - if ((*it)->Name() == name) - return *it; - } - return nullptr; - } - } -} - -CPropertyTemplate* CStructTemplate::PropertyByID(u32 ID) -{ - for (auto it = mProperties.begin(); it != mProperties.end(); it++) - { - if ((*it)->PropertyID() == ID) - return *it; - } - return nullptr; -} - -CStructTemplate* CStructTemplate::StructByIndex(u32 index) -{ - CPropertyTemplate *prop = PropertyByIndex(index); - - if (prop->Type() == eStructProperty) - return static_cast(prop); - else - return nullptr; -} - -CStructTemplate* CStructTemplate::StructByName(std::string name) -{ - CPropertyTemplate *prop = PropertyByName(name); - - if (prop && prop->Type() == eStructProperty) - return static_cast(prop); - else - return nullptr; -} - -CStructTemplate* CStructTemplate::StructByID(u32 ID) -{ - CPropertyTemplate *prop = PropertyByID(ID); - - if (prop && prop->Type() == eStructProperty) - return static_cast(prop); - else - return nullptr; -} - -// ************ DEBUG ************ -void CStructTemplate::DebugPrintProperties(std::string base) -{ - base = base + Name() + "::"; - for (auto it = mProperties.begin(); it != mProperties.end(); it++) - { - CPropertyTemplate *tmp = *it; - if (tmp->Type() == eStructProperty) - { - CStructTemplate *tmp2 = static_cast(tmp); - tmp2->DebugPrintProperties(base); - } - else - std::cout << base << tmp->Name() << "\n"; - } -} - -/******************* - * CScriptTemplate * - *******************/ CScriptTemplate::CScriptTemplate(CMasterTemplate *pMaster) { - mpBaseStruct = nullptr; mpMaster = pMaster; mVisible = true; + mVolumeShape = eNoShape; } CScriptTemplate::~CScriptTemplate() { - if (mpBaseStruct) - delete mpBaseStruct; + for (u32 iSet = 0; iSet < mPropertySets.size(); iSet++) + delete mPropertySets[iSet].pBaseStruct; } CMasterTemplate* CScriptTemplate::MasterTemplate() @@ -236,27 +25,51 @@ CMasterTemplate* CScriptTemplate::MasterTemplate() return mpMaster; } -std::string CScriptTemplate::TemplateName() const +std::string CScriptTemplate::TemplateName(s32 propCount) const { - return mTemplateName; + // Return original name if there is only one property set + // or if caller doesn't want to distinguish between sets + if ((NumPropertySets() == 1) || (propCount == -1)) + return mTemplateName; + + // Otherwise we return the template name with the set name appended + for (auto it = mPropertySets.begin(); it != mPropertySets.end(); it++) + if (it->pBaseStruct->Count() == propCount) + return mTemplateName + " (" + it->SetName + ")"; + + return mTemplateName + " (Invalid)"; } -CStructTemplate* CScriptTemplate::BaseStruct() +std::string CScriptTemplate::PropertySetNameByCount(s32 propCount) const { - return mpBaseStruct; + for (auto it = mPropertySets.begin(); it != mPropertySets.end(); it++) + if (it->pBaseStruct->Count() == propCount) + return it->SetName; + + return ""; } -u32 CScriptTemplate::AttribCount() const +std::string CScriptTemplate::PropertySetNameByIndex(u32 index) const { - return mAttribs.size(); -} - -CAttribTemplate* CScriptTemplate::Attrib(u32 index) -{ - if (mAttribs.size() > index) - return &mAttribs[index]; + if (index < NumPropertySets()) + return mPropertySets[index].SetName; else - return nullptr; + return ""; +} + +u32 CScriptTemplate::NumPropertySets() const +{ + return mPropertySets.size(); +} + +CScriptTemplate::ERotationType CScriptTemplate::RotationType() const +{ + return mRotationType; +} + +CScriptTemplate::EScaleType CScriptTemplate::ScaleType() const +{ + return mScaleType; } u32 CScriptTemplate::ObjectID() const @@ -264,6 +77,206 @@ u32 CScriptTemplate::ObjectID() const return mObjectID; } +void CScriptTemplate::SetVisible(bool visible) +{ + mVisible = visible; +} + +bool CScriptTemplate::IsVisible() const +{ + return mVisible; +} + +void CScriptTemplate::DebugPrintProperties(int propCount) +{ + CStructTemplate *pTemp = BaseStructByCount(propCount); + if (pTemp) pTemp->DebugPrintProperties(""); +} + +// ************ PROPERTY FETCHING ************ +template +t TFetchProperty(CPropertyStruct *pProperties, const TIDString& ID) +{ + if (ID.empty()) return nullptr; + CPropertyBase *pProp = pProperties->PropertyByIDString(ID); + + if (pProp && (pProp->Type() == propType)) + return static_cast(pProp); + else + return nullptr; +} + +CStructTemplate* CScriptTemplate::BaseStructByCount(s32 propCount) +{ + for (u32 iSet = 0; iSet < mPropertySets.size(); iSet++) + if (mPropertySets[iSet].pBaseStruct->Count() == propCount) + return mPropertySets[iSet].pBaseStruct; + + return nullptr; +} + +CStructTemplate* CScriptTemplate::BaseStructByIndex(u32 index) +{ + if (index < NumPropertySets()) + return mPropertySets[index].pBaseStruct; + else + return nullptr; +} + +EVolumeShape CScriptTemplate::VolumeShape(CScriptObject *pObj) +{ + if (pObj->Template() != this) + { + Log::Error(pObj->Template()->TemplateName() + " instance somehow called VolumeShape() on " + TemplateName() + " template"); + return eInvalidShape; + } + + if (mVolumeShape == eConditionalShape) + { + CPropertyBase *pProp = pObj->Properties()->PropertyByIDString(mVolumeConditionIDString); + + // Get value of the condition test property (only boolean, integral, and enum types supported) + int v; + switch (pProp->Type()) + { + case eBoolProperty: + v = (static_cast(pProp)->Get() ? 1 : 0); + break; + + case eByteProperty: + v = (int) static_cast(pProp)->Get(); + break; + + case eShortProperty: + v = (int) static_cast(pProp)->Get(); + break; + + case eLongProperty: + case eEnumProperty: + v = (int) static_cast(pProp)->Get(); + break; + } + + // Test and check whether any of the conditions are true + for (auto it = mVolumeConditions.begin(); it != mVolumeConditions.end(); it++) + { + if (it->Value == v) + return it->Shape; + } + + Log::Error(TemplateName() + " instance " + StringUtil::ToHexString(pObj->InstanceID(), true, true, 8) + " has unexpected volume shape value of " + StringUtil::ToHexString((u32) v, true, true)); + return eInvalidShape; + } + + else return mVolumeShape; +} + +CStringProperty* CScriptTemplate::FindInstanceName(CPropertyStruct *pProperties) +{ + return TFetchProperty(pProperties, mNameIDString); +} + +CVector3Property* CScriptTemplate::FindPosition(CPropertyStruct *pProperties) +{ + return TFetchProperty(pProperties, mPositionIDString); +} + +CVector3Property* CScriptTemplate::FindRotation(CPropertyStruct *pProperties) +{ + return TFetchProperty(pProperties, mRotationIDString); +} + +CVector3Property* CScriptTemplate::FindScale(CPropertyStruct *pProperties) +{ + return TFetchProperty(pProperties, mScaleIDString); +} + +CBoolProperty* CScriptTemplate::FindActive(CPropertyStruct *pProperties) +{ + return TFetchProperty(pProperties, mActiveIDString); +} + +CPropertyStruct* CScriptTemplate::FindLightParameters(CPropertyStruct *pProperties) +{ + return TFetchProperty(pProperties, mLightParametersIDString); +} + +CModel* CScriptTemplate::FindDisplayModel(CPropertyStruct *pProperties) +{ + for (auto it = mAssets.begin(); it != mAssets.end(); it++) + { + CResource *pRes = nullptr; + int animSetIndex = -1; + + // File + if (it->AssetSource == SEditorAsset::eFile) + { + std::string path = "../resources/" + it->AssetLocation; + pRes = gResCache.GetResource(path); + } + + // Property + else + { + CPropertyBase *pProp = pProperties->PropertyByIDString(it->AssetLocation); + + if (pProp->Type() == eFileProperty) + { + CFileProperty *pFile = static_cast(pProp); + pRes = pFile->Get(); + } + + else if (pProp->Type() == eStructProperty) + { + CPropertyStruct *pStruct = static_cast(pProp); + + // Slightly hacky code to fetch the correct parameters for each game + EGame game = mpMaster->GetGame(); + + if (game <= eCorruption) + pRes = static_cast(pStruct->PropertyByIndex(0))->Get(); + else + pRes = static_cast(pStruct->PropertyByIndex(1))->Get(); + + if (it->ForceNodeIndex >= 0) + animSetIndex = it->ForceNodeIndex; + else if (game >= eCorruptionProto) + animSetIndex = 0; + else + animSetIndex = static_cast(pStruct->PropertyByIndex(1))->Get(); + } + } + + // Verify resource exists + is correct type + if (pRes) + { + if ((it->AssetType == SEditorAsset::eModel) && (pRes->Type() == eModel)) + return static_cast(pRes); + + if ((it->AssetType == SEditorAsset::eAnimParams) && ((pRes->Type() == eAnimSet))) + { + CAnimSet *pSet = static_cast(pRes); + + if (animSetIndex < pSet->getNodeCount()) + { + CModel *pModel = pSet->getNodeModel(animSetIndex); + + if (pModel && (pModel->Type() == eModel)) + return pModel; + } + } + } + } + + return nullptr; +} + +bool CScriptTemplate::HasPosition() +{ + return (!mPositionIDString.empty()); +} + +// ************ OBJECT TRACKING ************ u32 CScriptTemplate::NumObjects() const { return mObjectList.size(); @@ -298,19 +311,3 @@ void CScriptTemplate::SortObjects() return (pA->InstanceID() < pB->InstanceID()); }); } - -void CScriptTemplate::SetVisible(bool Visible) -{ - mVisible = Visible; -} - -bool CScriptTemplate::IsVisible() -{ - return mVisible; -} - -// Debug function -void CScriptTemplate::DebugPrintProperties() -{ - mpBaseStruct->DebugPrintProperties(""); -} diff --git a/Resource/script/CScriptTemplate.h b/Resource/script/CScriptTemplate.h index c3239c93..ba907542 100644 --- a/Resource/script/CScriptTemplate.h +++ b/Resource/script/CScriptTemplate.h @@ -1,141 +1,128 @@ #ifndef CSCRIPTTEMPLATE_H #define CSCRIPTTEMPLATE_H +#include "CPropertyTemplate.h" +#include "CProperty.h" #include "EPropertyType.h" +#include "EVolumeShape.h" #include "EAttribType.h" #include #include #include #include #include -#include +#include class CMasterTemplate; +class CScriptObject; -/** - * CPropertyTemplate and CStructTemplate each define the layout of a single property/struct. - * The reason they're classes instead of structs is so their internal values can't be externally modified. - * CFileTemplate is a very simple subclass with one extra value - a file extension fourCC - */ -class CPropertyTemplate -{ - friend class CTemplateLoader; +typedef std::string TIDString; -protected: - EPropertyType mPropType; - std::string mPropName; - u32 mPropID; -public: - CPropertyTemplate(u32 ID) { mPropID = ID; } - CPropertyTemplate(EPropertyType type, std::string name, u32 ID) : mPropType(type), mPropName(name), mPropID(ID) {} - - virtual EPropertyType Type() const { return mPropType; } - inline std::string Name() const { return mPropName; } - inline u32 PropertyID() const { return mPropID; } - inline void SetName(const std::string& Name) { mPropName = Name; } -}; - -class CFileTemplate : public CPropertyTemplate -{ - friend class CTemplateLoader; - - CStringList mAcceptedExtensions; -public: - CFileTemplate(u32 ID) : CPropertyTemplate(ID) { mPropType = eFileProperty; } - - CFileTemplate(std::string name, u32 ID, const CStringList& extensions) - : CPropertyTemplate(ID) { - mPropType = eFileProperty; mPropName = name; mAcceptedExtensions = extensions; - } - - EPropertyType Type() const { return eFileProperty; } - const CStringList& Extensions() const { return mAcceptedExtensions; } -}; - -class CStructTemplate : public CPropertyTemplate -{ - friend class CTemplateLoader; - - bool mIsSingleProperty; - s32 mPropertyCount; - std::vector mProperties; -public: - CStructTemplate(); - ~CStructTemplate(); - - EPropertyType Type() const; - bool IsSingleProperty() const; - s32 TemplateCount() const; - u32 Count() const; - CPropertyTemplate* PropertyByIndex(u32 index); - CPropertyTemplate* PropertyByName(std::string name); - CPropertyTemplate* PropertyByID(u32 ID); - CStructTemplate* StructByIndex(u32 index); - CStructTemplate* StructByName(std::string name); - CStructTemplate* StructByID(u32 ID); - void DebugPrintProperties(std::string base); -}; - -/** - * CAttribTemplate defines editor attributes. - * They enable PWE to access and use object properties for use in the world editor. - */ -class CAttribTemplate -{ - friend class CTemplateLoader; - - EAttribType AttribType; - std::string AttribTarget; - std::string ResFile; - u32 ExtraSettings; -public: - CAttribTemplate() {} - EAttribType Type() const { return AttribType; } - std::string Target() const { return AttribTarget; } - std::string Resource() const { return ResFile; } - u32 Settings() const { return ExtraSettings; } -}; - -/** +/* * CScriptTemplate is a class that encases the data contained in one of the XML templates. * It essentially sets the layout of any given script object. * * It contains any data that applies globally to every instance of the object, such as - * property names, editor attribute properties, etc. + * property names, editor attribute properties, etc. */ -class CScriptObject; - class CScriptTemplate { friend class CTemplateLoader; + friend class CTemplateWriter; + +public: + enum ERotationType { + eRotationEnabled, eRotationDisabled + }; + + enum EScaleType { + eScaleEnabled, eScaleDisabled, eScaleVolume + }; + +private: + struct SPropertySet { + std::string SetName; + CStructTemplate *pBaseStruct; + }; + + struct SEditorAsset + { + enum { + eModel, eAnimParams + } AssetType; + + enum { + eProperty, eFile + } AssetSource; + + TIDString AssetLocation; + s32 ForceNodeIndex; // Force animsets to use specific node instead of one from property + }; CMasterTemplate *mpMaster; - CStructTemplate *mpBaseStruct; + std::vector mPropertySets; std::list mObjectList; + ERotationType mRotationType; + EScaleType mScaleType; std::string mTemplateName; - std::vector mAttribs; + std::string mSourceFile; u32 mObjectID; bool mVisible; + // Editor Properties + TIDString mNameIDString; + TIDString mPositionIDString; + TIDString mRotationIDString; + TIDString mScaleIDString; + TIDString mActiveIDString; + TIDString mLightParametersIDString; + std::vector mAssets; + + // Preview Volume + EVolumeShape mVolumeShape; + TIDString mVolumeConditionIDString; + + struct SVolumeCondition { + int Value; + EVolumeShape Shape; + }; + std::vector mVolumeConditions; + public: CScriptTemplate(CMasterTemplate *pMaster); ~CScriptTemplate(); CMasterTemplate* MasterTemplate(); - std::string TemplateName() const; - CStructTemplate* BaseStruct(); - u32 AttribCount() const; - CAttribTemplate* Attrib(u32 index); + std::string TemplateName(s32 propCount = -1) const; + std::string PropertySetNameByCount(s32 propCount) const; + std::string PropertySetNameByIndex(u32 index) const; + u32 NumPropertySets() const; + ERotationType RotationType() const; + EScaleType ScaleType() const; u32 ObjectID() const; + void SetVisible(bool visible); + bool IsVisible() const; + void DebugPrintProperties(int propCount = -1); + + // Property Fetching + CStructTemplate* BaseStructByCount(s32 propCount); + CStructTemplate* BaseStructByIndex(u32 index); + EVolumeShape VolumeShape(CScriptObject *pObj); + CStringProperty* FindInstanceName(CPropertyStruct *pProperties); + CVector3Property* FindPosition(CPropertyStruct *pProperties); + CVector3Property* FindRotation(CPropertyStruct *pProperties); + CVector3Property* FindScale(CPropertyStruct *pProperties); + CBoolProperty* FindActive(CPropertyStruct *pProperties); + CPropertyStruct* FindLightParameters(CPropertyStruct *pProperties); + CModel* FindDisplayModel(CPropertyStruct *pProperties); + bool HasPosition(); + + // Object Tracking u32 NumObjects() const; const std::list& ObjectList() const; void AddObject(CScriptObject *pObject); void RemoveObject(CScriptObject *pObject); void SortObjects(); - void SetVisible(bool Visible); - bool IsVisible(); - - void DebugPrintProperties(); }; #endif // CSCRIPTTEMPLATE_H diff --git a/Resource/script/EPropertyType.h b/Resource/script/EPropertyType.h index 4424a211..9e6033cd 100644 --- a/Resource/script/EPropertyType.h +++ b/Resource/script/EPropertyType.h @@ -16,6 +16,7 @@ enum EPropertyType eEnumProperty, eFileProperty, eStructProperty, + eArrayProperty, eUnknownProperty, eInvalidProperty }; diff --git a/Resource/script/EVolumeShape.h b/Resource/script/EVolumeShape.h new file mode 100644 index 00000000..a5e187c0 --- /dev/null +++ b/Resource/script/EVolumeShape.h @@ -0,0 +1,17 @@ +#ifndef EVOLUMESHAPE +#define EVOLUMESHAPE + +enum EVolumeShape +{ + eNoShape, + eAxisAlignedBoxShape, + eBoxShape, + eEllipsoidShape, + eCylinderShape, + eCylinderLargeShape, + eConditionalShape, + eInvalidShape +}; + +#endif // EVOLUMESHAPE + diff --git a/Scene/CScriptNode.cpp b/Scene/CScriptNode.cpp index 140e9955..bd7d109a 100644 --- a/Scene/CScriptNode.cpp +++ b/Scene/CScriptNode.cpp @@ -19,33 +19,44 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje if (mpInstance) { + CScriptTemplate *pTemp = mpInstance->Template(); + mpActiveModel = mpInstance->GetDisplayModel(); - mPosition = mpInstance->GetPosition(); - mRotation = CQuaternion::FromEuler(mpInstance->GetRotation()); - mScale = mpInstance->GetScale(); - SetName("[" + mpInstance->Template()->TemplateName() + "] " + mpInstance->GetInstanceName()); + mPosition = mpInstance->Position(); + mRotation = CQuaternion::FromEuler(mpInstance->Rotation()); + SetName("[" + pTemp->TemplateName(mpInstance->NumProperties()) + "] " + mpInstance->InstanceName()); + + if (pTemp->ScaleType() == CScriptTemplate::eScaleEnabled) + mScale = mpInstance->Scale(); + MarkTransformChanged(); - mHasValidPosition = ((mpInstance->GetAttribFlags() & ePositionAttrib) != 0); - mHasVolumePreview = ((mpInstance->GetAttribFlags() & eVolumeAttrib) != 0); + mHasValidPosition = pTemp->HasPosition(); + mHasVolumePreview = (pTemp->ScaleType() == CScriptTemplate::eScaleVolume); // Create volume preview node if (mHasVolumePreview) { - u32 VolumeShape = mpInstance->GetVolumeShape(); + EVolumeShape shape = mpInstance->VolumeShape(); CModel *pVolumeModel = nullptr; - if ((VolumeShape == 0) || (VolumeShape == 1)) // Box/OrientedBox + if ((shape == eAxisAlignedBoxShape) || (shape == eBoxShape)) pVolumeModel = (CModel*) gResCache.GetResource("../resources/VolumeBox.cmdl"); - else if (VolumeShape == 2) // Sphere + else if (shape == eEllipsoidShape) pVolumeModel = (CModel*) gResCache.GetResource("../resources/VolumeSphere.cmdl"); + else if (shape == eCylinderShape) + pVolumeModel = (CModel*) gResCache.GetResource("../resources/VolumeCylinder.cmdl"); + + else if (shape == eCylinderLargeShape) + pVolumeModel = (CModel*) gResCache.GetResource("../resources/VolumeCylinderLarge.cmdl"); + if (pVolumeModel) { mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel); - mpVolumePreviewNode->SetInheritance(true, (VolumeShape == 1), false); - mpVolumePreviewNode->Scale(mpInstance->GetVolume()); + mpVolumePreviewNode->SetInheritance(true, (shape != eAxisAlignedBoxShape), false); + mpVolumePreviewNode->Scale(mpInstance->Scale()); mpVolumePreviewNode->ForceAlphaEnabled(true); } } @@ -70,7 +81,7 @@ ENodeType CScriptNode::NodeType() std::string CScriptNode::PrefixedName() const { - return "[" + mpInstance->Template()->TemplateName() + "] " + mpInstance->GetInstanceName(); + return "[" + mpInstance->Template()->TemplateName() + "] " + mpInstance->InstanceName(); } void CScriptNode::AddToRenderer(CRenderer *pRenderer) @@ -137,9 +148,6 @@ void CScriptNode::Draw(ERenderOptions Options) return; } - // Set tev color (used rarely) - CGraphics::sPixelBlock.TevColor = mpInstance->GetTevColor().ToVector4f(); - mpActiveModel->Draw(Options, 0); } @@ -156,8 +164,6 @@ void CScriptNode::DrawAsset(ERenderOptions Options, u32 Asset) LoadModelMatrix(); LoadLights(); - CGraphics::sPixelBlock.TevColor = mpInstance->GetTevColor().ToVector4f(); - mpActiveModel->DrawSurface(Options, Asset, 0); } diff --git a/UI/CStartWindow.cpp b/UI/CStartWindow.cpp index f52a8c43..b190f0bb 100644 --- a/UI/CStartWindow.cpp +++ b/UI/CStartWindow.cpp @@ -113,9 +113,9 @@ void CStartWindow::FillAreaUI() u64 MREA = mpWorld->GetAreaResourceID(mSelectedAreaIndex); std::string MREAStr; if (MREA & 0xFFFFFFFF00000000) - MREAStr = StringUtil::ResToStr(MREA); + MREAStr = StringUtil::ToString(MREA); else - MREAStr = StringUtil::ResToStr( (u32) MREA ); + MREAStr = StringUtil::ToString( (u32) MREA ); ui->AreaMREALineEdit->setText(QString::fromStdString(MREAStr) + QString(".MREA") ); diff --git a/UI/WorldEditor/CLinkModel.cpp b/UI/WorldEditor/CLinkModel.cpp index eb436588..aa9b05c6 100644 --- a/UI/WorldEditor/CLinkModel.cpp +++ b/UI/WorldEditor/CLinkModel.cpp @@ -55,7 +55,7 @@ QVariant CLinkModel::data(const QModelIndex &index, int role) const if (pTargetObj) { QString ObjType = QString("[%1] ").arg(QString::fromStdString(pTargetObj->Template()->TemplateName())); - return ObjType + QString::fromStdString(pTargetObj->GetInstanceName()); + return ObjType + QString::fromStdString(pTargetObj->InstanceName()); } else { QString strID = QString::number(link.ObjectID, 16); diff --git a/UI/WorldEditor/CTypesInstanceModel.cpp b/UI/WorldEditor/CTypesInstanceModel.cpp index df2aa17d..ba3154aa 100644 --- a/UI/WorldEditor/CTypesInstanceModel.cpp +++ b/UI/WorldEditor/CTypesInstanceModel.cpp @@ -235,7 +235,7 @@ QVariant CTypesInstanceModel::data(const QModelIndex &index, int role) const CScriptObject *pObj = static_cast(index.internalPointer()); if (index.column() == 0) - return QString::fromStdString(pObj->GetInstanceName()); + return QString::fromStdString(pObj->InstanceName()); else if (index.column() == 1) {