Help with Actor Representation not updating on Mini Map

Hey all! Since yesterday I have been working on this code. My goal is: If a wheeled vehicle (tractor, truck or explorer) have a Path loaded in, it will show the name of the path as the name of the vehicle in the Map/Compass. This is my current C++ Code (All temporary, it's mainly for me to understand how the systems work and what the functions do) The output shows that I managed to update the actor name of the vehicle correctly, I managed to find the representation of the actor correctly as well, but when I update the representation, nothing happens in the game map, the map marker stays as "Tractor" I thought that changing the vehicle name would change the whole "Tooltip content" chain, but doesn't look like. Also when I hook into Hook_GetActorRepresentationText the vehicle object is always null for some reason that I couldn't understand Can anyone give me a direction on what to do? I'm a bit lost now. Thank you
193 Replies
Vanzin
VanzinOP4w ago
Update: I'm pretty sure that this function is the one used to get the marker tooltip text (because when I hook and override it I can see the change in the map):
/** This is the text to render in the compass */
UFUNCTION( BlueprintPure, Category = "Representation" )
virtual FText GetRepresentationText() const;
/** This is the text to render in the compass */
UFUNCTION( BlueprintPure, Category = "Representation" )
virtual FText GetRepresentationText() const;
Funny thing is by using the Accessors, I got access to the
/** This is the text to show for this actor representation */
UPROPERTY( Replicated )
FText mRepresentationText;
/** This is the text to show for this actor representation */
UPROPERTY( Replicated )
FText mRepresentationText;
and the
/** The human readable name for this vehicle. */
UPROPERTY( BlueprintReadOnly, EditDefaultsOnly, Category = "Vehicle" )
FText mDisplayName;
/** The human readable name for this vehicle. */
UPROPERTY( BlueprintReadOnly, EditDefaultsOnly, Category = "Vehicle" )
FText mDisplayName;
Even changing both of them with the new accessors and updating the representation object:
vehicle->SetmDisplayName(newVehicleName);
rep->SetmRepresentationText(newVehicleName);
representationManager->UpdateRepresentation(rep);

TArray<UFGActorRepresentation*> ActorRepresentations;
representationManager->GetAllActorRepresentations(ActorRepresentations);

for (UFGActorRepresentation* repInternal : ActorRepresentations)
{
FText repName = repInternal->GetRepresentationText();
UE_LOGFMT(YouNameItLog, Verbose, "Rep Internal: {0}", *repName.ToString());
}
vehicle->SetmDisplayName(newVehicleName);
rep->SetmRepresentationText(newVehicleName);
representationManager->UpdateRepresentation(rep);

TArray<UFGActorRepresentation*> ActorRepresentations;
representationManager->GetAllActorRepresentations(ActorRepresentations);

for (UFGActorRepresentation* repInternal : ActorRepresentations)
{
FText repName = repInternal->GetRepresentationText();
UE_LOGFMT(YouNameItLog, Verbose, "Rep Internal: {0}", *repName.ToString());
}
I still get the word "Tractor" instead -.- I will keep investigating 🥲 I feel that I'm almost there Might be that this is related to network as well, I saw some representations that are replicated. Oh no
Archengius
Archengius4w ago
mRepresentationText is re-read from the representation object each time the representation is updated. you should not touch that field.
Vanzin
VanzinOP4w ago
Even setting it in the representation object itself? rep->SetmRepresentationText(newVehicleName);
Archengius
Archengius4w ago
sorry, I was not clear, when i was talking about representation object i meant the represented object which is this object for wheeled vehicles
Archengius
Archengius4w ago
so you might want to probably either hook GetActorRepresentationText there or see what it returns and override that
Vanzin
VanzinOP4w ago
I did already and it works if I override the scope return But then I was thinking as that method is called many times, it would be better to somehow replace the value where that method gets it from
Archengius
Archengius4w ago
it is called once when the representation is updated you are good with just hooking it all of this data is cached
Vanzin
VanzinOP4w ago
Ok then! I will try out this way I was also thinking in adding a text field in the vehicle UI so the player can give it a custom name (like in trains for example), that's why I went down the path of replacing the value in the representation object
Archengius
Archengius4w ago
if you really want to go crazy you can override AFGWheeledVehicleInfo::AddRepresentation and make it use your own representation subclass then you can alter all aspects of how the representation appears on the map and the compass well, mostly compass, map is a bit hard-coded right now
Rex
Rex4w ago
Is it easy to replace the AFGWheeledVehicleInfo class a base game vehicle uses?
Archengius
Archengius4w ago
probably not and i don't really see why you would want to
Vanzin
VanzinOP4w ago
You meant AddAsRepresentation right?
Archengius
Archengius4w ago
yeah representation system nowadays is very powerful and allows you to do some really cool things
Vanzin
VanzinOP4w ago
So basically I would override the AFGWheeledVehicleInfo::AddAsRepresentation, create my own version of the UFGActorRepresentation with the whatever naming I need/want and then call AFGActorRepresentationManager::AddRepresentation Am I in the right path? 😂
Archengius
Archengius4w ago
yeah might want to derive from wheeled vehicle representation specifically tho it has it's own small custom behavior
Vanzin
VanzinOP4w ago
Thank you very much for the explanation @Archengius! This will take me some hours to try out now :LUL: Ok, this is what I got so far...
#pragma once

#include "YouNameIt.h"
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
#include "Representation/FGWheeledVehicleRepresentation.h"
#include "UCWheeledVehicleRepresentation.generated.h"

UCLASS()
class YOUNAMEIT_API UCWheeledVehicleRepresentation : public UFGWheeledVehicleRepresentation
{
GENERATED_BODY()
public:
UCWheeledVehicleRepresentation();

// Override any functions you need to customize, for example:
virtual FText GetRepresentationText() const override;
};
#pragma once

#include "YouNameIt.h"
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
#include "Representation/FGWheeledVehicleRepresentation.h"
#include "UCWheeledVehicleRepresentation.generated.h"

UCLASS()
class YOUNAMEIT_API UCWheeledVehicleRepresentation : public UFGWheeledVehicleRepresentation
{
GENERATED_BODY()
public:
UCWheeledVehicleRepresentation();

// Override any functions you need to customize, for example:
virtual FText GetRepresentationText() const override;
};
#include "UCWheeledVehicleRepresentation.h"

UCWheeledVehicleRepresentation::UCWheeledVehicleRepresentation() : UFGWheeledVehicleRepresentation()
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("UCustomWheeledVehicleRepresentation"));
}

FText UCWheeledVehicleRepresentation::GetRepresentationText() const
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("UCustomWheeledVehicleRepresentation::GetRepresentationText"));

return FText::FromString("Custom Vehicle Name");
}
#include "UCWheeledVehicleRepresentation.h"

UCWheeledVehicleRepresentation::UCWheeledVehicleRepresentation() : UFGWheeledVehicleRepresentation()
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("UCustomWheeledVehicleRepresentation"));
}

FText UCWheeledVehicleRepresentation::GetRepresentationText() const
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("UCustomWheeledVehicleRepresentation::GetRepresentationText"));

return FText::FromString("Custom Vehicle Name");
}
// AFGWheeledVehicleInfo
// virtual bool AddAsRepresentation() override;
static void Hook_AddAsRepresentation(TCallScope<bool(__cdecl*)(AFGWheeledVehicleInfo*)>& scope, AFGWheeledVehicleInfo* self)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("Hook_AddAsRepresentation"));

UCWheeledVehicleRepresentation* Representation = NewObject<UCWheeledVehicleRepresentation>();
Representation->SetupActorRepresentation(self, false);

if (self->HasAuthority())
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("OnServer"));

UWorld* WorldObject = self->GetWorld();
AFGActorRepresentationManager* RepresentationManager = AFGActorRepresentationManager::Get(WorldObject);
if (RepresentationManager)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("AFGActorRepresentationManager is set"));
UE_LOG(YouNameIt_Log, Verbose, TEXT("Representation Text is: %s"), *Representation->GetRepresentationText().ToString());

