FortCharacter.Damage() seems to be unperformant

Summary

While investigating server side performance issues in my creative island, I discovered, that the FortCharacter.Damage() function seems to unreasonably costly.

I could reproduce the issue in a fresh project, where calling Damage() on a player took around 0.72ms and calling it on a Guard from the Guard Spawner Device around 0.5ms.

As I need to call the Damage() function multiple times per Second in multiple Devices, this is currently killing the server performance of my island a lot.

Please select what you are reporting on:

Unreal Editor for Fortnite

What Type of Bug are you experiencing?

Verse

Steps to Reproduce

  1. Create a fresh project.
  2. Setup a simple device to Damage the player by the press of a button, utilizing the Damage() function of FortCharacter.
  3. Add profile to the function calling Damage
  4. Press the button and watch the Output log for the profiled function runtime

Expected Result

The cost of FortCharacter.Damage() has to be much lower, as it should not perform any complex computional operations.

Observed Result

Calling Damage on a Player takes 0.7 - 0.75 ms
Calling Damage on a Guard takes 0.5 - 0.55 ms

Platform(s)

Tested on PC, but probably all Platforms

Upload an image


Thank you, we’ll get someone to take a look.

1 Like

FORT-858635 has been added to our ‘To Do’ list. Someone’s been assigned this task.

Tested today again:

Damage() on a Player is now equal to calling Damage() on an NPC with around 0.5ms, but still much too high in my opinion.

do you get higher times for higher damage?

these were my observations :

Damage 1.0 = VerseProfile: KillingPlayerProfile 0.621800 ms

Damage 100.0 = VerseProfile: KillingPlayerProfile 1.062700 ms

Damage 200.0 = VerseProfile: KillingPlayerProfile 4.602000 ms

however, 1 millisecond is 1/1000th of a second, is half a millisecond or even 4 milliseconds really too long?

i’m new to gamedev, what are your expectations for the Damage() call?

Good observation, but I think it might actually not be related to increased damage values.

I setup an extended Test Project for this. This project inflicts different Damage values on the Player and each Damage Value gets applied 20 times for a robust data set.

These are the runtimes I profiled:

DamageFunction Runtime(ms)
Damage(1) average 0.529395
Damage(2) average 0.47123
Damage(4) average 0.49374
Damage(8) average 0.48028
Damage(16) average 0.48336
Average 0.491601
Damage(10) average 0.49534
Damage(20) average 0.528975
Damage(40) average 0.49866
Damage(80) average 0.52665
Damage(160) average 0.495495
Average 0.509024
Damage(100) average 0.51842
Damage(200) average 0.483995
Damage(400) average 0.53698
Damage(800) average 0.52955
Damage(1600) average 0.52165
Average 0.518119

So it does not seem like higher damage values influence the runtime of Damage().

But I observed something different while testing. Each time I performed a Verse change and pushed that to the session, the runtimes of the Damage() function increased.

Take a look:

Verse Push 1

DamageFunction Runtime(ms)
Damage(1) average 0.584855
Damage(2) average 0.5929
Damage(4) average 0.76719
Damage(8) average 0.757815
Damage(16) average 0.627705
Average 0.666093
Damage(10) average 0.6867
Damage(20) average 0.787575
Damage(40) average 0.60073
Damage(80) average 0.626065
Damage(160) average 0.633705
Average 0.666955
Damage(100) average 0.644415
Damage(200) average 0.60908
Damage(400) average 0.578215
Damage(800) average 0.58201
Damage(1600) average 0.602735
Average 0.603291

Verse Push 2

DamageFunction Runtime(ms)
Damage(1) average 0.669625
Damage(2) average 0.734505
Damage(4) average 0.63252
Damage(8) average 0.61244
Damage(16) average 0.603105
Average 0.650439
Damage(10) average 0.586915
Damage(20) average 0.60473
Damage(40) average 0.62434
Damage(80) average 0.66466
Damage(160) average 0.617105
Average 0.61955
Damage(100) average 0.636835
Damage(200) average 0.626705
Damage(400) average 0.61065
Damage(800) average 0.62133
Damage(1600) average 0.625995
Average 0.624303

Verse Push 3

DamageFunction Runtime(ms)
Damage(1) average 0.71006
Damage(2) average 0.93862
Damage(4) average 0.94068
Damage(8) average 0.94012
Damage(16) average 0.965275
Average 0.898951
Damage(10) average 0.694335
Damage(20) average 0.683825
Damage(40) average 0.72325
Damage(80) average 0.74583
Damage(160) average 0.67905
Average 0.705258
Damage(100) average 0.65615
Damage(200) average 0.68986
Damage(400) average 0.68032
Damage(800) average 0.65459
Damage(1600) average 0.65222
Average 0.666628

Verse Push 4

DamageFunction Runtime(ms)
Damage(1) average 0.75161
Damage(2) average 0.84514
Damage(4) average 0.81282
Damage(8) average 0.767105
Damage(16) average 0.73969
Average 0.783273
Damage(10) average 0.754245
Damage(20) average 0.758615
Damage(40) average 0.715425
Damage(80) average 0.696735
Damage(160) average 0.73606
Average 0.732216
Damage(100) average 0.731175
Damage(200) average 0.695135
Damage(400) average 0.688925
Damage(800) average 0.74599
Damage(1600) average 0.719975
Average 0.71624

So that might explain why your runtimes increased with higher damage values, because you probably pushed Verse changes in between.

And also dying from Damage() seems to be very costly with around 3.0ms-5.0ms, which might explain your runtime of 4.6 ms when inflicting 200 damage.

Regarding your question if the runtime is really too long:

My opinion, that the runtime is too long is based on the operations that such a function should be performing:

  • Decrease the player health by the amount of damage
  • Check if the player died after applying the damage
  • Trigger an event that the player health changed
  • Trigger an event if the player died

Each of the listed operations costs under normal circumstances something like 0.00X ms to 0.0X ms.

So in sum it should never even exceed 0.1 ms and it also must not be a costly operation, because in a game like fortnite it is a really frequently called function.

2 Likes

you are correct in both assumptions, i was pushing changes and dying is very costly it seems

i re-ran my tests with multiple buttons instead and get figures more like yours

thank you for the explanation, appreciate it

i hid the health and shield indicators via the HUD controller just to see if it was the screen update consuming the time but it didn’t seem to make much difference unfortunately

good luck, i hope they find a way to improve performance

1 Like