More work on blueprint component lists
This commit is contained in:
@@ -9,6 +9,9 @@
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
|
||||
FWingActorComponent::FWingActorComponent(USCS_Node *Node) :
|
||||
SCSNode(Node), Owner(Node->GetSCS()->GetBlueprint()->GeneratedClass) {}
|
||||
|
||||
FString FWingActorComponent::GetName() const
|
||||
{
|
||||
if (SCSNode) return WingUtils::FormatName(SCSNode);
|
||||
@@ -48,56 +51,112 @@ bool FWingActorComponent::IsOwnedBy(const UBlueprint* BP) const
|
||||
return BP && BP->GeneratedClass == Owner;
|
||||
}
|
||||
|
||||
bool FWingActorComponent::SetParent(USCS_Node* ChildNode, const FWingActorComponent* Parent)
|
||||
bool FWingActorComponent::CheckEditableComponent(UBlueprint *BP, const FWingActorComponent *Component)
|
||||
{
|
||||
// Validate before modifying anything
|
||||
if (Parent)
|
||||
if ((!Component) || (Component->IsEmpty()))
|
||||
{
|
||||
if (Parent->SCSNode)
|
||||
{
|
||||
// Check for cycles: walk up from parent to make sure we don't reach the child
|
||||
USCS_Node* Ancestor = Parent->SCSNode;
|
||||
while (Ancestor)
|
||||
{
|
||||
if (Ancestor == ChildNode)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Cannot reparent — would create a cycle.\n"));
|
||||
return false;
|
||||
}
|
||||
Ancestor = Ancestor->GetSCS()->FindParentNode(Ancestor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
USceneComponent* NativeScene = Cast<USceneComponent>(Parent->NativeComponent);
|
||||
if (!NativeScene)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Native parent '%s' is not a SceneComponent — cannot attach to it.\n"),
|
||||
*Parent->GetName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
UWingServer::Printf(TEXT("Component does not exist.\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear any existing parent attachment
|
||||
ChildNode->Modify();
|
||||
ChildNode->bIsParentComponentNative = false;
|
||||
ChildNode->ParentComponentOrVariableName = NAME_None;
|
||||
ChildNode->ParentComponentOwnerClassName = NAME_None;
|
||||
|
||||
if (!Parent)
|
||||
return true;
|
||||
|
||||
if (Parent->SCSNode)
|
||||
if (Component->IsNative())
|
||||
{
|
||||
ChildNode->SetParent(Parent->SCSNode);
|
||||
return true;
|
||||
UWingServer::Printf(TEXT("Cannot edit native components.\n"));
|
||||
return false;
|
||||
}
|
||||
if (!Component->IsOwnedBy(BP))
|
||||
{
|
||||
UWingServer::Printf(TEXT("Component %s is inherited, to edit it, you must edit BP %s\n"),
|
||||
*WingUtils::FormatName(*Component), *WingUtils::FormatName(Component->Owner));
|
||||
return false;
|
||||
}
|
||||
|
||||
ChildNode->SetParent(Cast<USceneComponent>(Parent->NativeComponent));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWingActorComponent::CheckValidParent(const FWingActorComponent *Parent)
|
||||
{
|
||||
if ((!Parent) || (Parent->IsEmpty()))
|
||||
{
|
||||
UWingServer::Printf(TEXT("Cannot create a component without a parent.\n"));
|
||||
return false;
|
||||
}
|
||||
if (Parent->IsNative() && (!Parent->NativeComponent->GetClass()->IsChildOf(USceneComponent::StaticClass())))
|
||||
{
|
||||
UWingServer::Printf(TEXT("Native component %s is not a scene component, cannot be a parent."),
|
||||
*WingUtils::FormatName(Parent->NativeComponent));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWingActorComponent::CheckValidComponentClass(UClass *Class)
|
||||
{
|
||||
if (!Class->IsChildOf(UActorComponent::StaticClass()))
|
||||
{
|
||||
UWingServer::Printf(TEXT("Cannot create a component of class %s, which is not an actor component.\n"),
|
||||
*WingUtils::FormatName(Class));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FWingActorComponent::AddNodeInternal(UBlueprint *BP, USCS_Node *NewNode, const FWingActorComponent *Parent)
|
||||
{
|
||||
if (Parent->SCSNode && Parent->IsOwnedBy(BP))
|
||||
{
|
||||
Parent->SCSNode->AddChildNode(NewNode, true);
|
||||
}
|
||||
else if (Parent->SCSNode)
|
||||
{
|
||||
NewNode->SetParent(Parent->SCSNode);
|
||||
BP->SimpleConstructionScript->AddNode(NewNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewNode->SetParent(Cast<USceneComponent>(Parent->NativeComponent));
|
||||
BP->SimpleConstructionScript->AddNode(NewNode);
|
||||
}
|
||||
}
|
||||
|
||||
USCS_Node *FWingActorComponent::AddComponent(UBlueprint *BP, UClass *Class, const FWingActorComponent* Parent, const FString &Name)
|
||||
{
|
||||
if (!CheckValidParent(Parent)) return nullptr;
|
||||
if (!CheckValidComponentClass(Class)) return nullptr;
|
||||
|
||||
USCS_Node *NewNode = BP->SimpleConstructionScript->CreateNode(Class, FName(*Name));
|
||||
if (NewNode == nullptr)
|
||||
{
|
||||
UWingServer::Printf(TEXT("Could not create new component %s of class %s, unknown reason.\n"),
|
||||
*Name, *WingUtils::FormatName(Class));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AddNodeInternal(BP, NewNode, Parent);
|
||||
return NewNode;
|
||||
}
|
||||
|
||||
bool FWingActorComponent::ReparentComponent(UBlueprint *BP, USCS_Node *SCSNode, const FWingActorComponent* Parent)
|
||||
{
|
||||
FWingActorComponent Component(SCSNode);
|
||||
if (!CheckEditableComponent(BP, &Component)) return false;
|
||||
if (!CheckValidParent(Parent)) return false;
|
||||
|
||||
if (Parent->SCSNode == SCSNode)
|
||||
{
|
||||
UWingServer::Printf(TEXT("You may not parent a component to itself.\n"));
|
||||
return false;
|
||||
}
|
||||
if (Parent->SCSNode && Parent->SCSNode->IsChildOf(SCSNode))
|
||||
{
|
||||
UWingServer::Printf(TEXT("You may not parent a component to one of its own children.\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
BP->SimpleConstructionScript->RemoveNode(SCSNode);
|
||||
AddNodeInternal(BP, SCSNode, Parent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
TArray<FWingActorComponent> FWingActorComponent::GetAll(UBlueprint* BP)
|
||||
{
|
||||
TArray<FWingActorComponent> Result;
|
||||
@@ -123,9 +182,8 @@ TArray<FWingActorComponent> FWingActorComponent::GetAll(UBlueprint* BP)
|
||||
{
|
||||
UBlueprint* WalkBP = Hierarchy[i];
|
||||
if (!WalkBP->SimpleConstructionScript) continue;
|
||||
UClass* OwnerClass = WalkBP->GeneratedClass;
|
||||
for (USCS_Node* Node : WalkBP->SimpleConstructionScript->GetAllNodes())
|
||||
Result.Emplace(Node, OwnerClass);
|
||||
Result.Emplace(Node);
|
||||
}
|
||||
|
||||
return Result;
|
||||
|
||||
@@ -115,20 +115,15 @@ WingFetcher& WingFetcher::Asset(const FString& PackagePath)
|
||||
{
|
||||
if (bError) return *this;
|
||||
|
||||
// Try to find the object in memory first (silent), then load if needed.
|
||||
// LoadObject logs its own errors when the package doesn't exist, so
|
||||
// we check DoesPackageExist first to avoid redundant log spam.
|
||||
SetObj(FindObject<UObject>(nullptr, *PackagePath));
|
||||
if (!Obj)
|
||||
// Check if the package exists before calling LoadObject, because
|
||||
// LoadObject logs its own errors when the package doesn't exist.
|
||||
FString PackageName = FPackageName::ObjectPathToPackageName(PackagePath);
|
||||
if (!FPackageName::DoesPackageExist(PackageName))
|
||||
{
|
||||
FString PackageName = FPackageName::ObjectPathToPackageName(PackagePath);
|
||||
if (!FPackageName::DoesPackageExist(PackageName))
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Asset '%s' does not exist.\n"), *PackagePath);
|
||||
return SetError();
|
||||
}
|
||||
SetObj(LoadObject<UObject>(nullptr, *PackagePath));
|
||||
UWingServer::Printf(TEXT("ERROR: Asset '%s' does not exist.\n"), *PackagePath);
|
||||
return SetError();
|
||||
}
|
||||
SetObj(LoadObject<UObject>(nullptr, *PackagePath));
|
||||
if (!Obj)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Could not load asset '%s'\n"), *PackagePath);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Materials/MaterialExpression.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "MaterialEditingLibrary.h"
|
||||
#include "Subsystems/AssetEditorSubsystem.h"
|
||||
|
||||
void FWingNotifier::AddTouchedObject(UObject* Obj)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user