How To Get The Value Of A Component In The Actor?

I Heard Use CastTo In Blueprint Not Good,So I Started Learning C++
I Had A Question,How To Get The Value Of A Component In The Actor?
If I Want To Change This Value,How?
Here Is The Code I Tried To Write

MyBlueprintFunctionLibrary.h

UFUNCTION(BlueprintCallable)
static bool FindComponentValue(AActor* InActor, UClass InComponentClass,FString InComponentStr,FName InPropertyName);
MyBlueprintFunctionLibrary.cpp

bool UMyBlueprintFunctionLibrary::FindComponentValue(AActor* InActor, UClass InComponentClass,FString InComponentStr,FName InPropertyName)
{
    if (InActor == nullptr) return false;

    //Get Actor Class
    UClass* ActorClass = InActor->GetClass();
    if (ActorClass == nullptr) return false;

    //Get Actor Components

    //for Components,Get the component corresponding to the InComponentStr

        //If Get Is True Then Find Component Property Corresponding To The InPropertyName
        
        //If Find Is True Then Print The Value Of The Property Or Set The Value


        return true;
}

Thanks for your help

the first step is to get a hold of the actor (line-trace/collision), UWorld->GetActorOfClass<MyClass>()

if there is only ever to be one of these components on the actor then you can do a
Actor->FindeComponentByClass<UMyCompontent>(), which can be wrapped into an if statement

UMyComponent* GetActorComponent(AActor* inActor)
{
    if( UMyComponent* component = inActor->FindComponentByClass<UMyComonent>())
    {
         return component;
    }
    return nullptr;
}

there is also a plural version of this function but you will have to maybe step through them to find the “correct one”

if you really want to go through with getting properties by string (I would strongly suggest not doing this as it can lead to runtime resolution issues) then you might want to look into the different versions of PostEditChangeProperty, and PostEditChangeChainProplerty, which can deal with explicit properties by string.

