// Copyright Epic Games, Inc. All Rights Reserved. #include "LuckyMujocoEditor.h" #include "Misc/MessageDialog.h" #include "Modules/ModuleManager.h" #include "Interfaces/IPluginManager.h" #include "Misc/Paths.h" #include "HAL/PlatformProcess.h" #include "AssetToolsModule.h" #include "MujocoComponentDetails.h" #include "Selection.h" #include "Engine/StaticMeshActor.h" #include "Actors/MujocoStaticMeshActor.h" #include "Components/MujocoBodyComponent.h" #include "Components/MujocoGeomComponent.h" #include "LevelEditor.h" DEFINE_LOG_CATEGORY(LogMujoco); #define LOCTEXT_NAMESPACE "FLuckyMujocoEditorModule" void RegisterMujocoMeshActorConversion() { if (UToolMenus* ToolMenus = UToolMenus::Get()) { if (UToolMenu* Menu = ToolMenus->ExtendMenu("LevelEditor.ActorContextMenu")) { FToolMenuSection& Section = Menu->FindOrAddSection("ActorTypeTools"); Section.AddMenuEntry("ConvertToMujocoStaticMeshActor", // FText::FromString("Convert to Mujoco Body"), // FText::FromString("Convert the selected StaticMeshActor to MujocoStaticMeshActor."), // FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Import"), // FUIAction(FExecuteAction::CreateLambda([]() { for (FSelectionIterator It(GEditor->GetSelectedActorIterator()); It; ++It) { AStaticMeshActor* OldActor = Cast(*It); if (OldActor) { UWorld* World = OldActor->GetWorld(); FActorSpawnParameters Params; Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; if (AMujocoStaticMeshActor* NewActor = World->SpawnActor(AMujocoStaticMeshActor::StaticClass(), OldActor->GetTransform(), Params)) { TInlineComponentArray StaticMeshComponents; OldActor->GetComponents(StaticMeshComponents); UMujocoBodyComponent* MujocoBodyComponent = NewObject(NewActor, FName(*(OldActor->GetActorLabel() + TEXT("_Body")))); NewActor->AddInstanceComponent(MujocoBodyComponent); NewActor->SetRootComponent(MujocoBodyComponent); if (StaticMeshComponents.Num() > 0) { for (UStaticMeshComponent* StaticMeshComponent : StaticMeshComponents) { if (UStaticMesh* StaticMesh = StaticMeshComponent->GetStaticMesh()) { UMujocoGeomComponent* Geom = NewObject(NewActor, FName(*(StaticMesh->GetName() + TEXT("_Geom")))); Geom->SetupAttachment(MujocoBodyComponent); Geom->SetStaticMesh(StaticMesh); Geom->SetWorldScale3D(StaticMeshComponent->GetComponentScale()); Geom->SetCollisionEnabled(StaticMeshComponent->GetCollisionEnabled()); int32 NumMaterials = StaticMeshComponent->GetNumMaterials(); for (int32 i = 0; i < NumMaterials; i++) { Geom->SetMaterial(i, StaticMeshComponent->GetMaterial(i)); } FProperty* OldProperty = Geom->GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UMujocoGeomComponent, MujocoStaticMesh)); Geom->PreEditChange(OldProperty); Geom->MujocoStaticMesh = StaticMesh; FPropertyChangedEvent PropertyChangedEvent(OldProperty, EPropertyChangeType::ValueSet); Geom->PostEditChangeProperty(PropertyChangedEvent); NewActor->AddInstanceComponent(Geom); } } } FTransform NewTransform = OldActor->GetTransform(); NewTransform.SetScale3D(FVector::OneVector); NewActor->SetActorTransform(NewTransform); NewActor->SetActorLabel(OldActor->GetActorLabel()); NewActor->RegisterAllComponents(); World->DestroyActor(OldActor); if (FLevelEditorModule* LevelEditorModule = FModuleManager::GetModulePtr("LevelEditor")) { LevelEditorModule->BroadcastComponentsEdited(); } GEditor->SelectActor(NewActor, true, true); } } } }))); } } } void FLuckyMujocoEditorModule::StartupModule() { FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked(TEXT("PropertyEditor")); PropertyModule.RegisterCustomPropertyTypeLayout("MujocoActuatorV2", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMujocoPropertyCustomization::MakeInstance)); PropertyModule.RegisterCustomPropertyTypeLayout("MujocoEquality", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMujocoPropertyCustomization::MakeInstance)); PropertyModule.RegisterCustomPropertyTypeLayout("MujocoTendonSpatialSite", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMujocoPropertyCustomization::MakeInstance)); PropertyModule.RegisterCustomPropertyTypeLayout("MujocoTendonSpatialGeom", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMujocoPropertyCustomization::MakeInstance)); PropertyModule.RegisterCustomPropertyTypeLayout("MujocoTendonPulley", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMujocoPropertyCustomization::MakeInstance)); PropertyModule.RegisterCustomPropertyTypeLayout("MujocoTendonFixedJoint", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FMujocoPropertyCustomization::MakeInstance)); PropertyModule.NotifyCustomizationModuleChanged(); IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); RegisterMujocoMeshActorConversion(); } void FLuckyMujocoEditorModule::ShutdownModule() { if (FModuleManager::Get().IsModuleLoaded("AssetTools")) { IAssetTools& AssetTools = FModuleManager::GetModuleChecked("AssetTools").Get(); } FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked(TEXT("PropertyEditor")); PropertyModule.UnregisterCustomPropertyTypeLayout("MujocoActuatorV2"); PropertyModule.UnregisterCustomPropertyTypeLayout("MujocoEquality"); PropertyModule.UnregisterCustomPropertyTypeLayout("MujocoTendonSpatialSite"); PropertyModule.UnregisterCustomPropertyTypeLayout("MujocoTendonSpatialGeom"); PropertyModule.UnregisterCustomPropertyTypeLayout("MujocoTendonPulley"); PropertyModule.UnregisterCustomPropertyTypeLayout("MujocoTendonFixedJoint"); PropertyModule.NotifyCustomizationModuleChanged(); } #undef LOCTEXT_NAMESPACE IMPLEMENT_MODULE(FLuckyMujocoEditorModule, LuckyMujocoEditor)