I have error whem I try access ULandscapeSplinesComponent TrackSplines and other classes

Hi guys

I’m trying to re-write an old script to the new version of EU4 and I’m having trouble.

The first error is that: It gives error in the first STRUCT OFFSET
(pointer to incomplete class type is not allowed)

FInterpCurveVector& HackAccessSplineInfo(ULandscapeSplineSegment* SplineSegment)
    {
        //This ugly code will crash badly if the ULandscapeSplineSegment changes
        BYTE* HackPtr = (BYTE*)SplineSegment;
    #if WITH_EDITORONLY_DATA
        HackPtr += STRUCT_OFFSET(ULandscapeSplineSegment, LDMaxDrawDistance) + sizeof(uint32) * 3;
    #else
        HackPtr += STRUCT_OFFSET(ULandscapeSplineSegment, Connections[1]) + sizeof(FLandscapeSplineSegmentConnection);
    #endif
        return *(FInterpCurveVector*)HackPtr;
    }

The second error (ULandscapeSplinesComponent* APlayerController::TrackSplines pointer to incomplete class type is not allowed) at the TrackSplines and CurrentControlPoint too.

if (GetPawn())
    {
        for (TObjectIterator<ULandscapeSplinesComponent> ObjIt; ObjIt; ++ObjIt)
        {
            TrackSplines = *ObjIt;

            ULandscapeSplineControlPoint* ClosestControlPoint = nullptr;

            //Find the controlpoint closest to the player start point
            FVector PlayerStartLocation = GetPawn()->GetActorLocation() - TrackSplines->GetOwner()->GetActorLocation();
            float ClosestDistSq = FLT_MAX;
            for (int32 i = 0; i < TrackSplines->ControlPoints.Num(); i++)
            {
                float DistSq = (TrackSplines->ControlPoints[i]->Location - PlayerStartLocation).SizeSquared();
                if (DistSq < ClosestDistSq)
                {
                    ClosestDistSq = DistSq;
                    ClosestControlPoint = TrackSplines->ControlPoints[i];
                }
            }

bool bTrackHasErrors = false;
            OrderedSegments.Empty(TrackSplines->Segments.Num());
            ULandscapeSplineControlPoint* CurrentControlPoint = ClosestControlPoint;
            while (CurrentControlPoint)
            {
                int32 i = 0;
                for (; i < CurrentControlPoint->ConnectedSegments.Num(); i++)
                {
                    if (OrderedSegments.Num() == 0 || CurrentControlPoint->ConnectedSegments[i].Segment != OrderedSegments[0])
                    {
                        OrderedSegments.Insert(CurrentControlPoint->ConnectedSegments[i].Segment, 0);
                        check(CurrentControlPoint != CurrentControlPoint->ConnectedSegments[i].GetFarConnection().ControlPoint);
                        CurrentControlPoint = CurrentControlPoint->ConnectedSegments[i].GetFarConnection().ControlPoint;
                        break;
                    }
                }

                //We didn't find another segment to link to, we have an error!
                if (i == CurrentControlPoint->ConnectedSegments.Num())
                {
                    bTrackHasErrors = true;
                    break;
                }

                //Back to the start
                if (CurrentControlPoint == ClosestControlPoint)
                    break;
            }

This one to (class APlayerCameraManager has no member bFollowHmdOrientation)

void ARollerCoasterPlayerController::PlayerTick(float DeltaTime)
{
    //If we're requesting a stop, do it immediately
    if (Stopped)
    {
        CurrentRollerCoasterVelocity = 0.f;
    }
    else
    {
        CurrentRollerCoasterVelocity += AddVelocity;
        AddVelocity = 0.f;
    }

    if (GetPawn() && TrackSplines)
    {
        DeltaRemaining += DeltaTime;

        static float FixedStepTime = 1.f / 150.f;
        while (DeltaRemaining >= FixedStepTime)
        {
            UpdatePlayer(FixedStepTime);
            DeltaRemaining -= FixedStepTime;
        }
    }

    PlayerCameraManager->bFollowHmdOrientation = true;

    Super::PlayerTick(DeltaTime);
}

And the last one at the CurrentSegment
(ULandscapeSplineSegment8 CurrentSegment pointer to incomplete class type is not allowed)

// Calculate the roll values
    float NewRotationRoll = 0.f;
    if (CurrentSegment->Connections[0].ControlPoint && CurrentSegment->Connections[1].ControlPoint)
    {
        FVector StartLocation; FRotator StartRotation;
        CurrentSegment->Connections[0].ControlPoint->GetConnectionLocationAndRotation(CurrentSegment->Connections[0].SocketName, StartLocation, StartRotation);
        FVector EndLocation; FRotator EndRotation;
        CurrentSegment->Connections[1].ControlPoint->GetConnectionLocationAndRotation(CurrentSegment->Connections[1].SocketName, EndLocation, EndRotation);
        NewRotationRoll = FMath::Lerp(-StartRotation.Roll, -EndRotation.Roll, NewKeyTime);
    }
    NewRotation.Roll = NewRotationRoll;

Lot problemas I know but some one can help-me?

Hey Damien,

I encountered similar issues when trying to subclass the Landscape classes, and it is because that these classes (ULandscapeSplineComponent being one example from your description) are marked with a tag called “MinimalAPI”

https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Reference/Classes/Specifiers/MinimalAPI/

This tag effectively prevents these classes from being inherited, because it forces the exclusion of the implementation/data members at compile time. Only the signatures and names are visible. This is done in order to improve compile time.

If you wish to extend these classes, you will have to download Unreals source from GitHub and compile the engine from source, and then manually strip out these tags, as the binary version of the engine that is distributed by the launcher cannot be recompiled.

Hi Nightmask

Thanks for our answer. I will download and test to see if I have access to this class. Then I say if everything worked.

Hi Nightmask

How can I strip out these tags? Inside LandscapeSplinesComponent.h and .cpp?

Hey Damien,

So for an example let’s look at Landscape.h (a class that I am a little more familiar with, bear with me)

UCLASS(Placeable, hidecategories = LandscapeProxy, showcategories = (Display, Movement, Collision, Lighting, LOD, Input), MinimalAPI)
class ALandscape : public ALandscapeProxy
{
	GENERATED_UCLASS_BODY()

	// Make a key for XYtoComponentMap
	static FIntPoint MakeKey( int32 X, int32 Y ) { return FIntPoint(X, Y); }
	static void UnpackKey( FIntPoint Key, int32& OutX, int32& OutY ) { OutX = Key.X; OutY = Key.Y; }

	//~ Begin AActor Interface
#if WITH_EDITOR
	virtual void CheckForErrors() override;
#endif
.... (Rest of class follows)
};

At the top you will see, in the UCLASS macro statement, the tag MinimalAPI.
This is the source of the problem, in so far as I can make out.

Apart from that, there are also things in the Landscape classes that are marked with the code guard ‘#if WITH_EDITOR’ which cause those functions or members variables type data to be removed when your game is cooked.

You might need to go through your classes and find out which instances of those functions are necessary to you even in the cooked game and remove the code guards around them. However this is obviously more complicated than it sounds, and might cause things to break in other parts of the engine.

Good luck!