513 lines
16 KiB
C++
513 lines
16 KiB
C++
|
#include "MujocoAttributeHandler.h"
|
||
|
#include "Enums/MujocoEnums.h"
|
||
|
#include "LuckyMujocoEditor.h"
|
||
|
|
||
|
using AttributeHandler = TFunction<void(const FString&, void*, FProperty*)>;
|
||
|
|
||
|
void HandleEnumAttribute(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (FEnumProperty* EnumProp = CastField<FEnumProperty>(Prop))
|
||
|
{
|
||
|
UEnum* EnumDef = EnumProp->GetEnum();
|
||
|
|
||
|
FName Search = FName(*ValueStr);
|
||
|
|
||
|
int64 EnumIndex = EnumDef->GetIndexByName(Search);
|
||
|
if (EnumIndex == INDEX_NONE)
|
||
|
{
|
||
|
FName SearchLover = FName(*ValueStr.ToLower());
|
||
|
EnumIndex = EnumDef->GetIndexByName(SearchLover);
|
||
|
|
||
|
if (EnumIndex == INDEX_NONE)
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Invalid enum value: %s"), *ValueStr);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
EnumProp->GetUnderlyingProperty()->SetIntPropertyValue(EnumProp->ContainerPtrToValuePtr<void>(DataPtr), EnumIndex);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Failed to set enum value: %s"), *ValueStr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename T> void HandleOptionalEnumAttribute(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Unhandled optional enum attribute: %s"), *ValueStr);
|
||
|
}
|
||
|
|
||
|
template <> void HandleOptionalEnumAttribute<EDynType>(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (auto* OptionalEnum = static_cast<TOptional<EDynType>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
EDynType EnumValue = EDynType::None;
|
||
|
if (ValueStr == TEXT("integrator"))
|
||
|
{
|
||
|
EnumValue = EDynType::Integrator;
|
||
|
}
|
||
|
else if (ValueStr == TEXT("filter"))
|
||
|
{
|
||
|
EnumValue = EDynType::Filter;
|
||
|
}
|
||
|
else if (ValueStr == TEXT("filterexact"))
|
||
|
{
|
||
|
EnumValue = EDynType::FilterExact;
|
||
|
}
|
||
|
else if (ValueStr == TEXT("muscle"))
|
||
|
{
|
||
|
EnumValue = EDynType::Muscle;
|
||
|
}
|
||
|
else if (ValueStr == TEXT("user"))
|
||
|
{
|
||
|
EnumValue = EDynType::User;
|
||
|
}
|
||
|
*OptionalEnum = TOptional<EDynType>{ EnumValue };
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Failed to set optional enum value: %s"), *ValueStr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <> void HandleOptionalEnumAttribute<EGainType>(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (auto* OptionalEnum = static_cast<TOptional<EGainType>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
EGainType EnumValue = EGainType::Fixed;
|
||
|
if (ValueStr == TEXT("affine"))
|
||
|
{
|
||
|
EnumValue = EGainType::Affine;
|
||
|
}
|
||
|
else if (ValueStr == TEXT("muscle"))
|
||
|
{
|
||
|
EnumValue = EGainType::Muscle;
|
||
|
}
|
||
|
else if (ValueStr == TEXT("user"))
|
||
|
{
|
||
|
EnumValue = EGainType::User;
|
||
|
}
|
||
|
*OptionalEnum = TOptional<EGainType>{ EnumValue };
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Failed to set optional enum value: %s"), *ValueStr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <> void HandleOptionalEnumAttribute<EBiasType>(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (auto* OptionalEnum = static_cast<TOptional<EBiasType>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
EBiasType EnumValue = EBiasType::None;
|
||
|
if (ValueStr == TEXT("affine"))
|
||
|
{
|
||
|
EnumValue = EBiasType::Affine;
|
||
|
}
|
||
|
else if (ValueStr == TEXT("muscle"))
|
||
|
{
|
||
|
EnumValue = EBiasType::Muscle;
|
||
|
}
|
||
|
else if (ValueStr == TEXT("user"))
|
||
|
{
|
||
|
EnumValue = EBiasType::User;
|
||
|
}
|
||
|
*OptionalEnum = TOptional<EBiasType>{ EnumValue };
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Failed to set optional enum value: %s"), *ValueStr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename T> void HandleOptionalEnum(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (auto* OptionalEnum = static_cast<TOptional<T>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalEnum = TOptional<T>{ static_cast<T>(FCString::Atoi(*ValueStr)) };
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Failed to set optional enum value: %s"), *ValueStr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HandleOptionalInt(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (auto* OptionalInt = static_cast<TOptional<int32>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalInt = TOptional<int32>{ FCString::Atoi(*ValueStr) };
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Failed to set optional int value: %s"), *ValueStr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename T> void HandleOptionalNumber(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (auto* OptionalFloat = static_cast<TOptional<T>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalFloat = TOptional<T>{ FCString::Atod(*ValueStr) };
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Failed to set optional float value: %s"), *ValueStr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HandleVector2D(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
TArray<FString> Components;
|
||
|
ValueStr.ParseIntoArray(Components, TEXT(" "), true);
|
||
|
if (Components.Num() >= 2)
|
||
|
{
|
||
|
FVector2D Range(FCString::Atod(*Components[0]), FCString::Atod(*Components[1]));
|
||
|
if (auto* OptionalRange = static_cast<TOptional<FVector2D>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalRange = TOptional<FVector2D>{ Range };
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Invalid Vector2D value: %s"), *ValueStr);
|
||
|
}
|
||
|
|
||
|
void HandleVector3D(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
TArray<FString> Components;
|
||
|
ValueStr.ParseIntoArray(Components, TEXT(" "), true);
|
||
|
if (Components.Num() >= 3)
|
||
|
{
|
||
|
FVector Vector(FCString::Atod(*Components[0]), FCString::Atod(*Components[1]), FCString::Atod(*Components[2]));
|
||
|
if (auto* OptionalVector = static_cast<TOptional<FVector>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalVector = TOptional<FVector>{ Vector };
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Invalid Vector3D value: %s"), *ValueStr);
|
||
|
}
|
||
|
|
||
|
void HandleVector4D(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
TArray<FString> Components;
|
||
|
ValueStr.ParseIntoArray(Components, TEXT(" "), true);
|
||
|
if (Components.Num() >= 4)
|
||
|
{
|
||
|
FVector4 Vector(FCString::Atod(*Components[0]), FCString::Atod(*Components[1]), FCString::Atod(*Components[2]), FCString::Atod(*Components[3]));
|
||
|
if (auto* OptionalVector = static_cast<TOptional<FVector4>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalVector = TOptional<FVector4>{ Vector };
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Invalid Vector4D value: %s"), *ValueStr);
|
||
|
}
|
||
|
|
||
|
void HandleOptionalBool(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (auto* OptionalBool = static_cast<TOptional<bool>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalBool = TOptional<bool>{ FCString::ToBool(*ValueStr) };
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Failed to set optional bool value: %s"), *ValueStr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HandleFName(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (auto* NamePtr = static_cast<FName*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*NamePtr = FName(*ValueStr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Failed to set FName value: %s"), *ValueStr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HandleGear(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
TArray<FString> Components;
|
||
|
ValueStr.ParseIntoArray(Components, TEXT(" "), true);
|
||
|
if (Components.Num() >= 6)
|
||
|
{
|
||
|
FMujocoGear Gear;
|
||
|
Gear.G0.X = FCString::Atod(*Components[0]);
|
||
|
Gear.G0.Y = FCString::Atod(*Components[1]);
|
||
|
Gear.G0.Z = FCString::Atod(*Components[2]);
|
||
|
Gear.G1.X = FCString::Atod(*Components[3]);
|
||
|
Gear.G1.Y = FCString::Atod(*Components[4]);
|
||
|
Gear.G1.Z = FCString::Atod(*Components[5]);
|
||
|
|
||
|
if (auto* OptionalGear = static_cast<TOptional<FMujocoGear>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalGear = TOptional<FMujocoGear>{ Gear };
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Invalid Gear value: %s"), *ValueStr);
|
||
|
}
|
||
|
|
||
|
void HandleSolImp(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
TArray<FString> Components;
|
||
|
ValueStr.ParseIntoArray(Components, TEXT(" "), true);
|
||
|
|
||
|
FMujocoSolImp SolImp;
|
||
|
|
||
|
float* SolImpPtr = &SolImp.DMin;
|
||
|
for (int i = 0; i < 5 && i < Components.Num(); ++i)
|
||
|
{
|
||
|
SolImpPtr[i] = FCString::Atod(*Components[i]);
|
||
|
}
|
||
|
|
||
|
if (auto* OptionalSolImp = static_cast<TOptional<FMujocoSolImp>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalSolImp = TOptional<FMujocoSolImp>{ SolImp };
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HandleSolRef(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
TArray<FString> Components;
|
||
|
ValueStr.ParseIntoArray(Components, TEXT(" "), true);
|
||
|
if (Components.Num() >= 2)
|
||
|
{
|
||
|
FMujocoSolRef SolRef;
|
||
|
SolRef.TimeConst = FCString::Atod(*Components[0]);
|
||
|
SolRef.DampRatio = FCString::Atod(*Components[1]);
|
||
|
|
||
|
if (auto* OptionalSolRef = static_cast<TOptional<FMujocoSolRef>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalSolRef = TOptional<FMujocoSolRef>{ SolRef };
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Invalid SolRef value: %s"), *ValueStr);
|
||
|
}
|
||
|
|
||
|
void HandlePolyCoef(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
TArray<FString> Components;
|
||
|
ValueStr.ParseIntoArray(Components, TEXT(" "), true);
|
||
|
|
||
|
FMujocoPolyCoef PolyCoef;
|
||
|
float* PolyCoefPtr = &PolyCoef.A0;
|
||
|
for (int i = 0; i < 5 && i < Components.Num(); ++i)
|
||
|
{
|
||
|
PolyCoefPtr[i] = FCString::Atod(*Components[i]);
|
||
|
}
|
||
|
if (auto* OptionalPolyCoef = static_cast<TOptional<FMujocoPolyCoef>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalPolyCoef = TOptional<FMujocoPolyCoef>{ PolyCoef };
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void HandleRelPose(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
TArray<FString> Components;
|
||
|
ValueStr.ParseIntoArray(Components, TEXT(" "), true);
|
||
|
FMujocoRelPose RelPose;
|
||
|
|
||
|
double* RelPosePtr[] = { &RelPose.Pos.X, &RelPose.Pos.Y, &RelPose.Pos.Z, &RelPose.Rot.X, &RelPose.Rot.Y, &RelPose.Rot.Z };
|
||
|
|
||
|
for (int i = 0; i < 6 && i < Components.Num(); ++i)
|
||
|
{
|
||
|
*RelPosePtr[i] = FCString::Atod(*Components[i]);
|
||
|
}
|
||
|
|
||
|
if (auto* OptionalRelPose = static_cast<TOptional<FMujocoRelPose>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalRelPose = TOptional<FMujocoRelPose>{ RelPose };
|
||
|
return;
|
||
|
}
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Invalid RelPose value: %s"), *ValueStr);
|
||
|
}
|
||
|
|
||
|
void HandleFriction(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
TArray<FString> Components;
|
||
|
ValueStr.ParseIntoArray(Components, TEXT(" "), true);
|
||
|
|
||
|
FMujocoFriction Friction;
|
||
|
float* FrictionPtr = &Friction.Sliding;
|
||
|
for (int i = 0; i < 3 && i < Components.Num(); ++i)
|
||
|
{
|
||
|
FrictionPtr[i] = FCString::Atod(*Components[i]);
|
||
|
}
|
||
|
|
||
|
if (auto* OptionalFriction = static_cast<TOptional<FMujocoFriction>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
*OptionalFriction = TOptional<FMujocoFriction>{ Friction };
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Invalid Friction value: %s"), *ValueStr);
|
||
|
}
|
||
|
|
||
|
template <typename T> void HandleNumberArray(const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
TArray<FString> Components;
|
||
|
ValueStr.ParseIntoArray(Components, TEXT(" "), true);
|
||
|
|
||
|
if (auto* FloatArrayPtr = static_cast<TArray<T>*>(Prop->ContainerPtrToValuePtr<void>(DataPtr)))
|
||
|
{
|
||
|
TArray<T> FloatArray;
|
||
|
for (const FString& Component : Components)
|
||
|
{
|
||
|
FloatArray.Add(FCString::Atod(*Component));
|
||
|
}
|
||
|
|
||
|
*FloatArrayPtr = FloatArray;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Invalid FloatArray value: %s"), *ValueStr);
|
||
|
}
|
||
|
|
||
|
static const TMap<FString, AttributeHandler> AttributeHandlers = {
|
||
|
{ TEXT("type"), &HandleEnumAttribute },
|
||
|
|
||
|
{ TEXT("dyntype"), &HandleOptionalEnumAttribute<EDynType> },
|
||
|
{ TEXT("biastype"), &HandleOptionalEnumAttribute<EBiasType> },
|
||
|
{ TEXT("gaintype"), &HandleOptionalEnumAttribute<EGainType> },
|
||
|
|
||
|
{ TEXT("group"), &HandleOptionalInt },
|
||
|
{ TEXT("priority"), &HandleOptionalInt },
|
||
|
{ TEXT("conaffinity"), &HandleOptionalInt },
|
||
|
{ TEXT("contype"), &HandleOptionalInt },
|
||
|
|
||
|
{ TEXT("condim"), &HandleOptionalEnum<EMujocoContactDim> },
|
||
|
{ TEXT("ctrllimited"), &HandleOptionalEnum<ELimitType> },
|
||
|
{ TEXT("forcelimited"), &HandleOptionalEnum<ELimitType> },
|
||
|
{ TEXT("actlimited"), &HandleOptionalEnum<ELimitType> },
|
||
|
|
||
|
{ TEXT("ctrlrange"), &HandleVector2D },
|
||
|
{ TEXT("forcerange"), &HandleVector2D },
|
||
|
{ TEXT("actrange"), &HandleVector2D },
|
||
|
{ TEXT("lengthrange"), &HandleVector2D },
|
||
|
|
||
|
{ TEXT("gear"), &HandleGear },
|
||
|
|
||
|
{ TEXT("cranklength"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("kp"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("kv"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("dampratio"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("timeconst"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("inheritrange"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("area"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("diameter"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("tausmooth"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("force"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("scale"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("vmax"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("fpmax"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("fvmax"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("lmin"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("lmax"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("gain"), &HandleOptionalNumber<double> },
|
||
|
|
||
|
{ TEXT("range"), &HandleVector2D },
|
||
|
{ TEXT("muscle_timeconsts"), &HandleVector2D },
|
||
|
{ TEXT("actuatorfrcrange"), &HandleVector2D },
|
||
|
|
||
|
{ TEXT("name"), &HandleFName },
|
||
|
{ TEXT("joint"), &HandleFName },
|
||
|
{ TEXT("body1"), &HandleFName },
|
||
|
{ TEXT("body2"), &HandleFName },
|
||
|
{ TEXT("site1"), &HandleFName },
|
||
|
{ TEXT("site2"), &HandleFName },
|
||
|
{ TEXT("joint1"), &HandleFName },
|
||
|
{ TEXT("joint2"), &HandleFName },
|
||
|
{ TEXT("jointinparent"), &HandleFName },
|
||
|
{ TEXT("site"), &HandleFName },
|
||
|
{ TEXT("refsite"), &HandleFName },
|
||
|
{ TEXT("body"), &HandleFName },
|
||
|
{ TEXT("tendon"), &HandleFName },
|
||
|
{ TEXT("tendon1"), &HandleFName },
|
||
|
{ TEXT("tendon2"), &HandleFName },
|
||
|
{ TEXT("cranksite"), &HandleFName },
|
||
|
{ TEXT("slidersite"), &HandleFName },
|
||
|
|
||
|
{ TEXT("pos"), &HandleVector3D },
|
||
|
{ TEXT("axis"), &HandleVector3D },
|
||
|
{ TEXT("diaginertia"), &HandleVector3D },
|
||
|
{ TEXT("size"), &HandleVector3D },
|
||
|
{ TEXT("bias"), &HandleVector3D },
|
||
|
|
||
|
{ TEXT("rgba"), &HandleVector4D },
|
||
|
|
||
|
{ TEXT("armature"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("springref"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("gravcomp"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("solreflimit"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("solimplimit"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("solreffriction"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("solimpfriction"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("margin"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("frictionloss"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("width"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("stiffness"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("damping"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("mass"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("density"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("shellinertia"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("solmix"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("gap"), &HandleOptionalNumber<double> },
|
||
|
{ TEXT("torquescale"), &HandleOptionalNumber<double> },
|
||
|
|
||
|
{ TEXT("actearly"), &HandleOptionalBool },
|
||
|
|
||
|
{ TEXT("dynprm"), &HandleNumberArray<double> },
|
||
|
{ TEXT("gainprm"), &HandleNumberArray<double> },
|
||
|
{ TEXT("biasprm"), &HandleNumberArray<double> },
|
||
|
|
||
|
{ TEXT("solimp"), &HandleSolImp },
|
||
|
{ TEXT("solref"), &HandleSolRef },
|
||
|
|
||
|
{ TEXT("polycoef"), &HandlePolyCoef },
|
||
|
|
||
|
{ TEXT("relpose"), &HandleRelPose },
|
||
|
|
||
|
{ TEXT("friction"), &HandleFriction },
|
||
|
|
||
|
{ TEXT("fullinertia"), &HandleGear },
|
||
|
|
||
|
{ TEXT("active"), &HandleOptionalBool },
|
||
|
};
|
||
|
|
||
|
void ProcessAttribute(const FString& AttrKey, const FString& ValueStr, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (const AttributeHandler* Handler = AttributeHandlers.Find(AttrKey))
|
||
|
{
|
||
|
(*Handler)(ValueStr, DataPtr, Prop);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Error, TEXT("Unhandled attribute: %s"), *AttrKey);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ParseMujocoElementAttribute(const tinyxml2::XMLElement* Element, const FString& AttrKey, void* DataPtr, FProperty* Prop)
|
||
|
{
|
||
|
if (!Element)
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("ParseXmlElementAttribute: Element is null."));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const char* XmlVal = Element->Attribute(TCHAR_TO_UTF8(*AttrKey));
|
||
|
if (XmlVal)
|
||
|
{
|
||
|
ProcessAttribute(AttrKey, UTF8_TO_TCHAR(XmlVal), DataPtr, Prop);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogMujoco, Warning, TEXT("Attribute %s not found"), *AttrKey);
|
||
|
}
|
||
|
}
|