RepresentationManager->AddRepresentation(Representation);
RepresentationManager->DumpActorRepresentations();
}
}
else
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("OnClient"));
}
}
// AFGWheeledVehicleInfo
// virtual bool AddAsRepresentation() override;
static void Hook_AddAsRepresentation(TCallScope<bool(__cdecl*)(AFGWheeledVehicleInfo*)>& scope, AFGWheeledVehicleInfo* self)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("Hook_AddAsRepresentation"));

UCWheeledVehicleRepresentation* Representation = NewObject<UCWheeledVehicleRepresentation>();
Representation->SetupActorRepresentation(self, false);

if (self->HasAuthority())
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("OnServer"));

UWorld* WorldObject = self->GetWorld();
AFGActorRepresentationManager* RepresentationManager = AFGActorRepresentationManager::Get(WorldObject);
if (RepresentationManager)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("AFGActorRepresentationManager is set"));
UE_LOG(YouNameIt_Log, Verbose, TEXT("Representation Text is: %s"), *Representation->GetRepresentationText().ToString());

RepresentationManager->AddRepresentation(Representation);
RepresentationManager->DumpActorRepresentations();
}
}
else
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("OnClient"));
}
}
But it's crashing:
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000038

FactoryGameEGS_FactoryGame_Win64_Shipping!UFGActorRepresentation::SetupActorRepresentation() [C:\BuildAgent\work\b731a33f2a691e17\UE4\FactoryGame\Source\FactoryGame\Private\FGActorRepresentation.cpp:76]
FactoryGameEGS_YouNameIt_Win64_Shipping!HYouNameIt::Hook_AddAsRepresentation() [D:\Satisfactory\Mods\SatisfactoryModLoader\Mods\YouNameIt\Source\YouNameIt\Private\YouNameIt.cpp:32]
FactoryGameEGS_YouNameIt_Win64_Shipping!HookInvokerExecutorMemberFunction<bool (__cdecl AFGWheeledVehicleInfo::*)(void),{AFGWheeledVehicleInfo::`vcall'{16}',912},0,bool,AFGWheeledVehicleInfo>::ApplyCallScalar() [D:\Satisfactory\Mods\SatisfactoryModLoader\Mods\SML\Source\SML\Public\Patching\NativeHookManager.h:433]
FactoryGameEGS_Engine_Win64_Shipping!AActor::DispatchBeginPlay() [C:\BuildAgent\work\b731a33f2a691e17\UE4\Engine\Source\Runtime\Engine\Private\Actor.cpp:4249]
FactoryGameEGS_Engine_Win64_Shipping!AWorldSettings::NotifyBeginPlay() [C:\BuildAgent\work\b731a33f2a691e17\UE4\Engine\Source\Runtime\Engine\Private\WorldSettings.cpp:301]
Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000038

FactoryGameEGS_FactoryGame_Win64_Shipping!UFGActorRepresentation::SetupActorRepresentation() [C:\BuildAgent\work\b731a33f2a691e17\UE4\FactoryGame\Source\FactoryGame\Private\FGActorRepresentation.cpp:76]
FactoryGameEGS_YouNameIt_Win64_Shipping!HYouNameIt::Hook_AddAsRepresentation() [D:\Satisfactory\Mods\SatisfactoryModLoader\Mods\YouNameIt\Source\YouNameIt\Private\YouNameIt.cpp:32]
FactoryGameEGS_YouNameIt_Win64_Shipping!HookInvokerExecutorMemberFunction<bool (__cdecl AFGWheeledVehicleInfo::*)(void),{AFGWheeledVehicleInfo::`vcall'{16}',912},0,bool,AFGWheeledVehicleInfo>::ApplyCallScalar() [D:\Satisfactory\Mods\SatisfactoryModLoader\Mods\SML\Source\SML\Public\Patching\NativeHookManager.h:433]
FactoryGameEGS_Engine_Win64_Shipping!AActor::DispatchBeginPlay() [C:\BuildAgent\work\b731a33f2a691e17\UE4\Engine\Source\Runtime\Engine\Private\Actor.cpp:4249]
FactoryGameEGS_Engine_Win64_Shipping!AWorldSettings::NotifyBeginPlay() [C:\BuildAgent\work\b731a33f2a691e17\UE4\Engine\Source\Runtime\Engine\Private\WorldSettings.cpp:301]
I think I'm not initializing the Custom Representation class correctly. Feels like a null pointer because I missed setting something If you have any idea why, please let me know, I will keep trying Ok, no progress so far, I'm stuck :Sadge:
Archengius
Archengius4w ago
you are using wrong functions. You only need to call AFGActorRepresentationManager::CreateAndAddNewRepresentation and nothing else you also do not really need to check HasAuthority, this function will never be called on the client i'm pretty sure
Vanzin
VanzinOP4w ago
Ah ok! Thanks for the hint! I updated the code to this:
static void Hook_AddAsRepresentation(TCallScope<bool(__cdecl*)(AFGWheeledVehicleInfo*)>& scope, AFGWheeledVehicleInfo* self)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("Hook_AddAsRepresentation"));
UE_LOG(YouNameIt_Log, Verbose, TEXT("Is Server? %s"), (self->HasAuthority() ? TEXT("true") : TEXT("false")));

UWorld* WorldObject = self->GetWorld();
UE_LOG(YouNameIt_Log, Verbose, TEXT("WorldObject Is Set? %s"), (WorldObject ? TEXT("true") : TEXT("false")));

AFGActorRepresentationManager* RepresentationManager = AFGActorRepresentationManager::Get(WorldObject);

if (RepresentationManager)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("AFGActorRepresentationManager is set"));

TSubclassOf<UCWheeledVehicleRepresentation> RepresentationClass = UCWheeledVehicleRepresentation::StaticClass();
UFGActorRepresentation* Representation = RepresentationManager->CreateAndAddNewRepresentation(self, false, RepresentationClass);

UE_LOG(YouNameIt_Log, Verbose, TEXT("Representation Text is: %s"), *Representation->GetRepresentationText().ToString());

RepresentationManager->DumpActorRepresentations();
scope.Override(true);
}

UE_LOG(YouNameIt_Log, Verbose, TEXT("AFGActorRepresentationManager is not set"));
scope.Override(false);
}
static void Hook_AddAsRepresentation(TCallScope<bool(__cdecl*)(AFGWheeledVehicleInfo*)>& scope, AFGWheeledVehicleInfo* self)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("Hook_AddAsRepresentation"));
UE_LOG(YouNameIt_Log, Verbose, TEXT("Is Server? %s"), (self->HasAuthority() ? TEXT("true") : TEXT("false")));

UWorld* WorldObject = self->GetWorld();
UE_LOG(YouNameIt_Log, Verbose, TEXT("WorldObject Is Set? %s"), (WorldObject ? TEXT("true") : TEXT("false")));

AFGActorRepresentationManager* RepresentationManager = AFGActorRepresentationManager::Get(WorldObject);

if (RepresentationManager)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("AFGActorRepresentationManager is set"));

TSubclassOf<UCWheeledVehicleRepresentation> RepresentationClass = UCWheeledVehicleRepresentation::StaticClass();
UFGActorRepresentation* Representation = RepresentationManager->CreateAndAddNewRepresentation(self, false, RepresentationClass);

UE_LOG(YouNameIt_Log, Verbose, TEXT("Representation Text is: %s"), *Representation->GetRepresentationText().ToString());

RepresentationManager->DumpActorRepresentations();
scope.Override(true);
}

