Skip to content

Commit

Permalink
Fixed multiplayer client crashes on UE 4.27
Browse files Browse the repository at this point in the history
  • Loading branch information
BenPyton committed Jul 18, 2024
1 parent c46dd29 commit 47b0474
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 27 deletions.
6 changes: 3 additions & 3 deletions Source/ProceduralDungeon/Private/DungeonGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,6 @@ void ADungeonGenerator::OnStateBegin(EGenerationState State)
case EGenerationState::Initialization:
DungeonLog_Info("======= Begin Dungeon Initialization =======");
Graph->SynchronizeRooms();
UpdateOctree();
break;
case EGenerationState::Load:
DungeonLog_Info("======= Begin Load All Levels =======");
Expand All @@ -571,7 +570,6 @@ void ADungeonGenerator::OnStateBegin(EGenerationState State)

void ADungeonGenerator::OnStateTick(EGenerationState State)
{
int RoomCount = 0;
switch (State)
{
case EGenerationState::Idle:
Expand All @@ -587,7 +585,8 @@ void ADungeonGenerator::OnStateTick(EGenerationState State)
SetState(EGenerationState::Initialization);
break;
case EGenerationState::Initialization:
SetState(EGenerationState::Load);
if (Graph->AreRoomsReady())
SetState(EGenerationState::Load);
break;
case EGenerationState::Load:
if (Graph->AreRoomsInitialized(CachedTmpRoomCount))
Expand Down Expand Up @@ -618,6 +617,7 @@ void ADungeonGenerator::OnStateEnd(EGenerationState State)
break;
case EGenerationState::Initialization:
DungeonLog_Info("======= End Dungeon Initialization =======");
UpdateOctree();
break;
case EGenerationState::Load:
DungeonLog_Info("======= End Load All Levels =======");
Expand Down
10 changes: 10 additions & 0 deletions Source/ProceduralDungeon/Private/DungeonGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,16 @@ bool UDungeonGraph::AreRoomsInitialized(int32& NbRoomInitialized) const
return NbRoomInitialized >= Rooms.Num();
}

bool UDungeonGraph::AreRoomsReady() const
{
for (URoom* Room : Rooms)
{
if (!(IsValid(Room) && Room->IsReady()))
return false;
}
return true;
}

void UDungeonGraph::RequestGeneration()
{
check(GetOwner()->HasAuthority());
Expand Down
64 changes: 49 additions & 15 deletions Source/ProceduralDungeon/Private/Room.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,20 @@ URoom::URoom()
void URoom::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION(URoom, RoomData, COND_InitialOnly);
DOREPLIFETIME_CONDITION(URoom, Position, COND_InitialOnly);
DOREPLIFETIME_CONDITION(URoom, Direction, COND_InitialOnly);
DOREPLIFETIME_CONDITION(URoom, Connections, COND_InitialOnly);
DOREPLIFETIME_CONDITION(URoom, GeneratorOwner, COND_InitialOnly);
DOREPLIFETIME_CONDITION(URoom, Id, COND_InitialOnly);

FDoRepLifetimeParams Params;
Params.bIsPushBased = true;
DOREPLIFETIME_WITH_PARAMS(URoom, bIsLocked, Params);
DOREPLIFETIME_WITH_PARAMS(URoom, CustomData, Params);

// InitialOnly is not called on newly created subobjects after the InitialCond of actor owner has already been called!!!
//Params.Condition = COND_InitialOnly;
DOREPLIFETIME_WITH_PARAMS(URoom, RoomData, Params);
DOREPLIFETIME_WITH_PARAMS(URoom, Position, Params);
DOREPLIFETIME_WITH_PARAMS(URoom, Direction, Params);
DOREPLIFETIME_WITH_PARAMS(URoom, Connections, Params);
DOREPLIFETIME_WITH_PARAMS(URoom, GeneratorOwner, Params);
DOREPLIFETIME_WITH_PARAMS(URoom, Id, Params);
}

bool URoom::ReplicateSubobjects(UActorChannel* Channel, FOutBunch* Bunch, FReplicationFlags* RepFlags)
Expand All @@ -78,15 +81,16 @@ void URoom::RegisterReplicableSubobjects(bool bRegister)

void URoom::Init(URoomData* Data, ADungeonGenerator* Generator, int32 RoomId)
{
RoomData = Data;
GeneratorOwner = Generator;
Id = RoomId;
SET_SUBOBJECT_REPLICATED_PROPERTY_VALUE(RoomData, Data);
SET_SUBOBJECT_REPLICATED_PROPERTY_VALUE(GeneratorOwner, Generator);
SET_SUBOBJECT_REPLICATED_PROPERTY_VALUE(Id, RoomId);
Instance = nullptr;
Position = FIntVector(0, 0, 0);
Direction = EDoorDirection::North;
SetPosition(FIntVector::ZeroValue);
SetDirection(EDoorDirection::North);

if (IsValid(RoomData))
{
MARK_PROPERTY_DIRTY_FROM_NAME(URoom, Connections, this);
for (int i = 0; i < RoomData->GetNbDoor(); i++)
{
Connections.Add(FRoomConnection());
Expand All @@ -109,6 +113,7 @@ void URoom::SetConnection(int Index, URoom* Room, int OtherIndex)
check(Index >= 0 && Index < Connections.Num());
Connections[Index].OtherRoom = Room;
Connections[Index].OtherDoorIndex = OtherIndex;
MARK_PROPERTY_DIRTY_FROM_NAME(URoom, Connections, this);
}

TWeakObjectPtr<URoom> URoom::GetConnection(int Index) const
Expand Down Expand Up @@ -214,11 +219,40 @@ void URoom::Lock(bool bLock)
DungeonLog_InfoSilent("[%s] Room '%s' setting IsLocked: %s", *GetAuthorityName(), *GetNameSafe(this), bIsLocked ? TEXT("True") : TEXT("False"));
}

void URoom::SetPosition(const FIntVector& NewPosition)
{
SET_SUBOBJECT_REPLICATED_PROPERTY_VALUE(Position, NewPosition);
}

void URoom::SetDirection(EDoorDirection NewDirection)
{
SET_SUBOBJECT_REPLICATED_PROPERTY_VALUE(Direction, NewDirection);
}

void URoom::OnRep_IsLocked()
{
DungeonLog_InfoSilent("[%s] Room '%s' IsLocked Replicated: %s", *GetAuthorityName(), *GetNameSafe(this), bIsLocked ? TEXT("True") : TEXT("False"));
}

void URoom::OnRep_Id()
{
DungeonLog_InfoSilent("[%s] Room '%s' Id Replicated: %d", *GetAuthorityName(), *GetNameSafe(this), Id);
}

void URoom::OnRep_RoomData()
{
DungeonLog_InfoSilent("[%s] Room '%s' RoomData Replicated: %s", *GetAuthorityName(), *GetNameSafe(this), *GetNameSafe(RoomData));
}

void URoom::OnRep_Connections()
{
DungeonLog_InfoSilent("[%s] Room '%s' Connections Replicated", *GetAuthorityName(), *GetNameSafe(this));
for (const auto& Connection : Connections)
{
DungeonLog_InfoSilent("- Connected to %s (door id: %d)", *GetNameSafe(Connection.OtherRoom.Get()), Connection.OtherDoorIndex);
}
}

ARoomLevel* URoom::GetLevelScript() const
{
if (Instance == nullptr || !IsValid(Instance))
Expand Down Expand Up @@ -335,20 +369,20 @@ FBoxMinAndMax URoom::RoomToWorld(const FBoxMinAndMax& RoomBox) const
void URoom::SetRotationFromDoor(int DoorIndex, EDoorDirection WorldRot)
{
check(DoorIndex >= 0 && DoorIndex < RoomData->Doors.Num());
Direction = WorldRot - RoomData->Doors[DoorIndex].Direction;
SetDirection(WorldRot - RoomData->Doors[DoorIndex].Direction);
}

void URoom::SetPositionFromDoor(int DoorIndex, FIntVector WorldPos)
{
check(DoorIndex >= 0 && DoorIndex < RoomData->Doors.Num());
Position = WorldPos - Rotate(RoomData->Doors[DoorIndex].Position, Direction);
SetPosition(WorldPos - Rotate(RoomData->Doors[DoorIndex].Position, Direction));
}

void URoom::SetPositionAndRotationFromDoor(int DoorIndex, FIntVector WorldPos, EDoorDirection WorldRot)
{
check(DoorIndex >= 0 && DoorIndex < RoomData->Doors.Num());
Direction = WorldRot - RoomData->Doors[DoorIndex].Direction;
Position = WorldPos - Rotate(RoomData->Doors[DoorIndex].Position, Direction);
SetDirection(WorldRot - RoomData->Doors[DoorIndex].Direction);
SetPosition(WorldPos - Rotate(RoomData->Doors[DoorIndex].Position, Direction));
}

bool URoom::IsOccupied(FIntVector Cell)
Expand Down
1 change: 1 addition & 0 deletions Source/ProceduralDungeon/Public/DungeonGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ class PROCEDURALDUNGEON_API UDungeonGraph : public UReplicableObject
bool AreRoomsLoaded(int32& NbRoomLoaded) const;
bool AreRoomsUnloaded(int32& NbRoomUnloaded) const;
bool AreRoomsInitialized(int32& NbRoomInitialized) const;
bool AreRoomsReady() const;

void RequestGeneration();
void RequestUnload();
Expand Down
35 changes: 26 additions & 9 deletions Source/ProceduralDungeon/Public/Room.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ struct FRoomConnection
public:
UPROPERTY()
TWeakObjectPtr<URoom> OtherRoom {nullptr};

UPROPERTY()
int OtherDoorIndex {-1};

UPROPERTY()
ADoor* DoorInstance {nullptr};
};

Expand Down Expand Up @@ -87,6 +91,7 @@ class PROCEDURALDUNGEON_API URoom : public UReplicableObject
void SetPlayerInside(bool PlayerInside);
void SetVisible(bool Visible);
FORCEINLINE uint64 GetRoomID() const { return Id; }
FORCEINLINE bool IsReady() const { return RoomData != nullptr; }

// Is the player currently inside the room?
// A player can be in multiple rooms at once, for example when he stands at the door frame,
Expand Down Expand Up @@ -168,19 +173,19 @@ class PROCEDURALDUNGEON_API URoom : public UReplicableObject
FVector GetBoundsExtent() const;

private:
UPROPERTY(Replicated)
UPROPERTY(ReplicatedUsing = OnRep_RoomData)
URoomData* RoomData {nullptr};

UPROPERTY(Replicated, Transient)
TArray<FCustomDataPair> CustomData;

UPROPERTY(Replicated)
UPROPERTY(ReplicatedUsing = OnRep_Connections)
TArray<FRoomConnection> Connections;

UPROPERTY(Replicated)
TWeakObjectPtr<ADungeonGenerator> GeneratorOwner {nullptr};

UPROPERTY(Replicated)
UPROPERTY(ReplicatedUsing = OnRep_Id)
int64 Id {-1};

bool bPlayerInside {false};
Expand All @@ -189,12 +194,6 @@ class PROCEDURALDUNGEON_API URoom : public UReplicableObject
UPROPERTY(ReplicatedUsing = OnRep_IsLocked)
bool bIsLocked {false};

UFUNCTION() // Needed macro for replication to work
void OnRep_IsLocked();

UFUNCTION() // needed macro for binding to delegate
void OnInstanceLoaded();

const FCustomDataPair* GetDataPair(const TSubclassOf<URoomCustomData>& DataType) const;

protected:
Expand All @@ -203,6 +202,24 @@ class PROCEDURALDUNGEON_API URoom : public UReplicableObject
virtual void RegisterReplicableSubobjects(bool bRegister) override;
//~ End UReplicableObject Interface

void SetPosition(const FIntVector& NewPosition);
void SetDirection(EDoorDirection NewDirection);

UFUNCTION() // Needed macro for replication to work
void OnRep_RoomData();

UFUNCTION() // Needed macro for replication to work
void OnRep_Id();

UFUNCTION() // Needed macro for replication to work
void OnRep_Connections();

UFUNCTION() // Needed macro for replication to work
void OnRep_IsLocked();

UFUNCTION() // needed macro for binding to delegate
void OnInstanceLoaded();

public:
void Init(URoomData* RoomData, ADungeonGenerator* Generator, int32 RoomId);

Expand Down

0 comments on commit 47b0474

Please sign in to comment.