123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <EditorDefs.h>
- #include "ProjectSettingsSerialization.h"
- #include "PlatformSettings_common.h"
- #include <AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h>
- #include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
- // Needed to overwrite ios icons and launchscreens
- #include <Util/FileUtil.h>
- namespace ProjectSettingsTool
- {
- const char* stringStr = "string";
- const char* arrayStr = "array";
- const char* trueStr = "true";
- const char* noDocumentError = "No json or xml document to use for Project Settings Tool serialization.";
- Serializer::Serializer(AzToolsFramework::InstanceDataNode* root)
- : m_root(root)
- , m_jsonDoc(nullptr)
- , m_jsonRoot(nullptr)
- , m_idString(AZ::SerializeTypeInfo<AZStd::string>::GetUuid())
- , m_idInt(AZ::SerializeTypeInfo<int>::GetUuid())
- , m_idBool(AZ::SerializeTypeInfo<bool>::GetUuid())
- {}
- Serializer::Serializer(AzToolsFramework::InstanceDataNode* root, rapidjson::Document* doc, rapidjson::Value* jsonRoot)
- : Serializer(root)
- {
- SetDocumentRoot(doc);
- if (jsonRoot != nullptr)
- {
- SetJsonRoot(jsonRoot);
- }
- else
- {
- SetJsonRoot(doc);
- }
- }
- Serializer::Serializer(AzToolsFramework::InstanceDataNode* root, AZStd::unique_ptr<PlistDictionary> dict)
- : Serializer(root)
- {
- SetDocumentRoot(AZStd::move(dict));
- }
- void Serializer::SetDocumentRoot(rapidjson::Document* doc)
- {
- m_jsonDoc = doc;
- }
- void Serializer::SetJsonRoot(rapidjson::Value* jsonRoot)
- {
- m_jsonRoot = jsonRoot;
- }
- void Serializer::SetDocumentRoot(AZStd::unique_ptr<PlistDictionary> dict)
- {
- m_plistDict = AZStd::move(dict);
- }
- bool Serializer::UiEqualToSettings() const
- {
- if (m_jsonRoot != nullptr)
- {
- return UiEqualToJson(m_jsonRoot);
- }
- else if (m_plistDict)
- {
- return UiEqualToPlist(m_root);
- }
- else
- {
- AZ_Assert(false, noDocumentError);
- return false;
- }
- }
- void Serializer::LoadFromSettings()
- {
- if (m_jsonRoot != nullptr)
- {
- LoadFromSettings(m_jsonRoot);
- }
- else if (m_plistDict)
- {
- LoadFromSettings(m_root);
- }
- else
- {
- AZ_Assert(false, noDocumentError);
- }
- }
- void Serializer::SaveToSettings()
- {
- if (m_jsonRoot != nullptr)
- {
- SaveToSettings(m_jsonRoot);
- }
- else if (m_plistDict)
- {
- SaveToSettings(m_root);
- }
- else
- {
- AZ_Assert(false, noDocumentError);
- }
- }
- bool Serializer::UiEqualToJson(rapidjson::Value* root) const
- {
- return UiEqualToJson(root, m_root);
- }
- void Serializer::LoadFromSettings(rapidjson::Value* root)
- {
- LoadFromSettings(root, m_root);
- }
- void Serializer::SaveToSettings(rapidjson::Value* root)
- {
- // This value needs to be an object to add members
- if (!root->IsObject())
- {
- root->SetObject();
- }
- SaveToSettings(root, m_root);
- }
- bool Serializer::UiEqualToJson(rapidjson::Value* root, AzToolsFramework::InstanceDataNode* node) const
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- auto childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- bool noDocElement = true;
- rapidjson::Value::MemberIterator jsonMember;
- const char* propertyName = childMeta->m_name;
- // If there is a json object try to find the member
- if (root != nullptr)
- {
- jsonMember = root->FindMember(propertyName);
- if (jsonMember != root->MemberEnd())
- {
- noDocElement = false;
- }
- }
- AZ::Uuid type = childMeta->m_typeId;
- if (m_idString == type)
- {
- AZStd::string uiValue;
- childNode.Read(uiValue);
- if (!uiValue.empty() && !noDocElement)
- {
- if (jsonMember->value.IsString())
- {
- if (uiValue != jsonMember->value.GetString())
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- else if (uiValue.empty() != noDocElement)
- {
- return false;
- }
- }
- else if (m_idInt == type)
- {
- int uiValue;
- childNode.Read(uiValue);
- if (!noDocElement)
- {
- if (jsonMember->value.IsInt())
- {
- if (uiValue != jsonMember->value.GetInt())
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- else if (m_idBool == type)
- {
- bool uiValue;
- childNode.Read(uiValue);
- if (uiValue)
- {
- if (!noDocElement)
- {
- if (jsonMember->value.IsString())
- {
- AZStd::string expectedJsonValue = trueStr;
- if (expectedJsonValue != jsonMember->value.GetString())
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- else if (!noDocElement)
- {
- return false;
- }
- }
- // Should be a class with members instead of base data type
- else
- {
- rapidjson::Value* jsonNode = nullptr;
- if (!noDocElement)
- {
- jsonNode = &jsonMember->value;
- }
- // Drill into class
- if (!UiEqualToJson(jsonNode, &childNode))
- {
- return false;
- }
- }
- }
- }
- }
- return true;
- }
- bool Serializer::UiEqualToPlist(AzToolsFramework::InstanceDataNode* node) const
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- auto childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- bool noDocElement = true;
- const char* propertyName = childMeta->m_name;
- XmlNode* plistNode = m_plistDict->GetPropertyValueNode(propertyName);
- if (plistNode != nullptr)
- {
- noDocElement = false;
- }
- AZ::Uuid type = childMeta->m_typeId;
- if (m_idString == type)
- {
- AZStd::string uiValue;
- childNode.Read(uiValue);
- if (!uiValue.empty() && !noDocElement)
- {
- if (AZStd::string(plistNode->name()) == stringStr)
- {
- if (uiValue != plistNode->value())
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- else if (uiValue.empty() != noDocElement)
- {
- return false;
- }
- }
- else if (m_idBool == type)
- {
- bool uiValue;
- childNode.Read(uiValue);
- if (uiValue)
- {
- if (!noDocElement)
- {
- if (AZStd::string(plistNode->name()) != trueStr)
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- else if (!noDocElement)
- {
- return false;
- }
- }
- else if (AZStd::string(childNode.GetClassMetadata()->m_name) == "IosOrientations")
- {
- // Enter even if nullptr to make sure all values should be false
- if (plistNode == nullptr || AZStd::string(plistNode->name()) == arrayStr)
- {
- if (!UiEqualToPlistArray(plistNode, &childNode))
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- else
- {
- if (!UiEqualToPlistImages(&childNode))
- {
- return false;
- }
- }
- }
- }
- }
- return true;
- }
- bool Serializer::UiEqualToPlistArray(XmlNode* array, AzToolsFramework::InstanceDataNode* node) const
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- const AZ::SerializeContext::ClassElement* childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- AZ::Uuid type = childMeta->m_typeId;
- if (m_idBool == type)
- {
- const char* propertyName = childMeta->m_name;
- bool uiValue;
- childNode.Read(uiValue);
- bool found = false;
- if (array != nullptr)
- {
- for (XmlNode* plistNode = array->first_node(); plistNode != nullptr; plistNode = plistNode->next_sibling())
- {
- if (AZStd::string(plistNode->value()) == propertyName)
- {
- if (!uiValue)
- {
- return false;
- }
- else
- {
- found = true;
- }
- break;
- }
- }
- }
- if (uiValue && !found)
- {
- return false;
- }
- }
- }
- }
- }
- return true;
- }
- bool Serializer::UiEqualToPlistImages(AzToolsFramework::InstanceDataNode* node) const
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- auto childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- AZ::Uuid type = childMeta->m_typeId;
- if (m_idString == type)
- {
- AZStd::string uiValue;
- childNode.Read(uiValue);
- if (!uiValue.empty())
- {
- return false;
- }
- }
- }
- }
- }
- return true;
- }
- void Serializer::LoadFromSettings(rapidjson::Value* root, AzToolsFramework::InstanceDataNode* node)
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- auto childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- const char* propertyName = childMeta->m_name;
- AZ::Uuid type = childMeta->m_typeId;
- if (root != nullptr)
- {
- rapidjson::Value::MemberIterator jsonMember = root->FindMember(propertyName);
- if (jsonMember != root->MemberEnd())
- {
- rapidjson::Value& jsonNode = jsonMember->value;
- if (m_idString == type)
- {
- if (jsonNode.IsString())
- {
- AZStd::string jsonValue = jsonNode.GetString();
- childNode.Write(jsonValue);
- }
- }
- else if (m_idInt == type)
- {
- if (jsonNode.IsInt())
- {
- int jsonValue = jsonNode.GetInt();
- childNode.Write(jsonValue);
- }
- }
- else if (m_idBool == type)
- {
- if (jsonNode.IsString())
- {
- bool value = false;
- AZStd::string jsonValue = jsonNode.GetString();
- if (jsonValue == trueStr)
- {
- value = true;
- }
- childNode.Write(value);
- }
- }
- // Should be a class with members instead of base data type
- else
- {
- if (jsonNode.IsObject())
- {
- // Drill into class
- LoadFromSettings(&jsonNode, &childNode);
- }
- }
- }
- else
- {
- SetDefaults(childNode, type);
- }
- }
- else
- {
- SetDefaults(childNode, type);
- }
- }
- }
- }
- }
- void Serializer::SaveToSettings(rapidjson::Value* root, AzToolsFramework::InstanceDataNode* node)
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- auto childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- const char* propertyName = childMeta->m_name;
- rapidjson::Value::MemberIterator jsonMember = root->FindMember(propertyName);
- if (jsonMember == root->MemberEnd())
- {
- root->AddMember(rapidjson::Value(propertyName, m_jsonDoc->GetAllocator())
- , rapidjson::Value(rapidjson::Type::kNullType)
- , m_jsonDoc->GetAllocator());
- jsonMember = root->FindMember(propertyName);
- }
- rapidjson::Value& jsonNode = jsonMember->value;
- AZ::Uuid type = childMeta->m_typeId;
- if (m_idString == type)
- {
- AZStd::string uiValue;
- childNode.Read(uiValue);
- if (!uiValue.empty())
- {
- jsonNode.SetString(uiValue.data(), m_jsonDoc->GetAllocator());
- }
- else
- {
- root->RemoveMember(propertyName);
- }
- }
- else if (m_idInt == type)
- {
- int uiValue;
- childNode.Read(uiValue);
- jsonNode.SetInt(uiValue);
- }
- else if (m_idBool == type)
- {
- bool uiValue;
- childNode.Read(uiValue);
- if (uiValue)
- {
- jsonNode.SetString(trueStr, m_jsonDoc->GetAllocator());
- }
- else
- {
- root->RemoveMember(propertyName);
- }
- }
- // Should be a class with members instead of base data type
- else
- {
- // This value needs to be an object to add members
- if (!jsonNode.IsObject())
- {
- jsonNode.SetObject();
- }
- // Drill into class
- SaveToSettings(&jsonNode, &childNode);
- if (jsonNode.ObjectEmpty())
- {
- root->RemoveMember(propertyName);
- }
- }
- }
- }
- }
- }
- void Serializer::LoadFromSettings(AzToolsFramework::InstanceDataNode* node)
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- const AZ::SerializeContext::ClassElement* childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- const char* propertyName = childMeta->m_name;
- XmlNode* plistNode = m_plistDict->GetPropertyValueNode(propertyName);
- AZ::Uuid type = childMeta->m_typeId;
- if (plistNode != nullptr)
- {
- if (m_idString == type)
- {
- if (AZStd::string(plistNode->name()) == stringStr)
- {
- AZStd::string plistValue = plistNode->value();
- childNode.Write(plistValue);
- }
- }
- else if (m_idBool == type)
- {
- if (AZStd::string(plistNode->name()) == trueStr)
- {
- childNode.Write(true);
- }
- }
- else if (AZStd::string(childNode.GetClassMetadata()->m_name) == "IosOrientations")
- {
- // Make sure it seems like an array in plist as well
- if (AZStd::string(plistNode->name()) == arrayStr)
- {
- LoadOrientations(plistNode, &childNode);
- }
- }
- else
- {
- SetClassToDefaults(&childNode);
- }
- }
- else
- {
- SetDefaults(childNode, type);
- }
- }
- }
- }
- }
- void Serializer::LoadOrientations(XmlNode* array, AzToolsFramework::InstanceDataNode* node)
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- const AZ::SerializeContext::ClassElement* childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- const char* propertyName = childMeta->m_name;
- bool found = false;
- if (array != nullptr)
- {
- for (XmlNode* plistNode = array->first_node(); plistNode != nullptr; plistNode = plistNode->next_sibling())
- {
- if (AZStd::string(plistNode->value()) == propertyName)
- {
- AZ::Uuid type = childMeta->m_typeId;
- if (m_idBool == type)
- {
- if (AZStd::string(plistNode->name()) == stringStr)
- {
- childNode.Write(true);
- found = true;
- }
- }
- else
- {
- AZ_Assert(false, "Unsupported type \"%s\" found in array.", childMeta->m_editData->m_name)
- }
- break;
- }
- }
- }
- if (!found)
- {
- childNode.Write(false);
- }
- }
- }
- }
- }
- void Serializer::SetClassToDefaults(AzToolsFramework::InstanceDataNode* node)
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- auto childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- AZ::Uuid type = childMeta->m_typeId;
- SetDefaults(childNode, type);
- }
- }
- }
- }
- void Serializer::SetDefaults(AzToolsFramework::InstanceDataNode& node, const AZ::Uuid& type)
- {
- if (m_idString == type)
- {
- node.Write(AZStd::string(""));
- return;
- }
- else if (m_idBool == type)
- {
- node.Write(false);
- return;
- }
- else if (m_idInt == type)
- {
- node.Write(0);
- return;
- }
- if (AZStd::string(node.GetClassMetadata()->m_name) == "IosOrientations")
- {
- LoadOrientations(nullptr, &node);
- }
- else
- {
- SetClassToDefaults(&node);
- }
- }
- void Serializer::SaveToSettings(AzToolsFramework::InstanceDataNode* node)
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- auto childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- const char* propertyName = childMeta->m_name;
- AZ::Uuid type = childMeta->m_typeId;
- if (m_idString == type)
- {
- AZStd::string uiValue;
- childNode.Read(uiValue);
- if (!uiValue.empty())
- {
- m_plistDict->SetPropertyValue(propertyName, uiValue.data());
- }
- else
- {
- m_plistDict->RemoveProperty(propertyName);
- }
- }
- else if (m_idBool == type)
- {
- bool uiValue;
- childNode.Read(uiValue);
- if (uiValue)
- {
- m_plistDict->SetPropertyValueName(propertyName, trueStr);
- m_plistDict->SetPropertyValue(propertyName, "");
- }
- else
- {
- m_plistDict->RemoveProperty(propertyName);
- }
- }
- else if (AZStd::string(childNode.GetClassMetadata()->m_name) == "IosOrientations")
- {
- XmlNode* plistNode = m_plistDict->GetPropertyValueNode(propertyName);
- if (plistNode == nullptr)
- {
- plistNode = m_plistDict->SetPropertyValueName(propertyName, arrayStr);
- }
- // Make sure the plist says this is an array type
- if (AZStd::string(plistNode->name()) == arrayStr)
- {
- if (!SaveOrientations(plistNode, &childNode))
- {
- m_plistDict->RemoveProperty(propertyName);
- }
- }
- }
- //Assume this is a class with image overrides
- else
- {
- OverwriteImages(&childNode);
- }
- }
- }
- }
- }
- bool Serializer::SaveOrientations(XmlNode* array, AzToolsFramework::InstanceDataNode* node)
- {
- bool anyEnabled = false;
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- const AZ::SerializeContext::ClassElement* childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- AZ::Uuid type = childMeta->m_typeId;
- if (m_idBool == type)
- {
- const char* propertyName = childMeta->m_name;
- bool uiValue;
- childNode.Read(uiValue);
- if (uiValue)
- {
- anyEnabled = true;
- }
- bool found = false;
- for (XmlNode* plistNode = array->first_node(); plistNode != nullptr; plistNode = plistNode->next_sibling())
- {
- if (AZStd::string(plistNode->value()) == propertyName)
- {
- if (!uiValue)
- {
- array->remove_node(plistNode);
- }
- else
- {
- found = true;
- }
- break;
- }
- }
- if (uiValue && !found)
- {
- array->append_node(m_plistDict->MakeNode(stringStr, propertyName));
- }
- }
- }
- }
- }
- return anyEnabled;
- }
- void Serializer::OverwriteImages(AzToolsFramework::InstanceDataNode* node)
- {
- const AZ::SerializeContext::ClassData* baseMeta = node->GetClassMetadata();
- if (baseMeta)
- {
- for (AzToolsFramework::InstanceDataNode& childNode : node->GetChildren())
- {
- auto childMeta = childNode.GetElementMetadata();
- if (childMeta)
- {
- AZ::Uuid type = childMeta->m_typeId;
- if (m_idString == type)
- {
- AZStd::string uiValue;
- childNode.Read(uiValue);
- if (!uiValue.empty())
- {
- AZ::Edit::ElementData* childEditMeta = childMeta->m_editData;
- if (childEditMeta != nullptr)
- {
- AZ::AttributeId handlerType = childEditMeta->m_elementId;
- // Special handling for iOS image overrides, the source images must be overwritten.
- if (handlerType == Handlers::ImagePreview)
- {
- AZ::Edit::Attribute* defaultPathAttr = childEditMeta->FindAttribute(Attributes::DefaultPath);
- if (defaultPathAttr != nullptr)
- {
- AzToolsFramework::PropertyAttributeReader reader(defaultPathAttr->GetContextData(), defaultPathAttr);
- AZStd::string defaultPath;
- if (reader.Read<AZStd::string>(defaultPath))
- {
- QString defaultPathQString = defaultPath.data();
- CFileUtil::OverwriteFile(defaultPathQString);
- CFileUtil::CopyFile(QString(uiValue.data()), defaultPathQString);
- // Clear the property so this isn't overwritten again for no reason
- childNode.Write(AZStd::string(""));
- }
- }
- else
- {
- AZ_Assert(false, "Could not find default path for \"%s\". Cannot override image.", childMeta->m_name)
- }
- }
- }
- }
- }
- else
- {
- AZ_Assert(false, "Unsupported type \"%s\" found in what should be image overrides.", childMeta->m_editData->m_name);
- }
- }
- }
- }
- }
- } // ProjectSettingsTool
|