Comical Actor Construction brokenness!

following happens when dragging an empty blueprint (from content panel) that inherits from our class into scene in editor.

Here is Log followed by cpp functions (number is pointer to class).

LogTemp:Warning: CNSTR 000000001BEDF900
LogTemp:Warning: CNSTR 000000001BEA9D00
LogTemp:Warning: CNSTR 0000000023F69600
LogTemp:Warning: OnConstruction 0000000023F69600
LogTemp:Warning: GEN GRID 0000000023F69600
LogTemp: Setting tile 0 position to X=-450.000 Y=-259.800 Z=0.000
LogTemp: Setting tile 0 position to X=-450.000 Y=259.800 Z=0.000
LogTemp: Setting tile 0 position to X=0.000 Y=-519.600 Z=0.000
LogTemp: Setting tile 0 position to X=0.000 Y=0.000 Z=0.000
LogTemp: Setting tile 0 position to X=0.000 Y=519.600 Z=0.000
LogTemp: Setting tile 0 position to X=450.000 Y=-259.800 Z=0.000
LogTemp: Setting tile 0 position to X=450.000 Y=259.800 Z=0.000
LogTemp: Setting tile 1 position to X=-450.000 Y=-259.800 Z=0.000
LogTemp: Setting tile 1 position to X=450.000 Y=-259.800 Z=0.000
LogTemp:Warning: OnConstruction 0000000023F69600
LogTemp:Warning: OnConstruction 0000000023F69600
LogTemp:Warning: OnConstruction 0000000023F69600
LogTemp:Warning: OnConstruction 0000000023F69600
LogTemp:Warning: OnConstruction 0000000023F69600
LogTemp:Warning: OnConstruction 0000000023F69600
LogSourceControl: Attempting 'p4 fstat -Or H:/UnrealBotBattle/BotBattle/Content/Maps/JoeTest.umap'
LogTemp:Warning: OnConstruction 0000000023F69600
LogTemp:Warning: OnConstruction 0000000023F69600
LogTemp:Warning: OnConstruction 0000000023F69600
LogTemp:Warning: CNSTR 000000001BEDCF00
LogTemp:Warning: OnConstruction 000000001BEDCF00
LogTemp:Warning: GEN GRID 000000001BEDCF00
LogTemp: Setting tile 0 position to X=-450.000 Y=-259.800 Z=0.000
LogTemp: Setting tile 0 position to X=-450.000 Y=259.800 Z=0.000
LogTemp: Setting tile 0 position to X=0.000 Y=-519.600 Z=0.000
LogTemp: Setting tile 0 position to X=0.000 Y=0.000 Z=0.000
LogTemp: Setting tile 0 position to X=0.000 Y=519.600 Z=0.000
LogTemp: Setting tile 0 position to X=450.000 Y=-259.800 Z=0.000
LogTemp: Setting tile 0 position to X=450.000 Y=259.800 Z=0.000
LogTemp: Setting tile 1 position to X=450.000 Y=-259.800 Z=0.000
LogTemp: Setting tile 1 position to X=450.000 Y=259.800 Z=0.000
LogTemp:Warning: OnConstruction 000000001BEDCF00
LogTemp:Warning: OnConstruction 000000001BEDCF00
LogTemp:Warning: OnConstruction 000000001BEDCF00



AHexGrid::AHexGrid(const class FObjectInitializer& PCIP)
	: Super(PCIP)
	{
	//gridShape = EGridShape::Hexagon;
	//maxQ = 1;

	scene = PCIP.CreateDefaultSubobject<USceneComponent>(this, TEXT("SceneComp"));
	if (scene)
		{
		RootComponent = scene;
		scene->SetMobility(EComponentMobility::Static);
		}

	if (!AddInstancedStaticMeshComponent(EHexType::Floor, TEXT("StaticMesh'/Game/Meshes/hextile.HexTile'"), 
		TEXT("InstancedFloorTile"), TEXT("Material'/Game/Materials/M_Basic_Floor.M_Basic_Floor'"), PCIP))
		{
		ERROR("BotBattle HexGrid: Failed to Load and Create FloorTile Component...");
		}

	if (!AddInstancedStaticMeshComponent(EHexType::Wall, TEXT("StaticMesh'/Game/Meshes/hex_wall.hex_wall'"), 
		TEXT("InstancedWallTile"), TEXT("Material'/Game/Materials/M_Basic_Wall.M_Basic_Wall'"), PCIP))
		{
		ERROR("BotBattle HexGrid: Failed to Load and Create WallTile Component...");
		}

	if (!AddInstancedStaticMeshComponent(EHexType::Start, TEXT("StaticMesh'/Game/Meshes/hextile.HexTile'"),
		TEXT("InstancedStartTile"), TEXT("Material'/Game/Materials/StartTileMat.StartTileMat'"), PCIP))
		{
		ERROR("BotBattle HexGrid: Failed to Load and Create StartTile Component...");
		}

	if (!AddInstancedStaticMeshComponent(EHexType::Flag, TEXT("StaticMesh'/Game/Meshes/hextile.HexTile'"),
		TEXT("InstancedFlagTile"), TEXT("Material'/Game/Materials/M_Tech_Hex_Tile_Pulse.M_Tech_Hex_Tile_Pulse'"), PCIP))
		{
		ERROR("BotBattle HexGrid: Failed to Load and Create FlatTile Component...");
		}

	WARNING("CNSTR %p", this);
	

	}

void AHexGrid::GenerateGrid() 
	{
	//need to protect against regenerating grid when we do not want to
	if (!bGridGenerated)
		{
		WARNING("GEN GRID %p", this);
		this->PositionTiles();
		bGridGenerated = true;
		}
	}

void AHexGrid::OnConstruction(const FTransform& Transform)
	{
	Super::OnConstruction(Transform);
	WARNING("OnConstruction %p", this);
	SetActorLocation(FVector(0.0, 0.0, 0.0));
	//Reset();
	GenerateGrid();
	

	}

Why on earth is OnConstruction called so many times on same object?

Not shown here, but PostInitializeComponents is never called. Why?

Why are multiple objects Constructed and added to scene?

I have included a dropbox link to our code.

uproject

Hi joessu,

Thanks for report! I’ve assigned a member of our team to look into this for you, and they’ll post here if they need any additional information from you.

Okay, explains multiple calls, but not why 2 unique instances get created and added to scene.

Btw I really appreciate you looking into our bugs. We are jamming through our implementation and seem to be getting hung up on some things. Thanks again for looking into stuff.

Hey joessu-

OnConstruction is called anytime asset is updated. This means as BP instance enters scene and as it’s being moved within level OnConstruction will be called for each update.

Cheers

This does not answer why to instances of grid are added to scene.

When asset is first dragged from content browser into scene there is an instance that is created. This instance is then destroyed and another copy of asset is created when left mouse button is released and asset is placed into level. It is second instance that is then updated if actor is moved within level.

Thanks, with this information clearly using OnConstruction to generate procedural content is not a good idea. Instead I am going to provide blutility functions to do this.
If i could change my vote to an upvote i would but it’s too late :frowning:

So we figured out root issue that was leading us to believe that everything in our construction was broken (even though we still think that rather than calling on construction, PostEditChangedProperty should be called).

Turns out return of AddInstance is not a handle that can be passed into RemoveInstance, as we had assumed. I highly suggest you guys add this to documentation. If it is in documentation, then I am very sad that we missed it as this sucked up a lot of everyone’s time.