Sorry i am past my morning coffee, so i did not look in your code, however last weekend i had similar problem with my code.
there are things i learned or discovered:
-
all components are initialized before actor, so any begin play or init in actor happens after init code in component. And this is really annoying since nothing short of tick and waiting that 0.2sec, or interface, and actor calling ActorIsReady() in component trough interface works.
-
First you have components init, then actor init, then begin play, then blueprints take over
-
and probably your case: when blueprint is loaded it WIPES all variables (and tags) from what was set in C++
ps.
now i try to read your post again, and make sense (for me) about you problem
Edit.
yes i think blueprint happily wipes C++ set variables.
I managed to slap that stupid blueprints with setting my variables in PostInit
my code to set components tags (after blueprints mercilessly wiped default stuff from C++):
void ACPP_CelestialBody::PostInitializeComponents()
{
Super::PostInitializeComponents();
if (RootGui)
{
// UE_LOG(LogTemp, Warning, TEXT("Post Init Root GUI"));
RootGui->ComponentTags.AddUnique(FName(K2G_MANAGE_ROOT_WIDGET));
}
if (RootVisual)
{
// UE_LOG(LogTemp, Warning, TEXT("Post Init Root Visual"));
RootVisual->ComponentTags.Add(FName(K2G_MANAGE_ROOT_MYMESH));
}
if (BodyMesh)
{
// UE_LOG(LogTemp, Warning, TEXT("Post Init Body Mesh"));
BodyMesh->ComponentTags.Add(FName(K2G_MANAGE_MYMESH));
BodyMesh->ComponentTags.Add(FName(K2G_MANAGE_SCALE));
BodyMesh->ComponentTags.Add(FName(K2G_MANAGE_MATERIAL));
}
NotifyComponentsOwnerIsReady();
}
and:
NotifyComponentsOwnerIsReady();
is that interface function i call to notify them that Really_Real_BeginGame happened, well from for loop inside it.
also my take on default arrays of stuff set in C++ (together with above wat to set defaults from C++ not from blueprints, where wiping or changing defaults happens after for eg. fixing blueprint compile errors from using live coding)
so my struct is like:
struct FPlanetData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Name; // Planet name
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString GamePlayTag; // like sun.earth.moon
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float BodyScale;
// with much more data in struct.
then i make function that sets my array from const like this:
bool UCPP_CommonFunctions::GetCelestialBodyData(const FGameplayTag& GameplayTag, FPlanetData& BodyData)
{
const TArray<FPlanetData> Bodies = {
{ "Sun", "sun.sun", 109.0f, 9, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 609.12f, 7.25f },
then in void ACPP_CelestialBody::PostInitializeComponents() i set that array in spite of blueprints messing it all. And that GameplayTag is for actor to know which one entry it belongs to. And gameplay tag is only one variable i am setting per actor from blueprints.
ps.
i really hate that whole mess: components before actor, begin play almost never being begin play, then blueprints happily assuming what is default state, and happily reverting it to that (unless live coding fails and wipes it again to different state)
pps.
one more tip:
RootGui->ComponentTags.AddUnique(FName(K2G_MANAGE_ROOT_WIDGET));
K2G_MANAGE_ROOT_WIDGET - this is #DEFINE macro to always have same spelling for gameplay tag, limits headaches when seeking for misspelled names