UE_LOG(YouNameIt_Log, Verbose, TEXT("AFGActorRepresentationManager is not set"));
scope.Override(false);
}
But looks like I never manage to get the instance of the Representation Manager
No description
Archengius
Archengius4w ago
Interesting. It should generally always be set.
Vanzin
VanzinOP4w ago
I found this from someone called Archengius :LUL: : https://github.com/Archengius/BPPseudoCodeGen/blob/0baffb28ccc98daad944e688a2f4089b4052ffd1/Outputs/Game/FactoryGame/Character/Player/BP_DeathMarker.BP_DeathMarker_C.txt#L124-L132 But it's 4 years old, so, not sure if is still correct. But here it also checks for the HasAuthority() I have been searching for examples in github, that's why I found this 😂
Rex
Rex4w ago
From what I see in the code, it retrieves the AFGActorRepresentationManager from the game state (AFGGameState)
Vanzin
VanzinOP4w ago
But the method signature uses the UWorld:
AFGActorRepresentationManager* AFGActorRepresentationManager::Get(UWorld* world){ return nullptr; }
or
AFGActorRepresentationManager* AFGActorRepresentationManager::Get(UObject* worldContext){ return nullptr; }
AFGActorRepresentationManager* AFGActorRepresentationManager::Get(UWorld* world){ return nullptr; }
or
AFGActorRepresentationManager* AFGActorRepresentationManager::Get(UObject* worldContext){ return nullptr; }
Not sure if you mean even deeper in the code
Rex
Rex4w ago
I decompiled the actual code What you see there is a stub, a placeholder to make the headers compile
Vanzin
VanzinOP4w ago
I guess there is no tutorial on how to do this right? 😂
Rex
Rex4w ago
It's neither easy nor self-explanatory In case you're curious, this is what the original implementations probably looked like
AFGActorRepresentationManager* AFGActorRepresentationManager::Get(UWorld* world)
{
if (IsValid(world)) {
if (AFGGameState* GameState = Cast<AFGGameState>(world->GameState)) {
return GameState->GetActorRepresentationManager();
}
}
return nullptr;
}

AFGActorRepresentationManager* AFGActorRepresentationManager::Get(UObject* worldContext)
{
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull)) {
if (AFGGameState* GameState = Cast<AFGGameState>(World->GameState)) {
return GameState->GetActorRepresentationManager();
}
}
return nullptr;
}
AFGActorRepresentationManager* AFGActorRepresentationManager::Get(UWorld* world)
{
if (IsValid(world)) {
if (AFGGameState* GameState = Cast<AFGGameState>(world->GameState)) {
return GameState->GetActorRepresentationManager();
}
}
return nullptr;
}

AFGActorRepresentationManager* AFGActorRepresentationManager::Get(UObject* worldContext)
{
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull)) {
if (AFGGameState* GameState = Cast<AFGGameState>(World->GameState)) {
return GameState->GetActorRepresentationManager();
}
}
return nullptr;
}
This is what the decompiler shows me:
AFGActorRepresentationManager * __cdecl AFGActorRepresentationManager::Get(UWorld *param_1)

{
TObjectPtr<> *this;
bool bVar1;
UClass *pUVar2;

/* 0x4fc7d0 16222 ?Get@AFGActorRepresentationManager@@SAPEAV1@PEAVUWorld@@@Z */
if (((param_1 != NULL) && ((*(uint *)&param_1->field_0x8 & 0x60000000) == 0)) &&
(this = &param_1->GameState, (this->field0_0x0).DebugPtr != NULL)) {
pUVar2 = AFGGameState::GetPrivateStaticClass();
bVar1 = FObjectPtr::IsA((FObjectPtr *)this,pUVar2);
if ((bVar1) && ((this->field0_0x0).DebugPtr != NULL)) {
return *(AFGActorRepresentationManager **)&(this->field0_0x0).DebugPtr[1].field_0x150;
}
}
return NULL;
}

AFGActorRepresentationManager * __cdecl AFGActorRepresentationManager::Get(UObject *param_1)

{
TObjectPtr<> *this;
bool bVar1;
UWorld *pUVar2;
UClass *pUVar3;

/* 0x4fc750 16221 ?Get@AFGActorRepresentationManager@@SAPEAV1@PEAVUObject@@@Z */
pUVar2 = UEngine::GetWorldFromContextObject(*(UEngine **)GEngine_exref,(UObject *)param_1,ReturnNull);
if (pUVar2 == NULL) {
return NULL;
}
if (((*(uint *)&pUVar2->field_0x8 & 0x60000000) == 0) &&
(this = &pUVar2->GameState, (this->field0_0x0).DebugPtr != NULL)) {
pUVar3 = AFGGameState::GetPrivateStaticClass();
bVar1 = FObjectPtr::IsA((FObjectPtr *)this,pUVar3);
if ((bVar1) && ((this->field0_0x0).DebugPtr != NULL)) {
return *(AFGActorRepresentationManager **)&(this->field0_0x0).DebugPtr[1].field_0x150;
}
}
return NULL;
}
AFGActorRepresentationManager * __cdecl AFGActorRepresentationManager::Get(UWorld *param_1)

{
TObjectPtr<> *this;
bool bVar1;
UClass *pUVar2;

/* 0x4fc7d0 16222 ?Get@AFGActorRepresentationManager@@SAPEAV1@PEAVUWorld@@@Z */
if (((param_1 != NULL) && ((*(uint *)&param_1->field_0x8 & 0x60000000) == 0)) &&
(this = &param_1->GameState, (this->field0_0x0).DebugPtr != NULL)) {
pUVar2 = AFGGameState::GetPrivateStaticClass();
bVar1 = FObjectPtr::IsA((FObjectPtr *)this,pUVar2);
if ((bVar1) && ((this->field0_0x0).DebugPtr != NULL)) {
return *(AFGActorRepresentationManager **)&(this->field0_0x0).DebugPtr[1].field_0x150;
}
}
return NULL;
}

AFGActorRepresentationManager * __cdecl AFGActorRepresentationManager::Get(UObject *param_1)

