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

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

View File

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

View File

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

View File

@@ -132,10 +132,16 @@ SNameKey CreateKey(IProperty* pProperty)
return Key;
}
SNameKey CreateKey(u32 ID, const char* pkTypeName)
{
return SNameKey( CCRC32::StaticHashString(pkTypeName), ID );
}
/** Loads property names into memory */
void LoadMap()
{
ASSERT( !gMapIsLoaded );
Log::Write("Loading property map");
if ( gkUseLegacyMapForNameLookups )
{
@@ -165,6 +171,7 @@ inline void ConditionalLoadMap()
void SaveMap(bool Force /*= false*/)
{
ASSERT( gMapIsLoaded );
Log::Write("Saving property map");
if( gMapIsDirty || Force )
{
@@ -210,21 +217,67 @@ const char* GetPropertyName(u32 ID, const char* pkTypeName)
// Does not support legacy map
ConditionalLoadMap();
SNameKey Key( CCRC32::StaticHashString(pkTypeName), ID );
SNameKey Key = CreateKey(ID, pkTypeName);
auto MapFind = gNameMap.find(Key);
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 */
void SetPropertyName(IProperty* pProperty, const char* pkNewName)
void SetPropertyName(u32 ID, const char* pkTypeName, const char* pkNewName)
{
if( gkUseLegacyMapForUpdates )
{
gLegacyNameMap[pProperty->ID()] = pkNewName;
auto Iter = gLegacyNameMap.find(ID);
if (Iter == gLegacyNameMap.end() || Iter->second != pkNewName)
{
Iter->second = pkNewName;
gMapIsDirty = true;
}
}
else
{
SNameKey Key = CreateKey(pProperty);
SNameKey Key = CreateKey(ID, pkTypeName);
auto MapFind = gNameMap.find(Key);
if (MapFind != gNameMap.end())
@@ -235,6 +288,7 @@ void SetPropertyName(IProperty* pProperty, const char* pkNewName)
{
TString OldName = Value.Name;
Value.Name = pkNewName;
gMapIsDirty = true;
// Update all properties with this ID with the new name
for (auto Iter = Value.PropertyList.begin(); Iter != Value.PropertyList.end(); Iter++)
@@ -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 */

View File

@@ -22,8 +22,17 @@ const char* GetPropertyName(IProperty* pProperty);
*/
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 */
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 */
void RegisterProperty(IProperty* pProperty);

View File

@@ -2,6 +2,7 @@
#include "IUIRelay.h"
#include "Core/Resource/Factory/CTemplateLoader.h"
#include "Core/Resource/Script/CGameTemplate.h"
#include "Core/Resource/Script/NPropertyMap.h"
#include <Common/Hash/CCRC32.h>
/** Default constructor */
@@ -146,17 +147,16 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
for (int TypeIdx = 0; TypeIdx < rkParams.TypeNames.size(); TypeIdx++)
{
CCRC32 FullHash = BaseHash;
FullHash.Hash( *rkParams.TypeNames[TypeIdx] );
const char* pkTypeName = *rkParams.TypeNames[TypeIdx];
FullHash.Hash( pkTypeName );
u32 PropertyID = FullHash.Digest();
//@FIXME
#if 0
// 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)
// Check if this hash is a property ID
if (NPropertyMap::IsValidPropertyName(PropertyID, pkTypeName))
{
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)
PropertyName.Name = rkParams.Prefix;
@@ -195,16 +195,15 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
{
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;
Log::Write(LogMsg);
}
}
#endif
}
// Every 250 tests, check with the progress notifier. Update the progress

View File

@@ -32,7 +32,7 @@ struct SGeneratedPropertyName
TString Name;
TString Type;
u32 ID;
std::vector<TString> XmlList;
std::set<TString> XmlList;
};
/** 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()
{
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
{
CGameTemplate* pGameTemplate = NGameList::GetGameTemplate(Game());
IProperty* pTemplateRoot = (IsArchetype() ? RootParent() : mpArchetype);
return pGameTemplate->GetPropertyArchetypeFilePath( pTemplateRoot->Name() );
return pGameTemplate->GetPropertyArchetypeFilePath( pTemplateRoot->Name() ).ChopFront(kChopAmount);
}
}
@@ -304,27 +324,36 @@ bool IProperty::ShouldCook(void* pPropertyData) const
void IProperty::SetName(const TString& rkNewName)
{
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)
if (mName != rkNewName)
{
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)
{
mDescription = rkNewDescription;
MarkDirty();
if (mDescription != rkNewDescription)
{
mDescription = rkNewDescription;
MarkDirty();
}
}
void IProperty::SetSuffix(const TString& rkNewSuffix)
{
mSuffix = rkNewSuffix;
MarkDirty();
if (mSuffix != rkNewSuffix)
{
mSuffix = rkNewSuffix;
MarkDirty();
}
}
void IProperty::MarkDirty()

View File

@@ -211,6 +211,7 @@ public:
inline IProperty* Parent() const;
inline IProperty* RootParent();
inline IProperty* Archetype() const;
inline IProperty* RootArchetype();
inline CScriptTemplate* ScriptTemplate() const;
inline TString Name() const;
inline TString Description() const;
@@ -286,6 +287,20 @@ inline IProperty* IProperty::Archetype() const
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
{
return mpScriptTemplate;