Convert legacy XML handling to rapidxml

Updates the Audio Controls Editor code to use rapidxml instead of legacy
xml apis.  Further makes improvements to path manipulations away from
strings towards PathView apis and similar.

Fixes some issues encountered with memory management when handling xml
data that did not occur previously.

Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com>
This commit is contained in:
amzn-phist
2021-07-22 17:37:44 -05:00
parent 4d5a985276
commit 5b148b1f40
15 changed files with 580 additions and 410 deletions
@@ -19,10 +19,7 @@
#include <AudioSystemControl_wwise.h>
#include <Common_wwise.h>
#include <ISystem.h>
#include <CryFile.h>
#include <CryPath.h>
#include <Util/PathUtil.h>
#include <QDir>
void InitWwiseResources()
{
@@ -217,28 +214,34 @@ namespace AudioControls
}
//-------------------------------------------------------------------------------------------//
TConnectionPtr CAudioSystemEditor_wwise::CreateConnectionFromXMLNode(XmlNodeRef node, EACEControlType atlControlType)
TConnectionPtr CAudioSystemEditor_wwise::CreateConnectionFromXMLNode(AZ::rapidxml::xml_node<char>* node, EACEControlType atlControlType)
{
if (node)
{
const AZStd::string tag(node->getTag());
TImplControlType type = TagToType(tag);
AZStd::string_view element(node->name());
TImplControlType type = TagToType(element);
if (type != AUDIO_IMPL_INVALID_TYPE)
{
AZStd::string name(node->getAttr(Audio::WwiseXmlTags::WwiseNameAttribute));
AZStd::string localized(node->getAttr(Audio::WwiseXmlTags::WwiseLocalizedAttribute));
AZStd::string name;
AZStd::string_view localized;
// Legacy Preload support
if (localized.empty())
if (auto nameAttr = node->first_attribute(Audio::WwiseXmlTags::WwiseNameAttribute, 0, false);
nameAttr != nullptr)
{
localized = node->getAttr(Audio::WwiseXmlTags::Legacy::WwiseLocalizedAttribute);
name = nameAttr->value();
}
bool isLocalized = AZ::StringFunc::Equal(localized.c_str(), "true");
if (auto localizedAttr = node->first_attribute(Audio::WwiseXmlTags::WwiseLocalizedAttribute, 0, false);
localizedAttr != nullptr)
{
localized = localizedAttr->value();
}
// If control not found, create a placeholder.
// We want to keep that connection even if it's not in the middleware.
// The user could be using the engine without the wwise project
bool isLocalized = AZ::StringFunc::Equal(localized, "true");
// If the control wasn't found, create a placeholder.
// We want to see that connection even if it's not in the middleware.
// User could be viewing the editor without a middleware project.
IAudioSystemControl* control = GetControlByName(name, isLocalized);
if (!control)
{
@@ -250,27 +253,26 @@ namespace AudioControls
}
}
// If it's a switch we actually connect to one of the states within the switch
// If it's a switch we connect to one of the states within the switch
if (type == eWCT_WWISE_SWITCH_GROUP || type == eWCT_WWISE_GAME_STATE_GROUP)
{
if (node->getChildCount() == 1)
if (auto childNode = node->first_node();
childNode != nullptr)
{
node = node->getChild(0);
if (node)
AZStd::string childName;
if (auto childNameAttr = childNode->first_attribute(Audio::WwiseXmlTags::WwiseNameAttribute, 0, false);
childNameAttr != nullptr)
{
AZStd::string childName(node->getAttr(Audio::WwiseXmlTags::WwiseNameAttribute));
IAudioSystemControl* childControl = GetControlByName(childName, false, control);
if (!childControl)
{
childControl = CreateControl(SControlDef(childName, type == eWCT_WWISE_SWITCH_GROUP ? eWCT_WWISE_SWITCH : eWCT_WWISE_GAME_STATE, false, control));
}
control = childControl;
childName = childNameAttr->value();
}
}
else
{
CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_ERROR, "Audio Controls Editor (Wwise): Error reading connection to Wwise control %s", name.c_str());
IAudioSystemControl* childControl = GetControlByName(childName, false, control);
if (!childControl)
{
childControl = CreateControl(SControlDef(
childName, type == eWCT_WWISE_SWITCH_GROUP ? eWCT_WWISE_SWITCH : eWCT_WWISE_GAME_STATE, false, control));
}
control = childControl;
}
}
@@ -289,16 +291,19 @@ namespace AudioControls
float mult = 1.0f;
float shift = 0.0f;
if (node->haveAttr(Audio::WwiseXmlTags::WwiseMutiplierAttribute))
if (auto multAttr = node->first_attribute(Audio::WwiseXmlTags::WwiseMutiplierAttribute, 0, false);
multAttr != nullptr)
{
const AZStd::string multProperty(node->getAttr(Audio::WwiseXmlTags::WwiseMutiplierAttribute));
mult = AZStd::stof(multProperty);
mult = AZStd::stof(AZStd::string(multAttr->value()));
}
if (node->haveAttr(Audio::WwiseXmlTags::WwiseShiftAttribute))
if (auto shiftAttr = node->first_attribute(Audio::WwiseXmlTags::WwiseShiftAttribute, 0, false);
shiftAttr != nullptr)
{
const AZStd::string shiftProperty(node->getAttr(Audio::WwiseXmlTags::WwiseShiftAttribute));
shift = AZStd::stof(shiftProperty);
shift = AZStd::stof(AZStd::string(shiftAttr->value()));
}
connection->m_mult = mult;
connection->m_shift = shift;
return connection;
@@ -308,11 +313,12 @@ namespace AudioControls
TStateConnectionPtr connection = AZStd::make_shared<CStateToRtpcConnection>(control->GetId());
float value = 0.0f;
if (node->haveAttr(Audio::WwiseXmlTags::WwiseValueAttribute))
if (auto valueAttr = node->first_attribute(Audio::WwiseXmlTags::WwiseValueAttribute, 0, false);
valueAttr != nullptr)
{
const AZStd::string valueProperty(node->getAttr(Audio::WwiseXmlTags::WwiseValueAttribute));
value = AZStd::stof(valueProperty);
value = AZStd::stof(AZStd::string(valueAttr->value()));
}
connection->m_value = value;
return connection;
}
@@ -329,28 +335,50 @@ namespace AudioControls
}
//-------------------------------------------------------------------------------------------//
XmlNodeRef CAudioSystemEditor_wwise::CreateXMLNodeFromConnection(const TConnectionPtr connection, const EACEControlType atlControlType)
AZ::rapidxml::xml_node<char>* CAudioSystemEditor_wwise::CreateXMLNodeFromConnection(const TConnectionPtr connection, const EACEControlType atlControlType)
{
const IAudioSystemControl* control = GetControl(connection->GetID());
if (control)
{
XmlAllocator& xmlAllocator(AudioControls::s_xmlAllocator);
switch (control->GetType())
{
case AudioControls::eWCT_WWISE_SWITCH:
[[fallthrough]];
case AudioControls::eWCT_WWISE_SWITCH_GROUP:
[[fallthrough]];
case AudioControls::eWCT_WWISE_GAME_STATE:
[[fallthrough]];
case AudioControls::eWCT_WWISE_GAME_STATE_GROUP:
{
const IAudioSystemControl* parent = control->GetParent();
if (parent)
{
XmlNodeRef switchNode = GetISystem()->CreateXmlNode(TypeToTag(parent->GetType()).data());
switchNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, parent->GetName().c_str());
AZStd::string_view parentType = TypeToTag(parent->GetType());
auto switchNode = xmlAllocator.allocate_node(
AZ::rapidxml::node_element,
xmlAllocator.allocate_string(parentType.data())
);
XmlNodeRef stateNode = switchNode->createNode(Audio::WwiseXmlTags::WwiseValueTag);
stateNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, control->GetName().c_str());
switchNode->addChild(stateNode);
auto switchNameAttr = xmlAllocator.allocate_attribute(
Audio::WwiseXmlTags::WwiseNameAttribute,
xmlAllocator.allocate_string(parent->GetName().c_str())
);
auto stateNode = xmlAllocator.allocate_node(
AZ::rapidxml::node_element,
Audio::WwiseXmlTags::WwiseValueTag
);
auto stateNameAttr = xmlAllocator.allocate_attribute(
Audio::WwiseXmlTags::WwiseNameAttribute,
xmlAllocator.allocate_string(control->GetName().c_str())
);
switchNode->append_attribute(switchNameAttr);
stateNode->append_attribute(stateNameAttr);
switchNode->append_node(stateNode);
return switchNode;
}
break;
@@ -358,51 +386,98 @@ namespace AudioControls
case AudioControls::eWCT_WWISE_RTPC:
{
XmlNodeRef connectionNode = GetISystem()->CreateXmlNode(TypeToTag(control->GetType()).data());
connectionNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, control->GetName().c_str());
auto connectionNode = xmlAllocator.allocate_node(
AZ::rapidxml::node_element,
xmlAllocator.allocate_string(TypeToTag(control->GetType()).data())
);
auto nameAttr = xmlAllocator.allocate_attribute(
Audio::WwiseXmlTags::WwiseNameAttribute,
xmlAllocator.allocate_string(control->GetName().c_str())
);
connectionNode->append_attribute(nameAttr);
if (atlControlType == eACET_RTPC)
{
AZStd::shared_ptr<const CRtpcConnection> rtpcConnection = AZStd::static_pointer_cast<const CRtpcConnection>(connection);
if (rtpcConnection->m_mult != 1.0f)
if (rtpcConnection->m_mult != 1.f)
{
connectionNode->setAttr(Audio::WwiseXmlTags::WwiseMutiplierAttribute, rtpcConnection->m_mult);
auto multAttr = xmlAllocator.allocate_attribute(
Audio::WwiseXmlTags::WwiseMutiplierAttribute,
xmlAllocator.allocate_string(AZStd::to_string(rtpcConnection->m_mult).c_str())
);
connectionNode->append_attribute(multAttr);
}
if (rtpcConnection->m_shift != 0.0f)
if (rtpcConnection->m_shift != 0.f)
{
connectionNode->setAttr(Audio::WwiseXmlTags::WwiseShiftAttribute, rtpcConnection->m_shift);
auto shiftAttr = xmlAllocator.allocate_attribute(
Audio::WwiseXmlTags::WwiseShiftAttribute,
xmlAllocator.allocate_string(AZStd::to_string(rtpcConnection->m_shift).c_str())
);
connectionNode->append_attribute(shiftAttr);
}
}
else if (atlControlType == eACET_SWITCH_STATE)
{
AZStd::shared_ptr<const CStateToRtpcConnection> stateConnection = AZStd::static_pointer_cast<const CStateToRtpcConnection>(connection);
connectionNode->setAttr(Audio::WwiseXmlTags::WwiseValueAttribute, stateConnection->m_value);
auto valueAttr = xmlAllocator.allocate_attribute(
Audio::WwiseXmlTags::WwiseValueAttribute,
xmlAllocator.allocate_string(AZStd::to_string(stateConnection->m_value).c_str())
);
connectionNode->append_attribute(valueAttr);
}
return connectionNode;
}
case AudioControls::eWCT_WWISE_EVENT:
{
XmlNodeRef connectionNode = GetISystem()->CreateXmlNode(TypeToTag(control->GetType()).data());
connectionNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, control->GetName().c_str());
return connectionNode;
}
[[fallthrough]];
case AudioControls::eWCT_WWISE_AUX_BUS:
{
XmlNodeRef connectionNode = GetISystem()->CreateXmlNode(TypeToTag(control->GetType()).data());
connectionNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, control->GetName().c_str());
auto connectionNode = xmlAllocator.allocate_node(
AZ::rapidxml::node_element,
xmlAllocator.allocate_string(TypeToTag(control->GetType()).data())
);
auto nameAttr = xmlAllocator.allocate_attribute(
Audio::WwiseXmlTags::WwiseNameAttribute,
xmlAllocator.allocate_string(control->GetName().c_str())
);
connectionNode->append_attribute(nameAttr);
return connectionNode;
}
case AudioControls::eWCT_WWISE_SOUND_BANK:
{
XmlNodeRef connectionNode = GetISystem()->CreateXmlNode(TypeToTag(control->GetType()).data());
connectionNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, control->GetName().c_str());
auto connectionNode = xmlAllocator.allocate_node(
AZ::rapidxml::node_element,
xmlAllocator.allocate_string(TypeToTag(control->GetType()).data())
);
auto nameAttr = xmlAllocator.allocate_attribute(
Audio::WwiseXmlTags::WwiseNameAttribute,
xmlAllocator.allocate_string(control->GetName().c_str())
);
connectionNode->append_attribute(nameAttr);
if (control->IsLocalized())
{
connectionNode->setAttr(Audio::WwiseXmlTags::WwiseLocalizedAttribute, "true");
auto locAttr = xmlAllocator.allocate_attribute(
Audio::WwiseXmlTags::WwiseLocalizedAttribute,
xmlAllocator.allocate_string("true")
);
connectionNode->append_attribute(locAttr);
}
return connectionNode;
}
}