{
TObjectPtr<> *this;
bool bVar1;
UWorld *pUVar2;
UClass *pUVar3;

/* 0x4fc750 16221 ?Get@AFGActorRepresentationManager@@SAPEAV1@PEAVUObject@@@Z */
pUVar2 = UEngine::GetWorldFromContextObject(*(UEngine **)GEngine_exref,(UObject *)param_1,ReturnNull);
if (pUVar2 == NULL) {
return NULL;
}
if (((*(uint *)&pUVar2->field_0x8 & 0x60000000) == 0) &&
(this = &pUVar2->GameState, (this->field0_0x0).DebugPtr != NULL)) {
pUVar3 = AFGGameState::GetPrivateStaticClass();
bVar1 = FObjectPtr::IsA((FObjectPtr *)this,pUVar3);
if ((bVar1) && ((this->field0_0x0).DebugPtr != NULL)) {
return *(AFGActorRepresentationManager **)&(this->field0_0x0).DebugPtr[1].field_0x150;
}
}
return NULL;
}
Actually, I think I omitted a check: second function checks object flags on the world So that you have an idea, ((param_1 != NULL) && ((*(uint *)&param_1->field_0x8 & 0x60000000) == 0) is equivalent to IsValid(param_1)
Vanzin
VanzinOP4w ago
You rewrote this output from the decompiler manually?
Rex
Rex4w ago
Yes And the decompiler output for these functions looks pretty good already
Archengius
Archengius4w ago
vanilla code is just this
if( AFGActorRepresentationManager* manager = AFGActorRepresentationManager::Get( this ) )
{
return manager->CreateAndAddNewRepresentation( this, false, UFGWheeledVehicleRepresentation::StaticClass() ) != nullptr;
}
if( AFGActorRepresentationManager* manager = AFGActorRepresentationManager::Get( this ) )
{
return manager->CreateAndAddNewRepresentation( this, false, UFGWheeledVehicleRepresentation::StaticClass() ) != nullptr;
}
so I am struggling to see how you're getting null there if you replace world context with just self it should work
Vanzin
VanzinOP4w ago
I tried that but I can't remember the output I will do it again
Rex
Rex4w ago
Is this on a multiplayer client? I see the actor doesn't have authority for some reason
Vanzin
VanzinOP4w ago
No, Singleplayer in my machine (only 1 instance) Crashed
Vanzin
VanzinOP4w ago
Just for matters of updating you, this is the current code:
Vanzin
VanzinOP4w ago
And before the crash, this was the output:
No description
Rex
Rex4w ago
Hmmm, I feel that self isn't fully initialised yet
Vanzin
VanzinOP4w ago
I ran again just to be sure, I did the exact same thing in game (build a tractor) and now this
No description
Vanzin
VanzinOP4w ago
vehicle was set somehow in the previous run, now is not anymore
Vanzin
VanzinOP4w ago
As it didn't crash, I waited a bit and tried again, crashed now:
No description
Vanzin
VanzinOP4w ago
So I think you are correct @Rex [they/them]
AFGWheeledVehicle* Vehicle = self->GetVehicle();
AFGWheeledVehicle* Vehicle = self->GetVehicle();
This is the call that get the vehicle object
Rex
Rex4w ago
This puzzles me
FactoryGameEGS_FactoryGame_Win64_Shipping!AFGWheeledVehicleInfo::execGetVehicleStatus() [C:\BuildAgent\work\b731a33f2a691e17\UE4\FactoryGame\Intermediate\Build\Win64\FactoryGameEGS\Inc\FactoryGame\UHT\FGWheeledVehicleInfo.gen.cpp:178]
FactoryGameEGS_Engine_Win64_Shipping!UEngine::GetWorldFromContextObject() [C:\BuildAgent\work\b731a33f2a691e17\UE4\Engine\Source\Runtime\Engine\Private\UnrealEngine.cpp:13263]
FactoryGameEGS_FactoryGame_Win64_Shipping!AFGActorRepresentationManager::Get() [C:\BuildAgent\work\b731a33f2a691e17\UE4\FactoryGame\Source\FactoryGame\Private\FGActorRepresentationManager.cpp:575]
FactoryGameEGS_YouNameIt_Win64_Shipping!HYouNameIt::Hook_AddAsRepresentation() [D:\Satisfactory\Mods\SatisfactoryModLoader\Mods\YouNameIt\Source\YouNameIt\Private\YouNameIt.cpp:43]
FactoryGameEGS_FactoryGame_Win64_Shipping!AFGWheeledVehicleInfo::execGetVehicleStatus() [C:\BuildAgent\work\b731a33f2a691e17\UE4\FactoryGame\Intermediate\Build\Win64\FactoryGameEGS\Inc\FactoryGame\UHT\FGWheeledVehicleInfo.gen.cpp:178]
FactoryGameEGS_Engine_Win64_Shipping!UEngine::GetWorldFromContextObject() [C:\BuildAgent\work\b731a33f2a691e17\UE4\Engine\Source\Runtime\Engine\Private\UnrealEngine.cpp:13263]
FactoryGameEGS_FactoryGame_Win64_Shipping!AFGActorRepresentationManager::Get() [C:\BuildAgent\work\b731a33f2a691e17\UE4\FactoryGame\Source\FactoryGame\Private\FGActorRepresentationManager.cpp:575]
FactoryGameEGS_YouNameIt_Win64_Shipping!HYouNameIt::Hook_AddAsRepresentation() [D:\Satisfactory\Mods\SatisfactoryModLoader\Mods\YouNameIt\Source\YouNameIt\Private\YouNameIt.cpp:43]
Vanzin
VanzinOP4w ago
I don't have a lot of knowledge yet, but it really feels like something was still loading/populating objects. Because in my previous save I had vehicles created already (saved) and it was crashing right after loading the session. Now I created a new save and I don't have any vehicle, that's how I managed to see that difference of the Vehicle being set or not
Rex
Rex4w ago
Is the crash info correct? I'm not seeing how the heck UEngine::GetWorldFromContextObject could possibly call AFGWheeledVehicleInfo::execGetVehicleStatus()
Vanzin
VanzinOP4w ago
I will make it crash again and copy, one minute
Vanzin
VanzinOP4w ago
No description
Vanzin
VanzinOP4w ago
Next test (I waited for some minutes before creating a tractor)
Vanzin
VanzinOP4w ago
No description
Vanzin
VanzinOP4w ago
So far what I could see is: self->GetVehicle(); returns a nullptr right after loading a savegame
Rex
Rex4w ago
I still don't understand the callstack You could open up the minidump file in VS, it's in Saved/Crashes (sort by most recent modification date)
Vanzin
VanzinOP4w ago
Ok, it's huge, what do you want to see specifically?
Rex
Rex4w ago
The minidump file can be opened in VS And you can run the debugger on that to see what happened
Vanzin
VanzinOP4w ago
Yes, I opened it, but it's a UI with a lot of dlls infos Uff, ok, let me see how can I do that
Vanzin
VanzinOP4w ago
I guess is here... Which one?
No description
Rex
Rex4w ago
Native Only
Vanzin
VanzinOP4w ago
No description
Vanzin
VanzinOP4w ago
Do you need the logs?
Rex
Rex4w ago
You'd want to look at the call stack and the local variables I don't have much time atm, unfortunately
Vanzin
VanzinOP4w ago
No problem at all! Thanks for the help Rex Feels like a Déjà vu The FGWheeledVehicle should have access to the GetWorld method right?
Archengius
Archengius4w ago
yes
Vanzin
VanzinOP4w ago
I'm lost :LUL:
Vanzin
VanzinOP4w ago
No description
Vanzin
VanzinOP4w ago
AFGWheeledVehicle* Vehicle = self->GetVehicle();
if (Vehicle != nullptr)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("Vehicle is set"));

UWorld* WorldObject = Vehicle->GetWorld();
UE_LOG(YouNameIt_Log, Verbose, TEXT("WorldObject Is Set? %s"), (WorldObject != nullptr ? TEXT("true") : TEXT("false")));

AFGActorRepresentationManager* RepresentationManager = AFGActorRepresentationManager::Get(WorldObject);
if (RepresentationManager != nullptr)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("AFGActorRepresentationManager is set"));

TSubclassOf<UCWheeledVehicleRepresentation> RepresentationClass = UCWheeledVehicleRepresentation::StaticClass();
UFGActorRepresentation* Representation = RepresentationManager->CreateAndAddNewRepresentation(self, false, RepresentationClass);

UE_LOG(YouNameIt_Log, Verbose, TEXT("Representation Text is: %s"), *Representation->GetRepresentationText().ToString());

RepresentationManager->DumpActorRepresentations();
scope.Override(true);
}

UE_LOG(YouNameIt_Log, Verbose, TEXT("AFGActorRepresentationManager is not set"));
}
else
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("Vehicle is not set"));
}
AFGWheeledVehicle* Vehicle = self->GetVehicle();
if (Vehicle != nullptr)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("Vehicle is set"));

UWorld* WorldObject = Vehicle->GetWorld();
UE_LOG(YouNameIt_Log, Verbose, TEXT("WorldObject Is Set? %s"), (WorldObject != nullptr ? TEXT("true") : TEXT("false")));

AFGActorRepresentationManager* RepresentationManager = AFGActorRepresentationManager::Get(WorldObject);
if (RepresentationManager != nullptr)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("AFGActorRepresentationManager is set"));

TSubclassOf<UCWheeledVehicleRepresentation> RepresentationClass = UCWheeledVehicleRepresentation::StaticClass();
UFGActorRepresentation* Representation = RepresentationManager->CreateAndAddNewRepresentation(self, false, RepresentationClass);

UE_LOG(YouNameIt_Log, Verbose, TEXT("Representation Text is: %s"), *Representation->GetRepresentationText().ToString());

RepresentationManager->DumpActorRepresentations();
scope.Override(true);
}