the issues you will run into with Properties by string, is that they are absolute, and where this looks to be intended to have Blueprint visibility sometimes strings behave differently between C++ and Blueprints (technically Blueprints hard force ANSI strings, while even with C++ FString these can be treated as C_Strings, but treating an ANSI string as a C_String or visa-versa can have parsing issues.

I would maybe suggest either exposing the given property to Blueprints (either make it public, or use UPROPERTY(meta=(AllowPrivateAccess=true)), or getters for those properties if validation shall be done on Get().

for the function you provided Components they will derive from UActorComponent, and should be passed as pointer.

If there are multiple identical classes,How should I distinguish them?

to distinguish between multiple things, like filtering things in real life, they either need to have something that is a “unique Identifier” (or unique enough) to distinguish them, or they need to be given something that is a “Unique Identifier”, and Actor->GetName doesn’t count because when you give it a name in the outliner that name will be completely different (almost random) during runtime even in PIE. For example if I give an actor (BP_TestingTargetDummy) the name TargetDummy_05 in the Outliner then even in PIE it could have the name BP_TestingTargetDummy_C_UAID_2CF05D6D9973539201_1544992946 which is “similar” to the name it will have in the released version, and GetActorNameOrLable outside of Editor is GetName()

for example if I want to have an Entity Manager, that holds pointers to all the Entities I care about (NPCs and Player to save on the lookups) then I can give them an int32 UniqueID, and I can use that.

if you really want to go down this rabbit whole (I really think you are overcomplicating this) then to get a UClass instance from a string. you will need to take the FString convert that to an FName which you then need to resolve to a UClass each of these steps is technically no more then 2 engine function calls, but they have a big list of things that can go wrong, and should be very strongly typed, and can easily fail. Then you add in how a string entered into a Blueprint is not completely the same as FString in C++.

after going through your initial post on this thread:
‘CastTo in Blueprints is not good’: yeah, kind of; but we are talking about like 5 additional processor cycles, so don’t be using them all the time, but

if ( AMyActor* actor = Cast<AMyActor>(inActor))
{
    // 'this test is to ensure the actor is not being destroyed'
    if ( isValid(actor) )   // there is also actor->IsValid()
    {
    }
}

if you are doing it every frame that is “faster” then the 2 blueprint node equivalent but can still introduce slow down, and should be avoided if possible.

and if this was going to be happening often then taking a String from Blueprints to get a UClass in C++ to then take a String From Blueprints to resolve to a property name in C++ is going to be a LOT slower then those 2 blueprint nodes. not to mention a lot more prone to errors.

can you give a more specific example of what you are trying to accomplish?

I Have A Actor,It Has Multiple ICON(WidgetComponent),I Need To Display One Of These ICON When Line Trace Hit,So My Idea Is To Modify It To Hide Or Show It In The Game When A Line Trace Hit.
I Know The DisplayName Of This Component,I Want To Find The Specific Component By DisplayName And Modify It Property.

Write this in the language I am familiar with

Local ComponentDisplayName = "ICON_1"
Local TheProperty = #ICON_1_State    
Local ThePropertyValue
Local NewValue = {True|False}

For i In Actor.ComponentS Do {
    If i.DisplayName == ComponentDisplayName Then (
        ThePropertyValue = GetComponentProperty(i, TheProperty)
        SetComponentProperty(i, TheProperty, NewValue)
    )
}

I don’t know how to express it in C++

I Was Looking For Documents And Couldn’t Find Any Way To Get ComponentS,Does That Mean I Need To Modify The Source Code To Implement Something Similar To GetComponentByDisplayName()

outside of the Editor GetDisplayName() should be considered random, even the order in the composition hierarchy “may” not be maintained even between different PIE sessions, and unless you are going to sort it the order from a Get Multiple type action should also be considered random.

the only thing about the name that will be consistent is that it shall include the name of the class, which might not be that helpful.

to solve the given situation directly, this can be done in both Blueprints or C++; if you need to have multiple of these Components then if you give either the Actor, or a component that there shall only be one of the reference to all of these icons, you can then access them directly that way.

  • you can put them into a struct, or just given them explicit names.
  • you can have specific function for each one, or a singular function that takes like an enumeration or a down and dirty integer

an example of if the Actor has the references exposed in C++ (this is doable in blueprints as well without any C++)

void TargetEntity(const FVector& Start, const FVector& End)
{
    FHitResult HitResult;
    GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility)
    if( HitResult.bBlockingHit)
    {
        if( AMyActor* OtherActor = Cast<AMyActor>(HitResult.GetActor())
        {
           if( IsValid(OtherActor))
           {
               // first bool is the new visibility state, and the second is if it should be propagated to components/children under it
               OtherActor->Icon5->SetVisibility(true, true);
           }
        }
    }
}

keep in mind that if something is defined in Blueprints then it should be delt with in Blueprints, if at all possible, because the way the reflection system works Blueprints can “easily” see into C++ but it gets very messy very quickly for C++ to try and see into Blueprints (that is technically the situation where your initial desire to try and string resolve Property names but at the very least you would be doing all the work in the C++ which is “easier” but still a headache that can cause frustrations even among experience programmers)

everything in the function I gave above will also work in Blueprints.

there are still other approaches where you give each of these Icons an integer/enumeration which you assign in the Editor manually (again if you are going to be working with these in C++ then you would want to define the Component in C++ as well)

for the ?function? you provided (I don’t completely understand ?Verse?, so this might not completely map)

// 'by giving the AquireTarget a default value you do not have supply the value if you want the default'
void SetTargetLock ( const FVector& Start, const FVector& End, const FString& IconName, bool AquireTarget = true )
{
    FHitResult HitResult;
    GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility)
    if ( HitResult.bBlockingHit && HitResult.GetActor() != nullptr && IsValid(HitResult.GetActor()) )
    {
       TArray<UMyWidgetComponent*> ComponentArray;
       HitResult.GetActor()->GetComponents<UMyWidgetComponent>(ComponentArray);
       for( UMyWidgetComponent* comp : ComponentArray )
       {
            // this presumes that the name will 
            if( comp->GetName() == IconName )
            {
                comp->SetVisibility(AquireTarget, true);
                break;
            }
       }
    }
}

in the long run if you have defined your classes and types in Blueprints, I would suggest doing this in Blueprints, unless there is already a large portion of your project in C++, and redefining an Actor, or a ActorComponent in C++ from Blueprints because the CastTo has a few extra processor cycles and can come with loading a type into memory for the lifetime of the blueprint, is like selling your car because the next model year came out.