diff --git a/src/Common/Common.h b/src/Common/Common.h index 56a37693..28a96445 100644 --- a/src/Common/Common.h +++ b/src/Common/Common.h @@ -5,7 +5,6 @@ #include "CAssetID.h" #include "CColor.h" #include "CFourCC.h" -#include "CHashFNV1A.h" #include "CScopedTimer.h" #include "CTimer.h" #include "EGame.h" @@ -17,6 +16,8 @@ #include "Log.h" #include "TString.h" #include "types.h" +#include "Hash/CCRC32.h" +#include "Hash/CFNV1A.h" #include "Serialization/Binary.h" #include "Serialization/XML.h" diff --git a/src/Common/Common.pro b/src/Common/Common.pro index a00adb96..d8491d3e 100644 --- a/src/Common/Common.pro +++ b/src/Common/Common.pro @@ -46,7 +46,6 @@ INCLUDEPATH += $$PWE_MAIN_INCLUDE \ HEADERS += \ CColor.h \ CFourCC.h \ - CHashFNV1A.h \ CTimer.h \ EKeyInputs.h \ EMouseInputs.h \ @@ -59,6 +58,7 @@ HEADERS += \ AssertMacro.h \ CScopedTimer.h \ CAssetID.h \ + Hash\CFNV1A.h \ Serialization/IArchive.h \ Serialization/CXMLWriter.h \ Serialization/CXMLReader.h \ @@ -83,7 +83,8 @@ HEADERS += \ FileIO\CBitStreamInWrapper.h \ FileIO\CFileLock.h \ FileIO.h \ - Common.h + Common.h \ + Hash/CCRC32.h # Source Files SOURCES += \ @@ -105,4 +106,5 @@ SOURCES += \ FileIO\IOUtil.cpp \ FileIO\IInputStream.cpp \ FileIO\IOutputStream.cpp \ - FileIO\CBitStreamInWrapper.cpp + FileIO\CBitStreamInWrapper.cpp \ + Hash/CCRC32.cpp diff --git a/src/Common/Hash/CCRC32.cpp b/src/Common/Hash/CCRC32.cpp new file mode 100644 index 00000000..9b814cd3 --- /dev/null +++ b/src/Common/Hash/CCRC32.cpp @@ -0,0 +1,123 @@ +#include "CCRC32.h" + +const u32 gkCrcTable[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +/** Default constructor, initializes the hash to the default value */ +CCRC32::CCRC32() + : mHash( 0xFFFFFFFF ) +{ +} + +/** Allows the hash to be initialized to an arbitrary value */ +CCRC32::CCRC32(u32 InitialValue) + : mHash( InitialValue ) +{ +} + +/** Hash arbitrary data */ +void CCRC32::Hash(const void* pkData, int Size) +{ + const u8* pkCastData = static_cast(pkData); + + while (Size--) + { + mHash = gkCrcTable[(mHash ^ *pkCastData++) & 0xFF] ^ (mHash >> 8); + } +} + +/** Retrieve the final output hash. (You can keep adding data to the hash after calling this.) */ +u32 CCRC32::Digest() const +{ + return mHash; +} + +/** Convenience hash methods */ +void CCRC32::Hash(u8 v) +{ + Hash(&v, 1); +} + +void CCRC32::Hash(u16 v) +{ + Hash(&v, 2); +} + +void CCRC32::Hash(u32 v) +{ + Hash(&v, 4); +} + +void CCRC32::Hash(u64 v) +{ + Hash(&v, 8); +} + +void CCRC32::Hash(float v) +{ + Hash(&v, 4); +} + +void CCRC32::Hash(double v) +{ + Hash(&v, 8); +} + +void CCRC32::Hash(const char* pkString) +{ + while (*pkString) + { + Hash(pkString++, 1); + } +} + +/** Static */ +u32 CCRC32::StaticHashString(const char* pkString) +{ + CCRC32 Hasher; + Hasher.Hash(pkString); + return Hasher.Digest(); +} diff --git a/src/Common/Hash/CCRC32.h b/src/Common/Hash/CCRC32.h new file mode 100644 index 00000000..36dd61ff --- /dev/null +++ b/src/Common/Hash/CCRC32.h @@ -0,0 +1,40 @@ +#ifndef CCRC32_H +#define CCRC32_H + +#include "Common/TString.h" +#include "Common/types.h" + +/** + * CRC32 hash implementation + */ +class CCRC32 +{ + /** Current hash value */ + u32 mHash; + +public: + /** Default constructor, initializes the hash to the default value */ + CCRC32(); + + /** Allows the hash to be initialized to an arbitrary value */ + CCRC32(u32 InitialValue); + + /** Hash arbitrary data */ + void Hash(const void* pkData, int Size); + + /** Retrieve the final output hash. (You can keep adding data to the hash after calling this.) */ + u32 Digest() const; + + /** Convenience hash methods */ + void Hash(u8 v); + void Hash(u16 v); + void Hash(u32 v); + void Hash(u64 v); + void Hash(float v); + void Hash(double v); + void Hash(const char* pkString); + + static u32 StaticHashString(const char* pkString); +}; + +#endif // CCRC32_H diff --git a/src/Common/CHashFNV1A.h b/src/Common/Hash/CFNV1A.h similarity index 90% rename from src/Common/CHashFNV1A.h rename to src/Common/Hash/CFNV1A.h index d0fb37d2..cc3ba211 100644 --- a/src/Common/CHashFNV1A.h +++ b/src/Common/Hash/CFNV1A.h @@ -1,10 +1,10 @@ -#ifndef CHASHFNV1A_H -#define CHASHFNV1A_H +#ifndef CFNV1A_H +#define CFNV1A_H -#include "types.h" -#include "TString.h" +#include "Common/types.h" +#include "Common/TString.h" -class CHashFNV1A +class CFNV1A { public: enum EHashLength { @@ -21,7 +21,7 @@ private: static const u64 skFNVPrime64 = 0x100000001B3; public: - CHashFNV1A(EHashLength Length) + CFNV1A(EHashLength Length) { if (Length == e32Bit) Init32(); @@ -65,4 +65,4 @@ public: inline void HashString(const TString& rkVal) { HashData(rkVal.Data(), rkVal.Size()); } }; -#endif // CHASHFNV1A_H +#endif // CFNV1A_H diff --git a/src/Common/TString.cpp b/src/Common/TString.cpp index 2e4b2b23..7c0ab6a5 100644 --- a/src/Common/TString.cpp +++ b/src/Common/TString.cpp @@ -1,5 +1,5 @@ #include "TString.h" -#include "CHashFNV1A.h" +#include "Hash/CFNV1A.h" #include #include #include @@ -7,14 +7,14 @@ // ************ TString ************ u32 TString::Hash32() const { - CHashFNV1A Hash(CHashFNV1A::e32Bit); + CFNV1A Hash(CFNV1A::e32Bit); Hash.HashString(*this); return Hash.GetHash32(); } u64 TString::Hash64() const { - CHashFNV1A Hash(CHashFNV1A::e64Bit); + CFNV1A Hash(CFNV1A::e64Bit); Hash.HashString(*this); return Hash.GetHash64(); } @@ -108,14 +108,14 @@ TWideString TString::ToUTF16() const // ************ TWideString ************ u32 TWideString::Hash32() const { - CHashFNV1A Hash(CHashFNV1A::e32Bit); + CFNV1A Hash(CFNV1A::e32Bit); Hash.HashData(Data(), Size() * sizeof(wchar_t)); return Hash.GetHash32(); } u64 TWideString::Hash64() const { - CHashFNV1A Hash(CHashFNV1A::e64Bit); + CFNV1A Hash(CFNV1A::e64Bit); Hash.HashData(Data(), Size() * sizeof(wchar_t)); return Hash.GetHash64(); } diff --git a/src/Core/Resource/CMaterial.cpp b/src/Core/Resource/CMaterial.cpp index 61c412b7..d3093e62 100644 --- a/src/Core/Resource/CMaterial.cpp +++ b/src/Core/Resource/CMaterial.cpp @@ -4,7 +4,7 @@ #include "Core/Render/CRenderer.h" #include "Core/OpenGL/GLCommon.h" #include "Core/OpenGL/CShaderGenerator.h" -#include +#include #include #include @@ -243,7 +243,7 @@ u64 CMaterial::HashParameters() { if (mRecalcHash) { - CHashFNV1A Hash(CHashFNV1A::e64Bit); + CFNV1A Hash(CFNV1A::e64Bit); Hash.HashLong(mVersion); Hash.HashLong(mOptions); diff --git a/src/Core/Resource/CMaterialPass.cpp b/src/Core/Resource/CMaterialPass.cpp index 1bb49920..319ee936 100644 --- a/src/Core/Resource/CMaterialPass.cpp +++ b/src/Core/Resource/CMaterialPass.cpp @@ -58,7 +58,7 @@ CMaterialPass* CMaterialPass::Clone(CMaterial *pParent) return pOut; } -void CMaterialPass::HashParameters(CHashFNV1A& rHash) +void CMaterialPass::HashParameters(CFNV1A& rHash) { if (mEnabled) { diff --git a/src/Core/Resource/CMaterialPass.h b/src/Core/Resource/CMaterialPass.h index 3dcd1ef2..5fe98288 100644 --- a/src/Core/Resource/CMaterialPass.h +++ b/src/Core/Resource/CMaterialPass.h @@ -6,7 +6,7 @@ #include "ETevEnums.h" #include "Core/Render/FRenderOptions.h" #include -#include +#include class CMaterial; @@ -45,7 +45,7 @@ public: CMaterialPass(CMaterial *pParent); ~CMaterialPass(); CMaterialPass* Clone(CMaterial *pParent); - void HashParameters(CHashFNV1A& rHash); + void HashParameters(CFNV1A& rHash); void LoadTexture(u32 PassIndex); void SetAnimCurrent(FRenderOptions Options, u32 PassIndex); diff --git a/src/Core/Resource/Factory/CTemplateLoader.cpp b/src/Core/Resource/Factory/CTemplateLoader.cpp index 4eebdae2..b6d0ec23 100644 --- a/src/Core/Resource/Factory/CTemplateLoader.cpp +++ b/src/Core/Resource/Factory/CTemplateLoader.cpp @@ -256,6 +256,7 @@ void CTemplateLoader::LoadStructTemplate(const TString& rkTemplateFileName, CStr } } pSource->mSourceFile = rkTemplateFileName; + pSource->mTypeName = pSource->mSourceFile.GetFileName(false); TString NameAttr = TString(pRootElem->Attribute("name")); if (!NameAttr.IsEmpty()) @@ -373,7 +374,13 @@ void CTemplateLoader::LoadEnumerators(XMLElement *pEnumeratorsElem, CEnumTemplat const char *pkName = pChild->Attribute("name"); if (pkID && pkName) - pTemp->mEnumerators.push_back(CEnumTemplate::SEnumerator(pkName, TString(pkID).ToInt32())); + { + u32 EnumeratorID = TString(pkID).ToInt32(); + pTemp->mEnumerators.push_back(CEnumTemplate::SEnumerator(pkName, EnumeratorID)); + + if (EnumeratorID > 0xFF) + pTemp->mUsesHashes = true; + } else { diff --git a/src/Core/Resource/Script/EPropertyType.h b/src/Core/Resource/Script/EPropertyType.h index 0cfad3e1..391f9a9e 100644 --- a/src/Core/Resource/Script/EPropertyType.h +++ b/src/Core/Resource/Script/EPropertyType.h @@ -28,6 +28,7 @@ enum EPropertyType // functions defined in IPropertyTemplate.cpp EPropertyType PropStringToPropEnum(TString Prop); TString PropEnumToPropString(EPropertyType Prop); +const char* HashablePropTypeName(EPropertyType Prop); #endif // EPROPERTYTYPE diff --git a/src/Core/Resource/Script/IPropertyTemplate.cpp b/src/Core/Resource/Script/IPropertyTemplate.cpp index b90cb189..29d9e25f 100644 --- a/src/Core/Resource/Script/IPropertyTemplate.cpp +++ b/src/Core/Resource/Script/IPropertyTemplate.cpp @@ -1,5 +1,6 @@ #include "IPropertyTemplate.h" #include "CMasterTemplate.h" +#include #include // ************ IPropertyTemplate ************ @@ -69,6 +70,36 @@ bool IPropertyTemplate::IsFromStructTemplate() const return false; } +bool IPropertyTemplate::IsNameCorrect() const +{ + // Check whether the property name is correct... i.e., if we hash it, does it match the property ID? + // Only valid for Prime 2 and up, since Prime 1 doesn't have real property IDs, so we can't validate names + if (Game() >= eEchoesDemo) + { + // Don't hash for single-property structs + if ( (!Parent() || !Parent()->IsSingleProperty()) && + // Don't hash for the three properties in EditorProperties that have fourCC property IDs + mID != FOURCC('INAM') && + mID != FOURCC('XFRM') && + mID != FOURCC('ACTV') ) + { + // Only re-hash if we need to. Save the result (output won't change if function is called multiple times) + if (!mHasCachedNameCheck) + { + // The property ID is just a CRC32 of the property name + the type + CCRC32 Hash; + Hash.Hash(*mName); + Hash.Hash(GetTypeNameString()); + mCachedNameIsCorrect = Hash.Digest() == mID; + mHasCachedNameCheck = true; + } + return mCachedNameIsCorrect; + } + } + + return true; +} + TString IPropertyTemplate::FindStructSource() const { const CStructTemplate *pkStruct = mpParent; @@ -95,6 +126,7 @@ void CStructTemplate::CopyStructData(const CStructTemplate *pkStruct) mVersionPropertyCounts = pkStruct->mVersionPropertyCounts; mIsSingleProperty = pkStruct->mIsSingleProperty; mSourceFile = pkStruct->mSourceFile; + mTypeName = pkStruct->mTypeName; mSubProperties.resize(pkStruct->mSubProperties.size()); @@ -271,6 +303,30 @@ EPropertyType PropStringToPropEnum(TString Prop) return eInvalidProperty; } +const char* HashablePropTypeName(EPropertyType Prop) +{ + // Variants that match Retro's internal type names for generating property IDs. case sensitive + switch (Prop) + { + case eBoolProperty: return "bool"; + case eLongProperty: return "int"; + case eEnumProperty: return "enum"; + case eBitfieldProperty: return "bitfield"; + case eFloatProperty: return "float"; + case eStringProperty: return "string"; + case eColorProperty: return "Color"; + case eVector3Property: return "Vector3f"; + case eSoundProperty: return "SfxId"; + case eAssetProperty: return "asset"; + case eMayaSplineProperty: return "MayaSpline"; + + // All other types are either invalid or need a custom reimplementation because they can return multiple strings (like struct) + default: + ASSERT(false); + return nullptr; + } +} + // ************ DEBUG ************ void CStructTemplate::DebugPrintProperties(TString base) { diff --git a/src/Core/Resource/Script/IPropertyTemplate.h b/src/Core/Resource/Script/IPropertyTemplate.h index aa9aeaaf..458468ea 100644 --- a/src/Core/Resource/Script/IPropertyTemplate.h +++ b/src/Core/Resource/Script/IPropertyTemplate.h @@ -40,6 +40,8 @@ protected: u32 mID; ECookPreference mCookPreference; std::vector mAllowedVersions; + mutable bool mHasCachedNameCheck; + mutable bool mCachedNameIsCorrect; public: IPropertyTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0) @@ -49,6 +51,8 @@ public: , mpMasterTemplate(pMaster) , mName("UNSET PROPERTY NAME") , mCookPreference(eNoCookPreference) + , mHasCachedNameCheck(false) + , mCachedNameIsCorrect(false) { } @@ -59,6 +63,8 @@ public: , mpMasterTemplate(pMaster) , mName(rkName) , mCookPreference(CookPreference) + , mHasCachedNameCheck(false) + , mCachedNameIsCorrect(false) { } @@ -93,6 +99,7 @@ public: virtual bool HasValidRange() const { return false; } virtual TString RangeToString() const { return ""; } virtual TString Suffix() const { return ""; } + virtual const char* GetTypeNameString() const { return HashablePropTypeName(Type()); } virtual void SetParam(const TString& rkParamName, const TString& rkValue) { @@ -118,6 +125,7 @@ public: TIDString IDString(bool FullPath) const; bool IsDescendantOf(const CStructTemplate *pStruct) const; bool IsFromStructTemplate() const; + bool IsNameCorrect() const; TString FindStructSource() const; CStructTemplate* RootStruct(); @@ -129,7 +137,7 @@ public: inline CStructTemplate* Parent() const { return mpParent; } inline CScriptTemplate* ScriptTemplate() const { return mpScriptTemplate; } inline CMasterTemplate* MasterTemplate() const { return mpMasterTemplate; } - inline void SetName(const TString& rkName) { mName = rkName; } + inline void SetName(const TString& rkName) { mName = rkName; mHasCachedNameCheck = false; } inline void SetDescription(const TString& rkDesc) { mDescription = rkDesc; } }; @@ -302,13 +310,13 @@ public: }; // Typedefs for all property types that don't need further functionality. -typedef TTypedPropertyTemplate TBoolTemplate; -typedef TNumericalPropertyTemplate TByteTemplate; -typedef TNumericalPropertyTemplate TShortTemplate; -typedef TNumericalPropertyTemplate TLongTemplate; -typedef TNumericalPropertyTemplate TFloatTemplate; -typedef TTypedPropertyTemplate TVector3Template; -typedef TTypedPropertyTemplate TColorTemplate; +typedef TTypedPropertyTemplate TBoolTemplate; +typedef TNumericalPropertyTemplate TByteTemplate; +typedef TNumericalPropertyTemplate TShortTemplate; +typedef TNumericalPropertyTemplate TLongTemplate; +typedef TNumericalPropertyTemplate TFloatTemplate; +typedef TTypedPropertyTemplate TVector3Template; +typedef TTypedPropertyTemplate TColorTemplate; // TCharacterTemplate, TSoundTemplate, TStringTemplate, and TMayaSplineTemplate get their own subclasses so they can reimplement a couple functions class TCharacterTemplate : public TTypedPropertyTemplate @@ -327,6 +335,13 @@ public: { return new TCharacterProperty(this, pInstance, pParent, CAnimationParameters(Game())); } + + const char* GetTypeNameString() const + { + return (Game() < eCorruptionProto ? "AnimationParameters" : "CharacterAnimationSet"); + } + + IMPLEMENT_TEMPLATE_CLONE(TCharacterTemplate) }; class TSoundTemplate : public TTypedPropertyTemplate @@ -345,6 +360,8 @@ public: { return new TSoundProperty(this, pInstance, pParent, -1); } + + IMPLEMENT_TEMPLATE_CLONE(TSoundTemplate) }; class TStringTemplate : public TTypedPropertyTemplate @@ -363,6 +380,8 @@ public: { return new TStringProperty(this, pInstance, pParent); } + + IMPLEMENT_TEMPLATE_CLONE(TStringTemplate) }; class TMayaSplineTemplate : public TTypedPropertyTemplate, eMayaSplineProperty, CMayaSplineValue, false> @@ -381,6 +400,8 @@ public: { return new TMayaSplineProperty(this, pInstance, pParent); } + + IMPLEMENT_TEMPLATE_CLONE(TMayaSplineTemplate) }; // CAssetTemplate - Property template for assets. Tracks a list of resource types that @@ -448,15 +469,18 @@ class CEnumTemplate : public TTypedPropertyTemplate mEnumerators; TString mSourceFile; + bool mUsesHashes; public: CEnumTemplate(u32 ID, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0) : TTypedPropertyTemplate(ID, pScript, pMaster, pParent) + , mUsesHashes(false) { } CEnumTemplate(u32 ID, const TString& rkName, ECookPreference CookPreference, CScriptTemplate *pScript, CMasterTemplate *pMaster, CStructTemplate *pParent = 0) : TTypedPropertyTemplate(ID, rkName, CookPreference, pScript, pMaster, pParent) + , mUsesHashes(false) { } @@ -480,6 +504,7 @@ public: const CEnumTemplate *pkEnum = static_cast(pkTemp); mEnumerators = pkEnum->mEnumerators; mSourceFile = pkEnum->mSourceFile; + mUsesHashes = pkEnum->mUsesHashes; } virtual bool Matches(const IPropertyTemplate *pkTemp) const @@ -488,7 +513,13 @@ public: return ( (TTypedPropertyTemplate::Matches(pkTemp)) && (mEnumerators == pkEnum->mEnumerators) && - (mSourceFile == pkEnum->mSourceFile) ); + (mSourceFile == pkEnum->mSourceFile) && + (mUsesHashes == pkEnum->mUsesHashes) ); + } + + virtual const char* GetTypeNameString() const + { + return (mUsesHashes ? "enum" : "choice"); } inline TString SourceFile() const { return mSourceFile; } @@ -603,6 +634,7 @@ protected: std::vector mVersionPropertyCounts; bool mIsSingleProperty; TString mSourceFile; + TString mTypeName; void DetermineVersionPropertyCounts(); public: @@ -656,7 +688,8 @@ public: if ( (IPropertyTemplate::Matches(pkTemp)) && (mVersionPropertyCounts == pkStruct->mVersionPropertyCounts) && (mIsSingleProperty == pkStruct->mIsSingleProperty) && - (mSourceFile == pkStruct->mSourceFile) ) + (mSourceFile == pkStruct->mSourceFile) && + (mTypeName == pkStruct->mTypeName) ) { return StructDataMatches(pkStruct); } @@ -664,6 +697,12 @@ public: return false; } + const char* GetTypeNameString() const + { + // hack - currently templates embedded within another XML can't have a type name + return mTypeName.IsEmpty() ? *mName : *mTypeName; + } + bool StructDataMatches(const CStructTemplate *pkStruct) const { if ( (mIsSingleProperty == pkStruct->mIsSingleProperty) && diff --git a/src/Editor/CPropertyNameValidator.cpp b/src/Editor/CPropertyNameValidator.cpp new file mode 100644 index 00000000..28831eff --- /dev/null +++ b/src/Editor/CPropertyNameValidator.cpp @@ -0,0 +1,29 @@ +#include "CPropertyNameValidator.h" +#include + +CPropertyNameValidator::CPropertyNameValidator(QObject* pParent) + : QValidator(pParent) +{} + +/** Set the property to validate against */ +void CPropertyNameValidator::SetProperty(IPropertyTemplate* pProp) +{ + mpProperty = pProp; + emit changed(); +} + +/** Perform validation */ +QValidator::State CPropertyNameValidator::validate(QString& rInput, int&) const +{ + if (mpProperty) + { + CCRC32 Hash; + Hash.Hash( rInput.toStdString().c_str() ); + Hash.Hash( mpProperty->GetTypeNameString() ); + u32 PropertyID = Hash.Digest(); + + return ( PropertyID == mpProperty->PropertyID() ? QValidator::Acceptable : QValidator::Invalid ); + } + + return QValidator::Invalid; +} diff --git a/src/Editor/CPropertyNameValidator.h b/src/Editor/CPropertyNameValidator.h new file mode 100644 index 00000000..a835afc6 --- /dev/null +++ b/src/Editor/CPropertyNameValidator.h @@ -0,0 +1,25 @@ +#ifndef CPROPERTYNAMEVALIDATOR_H +#define CPROPERTYNAMEVALIDATOR_H + +#include +#include + +/** QValidator subclass that checks if a property name is valid */ +class CPropertyNameValidator : public QValidator +{ + Q_OBJECT + + /** The property being validated against */ + IPropertyTemplate* mpProperty; + +public: + CPropertyNameValidator(QObject* pParent = 0); + + /** Set the property to validate against */ + void SetProperty(IPropertyTemplate* pProp); + + /** Perform validation */ + QValidator::State validate(QString& rInput, int& rPos) const; +}; + +#endif // CPROPERTYNAMEVALIDATOR_H diff --git a/src/Editor/Editor.pro b/src/Editor/Editor.pro index 9a64710a..df5e2079 100644 --- a/src/Editor/Editor.pro +++ b/src/Editor/Editor.pro @@ -196,7 +196,10 @@ HEADERS += \ Undo/CRenameDirectoryCommand.h \ CFileNameValidator.h \ Undo/ICreateDeleteDirectoryCommand.h \ - ResourceBrowser/CVirtualDirectoryTreeView.h + ResourceBrowser/CVirtualDirectoryTreeView.h \ + CPropertyNameValidator.h \ + Widgets/CSoftValidatorLineEdit.h \ + Widgets/CValidityLabel.h # Source Files SOURCES += \ @@ -270,7 +273,8 @@ SOURCES += \ ResourceBrowser/CResourceTableModel.cpp \ ResourceBrowser/CResourceTableView.cpp \ ResourceBrowser/CVirtualDirectoryModel.cpp \ - ResourceBrowser/CVirtualDirectoryTreeView.cpp + ResourceBrowser/CVirtualDirectoryTreeView.cpp \ + CPropertyNameValidator.cpp # UI Files FORMS += \ diff --git a/src/Editor/PropertyEdit/CPropertyModel.cpp b/src/Editor/PropertyEdit/CPropertyModel.cpp index b7344a7e..7eb5d8bc 100644 --- a/src/Editor/PropertyEdit/CPropertyModel.cpp +++ b/src/Editor/PropertyEdit/CPropertyModel.cpp @@ -10,6 +10,7 @@ CPropertyModel::CPropertyModel(QObject *pParent /*= 0*/) : QAbstractItemModel(pParent) , mpBaseStruct(nullptr) , mBoldModifiedProperties(true) + , mShowNameValidity(false) { } @@ -442,6 +443,23 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const return QSize(0, 23); } + if (Role == Qt::ForegroundRole) + { + if (mShowNameValidity && mpBaseStruct->Template()->Game() >= eEchoesDemo) + { + IProperty *pProp = PropertyForIndex(rkIndex, true); + IPropertyTemplate *pTemp = (pProp ? pProp->Template() : nullptr); + + // Don't highlight the name of the root property + if (pTemp && pTemp->Parent() != nullptr) + { + static const QColor skRightColor = QColor(128, 255, 128); + static const QColor skWrongColor = QColor(255, 128, 128); + return QBrush( pTemp->IsNameCorrect() ? skRightColor : skWrongColor ); + } + } + } + return QVariant::Invalid; } @@ -585,3 +603,16 @@ void CPropertyModel::ArrayResized(const QModelIndex& rkIndex, u32 OldSize) endRemoveRows(); } } + +void CPropertyModel::SetShowPropertyNameValidity(bool Enable) +{ + mShowNameValidity = Enable; + + // Emit data changed so that name colors are updated; + QVector Roles; + Roles << Qt::ForegroundRole; + + QModelIndex TopLeft = index(0, 0, QModelIndex()); + QModelIndex BottomRight = index( rowCount(QModelIndex()) - 1, 0, QModelIndex()); + emit dataChanged(TopLeft, BottomRight, Roles); +} diff --git a/src/Editor/PropertyEdit/CPropertyModel.h b/src/Editor/PropertyEdit/CPropertyModel.h index d05f3071..4fa7686f 100644 --- a/src/Editor/PropertyEdit/CPropertyModel.h +++ b/src/Editor/PropertyEdit/CPropertyModel.h @@ -11,6 +11,7 @@ class CPropertyModel : public QAbstractItemModel CPropertyStruct *mpBaseStruct; bool mBoldModifiedProperties; + bool mShowNameValidity; QFont mFont; public: @@ -31,6 +32,8 @@ public: void ArrayResized(const QModelIndex& rkIndex, u32 OldSize); void ResizeArray(const QModelIndex& rkIndex, u32 NewSize); + void SetShowPropertyNameValidity(bool Enable); + inline void SetFont(QFont Font) { mFont = Font; } inline void SetBoldModifiedProperties(bool Enable) { mBoldModifiedProperties = Enable; } diff --git a/src/Editor/PropertyEdit/CPropertyView.cpp b/src/Editor/PropertyEdit/CPropertyView.cpp index 30114f2e..3177d2db 100644 --- a/src/Editor/PropertyEdit/CPropertyView.cpp +++ b/src/Editor/PropertyEdit/CPropertyView.cpp @@ -19,6 +19,12 @@ CPropertyView::CPropertyView(QWidget *pParent) setModel(mpModel); setContextMenuPolicy(Qt::CustomContextMenu); + + mpShowNameValidityAction = new QAction("Show whether property name is correct", this); + mpShowNameValidityAction->setCheckable(true); + mpShowNameValidityAction->setChecked(false); + connect(mpShowNameValidityAction, SIGNAL(triggered(bool)), this, SLOT(ToggleShowNameValidity(bool))); + mpEditTemplateAction = new QAction("Edit template", this); connect(mpEditTemplateAction, SIGNAL(triggered()), this, SLOT(EditPropertyTemplate())); @@ -216,10 +222,21 @@ void CPropertyView::CreateContextMenu(const QPoint& rkPos) QMenu Menu; Menu.addAction(mpEditTemplateAction); + + if (mpEditor->CurrentGame() >= eEchoesDemo) + { + Menu.addAction(mpShowNameValidityAction); + } + Menu.exec(viewport()->mapToGlobal(rkPos)); } } +void CPropertyView::ToggleShowNameValidity(bool ShouldShow) +{ + mpModel->SetShowPropertyNameValidity(ShouldShow); +} + void CPropertyView::EditPropertyTemplate() { CTemplateEditDialog Dialog(mpMenuProperty->Template(), mpEditor); diff --git a/src/Editor/PropertyEdit/CPropertyView.h b/src/Editor/PropertyEdit/CPropertyView.h index 29602de0..bdec0967 100644 --- a/src/Editor/PropertyEdit/CPropertyView.h +++ b/src/Editor/PropertyEdit/CPropertyView.h @@ -16,6 +16,7 @@ class CPropertyView : public QTreeView CScriptObject *mpObject; IProperty *mpMenuProperty; + QAction *mpShowNameValidityAction; QAction *mpEditTemplateAction; public: @@ -34,6 +35,7 @@ public slots: void OnPropertyModified(const QModelIndex& rkIndex); void CreateContextMenu(const QPoint& rkPos); + void ToggleShowNameValidity(bool ShouldShow); void EditPropertyTemplate(); }; diff --git a/src/Editor/Widgets/CSoftValidatorLineEdit.h b/src/Editor/Widgets/CSoftValidatorLineEdit.h new file mode 100644 index 00000000..dda4a50c --- /dev/null +++ b/src/Editor/Widgets/CSoftValidatorLineEdit.h @@ -0,0 +1,125 @@ +#ifndef CSOFTVALIDATORLINEEDIT_H +#define CSOFTVALIDATORLINEEDIT_H + +#include "CTimedLineEdit.h" +#include + +/** + * A QLineEdit subclass that can use a QValidator to check if the input meets certain criteria. + * If the criteria is met, the line edit has a green outline; otherwise, a red outline. + * Unlike the normal QLineEdit validator, the effects of this are strictly cosmetic. + */ +class CSoftValidatorLineEdit : public CTimedLineEdit +{ + Q_OBJECT + + /** The validator that input is checked against */ + QValidator* mpSoftValidator; + + /** Whether to only validate when the user stops typing. Good for slow validators. */ + bool mOnlyValidateOnFinishedTyping; + + /** Whether the current input is valid */ + bool mInputIsValid; + +signals: + /** Emitted when the validity of the input changes */ + void SoftValidityChanged(bool NewValid); + +protected slots: + /** Internal update function */ + void InternalUpdate() + { + bool NewValidity = false; + + if ( mpSoftValidator ) + { + int DummyPos; + if ( mpSoftValidator->validate(text(), DummyPos) == QValidator::Acceptable ) + { + NewValidity = true; + setStyleSheet("border: 1px solid green"); + } + else + { + NewValidity = false; + setStyleSheet("border: 1px solid red"); + } + } + else + { + NewValidity = true; + setStyleSheet(""); + } + + if (NewValidity != mInputIsValid) + { + mInputIsValid = NewValidity; + emit SoftValidityChanged(mInputIsValid); + } + } + +public: + CSoftValidatorLineEdit(QWidget *pParent = 0) + : CTimedLineEdit(pParent) + , mpSoftValidator(nullptr) + , mOnlyValidateOnFinishedTyping(false) + , mInputIsValid(true) + {} + + /** Set the soft validator to use */ + void SetSoftValidator(QValidator* pValidator) + { + if (mpSoftValidator) + { + disconnect(mpSoftValidator); + mpSoftValidator = nullptr; + } + + if (pValidator) + { + mpSoftValidator = pValidator; + connect(mpSoftValidator, SIGNAL(changed()), this, SLOT(InternalUpdate())); + } + + InternalUpdate(); + } + + /** Set whether the input should only be validated when the user finishes typing. */ + void SetOnlyDoSoftValidationOnFinishedTyping(bool Enable) + { + mOnlyValidateOnFinishedTyping = Enable; + + if (!mOnlyValidateOnFinishedTyping) + InternalUpdate(); + } + + /** Check whether the input is valid */ + inline bool IsInputValid() const + { + return mInputIsValid; + } + +public slots: + virtual void OnTextChanged() + { + CTimedLineEdit::OnTextChanged(); + + if (!mOnlyValidateOnFinishedTyping) + { + InternalUpdate(); + } + } + + virtual void OnTimeout() + { + CTimedLineEdit::OnTimeout(); + + if (mOnlyValidateOnFinishedTyping) + { + InternalUpdate(); + } + } +}; + +#endif // CSOFTVALIDATORLINEEDIT_H diff --git a/src/Editor/Widgets/CValidityLabel.h b/src/Editor/Widgets/CValidityLabel.h new file mode 100644 index 00000000..ddd80036 --- /dev/null +++ b/src/Editor/Widgets/CValidityLabel.h @@ -0,0 +1,71 @@ +#ifndef CVALIDITYLABEL_H +#define CVALIDITYLABEL_H + +#include + +/** QLabel subclass that displays different text in either red or green depending on a flag. */ +class CValidityLabel : public QLabel +{ + Q_OBJECT + + /** String to display if valid */ + QString mValidString; + + /** String to display if invalid */ + QString mInvalidString; + + /** Whether we are displaying the valid or invalid string */ + bool mValid; + +public: + CValidityLabel(QWidget* pParent = 0) + : QLabel(pParent) + { + SetValid(true); + } + + CValidityLabel(const QString& rkValidText, const QString& rkInvalidText, QWidget* pParent = 0) + : QLabel( rkValidText, pParent ) + , mValidString( rkValidText ) + , mInvalidString( rkInvalidText ) + { + SetValid(true); + } + + /** Configure the strings to display */ + void SetValidityText(const QString& rkValidText, const QString& rkInvalidText) + { + mValidString = rkValidText; + mInvalidString = rkInvalidText; + setText(mValid ? mValidString : mInvalidString); + } + + /** Returns whether we are valid */ + inline bool IsValid() const + { + return mValid; + } + +public slots: + /** Updates the label as either valid or invalid */ + void SetValid(bool Valid) + { + mValid = Valid; + QPalette NewPalette; + + if (mValid) + { + NewPalette.setColor( foregroundRole(), Qt::green ); + setText(mValidString); + } + else + { + NewPalette.setColor( foregroundRole(), Qt::red ); + setText(mInvalidString); + } + + setPalette(NewPalette); + } +}; + +#endif // CVALIDITYLABEL_H diff --git a/src/Editor/WorldEditor/CTemplateEditDialog.cpp b/src/Editor/WorldEditor/CTemplateEditDialog.cpp index 4b6b5670..10d87350 100644 --- a/src/Editor/WorldEditor/CTemplateEditDialog.cpp +++ b/src/Editor/WorldEditor/CTemplateEditDialog.cpp @@ -8,23 +8,26 @@ CTemplateEditDialog::CTemplateEditDialog(IPropertyTemplate *pTemplate, QWidget *pParent) : QDialog(pParent) - , ui(new Ui::CTemplateEditDialog) + , mpUI(new Ui::CTemplateEditDialog) + , mpValidator(new CPropertyNameValidator(this)) , mpTemplate(pTemplate) , mGame(pTemplate->Game()) , mOriginalName(pTemplate->Name()) , mOriginalDescription(pTemplate->Description()) + , mOriginalNameWasValid(true) { - ui->setupUi(this); + mpUI->setupUi(this); - ui->IDDisplayLabel->setText(TO_QSTRING(pTemplate->IDString(false))); - ui->PathDisplayLabel->setText(TO_QSTRING(pTemplate->IDString(true))); - ui->NameLineEdit->setText(TO_QSTRING(pTemplate->Name())); - ui->DescriptionTextEdit->setPlainText(TO_QSTRING(pTemplate->Description())); + mpUI->IDDisplayLabel->setText(TO_QSTRING(pTemplate->IDString(false))); + mpUI->PathDisplayLabel->setText(TO_QSTRING(pTemplate->IDString(true))); + mpUI->NameLineEdit->setText(TO_QSTRING(pTemplate->Name())); + mpUI->DescriptionTextEdit->setPlainText(TO_QSTRING(pTemplate->Description())); if (mGame <= ePrime) { - ui->TemplatesGroupBox->hide(); - ui->RenameAllCheckBox->setText("Rename all copies of this property"); + mpUI->TemplatesGroupBox->hide(); + mpUI->RenameAllCheckBox->setText("Rename all copies of this property"); + mpUI->ValidityLabel->hide(); resize(width(), minimumHeight()); } @@ -34,7 +37,14 @@ CTemplateEditDialog::CTemplateEditDialog(IPropertyTemplate *pTemplate, QWidget * std::vector TemplateList = CMasterTemplate::XMLsUsingID(pTemplate->PropertyID()); for (u32 iTemp = 0; iTemp < TemplateList.size(); iTemp++) - ui->TemplatesListWidget->addItem(TO_QSTRING(TemplateList[iTemp])); + mpUI->TemplatesListWidget->addItem(TO_QSTRING(TemplateList[iTemp])); + + mpUI->ValidityLabel->SetValidityText("Hash match! Property name is likely correct.", "Hash mismatch! Property name is likely wrong."); + connect(mpUI->NameLineEdit, SIGNAL( SoftValidityChanged(bool) ), mpUI->ValidityLabel, SLOT( SetValid(bool) ) ); + + mpValidator->SetProperty(pTemplate); + mpUI->NameLineEdit->SetSoftValidator(mpValidator); + mOriginalNameWasValid = mpUI->NameLineEdit->IsInputValid(); } TString Source; @@ -65,26 +75,36 @@ CTemplateEditDialog::CTemplateEditDialog(IPropertyTemplate *pTemplate, QWidget * Source = "None"; } - ui->SourceFileDisplayLabel->setText(TO_QSTRING(Source)); + mpUI->SourceFileDisplayLabel->setText(TO_QSTRING(Source)); - connect(ui->ButtonBox, SIGNAL(accepted()), this, SLOT(ApplyChanges())); - connect(ui->ButtonBox, SIGNAL(rejected()), this, SLOT(close())); + connect(mpUI->ButtonBox, SIGNAL(accepted()), this, SLOT(ApplyChanges())); + connect(mpUI->ButtonBox, SIGNAL(rejected()), this, SLOT(close())); } CTemplateEditDialog::~CTemplateEditDialog() { - delete ui; + delete mpUI; } // ************ PUBLIC SLOTS ************ void CTemplateEditDialog::ApplyChanges() { + // Make sure the user *really* wants to change the property if the hash used to be correct and now isn't... + if (mOriginalNameWasValid && !mpUI->NameLineEdit->IsInputValid()) + { + bool ReallyApply = UICommon::YesNoQuestion(this, "Name mismatch", + "The new property name does not match the property ID. It is very likely that the original name was correct and the new one isn't. Are you sure you want to change it?"); + + if (!ReallyApply) + return; + } + FindEquivalentProperties(mpTemplate); bool NeedsListResave = false; - bool RenameAll = ui->RenameAllCheckBox->isChecked(); + bool RenameAll = mpUI->RenameAllCheckBox->isChecked(); - TString NewName = TO_TSTRING(ui->NameLineEdit->text()); + TString NewName = TO_TSTRING(mpUI->NameLineEdit->text()); if (NewName.IsEmpty()) NewName = "Unknown"; if (mOriginalName != NewName) @@ -110,7 +130,7 @@ void CTemplateEditDialog::ApplyChanges() NeedsListResave = true; } - TString NewDescription = TO_TSTRING(ui->DescriptionTextEdit->toPlainText()); + TString NewDescription = TO_TSTRING(mpUI->DescriptionTextEdit->toPlainText()); UpdateDescription(NewDescription); // Resave templates diff --git a/src/Editor/WorldEditor/CTemplateEditDialog.h b/src/Editor/WorldEditor/CTemplateEditDialog.h index 8fbe1607..771879cc 100644 --- a/src/Editor/WorldEditor/CTemplateEditDialog.h +++ b/src/Editor/WorldEditor/CTemplateEditDialog.h @@ -1,6 +1,7 @@ #ifndef CTEMPLATEEDITDIALOG_H #define CTEMPLATEEDITDIALOG_H +#include "Editor/CPropertyNameValidator.h" #include #include #include @@ -12,13 +13,15 @@ class CTemplateEditDialog; class CTemplateEditDialog : public QDialog { Q_OBJECT - Ui::CTemplateEditDialog *ui; + Ui::CTemplateEditDialog* mpUI; + CPropertyNameValidator* mpValidator; IPropertyTemplate *mpTemplate; EGame mGame; TString mOriginalName; TString mOriginalDescription; + bool mOriginalNameWasValid; // These members help track what templates need to be updated and resaved after the user clicks OK QVector mScriptTemplatesToResave; diff --git a/src/Editor/WorldEditor/CTemplateEditDialog.ui b/src/Editor/WorldEditor/CTemplateEditDialog.ui index cd480b6a..fbde5739 100644 --- a/src/Editor/WorldEditor/CTemplateEditDialog.ui +++ b/src/Editor/WorldEditor/CTemplateEditDialog.ui @@ -13,9 +13,9 @@ Edit Template - + - + @@ -62,6 +62,26 @@ + + + + Source File: + + + + + + + IBeamCursor + + + SOURCE FILE GOES HERE + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + @@ -70,7 +90,31 @@ - + + + 0 + + + + + + + + + 7 + 50 + false + + + + Valid + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + @@ -104,26 +148,6 @@ - - - - Source File: - - - - - - - IBeamCursor - - - SOURCE FILE GOES HERE - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - @@ -205,6 +229,18 @@ + + + CSoftValidatorLineEdit + QLineEdit +
Editor/Widgets/CSoftValidatorLineEdit.h
+
+ + CValidityLabel + QLabel +
Editor/Widgets/CValidityLabel.h
+
+
diff --git a/templates/Properties.xml b/templates/Properties.xml index bf5db53a..c1998217 100644 --- a/templates/Properties.xml +++ b/templates/Properties.xml @@ -1,10 +1,10 @@ - + - + @@ -90,7 +90,7 @@ - + @@ -251,7 +251,7 @@ - + @@ -429,7 +429,7 @@ - + @@ -440,7 +440,7 @@ - + @@ -728,7 +728,7 @@ - + @@ -779,7 +779,7 @@ - + @@ -828,7 +828,7 @@ - + @@ -968,7 +968,7 @@ - + @@ -1150,7 +1150,7 @@ - + @@ -1233,7 +1233,7 @@ - + @@ -1279,7 +1279,7 @@ - + @@ -1637,7 +1637,7 @@ - + @@ -1703,7 +1703,7 @@ - + @@ -1845,7 +1845,7 @@ - + @@ -2174,7 +2174,7 @@ - + @@ -2212,11 +2212,11 @@ - + - + @@ -2275,7 +2275,7 @@ - + @@ -2438,7 +2438,7 @@ - + @@ -2569,7 +2569,7 @@ - + @@ -2609,7 +2609,7 @@ - + @@ -2712,7 +2712,7 @@ - + @@ -2785,7 +2785,7 @@ - + @@ -2815,7 +2815,7 @@ - + @@ -3031,7 +3031,7 @@ - + @@ -3066,7 +3066,7 @@ - + @@ -3352,7 +3352,7 @@ - + @@ -3489,7 +3489,7 @@ - + @@ -3623,7 +3623,7 @@ - + @@ -3646,7 +3646,7 @@ - + @@ -3734,7 +3734,7 @@ - + @@ -3819,17 +3819,17 @@ - + - + - + @@ -3933,7 +3933,7 @@ - + @@ -3948,7 +3948,7 @@ - + @@ -3988,7 +3988,7 @@ - + @@ -4090,7 +4090,7 @@ - + @@ -4486,7 +4486,7 @@ - + @@ -4655,7 +4655,7 @@ - + @@ -4690,7 +4690,7 @@ - + @@ -4782,7 +4782,7 @@ - + @@ -4812,7 +4812,7 @@ - + @@ -4903,7 +4903,7 @@ - + @@ -4953,7 +4953,7 @@ - + @@ -5503,7 +5503,7 @@ - + @@ -5541,7 +5541,7 @@ - + @@ -5583,7 +5583,7 @@ - + @@ -5878,7 +5878,7 @@ - + @@ -5940,7 +5940,7 @@ - + @@ -5988,7 +5988,7 @@ - + @@ -6019,7 +6019,7 @@ - + @@ -6260,7 +6260,7 @@ - + @@ -6284,7 +6284,7 @@ - + @@ -6308,7 +6308,7 @@ - + @@ -6391,7 +6391,7 @@ - + @@ -6530,7 +6530,7 @@ - + @@ -6608,7 +6608,7 @@ - + @@ -6656,7 +6656,7 @@ - + @@ -6756,7 +6756,7 @@ - + @@ -6890,7 +6890,7 @@ - + @@ -6905,7 +6905,7 @@ - + @@ -6997,7 +6997,7 @@ - + @@ -7014,8 +7014,8 @@ - - + + @@ -7051,7 +7051,7 @@ - + @@ -7306,7 +7306,7 @@ - + @@ -7401,7 +7401,7 @@ - + @@ -7430,7 +7430,7 @@ - + @@ -7560,7 +7560,7 @@ - + @@ -7666,7 +7666,7 @@ - + @@ -7783,7 +7783,7 @@ - + @@ -7851,7 +7851,7 @@ - + @@ -7886,7 +7886,7 @@ - + @@ -7923,7 +7923,7 @@ - + @@ -8064,7 +8064,7 @@ - + @@ -8082,7 +8082,7 @@ - + @@ -8221,7 +8221,7 @@ - + @@ -8244,7 +8244,7 @@ - + @@ -8385,7 +8385,7 @@ - + @@ -8439,7 +8439,7 @@ - + @@ -8451,7 +8451,7 @@ - + @@ -8538,7 +8538,7 @@ - + @@ -8583,7 +8583,7 @@ - + @@ -8619,7 +8619,7 @@ - + @@ -8659,7 +8659,7 @@ - + @@ -8774,7 +8774,7 @@ - + @@ -8878,7 +8878,7 @@ - + @@ -8891,9 +8891,9 @@ - + - + @@ -8932,7 +8932,7 @@ - + @@ -9014,7 +9014,7 @@ - + @@ -9260,7 +9260,7 @@ - + @@ -9316,7 +9316,7 @@ - + @@ -9618,7 +9618,7 @@ - + @@ -9687,7 +9687,7 @@ - + @@ -9714,7 +9714,7 @@ - + @@ -10012,7 +10012,7 @@ - + @@ -10079,7 +10079,7 @@ - + @@ -10279,7 +10279,7 @@ - + @@ -10360,7 +10360,7 @@ - + @@ -10495,7 +10495,7 @@ - + @@ -10617,7 +10617,7 @@ - + @@ -10643,7 +10643,7 @@ - + @@ -10690,7 +10690,7 @@ - + @@ -10714,7 +10714,7 @@ - + @@ -10755,7 +10755,7 @@ - + @@ -10837,7 +10837,7 @@ - + @@ -10849,7 +10849,7 @@ - + @@ -10941,7 +10941,7 @@ - + @@ -10980,7 +10980,7 @@ - + @@ -11262,7 +11262,7 @@ - + @@ -11325,7 +11325,7 @@ - + @@ -11349,7 +11349,7 @@ - + @@ -11470,7 +11470,7 @@ - + diff --git a/templates/dkcr/Script/AreaNode.xml b/templates/dkcr/Script/AreaNode.xml index 132f8480..a3ffb3f9 100644 --- a/templates/dkcr/Script/AreaNode.xml +++ b/templates/dkcr/Script/AreaNode.xml @@ -39,7 +39,7 @@ 0.0, 0.0, 0.0 - + diff --git a/templates/dkcr/Script/Cable.xml b/templates/dkcr/Script/Cable.xml index 223008ef..8f96923b 100644 --- a/templates/dkcr/Script/Cable.xml +++ b/templates/dkcr/Script/Cable.xml @@ -92,7 +92,7 @@ 5.0 - + false diff --git a/templates/dkcr/Script/CameraShaker.xml b/templates/dkcr/Script/CameraShaker.xml index 05d24d32..507bb839 100644 --- a/templates/dkcr/Script/CameraShaker.xml +++ b/templates/dkcr/Script/CameraShaker.xml @@ -21,7 +21,7 @@ 1.0 - + diff --git a/templates/dkcr/Script/Effect.xml b/templates/dkcr/Script/Effect.xml index 3c071b19..72f810a2 100644 --- a/templates/dkcr/Script/Effect.xml +++ b/templates/dkcr/Script/Effect.xml @@ -3,7 +3,7 @@ Effect - + true diff --git a/templates/dkcr/Script/FactorySwitch.xml b/templates/dkcr/Script/FactorySwitch.xml index 2617af6a..7391203f 100644 --- a/templates/dkcr/Script/FactorySwitch.xml +++ b/templates/dkcr/Script/FactorySwitch.xml @@ -13,8 +13,8 @@ - - + + false diff --git a/templates/dkcr/Script/HUD.xml b/templates/dkcr/Script/HUD.xml index 4d59b91e..add619f0 100644 --- a/templates/dkcr/Script/HUD.xml +++ b/templates/dkcr/Script/HUD.xml @@ -136,8 +136,8 @@ - - + + diff --git a/templates/dkcr/Script/IslandArea.xml b/templates/dkcr/Script/IslandArea.xml index 1727e3d7..45f81367 100644 --- a/templates/dkcr/Script/IslandArea.xml +++ b/templates/dkcr/Script/IslandArea.xml @@ -94,8 +94,8 @@ - - + + diff --git a/templates/dkcr/Script/IslandHUD.xml b/templates/dkcr/Script/IslandHUD.xml index 9049c7fb..1ffb58ba 100644 --- a/templates/dkcr/Script/IslandHUD.xml +++ b/templates/dkcr/Script/IslandHUD.xml @@ -17,7 +17,7 @@ - + @@ -77,11 +77,11 @@ - - - - - + + + + + diff --git a/templates/dkcr/Script/OceanBridge.xml b/templates/dkcr/Script/OceanBridge.xml index d146a26c..29c138ca 100644 --- a/templates/dkcr/Script/OceanBridge.xml +++ b/templates/dkcr/Script/OceanBridge.xml @@ -16,8 +16,8 @@ - - + + @@ -179,20 +179,20 @@ - + - + - + - + - - + + diff --git a/templates/dkcr/Script/Pickup.xml b/templates/dkcr/Script/Pickup.xml index dfa96249..4d96bccc 100644 --- a/templates/dkcr/Script/Pickup.xml +++ b/templates/dkcr/Script/Pickup.xml @@ -12,7 +12,7 @@ - + diff --git a/templates/dkcr/Script/VolcanoBossBodyPart.xml b/templates/dkcr/Script/VolcanoBossBodyPart.xml index edc8defd..9dcc7822 100644 --- a/templates/dkcr/Script/VolcanoBossBodyPart.xml +++ b/templates/dkcr/Script/VolcanoBossBodyPart.xml @@ -127,7 +127,7 @@ 0.2 - + diff --git a/templates/dkcr/Structs/GenericCreatureStructA.xml b/templates/dkcr/Structs/GenericCreatureStructA.xml index b200c8ae..e7d99cbe 100644 --- a/templates/dkcr/Structs/GenericCreatureStructA.xml +++ b/templates/dkcr/Structs/GenericCreatureStructA.xml @@ -332,7 +332,7 @@ - + diff --git a/templates/dkcr/Structs/PatternedAI.xml b/templates/dkcr/Structs/PatternedAI.xml index d81604a2..91d8b789 100644 --- a/templates/dkcr/Structs/PatternedAI.xml +++ b/templates/dkcr/Structs/PatternedAI.xml @@ -39,7 +39,7 @@ - + true diff --git a/templates/dkcr/Structs/PeanutStruct.xml b/templates/dkcr/Structs/PeanutStruct.xml index 9b6065e9..dc96ac12 100644 --- a/templates/dkcr/Structs/PeanutStruct.xml +++ b/templates/dkcr/Structs/PeanutStruct.xml @@ -2,7 +2,7 @@ - - + + diff --git a/templates/dkcr/Structs/UnknownStruct.xml b/templates/dkcr/Structs/UnknownStruct.xml index abacd4f8..93b079ad 100644 --- a/templates/dkcr/Structs/UnknownStruct.xml +++ b/templates/dkcr/Structs/UnknownStruct.xml @@ -1,6 +1,6 @@ - + diff --git a/templates/mp2/Script/AtomicBeta.xml b/templates/mp2/Script/AtomicBeta.xml index 080ed6f8..121f2a97 100644 --- a/templates/mp2/Script/AtomicBeta.xml +++ b/templates/mp2/Script/AtomicBeta.xml @@ -80,15 +80,9 @@ 1.0 - - -1 - - - -1 - - - -1 - + + + 1.0 diff --git a/templates/mp2demo/Script/Brizgee.xml b/templates/mp2demo/Script/Brizgee.xml index 1d64466c..eccd5c49 100644 --- a/templates/mp2demo/Script/Brizgee.xml +++ b/templates/mp2demo/Script/Brizgee.xml @@ -41,15 +41,9 @@ 2.0 - - -1 - - - -1 - - - -1 - + + + diff --git a/templates/mp2demo/Script/Midi.xml b/templates/mp2demo/Script/Midi.xml index eba1611c..7f3cb23c 100644 --- a/templates/mp2demo/Script/Midi.xml +++ b/templates/mp2demo/Script/Midi.xml @@ -3,7 +3,7 @@ Midi - + 0.0