UE_LOG(YouNameIt_Log, Verbose, TEXT("AFGActorRepresentationManager is not set"));
}
else
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("Vehicle is not set"));
}
Or am I too dumb to see what is wrong here or something Supernatural is happening
Rex
Rex4w ago
That address is really weird
Vanzin
VanzinOP4w ago
This is crazy for me hahaha
Vanzin
VanzinOP4w ago
The other test, I placed 2 vehicles, 1 right after the other, first one the hook didn't manage to get the Vehicle Object, second one that I placed right after manage to get it and then crash
No description
Vanzin
VanzinOP4w ago
This is what you wanted to see before Rex?
No description
Rex
Rex4w ago
There's a window for locals, that can show you what the vehicle's properties look like
Vanzin
VanzinOP4w ago
This?
No description
Rex
Rex4w ago
Yeah, you can expand that and dig around to see if the actor is initialised and such But I'm honestly stumped
Vanzin
VanzinOP4w ago
Yeah, I started writing C++ on Friday, so this is way complex for me right now :LUL:
No description
Rex
Rex4w ago
Okay, vehicle is invalid memory, it seems What about self?
Vanzin
VanzinOP4w ago
No description
No description
Rex
Rex4w ago
Do you crash if you try to print self->GetPathName()?
Vanzin
VanzinOP4w ago
Lemme see Looks like I don't
Vanzin
VanzinOP4w ago
No description
Rex
Rex4w ago
Can you please show the code? Why is the hook logging a... Material instance?
Vanzin
VanzinOP4w ago
lol, I can't sent the code
Your message could not be delivered. This is usually because you don't share a server with the recipient or the recipient is only accepting direct messages from friends. You can see the full list of reasons here:
Your message could not be delivered. This is usually because you don't share a server with the recipient or the recipient is only accepting direct messages from friends. You can see the full list of reasons here:
What?!
Rex
Rex4w ago
Oh, did you try DMing me? It might work here
Vanzin
VanzinOP4w ago
No, I did not
Vanzin
VanzinOP4w ago
Well, as a file worked -.-
Rex
Rex4w ago
Okay, what the actual ficsit self is a material instance
Vanzin
VanzinOP4w ago
But it's typed as AFGWheeledVehicleInfo* self whaat
Rex
Rex4w ago
Try self->GetClass()->GetName() expects :bricko: to be shat
Vanzin
VanzinOP4w ago
Ah moment, I packed the wrong mod hehehe
Vanzin
VanzinOP4w ago
Vanzin
VanzinOP4w ago
added this: UE_LOG(YouNameIt_Log, Verbose, TEXT("Class Name: %s"), *self->GetClass()->GetName());
Rex
Rex4w ago
Ah, self was NULL this time
Vanzin
VanzinOP4w ago
No, it had value:
No description
Vanzin
VanzinOP4w ago
Path name was logged
Rex
Rex4w ago
Huuuuuh, does it not have a valid class?
Vanzin
VanzinOP4w ago
Idk :NOOOO:
Archengius
Archengius4w ago
I think I understand what is happening You are trying to hook an interface function. Hooking is a bit weird when it comes to multiple inheritance and can hook wrong function Which hooking macro are you using?
Vanzin
VanzinOP4w ago
Yes, from IFGActorRepresentationInterface
SUBSCRIBE_UOBJECT_METHOD(AFGWheeledVehicleInfo, AddAsRepresentation, &HYouNameIt::Hook_AddAsRepresentation);
SUBSCRIBE_UOBJECT_METHOD(AFGWheeledVehicleInfo, AddAsRepresentation, &HYouNameIt::Hook_AddAsRepresentation);
Archengius
Archengius4w ago
Try using the _MANUAL macro instead
Rex
Rex4w ago
There's none
Archengius
Archengius4w ago
Idk what's there to replace it then
Rex
Rex4w ago
Nothing, actually Until the other day, when I made https://github.com/satisfactorymodding/SatisfactoryModLoader/pull/303 I've never seen the _MANUAL macros before, not sure if they're the same as _EXPLICIT ones
Archengius
Archengius4w ago
But you should hook IFGActorRepresentationInterface::AddRepresentation, and pass (IFGActorRepresentationInterface*) GetMutableDefault<AFGWheeledVehicleInfo>() as object instance
Rex
Rex4w ago
SUBSCRIBE_METHOD_VIRTUAL(IFGActorRepresentationInterface::AddRepresentation, (IFGActorRepresentationInterface*)GetMutableDefault<AFGWheeledVehicleInfo>(), &HYouNameIt::Hook_AddAsRepresentation)
SUBSCRIBE_METHOD_VIRTUAL(IFGActorRepresentationInterface::AddRepresentation, (IFGActorRepresentationInterface*)GetMutableDefault<AFGWheeledVehicleInfo>(), &HYouNameIt::Hook_AddAsRepresentation)
I think that should be it
Vanzin
VanzinOP4w ago
The signature of the Hook stays the same?
static void Hook_AddAsRepresentation(TCallScope<bool(__cdecl*)(AFGWheeledVehicleInfo*)>& scope, AFGWheeledVehicleInfo* self)
static void Hook_AddAsRepresentation(TCallScope<bool(__cdecl*)(AFGWheeledVehicleInfo*)>& scope, AFGWheeledVehicleInfo* self)
Archengius
Archengius4w ago
self might have to become IFGActorRepresentationInterface You can static cast it back to wheeled vehicle info tho Or Cast<> it back which might be a bit safer
Vanzin
VanzinOP4w ago
lol, I just saw it in that interface
No description
Vanzin
VanzinOP4w ago
Ah I see Fixed
Archengius
Archengius4w ago
AddAsRepresentation I think is the name
Rex
Rex4w ago
Indeed
/** Adds the actor to the actor representation manager */
UFUNCTION( BlueprintCallable, Category = "Representation" )
virtual bool AddAsRepresentation() = 0;
/** Adds the actor to the actor representation manager */
UFUNCTION( BlueprintCallable, Category = "Representation" )
virtual bool AddAsRepresentation() = 0;
Vanzin
VanzinOP4w ago
SUBSCRIBE_METHOD_VIRTUAL(IFGActorRepresentationInterface::AddAsRepresentation, (IFGActorRepresentationInterface*)GetMutableDefault<AFGWheeledVehicleInfo>(), &HYouNameIt::Hook_AddAsRepresentation)

static void Hook_AddAsRepresentation(TCallScope<bool(__cdecl*)(AFGWheeledVehicleInfo*)>& scope, IFGActorRepresentationInterface* self)
SUBSCRIBE_METHOD_VIRTUAL(IFGActorRepresentationInterface::AddAsRepresentation, (IFGActorRepresentationInterface*)GetMutableDefault<AFGWheeledVehicleInfo>(), &HYouNameIt::Hook_AddAsRepresentation)

