I have an actor in my game right now that will place a static mesh in the world at a coordinate location and at cesium terrain height. I am using SampleHeightMostDetailed to get the placement height, which is called during BeginPlay for the spawner. The issue I am having is this causes an access violation exception. The call stack says it crashes inside of CreditSystem::createCredit but the plugin doesn’t come with debug symbols.
I am using Cesium for Unreal v2.8.0 downloaded through the Epic Games Launcher. I am running into this issue in the PIE. So far this issue has been with the Tileset and all Cesium actors in the outliner. Once this actor is working it will be used on a level that generates everything at runtime.
To better isolate the problem I have created a new empty level and added Cesium CWT + Bing Maps Aerial to it though the Cesium menu. CesiumCameraManager and CesiumCreditSystemBP as also added from this.
Then I add my spawner with one object to spawn at runtime.
When I press play I get the exception I mentioned above.
Here is the spawner class I wrote:
Spawner.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "StaticObstacle.h"
#include <CesiumGeoreference.h>
#include <Cesium3DTileset.h>
#include "StaticObstacleSpawner.generated.h"
USTRUCT(BlueprintType)
struct FStaticObstacleContainer
{
GENERATED_BODY()
/* Placement */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Placement")
FVector LongitudeLatitudeHeight;
/* Mesh Settings*/
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Mesh")
UStaticMesh* Mesh;
UPROPERTY()
TWeakObjectPtr<AStaticObstacle> Obstacle;
};
UCLASS()
class ODYSSEY_VW_API AStaticObstacleSpawner : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AStaticObstacleSpawner();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
TWeakObjectPtr<ACesiumGeoreference> Georeference;
TWeakObjectPtr<ACesium3DTileset> Tileset;
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Obstacles")
TArray<FStaticObstacleContainer> Obstacles;
UFUNCTION(BlueprintCallable)
void AddObstacle(double Longitude, double Latitude, UStaticMesh* Mesh);
};
Spawner.cpp
#include "Actors/Objects/StaticObstacleSpawner.h"
#include <Utility/GeoTools.h>
#include <Kismet/GameplayStatics.h>
// Sets default values
AStaticObstacleSpawner::AStaticObstacleSpawner()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
Georeference = ACesiumGeoreference::GetDefaultGeoreference(GetWorld());
}
// Called when the game starts or when spawned
void AStaticObstacleSpawner::BeginPlay()
{
Super::BeginPlay();
UWorld* World = GetWorld();
TArray<FVector> Locations;
for (FStaticObstacleContainer& Obstacle : Obstacles)
{
Locations.Add(Obstacle.LongitudeLatitudeHeight);
Obstacle.Obstacle = World->SpawnActor<AStaticObstacle>();
Obstacle.Obstacle->SetStaticMesh(Obstacle.Mesh);
Obstacle.Obstacle->SetCesiumLocation(Obstacle.LongitudeLatitudeHeight);
}
FCesiumSampleHeightMostDetailedCallback CesiumSampleHeightMostDetailedCallback;
CesiumSampleHeightMostDetailedCallback.BindLambda(
[this](ACesium3DTileset* Tileset, const TArray<FCesiumSampleHeightResult>& Results, const TArray<FString>& Strings) mutable
{
Tileset;
Strings;
if (this->Obstacles.Num() != Results.Num())
{
return;
}
auto LocationIter = Results.CreateConstIterator();
for (auto ObstacleIter = this->Obstacles.CreateIterator(); ObstacleIter; ++ObstacleIter)
{
if (LocationIter->SampleSuccess)
{
FVector LongitudeLatitudeHeight = LocationIter->LongitudeLatitudeHeight;
LongitudeLatitudeHeight.Z += UGeoTools::ElipsoidGeoidDifference(LongitudeLatitudeHeight.X, LongitudeLatitudeHeight.Y);
ObstacleIter->Obstacle->SetCesiumLocation(LongitudeLatitudeHeight);
}
LocationIter++;
}
}
);
if (!IsValid(Tileset.Get()))
{
Tileset = Cast<ACesium3DTileset>(UGameplayStatics::GetActorOfClass(World, ACesium3DTileset::StaticClass()));
}
Tileset->SampleHeightMostDetailed(Locations, CesiumSampleHeightMostDetailedCallback);
}
// Called every frame
void AStaticObstacleSpawner::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AStaticObstacleSpawner::AddObstacle(double Longitude, double Latitude, UStaticMesh* Mesh)
{
}
I’m having the same issue.
Unreal 5.4.4, Windows 11, tried with Cesium 2.8, 2.9 and 2.10
Calling the blueprint function “SampleHeightMostDetailed” from “Event BeginPlay” crashes Unreal (and can render both the project and the blueprint unopenable).
Probably happens because the tile isn’t fully loaded yet.
If I bind the event to “On Tileset Loaded” everything goes smoothly, and I don’t get any crashes.
I figured moving it to the OnTilesetLoad delegate would fix this issue. The Sample Height function call is async though so it should handle its components not being loaded yet