Summary
I discovered a case where accessing existing player data in a subsequent round from component.OnSimulate
will always cause a runtime crash.
The crash happens in v33.30 and is fully reproducible (starting with the second round - VARIANT A).
Please select what you are reporting on:
Verse
What Type of Bug are you experiencing?
Stability
Steps to Reproduce
The example is fully self contained.
- place an entity with the component code from below
- compile and run a round
- end the round
- start another round
Variant A (async) always crashes. If you try the non-async variant B, it will not crash and work as expected.
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SceneGraph }
using { /Fortnite.com/Game }
using { /Fortnite.com/Playspaces }
# Some simpler player data class.
vz_player_data_v1 := class<final><persistable> {
Number: int = 42
}
# A player store containing player data object.
vz_player_store := class<final><persistable> {
PlayerData_v1: ?vz_player_data_v1 = false
GetPlayerData()<transacts><decides>: vz_player_data_v1 = {
PlayerData_v1?
}
}
# Player store weak map.
var PlayerStore_1: weak_map(player, vz_player_store) = map {}
vz_test_persistence_component := class<final_super>(component) {
var Subscriptions<private>: []cancelable = array {}
#--------------------------#
# PROPERTIES FOR VARIANT A #
#--------------------------#
RoundEvent<private>: event() = event() {}
var IsRoundActive<private>: logic = false
#------------------#
# LIFETIME METHODS #
#------------------#
OnBeginSimulation<override>(): void = {
(super:)OnBeginSimulation()
if (RoundManager := Entity.GetFortRoundManager[]) {
set Subscriptions = array {
RoundManager.SubscribeRoundEnded(RoundEnded)
# VARIANT A - CRASHING
RoundManager.SubscribeRoundStarted(RoundStarted_A)
# VARIANT B - OKAY
#RoundManager.SubscribeRoundStarted(RoundStarted_B)
}
}
}
OnSimulate<override>()<suspends>: void = {
# CRASHING VARIANT (A)
if (not IsRoundActive?) {
Print("Will await round start")
RoundEvent.Await()
}
LookupPlayspaceParticipant()
}
#-----------#
# VARIANT A #
#-----------#
RoundStarted_A()<suspends>: void = {
Print("Round started")
set IsRoundActive = true
RoundEvent.Signal()
}
RoundEnded(): void = {
Print("Round ended")
set IsRoundActive = false
}
#-----------#
# VARIANT B #
#-----------#
RoundStarted_B()<suspends>: void = {
LookupPlayspaceParticipant()
}
#------------------------------------------------------------------------------#
#------------------------------------------------------------------------------#
LookupPlayspaceParticipant(): void = {
if (Playspace := Entity.GetPlayspaceForEntity[]) {
for (Participant: Playspace.GetParticipants()) {
ParticipantAdded(Participant)
}
}
}
ParticipantAdded(Participant: agent): void = {
# Get the player store object for the given player, persist it if it's new.
if (Player := player[Participant]) {
PlayerStore := if (ExistingPlayerStore := PlayerStore_1[Player]) {
Print("Using existing player store")
ExistingPlayerStore
} else {
Print("Creating new player store")
NewPlayerStore := vz_player_store {
PlayerData_v1 := option {
vz_player_data_v1 {}
}
}
if {
set PlayerStore_1[Player] = NewPlayerStore
Print("Stored new player store")
}
NewPlayerStore
}
Print("Try accessing the player data 1")
if (PlayerData := PlayerStore.PlayerData_v1?) {
Print(ToDiagnostic(PlayerData))
}
Print("Try accessing the player data 2")
if (PlayerData := PlayerStore.GetPlayerData[]) {
Print(ToDiagnostic(PlayerData))
}
}
}
}
Reproducible crash stack trace:
[2025.02.12-11.00.36:895][686]LogVerse: : Will await round start
[2025.02.12-11.00.55:428][940]LogVerse: : Round started
[2025.02.12-11.00.55:428][940]LogVerse: : Using existing player store
[2025.02.12-11.00.55:429][940]LogVerse: : Try accessing the player data 1
[2025.02.12-11.00.55:430][940]LogVerse: Error: VerseRuntimeErrors: Verse unrecoverable error: ErrRuntime_Internal: An internal runtime error occurred. There is no other information available. (Internal error encountered: Attempted to access vz_player_store_2147482641 via property __verse_0x5F3EF02F_PlayerStore_1, but vz_player_store_2147482641 is not valid (pending kill or garbage).)
Truncated callstack follows:
(.../vz_test_persistence_component:)ParticipantAdded(:agent) (Source: /vz_test_persistence_component.verse(117,10, 118,11))
(.../vz_test_persistence_component:)LookupPlayspaceParticipant (Source: /vz_test_persistence_component.verse(91,24, 92,25))
OnSimulate (Source: /vz_test_persistence_component.verse(59,30, 60,31))
Expected Result
It should not crash at runtime.
Observed Result
It always crashes at the beginning of the second and any further rounds in a uefn session.
Platform(s)
PC