static void Hook_AddAsRepresentation(TCallScope<bool(__cdecl*)(AFGWheeledVehicleInfo*)>& scope, IFGActorRepresentationInterface* self)
Too far from my knowledge 😂
No description
Archengius
Archengius4w ago
Call scope argument also is IFGActorRepresentationInterface Not just self
Vanzin
VanzinOP4w ago
Ok now seems all fine, besides that I will need to cast self correct?
Archengius
Archengius4w ago
Yeah
Vanzin
VanzinOP4w ago
Ok! Cross your fingers 🤞🏿 I will compile My neighboors will be mad at me, I just screamed very loud "It f* Worked!!"
Vanzin
VanzinOP4w ago
No description
Vanzin
VanzinOP4w ago
Oh wow! That was a long journey, thank you very very very much both of you!
Rex
Rex4w ago
Glad to see it's working now!
Archengius
Archengius4w ago
I guess somebody really needs to look into why hooking does not work correctly for this case. I was fairly confident that we fixed it at some point
Vanzin
VanzinOP4w ago
I will not be able to help to fix it (cause I have no knowledge) but I'm glad that I at least contributed to find the bug 😂
Vanzin
VanzinOP4w ago
Finally 🤩
No description
Vanzin
VanzinOP4w ago
Hey all! This is what I have done so far My idea here is that I will need to change the vehicle name in some occasions e.g: - Vehicle was created when map was loaded (check if vehicle has a path set and use its name) - Player created a new route and saved it (update the vehicle name - set path name) - Player deleted the route (update the vehicle name - set default name) - Player assigned vehicle to existing route (update vehicle name - set path name) - Player unassign vehicle from existing route (update vehicle name - set default name) I see that with AFGVehicleSubsystem I have many ways to get Vehicles by the TargetList and some other methods but not the opposite... and I failed hard trying to find a way that from the Vehicle or VehicleInfo object I can get the AFGSavedWheeledVehiclePath so then I would have access to its name (via accessor transformer). Could someone give me some direction here please? (I don't need the hooks and functions that I should hook, I already identified that, I just need help understanding how to get the path from the Vehicle). I didn't want to use FindSavedWheeledVehiclePaths but rather get the association directly, but not sure if is possible
Vanzin
VanzinOP4w ago
Also this is always false. I noticed that once I load the save game, the game takes a bit of time to start the auto-drive bot
No description
Vanzin
VanzinOP4w ago
TSubclassOf<AFGWheeledVehicle> TypeFilter = Vehicle->GetClass();
FString TextFilter = "";
TArray<AFGSavedWheeledVehiclePath*> Paths;
VehicleSubsystem->FindSavedWheeledVehiclePaths(TextFilter, TypeFilter, VehicleInfo, Paths);
TSubclassOf<AFGWheeledVehicle> TypeFilter = Vehicle->GetClass();
FString TextFilter = "";
TArray<AFGSavedWheeledVehiclePath*> Paths;
VehicleSubsystem->FindSavedWheeledVehiclePaths(TextFilter, TypeFilter, VehicleInfo, Paths);
This worked, I can find the Path with this, but also I can find the path if the VehicleInfo is not the one in that path 😂 But I also didn't like this approach
Vanzin
VanzinOP4w ago
Working fine but still can't get the correct vehicle path specifically for the current Vehicle
No description
No description
Vanzin
VanzinOP4w ago
Both of them show Path Count = 1 even though the VehicleInfo object is different and the last one has no path loaded
No description
Vanzin
VanzinOP3w ago
Saw this in the discord:
AFGSavedWheeledVehiclePath* VehiclePath = Cast<AFGSavedWheeledVehiclePath>(Vehicle);
FString PathName = VehiclePath->mPathName;
AFGSavedWheeledVehiclePath* VehiclePath = Cast<AFGSavedWheeledVehiclePath>(Vehicle);
FString PathName = VehiclePath->mPathName;
But also don't work 🥲 Another day, another failure :hypers: By using this function from AFGVehicleSubsystem:
void AFGVehicleSubsystem::FindSavedWheeledVehiclePaths(const FString& textFilter, TSubclassOf< AFGWheeledVehicle > typeFilter, const AFGWheeledVehicleInfo* vehicle, TArray< AFGSavedWheeledVehiclePath* >& result){ }
void AFGVehicleSubsystem::FindSavedWheeledVehiclePaths(const FString& textFilter, TSubclassOf< AFGWheeledVehicle > typeFilter, const AFGWheeledVehicleInfo* vehicle, TArray< AFGSavedWheeledVehiclePath* >& result){ }
Shouldn't the parameter const AFGWheeledVehicleInfo* vehicle filter for the saved path for that specific vehicle provided?
Rex
Rex3w ago
There's a separate TSubclassOf< AFGWheeledVehicle > typeFilter
Vanzin
VanzinOP3w ago
But I think that one is for which vehicle type: explorer, tractor, truck no?
Rex
Rex3w ago
That is just a class I guess it could be nullptr or something to represent "any path"
Vanzin
VanzinOP3w ago
So, I tried with this approach first:
TArray<AFGSavedWheeledVehiclePath*> Paths;
FString TextFilter = "";

// void AFGWheeledVehicle::FindSavedPaths(const FString& textFilter, bool filterOnVehicleType, TArray< AFGSavedWheeledVehiclePath* >& result) const{ }
Vehicle->FindSavedPaths(TextFilter, true, Paths);
TArray<AFGSavedWheeledVehiclePath*> Paths;
FString TextFilter = "";

// void AFGWheeledVehicle::FindSavedPaths(const FString& textFilter, bool filterOnVehicleType, TArray< AFGSavedWheeledVehiclePath* >& result) const{ }
Vehicle->FindSavedPaths(TextFilter, true, Paths);
This is directly called from the vehicle object itself, my assumption was that it would return only the Saved Paths for that specific vehicle, but looks like no, it's showing for both vehicles in the world, even though one of them has no path assigned to it
No description
Rex
Rex3w ago
Are the vehicles of the same type?
Vanzin
VanzinOP3w ago
Yeah, 2 tractors
Rex
Rex3w ago
Try adding a different vehicle to the mix to see what happens
Vanzin
VanzinOP3w ago
ok
Vanzin
VanzinOP3w ago
No description
Vanzin
VanzinOP3w ago
Added one explorer first and one truck Seems to me that FindSavedPaths will return all possible paths that can be loaded into that vehicle. Not the path that is actually loaded on it I will do another test and add a second tractor with a different saved path
Rex
Rex3w ago
I don't think the vehicle saves the saved path I couldn't find it yet Or it's in a superclass
Vanzin
VanzinOP3w ago
I think is here: (At least I hooked here and I managed to catch the event when I saved the path)
// AFGVehicleSubsystem
// void SaveWheeledVehiclePath( const FString& saveName, class AFGWheeledVehicleInfo* vehicle );
// AFGVehicleSubsystem
// void SaveWheeledVehiclePath( const FString& saveName, class AFGWheeledVehicleInfo* vehicle );
Rex
Rex3w ago
Save the path where? To the vehicle?
Vanzin
VanzinOP3w ago
I don't know where it's saved, I know that this function is called when you press the button to save the Path in the vehicle
Vanzin
VanzinOP3w ago
Looks like this is true, because now for all the tractors, the Path count is 2. So this function does not get the assigned path to that tractor, but rather get all available paths by the Vehicle Type:
Vehicle->FindSavedPaths(TextFilter, true, Paths);
Vehicle->FindSavedPaths(TextFilter, true, Paths);
No description
Rex
Rex3w ago
Tried using false?
Vanzin
VanzinOP3w ago
No, but I will do it now
Vanzin
VanzinOP3w ago
with false the function also gets the paths for other vehicle types (in this case truck)
No description
Rex
Rex3w ago
Hmmm
Vanzin
VanzinOP3w ago
I really don't understand how this whole structure works, by using the following method I thought that I could check if the Vehicle was using that Target List or not:
bool AFGVehicleSubsystem::IsWheeledVehiclePathInUse( AFGDrivingTargetList* targetList, const AFGWheeledVehicleInfo* byVehicle) const{ return bool(); }
bool AFGVehicleSubsystem::IsWheeledVehiclePathInUse( AFGDrivingTargetList* targetList, const AFGWheeledVehicleInfo* byVehicle) const{ return bool(); }
Like this:
AFGWheeledVehicleInfo* VehicleInfo = Cast<AFGWheeledVehicleInfo>(realActor);
if (VehicleInfo)
{
AFGVehicleSubsystem* VehicleSubsystem = AFGVehicleSubsystem::Get(VehicleInfo->GetWorld());
if (VehicleSubsystem)
{
FString TextFilter = "";
TSubclassOf<AFGWheeledVehicle> TypeFilter = VehicleInfo->GetClass();
TArray<AFGSavedWheeledVehiclePath*> Paths;
VehicleSubsystem->FindSavedWheeledVehiclePaths(TextFilter, TypeFilter, VehicleInfo, Paths);

bool isPathFound = false;
for (AFGSavedWheeledVehiclePath* Path : Paths)
{
if (Path && Path->mTargetList)
{
if (VehicleSubsystem->IsWheeledVehiclePathInUse(Path->mTargetList, VehicleInfo))
{
this->mDynamicRepresentationText = FText::FromString(Path->mPathName);
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] Vehicle is using Path: %s"), *Name, *Path->mPathName);
isPathFound = true;
break;
}

UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] Vehicle is not using Path: %s"), *Name, *Path->mPathName);
}
}

if (!isPathFound)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] No paths are in use by the vehicle"), *Name);
}
}
}
AFGWheeledVehicleInfo* VehicleInfo = Cast<AFGWheeledVehicleInfo>(realActor);
if (VehicleInfo)
{
AFGVehicleSubsystem* VehicleSubsystem = AFGVehicleSubsystem::Get(VehicleInfo->GetWorld());
if (VehicleSubsystem)
{
FString TextFilter = "";
TSubclassOf<AFGWheeledVehicle> TypeFilter = VehicleInfo->GetClass();
TArray<AFGSavedWheeledVehiclePath*> Paths;
VehicleSubsystem->FindSavedWheeledVehiclePaths(TextFilter, TypeFilter, VehicleInfo, Paths);

bool isPathFound = false;
for (AFGSavedWheeledVehiclePath* Path : Paths)
{
if (Path && Path->mTargetList)
{
if (VehicleSubsystem->IsWheeledVehiclePathInUse(Path->mTargetList, VehicleInfo))
{
this->mDynamicRepresentationText = FText::FromString(Path->mPathName);
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] Vehicle is using Path: %s"), *Name, *Path->mPathName);
isPathFound = true;
break;
}

UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] Vehicle is not using Path: %s"), *Name, *Path->mPathName);
}
}

