Fixed property name generator/template edit dialog to work with new property system

This commit is contained in:
Aruki 2018-10-09 23:15:15 -06:00
parent 803ea5788b
commit 22ab73883c
27 changed files with 394 additions and 212 deletions

View File

@ -11,9 +11,11 @@ using namespace std::experimental::filesystem::v1;
namespace FileUtil namespace FileUtil
{ {
#define ToPath(Path) u8path(Path)
bool Exists(const TString &rkFilePath) bool Exists(const TString &rkFilePath)
{ {
return exists(*rkFilePath); return exists(ToPath(*rkFilePath));
} }
bool IsRoot(const TString& rkPath) bool IsRoot(const TString& rkPath)
@ -26,22 +28,22 @@ bool IsRoot(const TString& rkPath)
bool IsFile(const TString& rkFilePath) bool IsFile(const TString& rkFilePath)
{ {
return is_regular_file(*rkFilePath); return is_regular_file(ToPath(*rkFilePath));
} }
bool IsDirectory(const TString& rkDirPath) bool IsDirectory(const TString& rkDirPath)
{ {
return is_directory(*rkDirPath); return is_directory(ToPath(*rkDirPath));
} }
bool IsAbsolute(const TString& rkDirPath) bool IsAbsolute(const TString& rkDirPath)
{ {
return path(*rkDirPath).is_absolute(); return ToPath(*rkDirPath).is_absolute();
} }
bool IsRelative(const TString& rkDirPath) bool IsRelative(const TString& rkDirPath)
{ {
return path(*rkDirPath).is_relative(); return ToPath(*rkDirPath).is_relative();
} }
bool IsEmpty(const TString& rkDirPath) bool IsEmpty(const TString& rkDirPath)
@ -52,7 +54,7 @@ bool IsEmpty(const TString& rkDirPath)
return false; return false;
} }
return is_empty(*rkDirPath); return is_empty(ToPath(*rkDirPath));
} }
bool MakeDirectory(const TString& rkNewDir) bool MakeDirectory(const TString& rkNewDir)
@ -63,7 +65,7 @@ bool MakeDirectory(const TString& rkNewDir)
return false; return false;
} }
return create_directories(*rkNewDir); return create_directories(ToPath(*rkNewDir));
} }
bool CopyFile(const TString& rkOrigPath, const TString& rkNewPath) bool CopyFile(const TString& rkOrigPath, const TString& rkNewPath)
@ -77,7 +79,7 @@ bool CopyFile(const TString& rkOrigPath, const TString& rkNewPath)
MakeDirectory(rkNewPath.GetFileDirectory()); MakeDirectory(rkNewPath.GetFileDirectory());
std::error_code Error; std::error_code Error;
// call std::filesystem::copy, not std::copy // call std::filesystem::copy, not std::copy
std::experimental::filesystem::copy(*rkOrigPath, *rkNewPath, Error); std::experimental::filesystem::copy(ToPath(*rkOrigPath), ToPath(*rkNewPath), Error);
return (Error.value() == 0); return (Error.value() == 0);
} }
@ -92,7 +94,7 @@ bool CopyDirectory(const TString& rkOrigPath, const TString& rkNewPath)
MakeDirectory(rkNewPath.GetFileDirectory()); MakeDirectory(rkNewPath.GetFileDirectory());
std::error_code Error; std::error_code Error;
// call std::filesystem::copy, not std::copy // call std::filesystem::copy, not std::copy
std::experimental::filesystem::copy(*rkOrigPath, *rkNewPath, Error); std::experimental::filesystem::copy(ToPath(*rkOrigPath), ToPath(*rkNewPath), Error);
return (Error.value() == 0); return (Error.value() == 0);
} }
@ -110,8 +112,9 @@ bool MoveFile(const TString& rkOldPath, const TString& rkNewPath)
return false; return false;
} }
int Result = rename(*rkOldPath, *rkNewPath); std::error_code Error;
return (Result == 0); rename(ToPath(*rkOldPath), ToPath(*rkNewPath), Error);
return Error.value() == 0;
} }
bool MoveDirectory(const TString& rkOldPath, const TString& rkNewPath) bool MoveDirectory(const TString& rkOldPath, const TString& rkNewPath)
@ -128,14 +131,15 @@ bool MoveDirectory(const TString& rkOldPath, const TString& rkNewPath)
return false; return false;
} }
int Result = rename(*rkOldPath, *rkNewPath); std::error_code Error;
return (Result == 0); rename(ToPath(*rkOldPath), ToPath(*rkNewPath), Error);
return Error.value() == 0;
} }
bool DeleteFile(const TString& rkFilePath) bool DeleteFile(const TString& rkFilePath)
{ {
if (!IsFile(rkFilePath)) return false; if (!IsFile(rkFilePath)) return false;
return remove(*rkFilePath) == 1; return remove(ToPath(*rkFilePath)) == 1;
} }
bool DeleteDirectory(const TString& rkDirPath, bool FailIfNotEmpty) bool DeleteDirectory(const TString& rkDirPath, bool FailIfNotEmpty)
@ -159,7 +163,7 @@ bool DeleteDirectory(const TString& rkDirPath, bool FailIfNotEmpty)
// Delete directory // Delete directory
std::error_code Error; std::error_code Error;
remove_all(*rkDirPath, Error); remove_all(ToPath(*rkDirPath), Error);
return (Error.value() == 0); return (Error.value() == 0);
} }
@ -200,12 +204,12 @@ bool ClearDirectory(const TString& rkDirPath)
u64 FileSize(const TString &rkFilePath) u64 FileSize(const TString &rkFilePath)
{ {
return (u64) (Exists(rkFilePath) ? file_size(*rkFilePath) : -1); return (u64) (Exists(rkFilePath) ? file_size(ToPath(*rkFilePath)) : -1);
} }
u64 LastModifiedTime(const TString& rkFilePath) u64 LastModifiedTime(const TString& rkFilePath)
{ {
return (u64) last_write_time(*rkFilePath).time_since_epoch().count(); return (u64) last_write_time(ToPath(*rkFilePath)).time_since_epoch().count();
} }
TString WorkingDirectory() TString WorkingDirectory()
@ -215,7 +219,7 @@ TString WorkingDirectory()
TString MakeAbsolute(TString Path) TString MakeAbsolute(TString Path)
{ {
if (!path(*Path).has_root_name()) if (!ToPath(*Path).has_root_name())
Path = WorkingDirectory() + "/" + Path; Path = WorkingDirectory() + "/" + Path;
TStringList Components = Path.Split("/\\"); TStringList Components = Path.Split("/\\");
@ -481,7 +485,7 @@ void GetDirectoryContents(TString DirPath, TStringList& rOut, bool Recursive /*=
if (Recursive) if (Recursive)
{ {
for (recursive_directory_iterator It(*DirPath); It != recursive_directory_iterator(); ++It) for (recursive_directory_iterator It(ToPath(*DirPath)); It != recursive_directory_iterator(); ++It)
{ {
AddFileLambda(It->path().string()); AddFileLambda(It->path().string());
} }
@ -489,7 +493,7 @@ void GetDirectoryContents(TString DirPath, TStringList& rOut, bool Recursive /*=
else else
{ {
for (directory_iterator It(*DirPath); It != directory_iterator(); ++It) for (directory_iterator It(ToPath(*DirPath)); It != directory_iterator(); ++It)
{ {
AddFileLambda(It->path().string()); AddFileLambda(It->path().string());
} }
@ -499,7 +503,7 @@ void GetDirectoryContents(TString DirPath, TStringList& rOut, bool Recursive /*=
TString FindFileExtension(const TString& rkDir, const TString& rkName) TString FindFileExtension(const TString& rkDir, const TString& rkName)
{ {
for (directory_iterator It(*rkDir); It != directory_iterator(); ++It) for (directory_iterator It(ToPath(*rkDir)); It != directory_iterator(); ++It)
{ {
TString Name = It->path().filename().string(); TString Name = It->path().filename().string();
if (Name.GetFileName(false) == rkName) return Name.GetFileExtension(); if (Name.GetFileName(false) == rkName) return Name.GetFileExtension();

View File

@ -20,7 +20,7 @@ public:
: IArchive() : IArchive()
, mOwnsStream(true) , mOwnsStream(true)
{ {
mArchiveFlags = AF_Binary | AF_Reader; mArchiveFlags = AF_Binary | AF_Reader | AF_NoSkipping;
mpStream = new CFileInStream(rkFilename, IOUtil::eBigEndian); mpStream = new CFileInStream(rkFilename, IOUtil::eBigEndian);
if (mpStream->IsValid()) if (mpStream->IsValid())
@ -35,7 +35,7 @@ public:
, mMagicValid(true) , mMagicValid(true)
, mOwnsStream(false) , mOwnsStream(false)
{ {
mArchiveFlags = AF_Binary | AF_Reader; mArchiveFlags = AF_Binary | AF_Reader | AF_NoSkipping;
ASSERT(pStream->IsValid()); ASSERT(pStream->IsValid());
mpStream = pStream; mpStream = pStream;
@ -47,7 +47,7 @@ public:
, mMagicValid(true) , mMagicValid(true)
, mOwnsStream(true) , mOwnsStream(true)
{ {
mArchiveFlags = AF_Binary | AF_Reader; mArchiveFlags = AF_Binary | AF_Reader | AF_NoSkipping;
mpStream = new CMemoryInStream(pData, DataSize, Endian); mpStream = new CMemoryInStream(pData, DataSize, Endian);
SetVersion(rkVersion); SetVersion(rkVersion);
} }

View File

@ -20,7 +20,7 @@ public:
, mMagic(Magic) , mMagic(Magic)
, mOwnsStream(true) , mOwnsStream(true)
{ {
mArchiveFlags = AF_Binary | AF_Writer; mArchiveFlags = AF_Binary | AF_Writer | AF_NoSkipping;
mpStream = new CFileOutStream(rkFilename, IOUtil::eBigEndian); mpStream = new CFileOutStream(rkFilename, IOUtil::eBigEndian);
if (mpStream->IsValid()) if (mpStream->IsValid())
@ -36,7 +36,7 @@ public:
, mOwnsStream(false) , mOwnsStream(false)
{ {
ASSERT(pStream->IsValid()); ASSERT(pStream->IsValid());
mArchiveFlags = AF_Binary | AF_Writer; mArchiveFlags = AF_Binary | AF_Writer | AF_NoSkipping;
mpStream = pStream; mpStream = pStream;
SetVersion(skCurrentArchiveVersion, FileVersion, Game); SetVersion(skCurrentArchiveVersion, FileVersion, Game);
} }
@ -46,7 +46,7 @@ public:
, mOwnsStream(false) , mOwnsStream(false)
{ {
ASSERT(pStream->IsValid()); ASSERT(pStream->IsValid());
mArchiveFlags = AF_Binary | AF_Writer; mArchiveFlags = AF_Binary | AF_Writer | AF_NoSkipping;
mpStream = pStream; mpStream = pStream;
SetVersion(rkVersion); SetVersion(rkVersion);
} }

View File

@ -17,12 +17,6 @@ CResTypeInfo::CResTypeInfo(EResType Type, const TString& rkTypeName, const TStri
smTypeMap[Type] = this; smTypeMap[Type] = this;
} }
CResTypeInfo::~CResTypeInfo()
{
// shouldn't happen - we want to just create these at launch and keep them around forever
ASSERT(false);
}
bool CResTypeInfo::IsInGame(EGame Game) const bool CResTypeInfo::IsInGame(EGame Game) const
{ {
for (u32 iGame = 0; iGame < mCookedExtensions.size(); iGame++) for (u32 iGame = 0; iGame < mCookedExtensions.size(); iGame++)

View File

@ -28,7 +28,7 @@ class CResTypeInfo
// Private Methods // Private Methods
CResTypeInfo(EResType Type, const TString& rkTypeName, const TString& rkRetroExtension); CResTypeInfo(EResType Type, const TString& rkTypeName, const TString& rkRetroExtension);
~CResTypeInfo(); ~CResTypeInfo() {}
// Public Methods // Public Methods
public: public:

View File

@ -55,6 +55,7 @@ void CGameTemplate::Load(const TString& kFilePath)
void CGameTemplate::Save() void CGameTemplate::Save()
{ {
Log::Write("Saving game template: " + mSourceFile);
CXMLWriter Writer(mSourceFile, "Game", 0, mGame); CXMLWriter Writer(mSourceFile, "Game", 0, mGame);
ASSERT(Writer.IsValid()); ASSERT(Writer.IsValid());
Serialize(Writer); Serialize(Writer);
@ -108,6 +109,7 @@ void CGameTemplate::SaveGameTemplates(bool ForceAll /*= false*/)
const TString kOutPath = kGameDir + Path.Path; const TString kOutPath = kGameDir + Path.Path;
FileUtil::MakeDirectory( kOutPath.GetFileDirectory() ); FileUtil::MakeDirectory( kOutPath.GetFileDirectory() );
Log::Write("Saving property template: " + kOutPath);
CXMLWriter Writer(kOutPath, "PropertyTemplate", 0, Game()); CXMLWriter Writer(kOutPath, "PropertyTemplate", 0, Game());
ASSERT(Writer.IsValid()); ASSERT(Writer.IsValid());

View File

@ -96,8 +96,9 @@ void CScriptTemplate::Serialize(IArchive& Arc)
void CScriptTemplate::Save(bool Force) void CScriptTemplate::Save(bool Force)
{ {
if (mDirty || Force) if (IsDirty() || Force)
{ {
Log::Write("Saving script template: " + mSourceFile);
CXMLWriter Writer(mSourceFile, "ScriptObject", 0, mpGame->Game()); CXMLWriter Writer(mSourceFile, "ScriptObject", 0, mpGame->Game());
ASSERT(Writer.IsValid()); ASSERT(Writer.IsValid());
Serialize(Writer); Serialize(Writer);

View File

@ -1,4 +1,5 @@
#include "NGameList.h" #include "NGameList.h"
#include <Common/Log.h>
namespace NGameList namespace NGameList
{ {
@ -85,6 +86,7 @@ inline void SerializeGameList(IArchive& Arc)
void LoadGameList() void LoadGameList()
{ {
ASSERT(!gLoadedGameList); ASSERT(!gLoadedGameList);
Log::Write("Loading game list");
CXMLReader Reader(gkGameListPath); CXMLReader Reader(gkGameListPath);
ASSERT(Reader.IsValid()); ASSERT(Reader.IsValid());
@ -97,6 +99,7 @@ void LoadGameList()
void SaveGameList() void SaveGameList()
{ {
ASSERT(gLoadedGameList); ASSERT(gLoadedGameList);
Log::Write("Saving game list");
CXMLWriter Writer(gkGameListPath, "GameList"); CXMLWriter Writer(gkGameListPath, "GameList");
ASSERT(Writer.IsValid()); ASSERT(Writer.IsValid());

View File

@ -132,10 +132,16 @@ SNameKey CreateKey(IProperty* pProperty)
return Key; return Key;
} }
SNameKey CreateKey(u32 ID, const char* pkTypeName)
{
return SNameKey( CCRC32::StaticHashString(pkTypeName), ID );
}
/** Loads property names into memory */ /** Loads property names into memory */
void LoadMap() void LoadMap()
{ {
ASSERT( !gMapIsLoaded ); ASSERT( !gMapIsLoaded );
Log::Write("Loading property map");
if ( gkUseLegacyMapForNameLookups ) if ( gkUseLegacyMapForNameLookups )
{ {
@ -165,6 +171,7 @@ inline void ConditionalLoadMap()
void SaveMap(bool Force /*= false*/) void SaveMap(bool Force /*= false*/)
{ {
ASSERT( gMapIsLoaded ); ASSERT( gMapIsLoaded );
Log::Write("Saving property map");
if( gMapIsDirty || Force ) if( gMapIsDirty || Force )
{ {
@ -210,21 +217,67 @@ const char* GetPropertyName(u32 ID, const char* pkTypeName)
// Does not support legacy map // Does not support legacy map
ConditionalLoadMap(); ConditionalLoadMap();
SNameKey Key( CCRC32::StaticHashString(pkTypeName), ID ); SNameKey Key = CreateKey(ID, pkTypeName);
auto MapFind = gNameMap.find(Key); auto MapFind = gNameMap.find(Key);
return MapFind == gNameMap.end() ? "Unknown" : *MapFind->second.Name; return MapFind == gNameMap.end() ? "Unknown" : *MapFind->second.Name;
} }
/** Returns whether the specified name is in the map. */
bool IsValidPropertyName(u32 ID, const char* pkTypeName)
{
SNameKey Key = CreateKey(ID, pkTypeName);
auto MapFind = gNameMap.find(Key);
return MapFind != gNameMap.end();
}
/** Retrieves a list of all properties that match the requested property ID. */
void RetrievePropertiesWithID(u32 ID, const char* pkTypeName, std::list<IProperty*>& OutList)
{
SNameKey Key = CreateKey(ID, pkTypeName);
auto MapFind = gNameMap.find(Key);
if (MapFind != gNameMap.end())
{
SNameValue& Value = MapFind->second;
OutList = Value.PropertyList;
}
}
/** Retrieves a list of all XML templates that contain a given property ID. */
void RetrieveXMLsWithProperty(u32 ID, const char* pkTypeName, std::set<TString>& OutSet)
{
SNameKey Key = CreateKey(ID, pkTypeName);
auto MapFind = gNameMap.find(Key);
if (MapFind != gNameMap.end())
{
SNameValue& NameValue = MapFind->second;
for (auto ListIter = NameValue.PropertyList.begin(); ListIter != NameValue.PropertyList.end(); ListIter++)
{
IProperty* pProperty = *ListIter;
OutSet.insert( pProperty->GetTemplateFileName() );
}
}
}
/** Updates the name of a given property in the map */ /** Updates the name of a given property in the map */
void SetPropertyName(IProperty* pProperty, const char* pkNewName) void SetPropertyName(u32 ID, const char* pkTypeName, const char* pkNewName)
{ {
if( gkUseLegacyMapForUpdates ) if( gkUseLegacyMapForUpdates )
{ {
gLegacyNameMap[pProperty->ID()] = pkNewName; auto Iter = gLegacyNameMap.find(ID);
if (Iter == gLegacyNameMap.end() || Iter->second != pkNewName)
{
Iter->second = pkNewName;
gMapIsDirty = true;
}
} }
else else
{ {
SNameKey Key = CreateKey(pProperty); SNameKey Key = CreateKey(ID, pkTypeName);
auto MapFind = gNameMap.find(Key); auto MapFind = gNameMap.find(Key);
if (MapFind != gNameMap.end()) if (MapFind != gNameMap.end())
@ -235,6 +288,7 @@ void SetPropertyName(IProperty* pProperty, const char* pkNewName)
{ {
TString OldName = Value.Name; TString OldName = Value.Name;
Value.Name = pkNewName; Value.Name = pkNewName;
gMapIsDirty = true;
// Update all properties with this ID with the new name // Update all properties with this ID with the new name
for (auto Iter = Value.PropertyList.begin(); Iter != Value.PropertyList.end(); Iter++) for (auto Iter = Value.PropertyList.begin(); Iter != Value.PropertyList.end(); Iter++)
@ -250,8 +304,6 @@ void SetPropertyName(IProperty* pProperty, const char* pkNewName)
} }
} }
} }
gMapIsDirty = true;
} }
/** Registers a property in the name map. Should be called on all properties that use the map */ /** Registers a property in the name map. Should be called on all properties that use the map */

View File

@ -22,8 +22,17 @@ const char* GetPropertyName(IProperty* pProperty);
*/ */
const char* GetPropertyName(u32 ID, const char* pkTypeName); const char* GetPropertyName(u32 ID, const char* pkTypeName);
/** Returns whether the specified name is in the map. */
bool IsValidPropertyName(u32 ID, const char* pkTypeName);
/** Retrieves a list of all properties that match the requested property ID. */
void RetrievePropertiesWithID(u32 ID, const char* pkTypeName, std::list<IProperty*>& OutList);
/** Retrieves a list of all XML templates that contain a given property ID. */
void RetrieveXMLsWithProperty(u32 ID, const char* pkTypeName, std::set<TString>& OutSet);
/** Updates the name of a given property in the map */ /** Updates the name of a given property in the map */
void SetPropertyName(IProperty* pProperty, const char* pkNewName); void SetPropertyName(u32 ID, const char* pkTypeName, const char* pkNewName);
/** Registers a property in the name map. Should be called on all properties that use the map */ /** Registers a property in the name map. Should be called on all properties that use the map */
void RegisterProperty(IProperty* pProperty); void RegisterProperty(IProperty* pProperty);

View File

@ -2,6 +2,7 @@
#include "IUIRelay.h" #include "IUIRelay.h"
#include "Core/Resource/Factory/CTemplateLoader.h" #include "Core/Resource/Factory/CTemplateLoader.h"
#include "Core/Resource/Script/CGameTemplate.h" #include "Core/Resource/Script/CGameTemplate.h"
#include "Core/Resource/Script/NPropertyMap.h"
#include <Common/Hash/CCRC32.h> #include <Common/Hash/CCRC32.h>
/** Default constructor */ /** Default constructor */
@ -146,17 +147,16 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
for (int TypeIdx = 0; TypeIdx < rkParams.TypeNames.size(); TypeIdx++) for (int TypeIdx = 0; TypeIdx < rkParams.TypeNames.size(); TypeIdx++)
{ {
CCRC32 FullHash = BaseHash; CCRC32 FullHash = BaseHash;
FullHash.Hash( *rkParams.TypeNames[TypeIdx] ); const char* pkTypeName = *rkParams.TypeNames[TypeIdx];
FullHash.Hash( pkTypeName );
u32 PropertyID = FullHash.Digest(); u32 PropertyID = FullHash.Digest();
//@FIXME // Check if this hash is a property ID
#if 0 if (NPropertyMap::IsValidPropertyName(PropertyID, pkTypeName))
// Check if this hash is a property ID - it's valid if there are any XMLs using this ID
SGeneratedPropertyName PropertyName;
CGameTemplate::XMLsUsingID(PropertyID, PropertyName.XmlList);
if (PropertyName.XmlList.size() > 0)
{ {
SGeneratedPropertyName PropertyName;
NPropertyMap::RetrieveXMLsWithProperty(PropertyID, pkTypeName, PropertyName.XmlList);
// Generate a string with the complete name. (We wait to do this until now to avoid needless string allocation) // Generate a string with the complete name. (We wait to do this until now to avoid needless string allocation)
PropertyName.Name = rkParams.Prefix; PropertyName.Name = rkParams.Prefix;
@ -195,16 +195,15 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
{ {
TString DelimitedXmlList; TString DelimitedXmlList;
for (int XmlIdx = 0; XmlIdx < PropertyName.XmlList.size(); XmlIdx++) for (auto Iter = PropertyName.XmlList.begin(); Iter != PropertyName.XmlList.end(); Iter++)
{ {
DelimitedXmlList += PropertyName.XmlList[XmlIdx] + "\n"; DelimitedXmlList += *Iter + "\n";
} }
TString LogMsg = TString::Format("%s [%s] : 0x%08X\n", *PropertyName.Name, *PropertyName.Type, PropertyName.ID) + DelimitedXmlList; TString LogMsg = TString::Format("%s [%s] : 0x%08X\n", *PropertyName.Name, *PropertyName.Type, PropertyName.ID) + DelimitedXmlList;
Log::Write(LogMsg); Log::Write(LogMsg);
} }
} }
#endif
} }
// Every 250 tests, check with the progress notifier. Update the progress // Every 250 tests, check with the progress notifier. Update the progress

View File

@ -32,7 +32,7 @@ struct SGeneratedPropertyName
TString Name; TString Name;
TString Type; TString Type;
u32 ID; u32 ID;
std::vector<TString> XmlList; std::set<TString> XmlList;
}; };
/** Generates property names and validates them against know property IDs. */ /** Generates property names and validates them against know property IDs. */

View File

@ -275,15 +275,35 @@ IProperty* IProperty::ChildByIDString(const TIDString& rkIdString)
TString IProperty::GetTemplateFileName() TString IProperty::GetTemplateFileName()
{ {
if (mpScriptTemplate) // We want to return the path to the XML file that this property originally belongs to.
// So, for example, if this is a property of a script template, we want to return that script template.
// However, if this property was copied from a property archetype... If we are a direct instance of an
// archetype property (for instance a DamageInfo struct instance), then we want to return the template
// that contains the instance. However, if we are a sub-property of an archetype, then we want to return
// the path to that archetype instead. Hopefully that makes sense!
IProperty* pTemplateRoot = this;
// If our archetype has a parent, then our archetype is a sub-property of the main archetype, and we
// need to go deeper to find the original source XML file.
//
// If our archetype doesn't have a parent, then we are an instance of the main archetype, and we stop here.
while (pTemplateRoot->Archetype() && pTemplateRoot->Archetype()->Parent())
{ {
return mpScriptTemplate->SourceFile(); pTemplateRoot = pTemplateRoot->Archetype();
}
pTemplateRoot = pTemplateRoot->RootParent();
// Now that we have the base property of our template, we can return the file path.
static const u32 kChopAmount = strlen("../templates/");
if (pTemplateRoot->ScriptTemplate())
{
return pTemplateRoot->ScriptTemplate()->SourceFile().ChopFront(kChopAmount);
} }
else else
{ {
CGameTemplate* pGameTemplate = NGameList::GetGameTemplate(Game()); CGameTemplate* pGameTemplate = NGameList::GetGameTemplate(Game());
IProperty* pTemplateRoot = (IsArchetype() ? RootParent() : mpArchetype); return pGameTemplate->GetPropertyArchetypeFilePath( pTemplateRoot->Name() ).ChopFront(kChopAmount);
return pGameTemplate->GetPropertyArchetypeFilePath( pTemplateRoot->Name() );
} }
} }
@ -304,27 +324,36 @@ bool IProperty::ShouldCook(void* pPropertyData) const
void IProperty::SetName(const TString& rkNewName) void IProperty::SetName(const TString& rkNewName)
{ {
mName = rkNewName; if (mName != rkNewName)
mFlags.ClearFlag(EPropertyFlag::HasCachedNameCheck);
// in Echoes and on, since property names are referenced by ID, renaming a property
// doesn't directly affect the serialized data, so it doesn't need to be flagged dirty
if (mGame <= EGame::Prime)
{ {
MarkDirty(); mName = rkNewName;
mFlags.ClearFlag(EPropertyFlag::HasCachedNameCheck);
// in Echoes and on, since property names are referenced by ID, renaming a property
// doesn't directly affect the serialized data, so it doesn't need to be flagged dirty
if (mGame <= EGame::Prime)
{
MarkDirty();
}
} }
} }
void IProperty::SetDescription(const TString& rkNewDescription) void IProperty::SetDescription(const TString& rkNewDescription)
{ {
mDescription = rkNewDescription; if (mDescription != rkNewDescription)
MarkDirty(); {
mDescription = rkNewDescription;
MarkDirty();
}
} }
void IProperty::SetSuffix(const TString& rkNewSuffix) void IProperty::SetSuffix(const TString& rkNewSuffix)
{ {
mSuffix = rkNewSuffix; if (mSuffix != rkNewSuffix)
MarkDirty(); {
mSuffix = rkNewSuffix;
MarkDirty();
}
} }
void IProperty::MarkDirty() void IProperty::MarkDirty()

View File

@ -211,6 +211,7 @@ public:
inline IProperty* Parent() const; inline IProperty* Parent() const;
inline IProperty* RootParent(); inline IProperty* RootParent();
inline IProperty* Archetype() const; inline IProperty* Archetype() const;
inline IProperty* RootArchetype();
inline CScriptTemplate* ScriptTemplate() const; inline CScriptTemplate* ScriptTemplate() const;
inline TString Name() const; inline TString Name() const;
inline TString Description() const; inline TString Description() const;
@ -286,6 +287,20 @@ inline IProperty* IProperty::Archetype() const
return mpArchetype; return mpArchetype;
} }
inline IProperty* IProperty::RootArchetype()
{
IProperty* pArchetype = Archetype();
IProperty* pOut = this;
while (pArchetype)
{
pOut = pArchetype;
pArchetype = pArchetype->Archetype();
}
return pOut;
}
inline CScriptTemplate* IProperty::ScriptTemplate() const inline CScriptTemplate* IProperty::ScriptTemplate() const
{ {
return mpScriptTemplate; return mpScriptTemplate;

View File

@ -225,13 +225,11 @@ void CGeneratePropertyNamesDialog::ApplyChanges()
{ {
QTreeWidgetItem* pItem = mCheckedItems[ItemIdx]; QTreeWidgetItem* pItem = mCheckedItems[ItemIdx];
u32 ID = TO_TSTRING( pItem->text(2) ).ToInt32(); u32 ID = TO_TSTRING( pItem->text(2) ).ToInt32();
TString Type = TO_TSTRING( pItem->text(1) );
TString NewName = TO_TSTRING( pItem->text(0) );
//FIXME NPropertyMap::SetPropertyName( ID, *Type, *NewName );
#if 0 pItem->setText( 3, TO_QSTRING(NewName) );
QString NewName = pItem->text(0);
NPropertyMap::SetPropertyName(::RenameProperty( ID, TO_TSTRING(NewName) );
pItem->setText(3, NewName);
#endif
} }
NPropertyMap::SaveMap(); NPropertyMap::SaveMap();
@ -270,9 +268,9 @@ void CGeneratePropertyNamesDialog::CheckForNewResults()
pItem->setCheckState(0, Qt::Unchecked); pItem->setCheckState(0, Qt::Unchecked);
// Add children items // Add children items
for (int XmlIdx = 0; XmlIdx < rkName.XmlList.size(); XmlIdx++) for (auto Iter = rkName.XmlList.begin(); Iter != rkName.XmlList.end(); Iter++)
{ {
QString XmlName = TO_QSTRING( rkName.XmlList[XmlIdx] ); QString XmlName = TO_QSTRING( *Iter );
ColumnText.clear(); ColumnText.clear();
ColumnText << XmlName; ColumnText << XmlName;

View File

@ -36,14 +36,11 @@ CTemplateEditDialog::CTemplateEditDialog(IProperty *pProperty, QWidget *pParent)
{ {
NGameList::LoadAllGameTemplates(); NGameList::LoadAllGameTemplates();
//@FIXME std::set<TString> Templates;
#if 0 NPropertyMap::RetrieveXMLsWithProperty( pProperty->ID(), pProperty->HashableTypeName(), Templates );
std::vector<TString> TemplateList;
CGameTemplate::XMLsUsingID(pProperty->ID(), TemplateList);
for (u32 iTemp = 0; iTemp < TemplateList.size(); iTemp++) for (auto Iter = Templates.begin(); Iter != Templates.end(); Iter++)
mpUI->TemplatesListWidget->addItem(TO_QSTRING(TemplateList[iTemp])); mpUI->TemplatesListWidget->addItem(TO_QSTRING(*Iter));
#endif
mpUI->ValidityLabel->SetValidityText("Hash match! Property name is likely correct.", "Hash mismatch! Property name is likely wrong."); 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) ) ); connect(mpUI->NameLineEdit, SIGNAL( SoftValidityChanged(bool) ), mpUI->ValidityLabel, SLOT( SetValid(bool) ) );
@ -94,7 +91,7 @@ void CTemplateEditDialog::ApplyChanges()
// Rename properties // Rename properties
if (RenameAll && (mGame >= EGame::EchoesDemo || mpProperty->Archetype() != nullptr)) if (RenameAll && (mGame >= EGame::EchoesDemo || mpProperty->Archetype() != nullptr))
{ {
NPropertyMap::SetPropertyName(mpProperty, *NewName); NPropertyMap::SetPropertyName(mpProperty->ID(), mpProperty->HashableTypeName(), *NewName);
} }
} }
@ -102,10 +99,8 @@ void CTemplateEditDialog::ApplyChanges()
UpdateDescription(NewDescription); UpdateDescription(NewDescription);
// Resave templates // Resave templates
NGameList::SaveTemplates();
NPropertyMap::SaveMap(); NPropertyMap::SaveMap();
CGameTemplate* pGameTemplate = NGameList::GetGameTemplate( mpProperty->Game() );
pGameTemplate->SaveGameTemplates();
close(); close();
} }
@ -115,23 +110,19 @@ void CTemplateEditDialog::UpdateDescription(const TString& rkNewDesc)
mpProperty->SetDescription(rkNewDesc); mpProperty->SetDescription(rkNewDesc);
// Update all copies of this property in memory with the new description // Update all copies of this property in memory with the new description
//@FIXME
#if 0
TString SourceFile = mpProperty->GetTemplateFileName(); TString SourceFile = mpProperty->GetTemplateFileName();
if (!SourceFile.IsEmpty()) if (!SourceFile.IsEmpty())
{ {
const std::vector<IProperty*>* pkTemplates = CGameTemplate::TemplatesWithMatchingID(mpProperty); std::list<IProperty*> Templates;
NPropertyMap::RetrievePropertiesWithID(mpProperty->ID(), mpProperty->HashableTypeName(), Templates);
if (pkTemplates) for (auto Iter = Templates.begin(); Iter != Templates.end(); Iter++)
{ {
for (u32 TemplateIdx = 0; TemplateIdx < pkTemplates->size(); TemplateIdx++) IProperty* pProperty = *Iter;
{
IProperty* pProp = pkTemplates->at(TemplateIdx);
if (pProp->GetTemplateFileName() == SourceFile && pProp->Description() == mOriginalDescription) if (pProperty->GetTemplateFileName() == SourceFile && pProperty->Description() == mOriginalDescription)
pProp->SetDescription(rkNewDesc); pProperty->SetDescription(rkNewDesc);
}
} }
} }
@ -140,73 +131,60 @@ void CTemplateEditDialog::UpdateDescription(const TString& rkNewDesc)
{ {
pProperty->SetDescription(rkNewDesc); pProperty->SetDescription(rkNewDesc);
} }
#endif
} }
void CTemplateEditDialog::FindEquivalentProperties(IProperty *pTemp) void CTemplateEditDialog::FindEquivalentProperties(IProperty* pProperty)
{ {
//FIXME // This function creates a list of properties in other games that are equivalent to this one.
/* // In this case "equivalent" means same template file and same ID string.
// Since MP1 doesn't have property IDs, we don't apply this to MP1.
if (mGame <= EGame::Prime) return; if (mGame <= EGame::Prime) return;
// Find the equivalent version of this property in other games. // Find the lowest-level archetype and retrieve the ID string relative to that archetype's XML file.
CScriptTemplate *pScript = pTemp->ScriptTemplate(); while (pProperty->Archetype())
TString Source = pTemp->FindStructSource();
// Determine struct-relative ID string
TIDString IDString;
if (Source.IsEmpty())
IDString = pTemp->IDString(true);
else
{ {
IDString = pTemp->IDString(false); pProperty = pProperty->Archetype();
CStructTemplate *pParent = pTemp->Parent();
while (pParent)
{
if (!pParent->SourceFile().IsEmpty()) break;
IDString.Prepend(pParent->IDString(false) + ":");
pParent = pParent->Parent();
}
} }
TString Name = pProperty->Name();
TIDString IDString = pProperty->IDString(true);
CScriptTemplate* pScript = pProperty->ScriptTemplate();
QList<CGameTemplate*> GameList = QList<CGameTemplate*>::fromStdList(CGameTemplate::GameList()); // Now iterate over all games, check for an equivalent property in an equivalent XML file.
for (int GameIdx = 0; GameIdx < (int) EGame::Max; GameIdx++)
if (Source.IsEmpty())
{ {
u32 ObjectID = pScript->ObjectID(); EGame Game = (EGame) GameIdx;
if (Game <= EGame::Prime || Game == mGame) continue;
foreach (CGameTemplate *pGame, GameList) CGameTemplate* pGame = NGameList::GetGameTemplate(Game);
// Check for equivalent properties in a script template
CStructProperty* pStruct = nullptr;
if (pScript)
{ {
if (pGame == pTemp->GameTemplate() || pGame->Game() <= EGame::Prime) continue; u32 ObjectID = pScript->ObjectID();
CScriptTemplate *pNewScript = pGame->TemplateByID(ObjectID); CScriptTemplate* pEquivalentScript = pGame->TemplateByID(ObjectID);
if (pNewScript) if (pEquivalentScript)
{ {
IPropertyTemplate *pNewTemp = pNewScript->BaseStruct()->PropertyByIDString(IDString); pStruct = pEquivalentScript->Properties();
}
}
// Check for equivalent properties in a property template
else
{
pStruct = TPropCast<CStructProperty>( pGame->FindPropertyArchetype(Name) );
}
if (pNewTemp) // If we have a struct, check if thestruct contains an equivalent property.
mEquivalentProperties << pNewTemp; if (pStruct)
{
IProperty* pEquivalentProperty = pStruct->ChildByIDString( IDString );
if (pEquivalentProperty)
{
mEquivalentProperties << pEquivalentProperty;
} }
} }
} }
else
{
foreach (CGameTemplate *pGame, GameList)
{
if (pGame == pTemp->GameTemplate() || pGame->Game() <= EGame::Prime) continue;
CStructTemplate *pStruct = pGame->StructAtSource(Source);
if (pStruct)
{
IPropertyTemplate *pNewTemp = pStruct->PropertyByIDString(IDString);
if (pNewTemp)
mEquivalentProperties << pNewTemp;
}
}
}*/
} }

View File

@ -35,7 +35,7 @@ public slots:
protected: protected:
void UpdateDescription(const TString& rkNewDesc); void UpdateDescription(const TString& rkNewDesc);
void FindEquivalentProperties(IProperty *pTemp); void FindEquivalentProperties(IProperty *pProperty);
}; };
#endif // CTEMPLATEEDITDIALOG_H #endif // CTEMPLATEEDITDIALOG_H

View File

@ -23,58 +23,78 @@ void QtLogRedirect(QtMsgType Type, const QMessageLogContext& /*rkContext*/, cons
} }
} }
int main(int argc, char *argv[]) class CMain
{ {
// Create application public:
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); /** Main function */
CEditorApplication App(argc, argv); int Main(int argc, char *argv[])
App.setApplicationName( APP_NAME );
App.setApplicationVersion( APP_VERSION );
App.setOrganizationName("Aruki");
App.setWindowIcon(QIcon(":/icons/AppIcon.ico"));
// Create UI relay
CUIRelay UIRelay(&App);
gpUIRelay = &UIRelay;
// Set up dark theme
qApp->setStyle(QStyleFactory::create("Fusion"));
QPalette DarkPalette;
DarkPalette.setColor(QPalette::Window, QColor(53,53,53));
DarkPalette.setColor(QPalette::WindowText, Qt::white);
DarkPalette.setColor(QPalette::Base, QColor(25,25,25));
DarkPalette.setColor(QPalette::AlternateBase, QColor(35,35,35));
DarkPalette.setColor(QPalette::ToolTipBase, Qt::white);
DarkPalette.setColor(QPalette::ToolTipText, Qt::white);
DarkPalette.setColor(QPalette::Text, Qt::white);
DarkPalette.setColor(QPalette::Button, QColor(53,53,53));
DarkPalette.setColor(QPalette::ButtonText, Qt::white);
DarkPalette.setColor(QPalette::BrightText, Qt::red);
DarkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
DarkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
DarkPalette.setColor(QPalette::HighlightedText, Qt::white);
qApp->setPalette(DarkPalette);
// Init log
bool Initialized = Log::InitLog("primeworldeditor.log");
if (!Initialized) QMessageBox::warning(0, "Error", "Couldn't open log file. Logging will not work for this session.");
qInstallMessageHandler(QtLogRedirect);
// Create editor resource store
gpEditorStore = new CResourceStore("../resources/");
if (!gpEditorStore->AreAllEntriesValid())
{ {
Log::Write("Editor store has invalid entries. Rebuilding database..."); // Create application
gpEditorStore->RebuildFromDirectory(); QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
gpEditorStore->ConditionalSaveStore(); CEditorApplication App(argc, argv);
App.setApplicationName( APP_NAME );
App.setApplicationVersion( APP_VERSION );
App.setOrganizationName("Aruki");
App.setWindowIcon(QIcon(":/icons/AppIcon.ico"));
// Create UI relay
CUIRelay UIRelay(&App);
gpUIRelay = &UIRelay;
// Set up dark theme
qApp->setStyle(QStyleFactory::create("Fusion"));
QPalette DarkPalette;
DarkPalette.setColor(QPalette::Window, QColor(53,53,53));
DarkPalette.setColor(QPalette::WindowText, Qt::white);
DarkPalette.setColor(QPalette::Base, QColor(25,25,25));
DarkPalette.setColor(QPalette::AlternateBase, QColor(35,35,35));
DarkPalette.setColor(QPalette::ToolTipBase, Qt::white);
DarkPalette.setColor(QPalette::ToolTipText, Qt::white);
DarkPalette.setColor(QPalette::Text, Qt::white);
DarkPalette.setColor(QPalette::Button, QColor(53,53,53));
DarkPalette.setColor(QPalette::ButtonText, Qt::white);
DarkPalette.setColor(QPalette::BrightText, Qt::red);
DarkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
DarkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
DarkPalette.setColor(QPalette::HighlightedText, Qt::white);
qApp->setPalette(DarkPalette);
// Init log
bool Initialized = Log::InitLog("primeworldeditor.log");
if (!Initialized) QMessageBox::warning(0, "Error", "Couldn't open log file. Logging will not work for this session.");
qInstallMessageHandler(QtLogRedirect);
// Create editor resource store
gpEditorStore = new CResourceStore("../resources/");
if (!gpEditorStore->AreAllEntriesValid())
{
Log::Write("Editor store has invalid entries. Rebuilding database...");
gpEditorStore->RebuildFromDirectory();
gpEditorStore->ConditionalSaveStore();
}
for (int i = 0; i < (int) EGame::Max; i++)
{
CGameTemplate* pGame = NGameList::GetGameTemplate( (EGame) i );
if (pGame) pGame->Save();
}
return 0;
// Execute application
App.InitEditor();
return App.exec();
} }
// Execute application /** Clean up any resources at the end of application execution */
App.InitEditor(); ~CMain()
int ReturnValue = App.exec(); {
NGameList::Shutdown();
}
};
// Clean up int main(int argc, char *argv[])
NGameList::Shutdown(); {
return ReturnValue; CMain Main;
return Main.Main(argc, argv);
} }

View File

@ -659,6 +659,10 @@
<Key>ActorMultiKeyframeStruct</Key> <Key>ActorMultiKeyframeStruct</Key>
<Value Path="Structs/ActorMultiKeyframeStruct.xml"/> <Value Path="Structs/ActorMultiKeyframeStruct.xml"/>
</Element> </Element>
<Element>
<Key>ActivationTime</Key>
<Value Path="Structs/ActivationTime.xml"/>
</Element>
<Element> <Element>
<Key>ActorParameters</Key> <Key>ActorParameters</Key>
<Value Path="Structs/ActorParameters.xml"/> <Value Path="Structs/ActorParameters.xml"/>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<PropertyTemplate ArchiveVer="4" Game="DKCReturns">
<PropertyArchetype Type="Struct">
<Name>ActivationTime</Name>
<Atomic>true</Atomic>
<SubProperties>
<Element Type="Float" ID="0x0">
<Name>Time</Name>
<DefaultValue>0.0</DefaultValue>
</Element>
<Element Type="Int" ID="0x1">
<Name>Unknown 1</Name>
<DefaultValue>0</DefaultValue>
</Element>
<Element Type="Int" ID="0x2">
<Name>Unknown 2</Name>
<DefaultValue>0</DefaultValue>
</Element>
<Element Type="Int" ID="0x3">
<Name>Unknown 3</Name>
<DefaultValue>0</DefaultValue>
</Element>
</SubProperties>
</PropertyArchetype>
</PropertyTemplate>

View File

@ -10,10 +10,7 @@
</Element> </Element>
<Element Type="Array" ID="0x1"> <Element Type="Array" ID="0x1">
<Name>Activation Times</Name> <Name>Activation Times</Name>
<ItemArchetype Type="Float" ID="0x0"> <ItemArchetype Type="Struct" Archetype="ActivationTime"/>
<Name></Name>
<DefaultValue>0.0</DefaultValue>
</ItemArchetype>
</Element> </Element>
</SubProperties> </SubProperties>
</PropertyArchetype> </PropertyArchetype>

View File

@ -839,6 +839,10 @@
<Key>Abilities</Key> <Key>Abilities</Key>
<Value Path="Structs/Abilities.xml"/> <Value Path="Structs/Abilities.xml"/>
</Element> </Element>
<Element>
<Key>ActivationTime</Key>
<Value Path="Structs/ActivationTime.xml"/>
</Element>
<Element> <Element>
<Key>ActorParameters</Key> <Key>ActorParameters</Key>
<Value Path="Structs/ActorParameters.xml"/> <Value Path="Structs/ActorParameters.xml"/>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<PropertyTemplate ArchiveVer="4" Game="Corruption">
<PropertyArchetype Type="Struct">
<Name>ActivationTime</Name>
<Atomic>true</Atomic>
<SubProperties>
<Element Type="Float" ID="0x0">
<Name>Time</Name>
<DefaultValue>0.0</DefaultValue>
</Element>
<Element Type="Int" ID="0x1">
<Name>Unknown 1</Name>
<DefaultValue>0</DefaultValue>
</Element>
<Element Type="Int" ID="0x2">
<Name>Unknown 2</Name>
<DefaultValue>0</DefaultValue>
</Element>
<Element Type="Int" ID="0x3">
<Name>Unknown 3</Name>
<DefaultValue>0</DefaultValue>
</Element>
</SubProperties>
</PropertyArchetype>
</PropertyTemplate>

View File

@ -10,10 +10,7 @@
</Element> </Element>
<Element Type="Array" ID="0x1"> <Element Type="Array" ID="0x1">
<Name>Activation Times</Name> <Name>Activation Times</Name>
<ItemArchetype Type="Float" ID="0x0"> <ItemArchetype Type="Struct" Archetype="ActivationTime"/>
<Name></Name>
<DefaultValue>0.0</DefaultValue>
</ItemArchetype>
</Element> </Element>
</SubProperties> </SubProperties>
</PropertyArchetype> </PropertyArchetype>

View File

@ -623,6 +623,10 @@
<Key>Abilities</Key> <Key>Abilities</Key>
<Value Path="Structs/Abilities.xml"/> <Value Path="Structs/Abilities.xml"/>
</Element> </Element>
<Element>
<Key>ActivationTime</Key>
<Value Path="Structs/ActivationTime.xml"/>
</Element>
<Element> <Element>
<Key>ActorParameters</Key> <Key>ActorParameters</Key>
<Value Path="Structs/ActorParameters.xml"/> <Value Path="Structs/ActorParameters.xml"/>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<PropertyTemplate ArchiveVer="4" Game="CorruptionProto">
<PropertyArchetype Type="Struct">
<Name>ActivationTime</Name>
<Atomic>true</Atomic>
<SubProperties>
<Element Type="Float" ID="0x0">
<Name>Time</Name>
<DefaultValue>0.0</DefaultValue>
</Element>
<Element Type="Int" ID="0x1">
<Name>Unknown 1</Name>
<DefaultValue>0</DefaultValue>
</Element>
<Element Type="Int" ID="0x2">
<Name>Unknown 2</Name>
<DefaultValue>0</DefaultValue>
</Element>
<Element Type="Int" ID="0x3">
<Name>Unknown 3</Name>
<DefaultValue>0</DefaultValue>
</Element>
</SubProperties>
</PropertyArchetype>
</PropertyTemplate>

View File

@ -10,10 +10,7 @@
</Element> </Element>
<Element Type="Array" ID="0x1"> <Element Type="Array" ID="0x1">
<Name>Activation Times</Name> <Name>Activation Times</Name>
<ItemArchetype Type="Float" ID="0x0"> <ItemArchetype Type="Struct" Archetype="ActivationTime"/>
<Name></Name>
<DefaultValue>0.0</DefaultValue>
</ItemArchetype>
</Element> </Element>
</SubProperties> </SubProperties>
</PropertyArchetype> </PropertyArchetype>