Project Interfaces¶
Modular Building System provides the following project extension interfaces:
| Interface | Purpose | Recommended Implementation Location |
|---|---|---|
IBuildingOwnerProvider |
Returns a stable owner ID for the initiator of a building operation. | PlayerState |
IBuildingWorldSupportProvider |
Determines whether a custom Actor can act as permanent world support. | The Actor that provides support |
Building Owner Provider¶
IBuildingOwnerProvider integrates the plugin's building ownership system with the project's player, faction, or NPC identification system.
The plugin usually obtains the PlayerState from the Controller that initiated the building operation, then reads an FBuildingOwnerId through this interface.
GetBuildingOwnerId¶
UFUNCTION(
BlueprintNativeEvent,
BlueprintCallable,
Category = "Building|Owner"
)
FBuildingOwnerId GetBuildingOwnerId();
| Type | Name | Data Type | Description |
|---|---|---|---|
| Return | OwnerId |
FBuildingOwnerId |
The stable building owner identifier associated with the current object. |
The returned value should remain stable across save operations and network synchronization.
Recommended Implementation Location¶
It is recommended to implement this interface in the project's PlayerState.
| Implementation Location | Recommendation |
|---|---|
PlayerState |
Recommended. Suitable for storing stable player identity and server replication. |
PlayerController |
Not recommended as the primary ownership source. It may not remain stable when the Controller changes. |
Pawn |
Not recommended. A Pawn may die, respawn, or be replaced. |
| Other objects | Can be used for faction, NPC, or system-level owners. |
Blueprint Implementation¶
In the project's PlayerState Blueprint:
Class Settings
→ Implemented Interfaces
→ Add Building Owner Provider
→ Implement Get Building Owner ID
Return the corresponding FBuildingOwnerId for the current player.
C++ Implementation¶
// Copyright 2026 Zhiying Li. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerState.h"
#include "Interfaces/BuildingOwnerProvider.h"
#include "MyPlayerState.generated.h"
UCLASS()
class AMyPlayerState
: public APlayerState
, public IBuildingOwnerProvider
{
GENERATED_BODY()
public:
virtual FBuildingOwnerId
GetBuildingOwnerId_Implementation() override;
};
// Copyright 2026 Zhiying Li. All Rights Reserved.
#include "MyPlayerState.h"
FBuildingOwnerId
AMyPlayerState::GetBuildingOwnerId_Implementation()
{
return FBuildingOwnerId::Player(
GetUniqueId().IsValid()
? GetUniqueId()->ToString()
: FString::FromInt(GetPlayerId())
);
}
The project should generate a stable ID according to its own save and online identity systems.
Calling from C++¶
The interface function is an Unreal Engine Interface Event and must be called through Execute_.
Warning
Do not call the interface event function directly:
Always call it through:
Owner Types¶
FBuildingOwnerId can represent different types of owners.
| Type | Description |
|---|---|
None |
No valid owner. |
Player |
A player owner. |
Faction |
A faction or team owner. |
NPC |
An NPC owner. |
System |
A game system or world owner. |
For more information about ownership data, see Building Entities.
Example¶
FString ATopiaPlayerState::GetStablePlayerSaveId() const
{
#if WITH_EDITOR
// PIE Test
if (!EditorStableSaveId.IsEmpty())
{
return EditorStableSaveId;
}
return FString::Printf(TEXT("PIE_Player_%d"), GetPlayerId());
#else
const FUniqueNetIdRepl PlayerUniqueId = GetUniqueId();
if (PlayerUniqueId.IsValid())
{
return PlayerUniqueId->ToString();
}
return TEXT("UnknownPlayer");
#endif
}
FBuildingOwnerId ATopiaPlayerState::
GetBuildingOwnerId_Implementation()
{
FBuildingOwnerId OwnerInfo;
OwnerInfo.Id = GetStablePlayerSaveId();
OwnerInfo.Type = EBuildingOwnerType::Player;
return OwnerInfo;
}
Building World Support Provider¶
IBuildingWorldSupportProvider allows a project to determine whether a specific Actor can act as permanent world support for a building structure.
This interface is optional. Standard terrain or static objects can also be configured as world support through collision channels and Tags.
CanProvideBuildingWorldSupport¶
UFUNCTION(
BlueprintNativeEvent,
BlueprintCallable,
Category = "Building|World Support"
)
bool CanProvideBuildingWorldSupport(
UPrimitiveComponent* HitComponent,
const FHitResult& HitResult
) const;
| Type | Name | Data Type | Description |
|---|---|---|---|
| Param | HitComponent |
UPrimitiveComponent* |
The component hit by the current support query. |
| Param | HitResult |
const FHitResult& |
The complete hit information from the current collision query. |
| Return | bCanProvideSupport |
bool |
Whether the current hit can act as permanent world support. |
The interface implementation can determine the result using:
- The hit component
- HISM Instance Index
- Hit location
- Surface normal
- Current Actor state
- Project-specific permissions or gameplay rules
Evaluation Order¶
World support detection is performed in the following order:
Check World Support Object Channel
→ Check World Support Excluded Tag
→ Call Building World Support Provider
→ Check the optional World Support Tag
| Check | Description |
|---|---|
| Object Channel | The hit component must use the configured World Support Object Channel. |
| Excluded Tag | An Actor or component with the exclusion Tag can never provide support. |
| Interface | If the Actor implements the interface, the interface determines the result. |
| Support Tag | If the Actor does not implement the interface and strict mode is enabled, it must have the support Tag. |
Warning
World Support Excluded Tag has higher priority than the interface.
Even if the interface returns true, an Actor or component with the exclusion Tag cannot provide support.
Blueprint Implementation¶
In the Actor Blueprint that requires custom support rules:
Class Settings
→ Implemented Interfaces
→ Add Building World Support Provider
→ Implement Can Provide Building World Support
For example, different results can be returned depending on the hit component:
| Hit Object | Return Value |
|---|---|
| Main ground component | true |
| Decorative component | false |
| Damaged platform | false |
| A specified load-bearing HISM Instance | true |
C++ Implementation¶
// Copyright 2026 Zhiying Li. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Interfaces/BuildingWorldSupportProvider.h"
#include "MyWorldSupportActor.generated.h"
UCLASS()
class AMyWorldSupportActor
: public AActor
, public IBuildingWorldSupportProvider
{
GENERATED_BODY()
public:
virtual bool
CanProvideBuildingWorldSupport_Implementation(
UPrimitiveComponent* HitComponent,
const FHitResult& HitResult
) const override;
};
// Copyright 2026 Zhiying Li. All Rights Reserved.
#include "MyWorldSupportActor.h"
bool AMyWorldSupportActor::
CanProvideBuildingWorldSupport_Implementation(
UPrimitiveComponent* HitComponent,
const FHitResult& HitResult
) const
{
return IsValid(HitComponent) &&
HitComponent->ComponentHasTag(
TEXT("CanSupportBuilding")
);
}
HISM Instances¶
When an HISM Component is hit, the Instance Index can be obtained from the hit result:
| Value | Description |
|---|---|
INDEX_NONE |
No valid Instance was hit. |
0 or greater |
The index of the hit HISM Instance. |
The interface can return different support results for different Instances.
Calling from C++¶
const bool bCanProvideSupport =
IBuildingWorldSupportProvider::
Execute_CanProvideBuildingWorldSupport(
HitActor,
HitComponent,
HitResult
);
Before calling the interface, check whether the Actor implements it:
if (
IsValid(HitActor) &&
HitActor->Implements<UBuildingWorldSupportProvider>()
)
{
const bool bCanProvideSupport =
IBuildingWorldSupportProvider::
Execute_CanProvideBuildingWorldSupport(
HitActor,
HitComponent,
HitResult
);
}
Choosing Between Interfaces and Tags¶
| Requirement | Recommended Method |
|---|---|
| All objects of the same type can provide support | Configure the collision channel. |
| Explicitly allow a specific Actor or component to provide support | Use World Support Tag. |
| Explicitly prevent a specific Actor or component from providing support | Use World Support Excluded Tag. |
| Evaluate support dynamically by component, Instance, or runtime state | Implement IBuildingWorldSupportProvider. |
When dynamic evaluation is not required, prefer collision channels and Tags instead of adding an interface implementation to simple objects.
Troubleshooting¶
| Issue | Description |
|---|---|
| The interface is not called | Check whether the hit component uses the correct World Support Object Channel. |
The interface returns true, but support is still rejected |
Check whether the Actor or component has the exclusion Tag. |
| The interface event cannot be found in Blueprint | Check whether the interface has been added in Class Settings. |
| Calling the interface from C++ causes an error | Use the corresponding Execute_ function. |
| HISM support evaluation is incorrect | Check whether HitResult.Item contains a valid Instance Index. |
| PlayerState returns an invalid Owner ID | Check whether the owner type and stable ID are configured correctly. |
For structural support configuration, see Structural Support and Collapse.