if (!isPathFound)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] No paths are in use by the vehicle"), *Name);
}
}
}
But then the logs:
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [AddAsRepresentationHook] Called...
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [UCWheeledVehicleRepresentation] Construct called...
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [SetupActorRepresentation][FGWheeledVehicleInfo_2147474260] Called...
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [SetupActorRepresentation][FGWheeledVehicleInfo_2147474260] Vehicle is not using Path: Truck path only!
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [SetupActorRepresentation][FGWheeledVehicleInfo_2147474260] Vehicle is not using Path: New Path with Different Tractor
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [SetupActorRepresentation][FGWheeledVehicleInfo_2147474260] Vehicle is not using Path: First Test Track Name
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [SetupActorRepresentation][FGWheeledVehicleInfo_2147474260] No paths are in use by the vehicle
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [GetRepresentationText] Called... Text: FGWheeledVehicleInfo_2147474260
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [AddAsRepresentationHook][FGWheeledVehicleInfo_2147474260] Representation Text is: FGWheeledVehicleInfo_2147474260
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [AddAsRepresentationHook] Called...
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [UCWheeledVehicleRepresentation] Construct called...
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [SetupActorRepresentation][FGWheeledVehicleInfo_2147474260] Called...
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [SetupActorRepresentation][FGWheeledVehicleInfo_2147474260] Vehicle is not using Path: Truck path only!
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [SetupActorRepresentation][FGWheeledVehicleInfo_2147474260] Vehicle is not using Path: New Path with Different Tractor
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [SetupActorRepresentation][FGWheeledVehicleInfo_2147474260] Vehicle is not using Path: First Test Track Name
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [SetupActorRepresentation][FGWheeledVehicleInfo_2147474260] No paths are in use by the vehicle
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [GetRepresentationText] Called... Text: FGWheeledVehicleInfo_2147474260
[2024.11.01-19.55.54:826][760]YouNameIt_Log: Verbose: [AddAsRepresentationHook][FGWheeledVehicleInfo_2147474260] Representation Text is: FGWheeledVehicleInfo_2147474260
Dammit 🥲 This idea it's hard to implement, omg
Rex
Rex3w ago
Which path is the vehicle using?
Vanzin
VanzinOP3w ago
Should be First Test Track Name
Vanzin
VanzinOP3w ago
No description
Vanzin
VanzinOP3w ago
And this is how I know that this one is the FGWheeledVehicleInfo_2147474260:
No description
Rex
Rex3w ago
/** Linked list with target nodes that make up our path to travel */
UPROPERTY( SaveGame, ReplicatedUsing = OnRep_TargetList )
TObjectPtr<AFGDrivingTargetList> mTargetList;
/** Linked list with target nodes that make up our path to travel */
UPROPERTY( SaveGame, ReplicatedUsing = OnRep_TargetList )
TObjectPtr<AFGDrivingTargetList> mTargetList;
Wheeled vehicles have this, try comparing this to the list you have here?
Vanzin
VanzinOP3w ago
just a normal == you mean?
Rex
Rex3w ago
For starters I'd just log the GetPathName() of all to see what you get
Vanzin
VanzinOP3w ago
Oh, we are into something
Vanzin
VanzinOP3w ago
Target list is ==
Target list is ==
was the comparison between the Path->targetList and the Vehicle->targetList
Rex
Rex3w ago
Please show me the line that prints Vehicle PathName: and stuff
Vanzin
VanzinOP3w ago
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] Vehicle PathName: %s"), *Name, *Vehicle->GetPathName());
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] Vehicle PathName: %s"), *Name, *Vehicle->GetPathName());
Rex
Rex3w ago
I don't see GetPathName() for any paths Oh, you only called it on the vehicle And I said paths when I meant target lists
Vanzin
VanzinOP3w ago
Ah ok, I will add it
Rex
Rex3w ago
But it shouldn't be needed if pointer equality works
Vanzin
VanzinOP3w ago
Now I'm curious what this function VehicleSubsystem->IsWheeledVehiclePathInUse(Path->mTargetList, VehicleInfo) supposed to do then?
Rex
Rex3w ago
reluctantly starts up Ghidra, defying their own laziness
Vanzin
VanzinOP3w ago
No no, it's ok, you don't need to, I was just saying
Rex
Rex3w ago
I am curious, though
bool __thiscall AFGVehicleSubsystem::IsWheeledVehiclePathInUse (AFGVehicleSubsystem *this,AFGDrivingTargetList *param_1,AFGWheeledVehicleInfo *param_2)
{
ForElementType<> FVar1;
AFGWheeledVehicleInfo *this_00;
AFGDrivingTargetList *pAVar2;
ForElementType<> FVar3;

/* 0x7fe2d0 22637
?IsWheeledVehiclePathInUse@AFGVehicleSubsystem@@QEBA_NPEAVAFGDrivingTargetList@@PEBVAFGWheeledVeh icleInfo@@@Z
*/
FVar3 = (this->mWheeledVehicles).AllocatorInstance;
FVar1 = (ForElementType<>)((longlong)FVar3 + (longlong)(this->mWheeledVehicles).ArrayNum * 8);
while( true ) {
if (FVar3 == FVar1) {
return false;
}
this_00 = *(AFGWheeledVehicleInfo **)FVar3;
if ((this_00 != NULL) &&
(((param_2 == NULL || (param_2 == this_00)) &&
(pAVar2 = AFGWheeledVehicleInfo::GetTargetList(this_00), pAVar2 == param_1)))) break;
FVar3 = (ForElementType<>)((longlong)FVar3 + 8);
}
return true;
}
bool __thiscall AFGVehicleSubsystem::IsWheeledVehiclePathInUse (AFGVehicleSubsystem *this,AFGDrivingTargetList *param_1,AFGWheeledVehicleInfo *param_2)
{
ForElementType<> FVar1;
AFGWheeledVehicleInfo *this_00;
AFGDrivingTargetList *pAVar2;
ForElementType<> FVar3;

/* 0x7fe2d0 22637
?IsWheeledVehiclePathInUse@AFGVehicleSubsystem@@QEBA_NPEAVAFGDrivingTargetList@@PEBVAFGWheeledVeh icleInfo@@@Z
*/
FVar3 = (this->mWheeledVehicles).AllocatorInstance;
FVar1 = (ForElementType<>)((longlong)FVar3 + (longlong)(this->mWheeledVehicles).ArrayNum * 8);
while( true ) {
if (FVar3 == FVar1) {
return false;
}
this_00 = *(AFGWheeledVehicleInfo **)FVar3;
if ((this_00 != NULL) &&
(((param_2 == NULL || (param_2 == this_00)) &&
(pAVar2 = AFGWheeledVehicleInfo::GetTargetList(this_00), pAVar2 == param_1)))) break;
FVar3 = (ForElementType<>)((longlong)FVar3 + 8);
}
return true;
}
Vanzin
VanzinOP3w ago
By looking at this, feels like almost exactly what I wrote :wonke:
Vanzin
VanzinOP3w ago
IT WORKS @Rex [they/them] !!!!!! What would I be without your help, thank you ❤️
No description
Rex
Rex3w ago
Suffering
bool AFGVehicleSubsystem::IsWheeledVehiclePathInUse(const AFGVehicleSubsystem *this, AFGDrivingTargetList *targetList, const AFGWheeledVehicleInfo *byVehicle)
{
for (AFGWheeledVehicleInfo* vehicleInfo : this->mWheeledVehicles) {
if (vehicleInfo == null) {
continue;
}
if (byVehicle == NULL || byVehicle == vehicleInfo) {
if (vehicleInfo->GetTargetList() == targetList)
return true;
}
}
return false;
}
bool AFGVehicleSubsystem::IsWheeledVehiclePathInUse(const AFGVehicleSubsystem *this, AFGDrivingTargetList *targetList, const AFGWheeledVehicleInfo *byVehicle)
{
for (AFGWheeledVehicleInfo* vehicleInfo : this->mWheeledVehicles) {
if (vehicleInfo == null) {
continue;
}
if (byVehicle == NULL || byVehicle == vehicleInfo) {
if (vehicleInfo->GetTargetList() == targetList)
return true;
}
}
return false;
}
Vanzin
VanzinOP3w ago
exactly what I did .-. Right? it's comparing the vehicle target list with the target list that you provide in the parameter In my case: I was providing the VehicleInfo and the targetlist from the Path
Rex
Rex3w ago
I don't know what your code is This uses AFGSavedWheeledVehiclePath
Vanzin
VanzinOP3w ago
FString TextFilter = "";
TSubclassOf<AFGWheeledVehicle> TypeFilter = VehicleInfo->GetClass();
TArray<AFGSavedWheeledVehiclePath*> Paths;
VehicleSubsystem->FindSavedWheeledVehiclePaths(TextFilter, TypeFilter, VehicleInfo, Paths);

