/* * 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 #include #include #include #include #include #include #include #include #include namespace Physics { namespace ClassConverters { bool RagdollNodeConfigConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) { if (classElement.GetVersion() < 2) { // this conversion is to deal with m_shapes in the RagdollNodeConfiguration changing from // AZStd::vector> to // AZStd::vector, AZStd::shared_ptr>>, // and the collider related information from ShapeConfiguration moving to ColliderConfiguration const int shapesIndex = classElement.FindElement(AZ_CRC("shapes", 0x93dba512)); if (shapesIndex != -1) { AZ::SerializeContext::DataElementNode& shapesElement = classElement.GetSubElement(shapesIndex); // copy the old shape config data before removing the original vector AZStd::vector shapesCopy; const int numSubElements = shapesElement.GetNumSubElements(); shapesCopy.reserve(numSubElements); for (int i = 0; i < numSubElements; i++) { AZ::SerializeContext::DataElementNode& sharedPtrElement = shapesElement.GetSubElement(i); if (sharedPtrElement.GetNumSubElements() > 0) { AZ::SerializeContext::DataElementNode& shape = sharedPtrElement.GetSubElement(0); shapesCopy.push_back(shape); } } // remove the old vector classElement.RemoveElement(shapesIndex); // add a new vector in the new format const int newShapesIndex = classElement.AddElement(context, "shapes"); if (newShapesIndex != -1) { AZ::SerializeContext::DataElementNode& newShapesElement = classElement.GetSubElement(newShapesIndex); // convert the old shapes into the new format and add to the vector for (AZ::SerializeContext::DataElementNode shape : shapesCopy) { const int pairIndex = newShapesElement.AddElementWithData( context, "element", AzPhysics::ShapeColliderPair()); AZ::SerializeContext::DataElementNode& pairElement = newShapesElement.GetSubElement(pairIndex); ColliderConfiguration colliderConfig; if (AZ::SerializeContext::DataElementNode* baseClassNode = shape.FindSubElement(AZ_CRC("BaseClass1", 0xd4925735))) { baseClassNode->FindSubElementAndGetData(AZ_CRC("Trigger", 0x1a6b0f5d), colliderConfig.m_isTrigger); baseClassNode->FindSubElementAndGetData(AZ_CRC("Position", 0x462ce4f5), colliderConfig.m_position); baseClassNode->FindSubElementAndGetData(AZ_CRC("Rotation", 0x297c98f1), colliderConfig.m_rotation); baseClassNode->FindSubElementAndGetData(AZ_CRC("CollisionLayer", 0x39931633), colliderConfig.m_collisionLayer); } shape.RemoveElementByName(AZ_CRC("BaseClass1", 0xd4925735)); pairElement.GetSubElement(0).AddElementWithData(context, "element", colliderConfig); pairElement.GetSubElement(1).AddElement(shape); } } } } // Don't remove the 'shapes' element here, even though it got removed with v3. The version converter converts elements bottom-up // which means the ragdoll node configs get converted before the ragdoll config. If we remove the shapes element here, we would // not be able to pass the shapes over to the character collider config. The ragdoll config version converter takes care of this. //if (classElement.GetVersion() < 3) //{ // classElement.RemoveElementByName(AZ_CRC("shapes", 0x93dba512)); //} // Version 4 adds visibility settings to hide rigid body settings that aren't relevant for the animation editor. if (classElement.GetVersion() < 4) { const int rigidBodyConfigIndex = classElement.FindElement(AZ_CRC("RigidBodyConfiguration", 0x152d8d79)); if (rigidBodyConfigIndex != -1) { AZ::SerializeContext::DataElementNode& rigidBodyConfigElement = classElement.GetSubElement(rigidBodyConfigIndex); // in the animation editor we want to show inertia, damping, sleep, interpolation, gravity and CCD properties // so the value should be (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 7) = 190 rigidBodyConfigElement.AddElementWithData(context, "Property Visibility Flags", 190); } } return true; } bool RagdollConfigConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) { if (classElement.GetVersion() < 3) { CharacterColliderConfiguration newColliderConfig; AZ::SerializeContext::DataElementNode* ragdollNodeConfig = classElement.FindSubElement(AZ_CRC("nodes", 0x1d3d05fc)); if (ragdollNodeConfig) { int numNodes = ragdollNodeConfig->GetNumSubElements(); for (int i = 0; i < numNodes; ++i) { AZ::SerializeContext::DataElementNode& nodeElement = ragdollNodeConfig->GetSubElement(i); AZStd::string name; AZ::SerializeContext::DataElementNode* baseClass1 = nodeElement.FindSubElement(AZ_CRC("BaseClass1", 0xd4925735)); if (baseClass1) { AZ::SerializeContext::DataElementNode* baseBaseClass1 = baseClass1->FindSubElement(AZ_CRC("BaseClass1", 0xd4925735)); if (baseBaseClass1 && baseBaseClass1->FindSubElementAndGetData(AZ_CRC("name", 0x5e237e06), name)) { AzPhysics::ShapeColliderPairList shapes; if (nodeElement.FindSubElementAndGetData(AZ_CRC("shapes", 0x93dba512), shapes)) { CharacterColliderNodeConfiguration newColliderNodeConfig; newColliderNodeConfig.m_name = name; newColliderNodeConfig.m_shapes = shapes; newColliderConfig.m_nodes.push_back(newColliderNodeConfig); } } } nodeElement.RemoveElementByName(AZ_CRC("shapes", 0x93dba512)); } } classElement.AddElementWithData(context, "colliders", newColliderConfig); } return true; } bool MaterialLibraryAssetConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) { if (classElement.GetVersion() <= 1) { AZStd::vector newConfiguration; auto oldConfigurationsListDataNode = AZ::Utils::FindDescendantElements(context, classElement, { AZ_CRC("Properties", 0x87c331c7) }); for (auto dataElement : oldConfigurationsListDataNode) { int elementsCount = dataElement->GetNumSubElements(); for (int i = 0; i < elementsCount; ++i) { MaterialConfiguration oldConfiguration; auto oldConfigurationDataNode = dataElement->GetSubElement(i); if (!oldConfigurationDataNode.GetDataHierarchy(context, oldConfiguration)) { return false; } MaterialId oldId; if (auto oldIdNode = oldConfigurationDataNode.FindSubElement(AZ_CRC("UID", 0x539b0606))) { oldIdNode->GetData(oldId); } MaterialFromAssetConfiguration configuration; configuration.m_configuration = oldConfiguration; configuration.m_id = oldId; newConfiguration.push_back(configuration); } } classElement.RemoveElementByName(AZ_CRC("Properties", 0x87c331c7)); if (classElement.AddElementWithData(context, "Properties", newConfiguration) == -1) { return false; } } return true; } bool ColliderConfigurationConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& dataElement) { // version 1->2 if (dataElement.GetVersion() <= 1) { // Convert collision group to group id dataElement.RemoveElementByName(AZ_CRC("CollisionGroup", 0xb08873ec)); dataElement.AddElement(context, "CollisionGroupId"); } // version 2->3 if (dataElement.GetVersion() <= 2) { // Force all new colliders to have exclusive shapes dataElement.RemoveElementByName(AZ_CRC("Exclusive", 0x012318fc)); dataElement.AddElementWithData(context, "Exclusive", true); } // version 3->4 if (dataElement.GetVersion() <= 3) { const int elementIndex = dataElement.FindElement(AZ_CRC("Trigger", 0x1a6b0f5d)); if (elementIndex >= 0) { bool isTrigger = false; AZ::SerializeContext::DataElementNode& triggerElement = dataElement.GetSubElement(elementIndex); const bool found = triggerElement.GetData(isTrigger); if (found && isTrigger) { // Version 4 added "InSceneQueries" field set to true by default. // The field is applicable to both trigger and simulated shapes. // However before all trigger shapes were always invisible to scene queries. // Setting "In Scene Queries" to false for all existing triggers to avoid breaking the existing content. const int idx = dataElement.AddElement(context, "InSceneQueries"); if (idx != -1) { if (!dataElement.GetSubElement(idx).SetData(context, false)) { return false; } } } } } return true; } bool MaterialSelectionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& dataElement) { bool success = true; if (dataElement.GetVersion() <= 1) { Physics::MaterialId materialId; success = dataElement.FindSubElementAndGetData(AZ_CRC("MaterialId", 0x9360e002), materialId); if (success) { dataElement.RemoveElementByName(AZ_CRC("MaterialId", 0x9360e002)); success = success && (dataElement.FindElement(AZ_CRC("MaterialId", 0x9360e002)) < 0); success = success && dataElement.AddElementWithData(context, "MaterialIds", AZStd::vector { materialId }); } } if (success && dataElement.GetVersion() <= 2) { dataElement.RemoveElementByName(AZ_CRC_CE("Material")); success = success && (dataElement.FindElement(AZ_CRC_CE("Material")) < 0); } return success; } } // namespace ClassConverters } // namespace Physics