AFGWheeledVehicle* Vehicle = VehicleInfo->GetVehicle();
if (Vehicle)
{
bool isPathFound = false;
for (AFGSavedWheeledVehiclePath* Path : Paths)
{
if (Path && Path->mTargetList)
{
if (VehicleSubsystem->IsWheeledVehiclePathInUse(Path->mTargetList, VehicleInfo))
{
this->mDynamicRepresentationText = FText::FromString(Path->mPathName);
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] Vehicle is using Path: %s"), *Name, *Path->mPathName);
isPathFound = true;
break;
}

UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] Vehicle is not using Path: %s"), *Name, *Path->mPathName);
}
}

if (!isPathFound)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] No paths are in use by the vehicle"), *Name);
}
}
else
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] No vehicle object"), *Name);
}
FString TextFilter = "";
TSubclassOf<AFGWheeledVehicle> TypeFilter = VehicleInfo->GetClass();
TArray<AFGSavedWheeledVehiclePath*> Paths;
VehicleSubsystem->FindSavedWheeledVehiclePaths(TextFilter, TypeFilter, VehicleInfo, Paths);

AFGWheeledVehicle* Vehicle = VehicleInfo->GetVehicle();
if (Vehicle)
{
bool isPathFound = false;
for (AFGSavedWheeledVehiclePath* Path : Paths)
{
if (Path && Path->mTargetList)
{
if (VehicleSubsystem->IsWheeledVehiclePathInUse(Path->mTargetList, VehicleInfo))
{
this->mDynamicRepresentationText = FText::FromString(Path->mPathName);
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] Vehicle is using Path: %s"), *Name, *Path->mPathName);
isPathFound = true;
break;
}

UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] Vehicle is not using Path: %s"), *Name, *Path->mPathName);
}
}

if (!isPathFound)
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] No paths are in use by the vehicle"), *Name);
}
}
else
{
UE_LOG(YouNameIt_Log, Verbose, TEXT("[SetupActorRepresentation][%s] No vehicle object"), *Name);
}
Rex
Rex3w ago
Ah, it's getting it from... UFGSplinePathMovementComponent?
Vanzin
VanzinOP3w ago
I mean, not sure, what?
Rex
Rex3w ago
I mean IsWheeledVehiclePathInUse because it calls vehicleInfo->GetTargetList()
AFGDrivingTargetList * __thiscall AFGWheeledVehicleInfo::GetTargetList(AFGWheeledVehicleInfo *this)
{
AFGDrivingTargetList *pAVar1;

/* 0x972fa0 21057 ?GetTargetList@AFGWheeledVehicleInfo@@QEBAPEAVAFGDrivingTargetList@@XZ */
pAVar1 = (AFGDrivingTargetList *)this->mSimulationMovement;
if (pAVar1 != NULL) {
return *(AFGDrivingTargetList **)&pAVar1->field_0x148;
}
return pAVar1;
}
AFGDrivingTargetList * __thiscall AFGWheeledVehicleInfo::GetTargetList(AFGWheeledVehicleInfo *this)
{
AFGDrivingTargetList *pAVar1;

/* 0x972fa0 21057 ?GetTargetList@AFGWheeledVehicleInfo@@QEBAPEAVAFGDrivingTargetList@@XZ */
pAVar1 = (AFGDrivingTargetList *)this->mSimulationMovement;
if (pAVar1 != NULL) {
return *(AFGDrivingTargetList **)&pAVar1->field_0x148;
}
return pAVar1;
}
Vanzin
VanzinOP3w ago
Yeah and then compares vehicleInfo->GetTargetList() with the TargetList in the parameters (in my case Path->mTargetList) returns false, But with the vehicleInfo->GetTargetList() == Path->mTargetList that I added later, it works fine
Rex
Rex3w ago
The types are wrong, but field_0x148 is mTargetList I'm saying that IsWheeledVehiclePathInUse is doing something else Hmmm, were your vehicles actually following the path?
Vanzin
VanzinOP3w ago
yes no change in the savegame Just from this:
if (VehicleSubsystem->IsWheeledVehiclePathInUse(Path->mTargetList, VehicleInfo))
if (VehicleSubsystem->IsWheeledVehiclePathInUse(Path->mTargetList, VehicleInfo))
To this:
if (Vehicle->GetTargetList() == Path->mTargetList)
if (Vehicle->GetTargetList() == Path->mTargetList)
Rex
Rex3w ago
That's a different function This is AFGWheeledVehicleInfo::GetTargetList
Vanzin
VanzinOP3w ago
Hmmmmmmm, true
Rex
Rex3w ago
You're calling
/**Returns the simulation component */
UFUNCTION( BlueprintPure, Category = "LinkedList" )
AFGDrivingTargetList* GetTargetList( bool createIfNeeded = false );
/**Returns the simulation component */
UFUNCTION( BlueprintPure, Category = "LinkedList" )
AFGDrivingTargetList* GetTargetList( bool createIfNeeded = false );
Vanzin
VanzinOP3w ago
AFGDrivingTargetList* AFGWheeledVehicleInfo::GetTargetList() const{ return nullptr; } The result must be different then from Vehicle->GetTargetList() and AFGWheeledVehicleInfo::GetTargetList() then
Rex
Rex3w ago
That's the stub in the project This I reconstructed myself Based on this Actual implementation would be equivalent to this
AFGDrivingTargetList* AFGWheeledVehicleInfo::GetTargetList() const
{
return mSimulationMovement ? mSimulationMovement->mTargetList : nullptr;
}
AFGDrivingTargetList* AFGWheeledVehicleInfo::GetTargetList() const
{
return mSimulationMovement ? mSimulationMovement->mTargetList : nullptr;
}
Vanzin
VanzinOP3w ago
Then it would be generated somewhere else not even from the Vehicle inside the VehicleInfo
Rex
Rex3w ago
Uh, what is generated elsewhere?
Vanzin
VanzinOP3w ago
So far I understood: VehicleInfo has a reference to a Vehicle (both of them have TargetLists) but they are different
Rex
Rex3w ago
Hence my question, maybe the simulation movement doesn't have a valid target list if the vehicle can't run VehicleInfo does not have a target list It gets a target list out of the simulation movement
Vanzin
VanzinOP3w ago
It does here
if (vehicleInfo->GetTargetList() == targetList)
return true;
if (vehicleInfo->GetTargetList() == targetList)
return true;
ah yeah yeah I meant the method
Rex
Rex3w ago
There's two methods
Rex
Rex3w ago
Ignore first and last (those are UE magic stuff)
No description
Vanzin
VanzinOP3w ago
Ok, got it Either way I will not be able to use IsWheeledVehiclePathInUse because the TargetList from the Path is not the same used in the VehicleInfo So this worked like a charm :alpacool:
Rex
Rex3w ago
Yeah, that's why I asked if the vehicles were moving
Want results from more Discord servers?
Add your server