Currently the developers are putting their own money into JC2-MP to keep the servers online.

Please take a few seconds of your time and disable your AdBlock plugin for our website.

Ad revenue is not going to developers, it is used purely for covering our hosting costs.

 

You are also free to donate, which removes all ads from our website!

Patch 0.3 was just released! Full changelog here: https://t.co/4A50m6IKen

2 years ago

Advertisement
October 16, 2019, 02:43:36 am

Author Topic: WorldNetworkObject vs. StaticObject  (Read 3451 times)

Dev_34

  • Full Member
  • ***
  • Posts: 158
    • View Profile
WorldNetworkObject vs. StaticObject
« on: February 26, 2016, 06:27:53 am »
I've found myself being put in the scenario where I need to sync something in the game world, and have a  hard time deciding whether I should use a WorldNetworkObject or a StaticObject.

In a specific situation I'm currently in, I need to sync a whole group of StaticObjects.
With multiple objects, it's obviously more efficient in terms of network usage to have one synced object moving in the game world that clients can use as a base position for spawning other objects, using ClientStaticObjects.

While for the above scenario it would logically make sense to use a WorldNetworkObject since the only attributes of the synced object that would need to be used are position, angle, and network values, WorldNetworkObjects occasionally don't load in properly when the client first joins, which can become a big issue in some cases. This makes the use of the StaticObject for the same purpose far more enticing.

StaticObjects, on the other hand, are far older in the API and never have streaming issues.

To me it would make sense to use an invisible StaticObject in the place of a WorldNetworkObject, since almost all of the functionalities of the WorldNetworkObject are possible with a StaticObject.

The only significant differences I can think of are the WorldNetworkObject:GetValues() call that isn't possible for StaticObjects, and that there is no client-side GetWorldNetworkObjects() iterator. This and the other differences can be worked around fairly easily.

So I guess my questions are:

Which one should I be using if I want to have a group of StaticObjects synced, given that I wouldn't create all these objects as server-side StaticObjects, but rather be using one WorldNetworkObject or StaticObject to represent the group?

Is there a notable difference in networking efficiency between the two? Does the syncing of the model and collision for a StaticObject have a discernible impact on how fast it is synced among clients in comparison to WorldNetworkObjects who don't have these arguments?

Am I overthinking this?

On a side-note, does anyone know how all this network traffic adds up?
Would changing the position of a StaticObject server-side result in a figurative Network:Send() with the new position of the object?
In that case I could see Network:Send as a better alternative in cases where many nearby server objects need to be synced with clients, as one could aggregate this data into one Network:Send and send on a delay. This is assuming jc-mp doesn't already do something like this.
« Last Edit: February 26, 2016, 06:42:05 am by Dev_34 »

JasonMRC

  • Donator
  • Hero Member
  • *****
  • Posts: 601
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #1 on: February 26, 2016, 07:00:30 am »
The best solution would be iteration and stream notice for SOs, NOs, WNOs. But unfortunately we don't have that yet.

I use StaticObjects to do what you are describing because I can't see when a WNO streams in nor can I iterate through it without manually handling a list of them.

The only significant differences I can think of are the WorldNetworkObject:GetValues() call that isn't possible for StaticObjects...
Can you explain the need for this? If you routinely need to get multiple values as a table perhaps have one value set as that table would be better?

Quote
Is there a notable difference in networking efficiency between the two? Does the syncing of the model and collision for a StaticObject have a discernible impact on how fast it is synced among clients?
The Model/Collisions are strings and synced regardless (Unless they are coded differently than one would assume). This can be used to your advantage. You can use the Model as a sort of Anchor and the Collision to store permanent data for that item. Of course if you have Build then you'll have to be careful to make sure your custom objects cannot be moved by players and aren't saved by your object saver.

I don't think there is a difference in efficiency between the two. Just be wary that having hundreds to thousands of StaticObjects in one stream area will cause client lag, as I imagine having lots of WNOs would also do.

A Dev or Betatester perhaps can address if one is more efficient, but operationally I think you should choose whichever is easiest for you to work with.

Dev_34

  • Full Member
  • ***
  • Posts: 158
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #2 on: February 26, 2016, 07:28:24 am »
I use StaticObjects to do what you are describing because I can't see when a WNO streams in nor can I iterate through it without manually handling a list of them.

Can't you see when one streams in with the WorldNetworkObjectCreate event?

The only significant differences I can think of are the WorldNetworkObject:GetValues() call that isn't possible for StaticObjects...
Can you explain the need for this? If you routinely need to get multiple values as a table perhaps have one value set as that table would be better?

Seems I contradicted myself there, I meant to list some of the slight differences between the two, and as I mentioned, they can easily be worked around.


The Model/Collisions are strings and synced regardless (Unless they are coded differently than one would assume). This can be used to your advantage. You can use the Model as a sort of Anchor and the Collision to store permanent data for that item. Of course if you have Build then you'll have to be careful to make sure your custom objects cannot be moved by players and aren't saved by your object saver.

Ha, I've never thought about this. This is really creative and I think I'll start doing this.


A Dev or Betatester perhaps can address if one is more efficient, but operationally I think you should choose whichever is easiest for you to work with.

I think you might be right. It's possible StaticObject and WorldNetworkObject were both just created out of similar templates, but slightly different for convenience, and maybe debating which one to use is pointless.


Just be wary that having hundreds to thousands of StaticObjects in one stream area will cause client lag, as I imagine having lots of WNOs would also do.

People have been saying this for a really long time, but all the tests I've run with StaticObjects seem to indicate that it's not the actual amount or presence of the StaticObjects that causes lag, it's the streaming in and out of them constantly for the client that seems to cause lag.
Lord Farquaad has recently put together a 'planet generator' script that spawns thousands of StaticObjects within very close proximity of each other, all with a streaming distance of 5000, meaning you'd stream that all in once.

On my computer, the initial streaming-in of these objects drops my FPS ~5-10 frames for a few seconds, then I get a solid 60 (my usual FPS) after that.

Maybe he can comment further on his findings regarding this.


Thanks for the reply, I think I'll go your route and use StaticObjects, especially now since I can put the model and collision strings to good use.

SinisterRectus

  • JC2-MP Betatester
  • Sr. Member
  • *****
  • Posts: 451
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #3 on: February 26, 2016, 02:05:05 pm »
Other differences:

- WorldNetworkObjects don't require an angle argument in their construction. If it's omitted, the zero angle is used.
- You can include values in the WNO construction. Useful if a player is within stream distance when the object is created.
- StaticObjects also have their 'fixed' property. I assume that's extra information to stream.
- WNOs use a different event for creation / destruction compared to SOs.
- WNOs inherit from NOs and share their ID pool with them.
- You cannot change or nil a StaticObject's model or collision data.

And in my personal opinion, using a StaticObject just to store information is poor practice. I'll investigate performance over the weekend.
« Last Edit: February 26, 2016, 02:13:26 pm by SinisterRectus »

JasonMRC

  • Donator
  • Hero Member
  • *****
  • Posts: 601
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #4 on: February 26, 2016, 08:14:48 pm »
I use StaticObjects to do what you are describing because I can't see when a WNO streams in nor can I iterate through it without manually handling a list of them.
Can't you see when one streams in with the WorldNetworkObjectCreate event?
I don't know. The event says Create, not Spawn and there is no note on the page about whether or not it fires on the client side each time it comes into stream. Can someone confirm this?

Quote
People have been saying this for a really long time, but all the tests I've run with StaticObjects seem to indicate that it's not the actual amount or presence of the StaticObjects that causes lag, it's the streaming in and out of them constantly for the client that seems to cause lag.
Lord Farquaad has recently put together a 'planet generator' script that spawns thousands of StaticObjects within very close proximity of each other, all with a streaming distance of 5000, meaning you'd stream that all in once.

On my computer, the initial streaming-in of these objects drops my FPS ~5-10 frames for a few seconds, then I get a solid 60 (my usual FPS) after that.
Do you know about how many objects that is?

Other differences:
- You cannot change or nil a StaticObject's model or collision data.

And in my personal opinion, using a StaticObject just to store information is poor practice. I'll investigate performance over the weekend.
Yes, using it just to store information is poor practice and I don't recommend it. The application which I was suggesting - and I believe Dev was asking about - is a way to make an extension of sorts using ClientStaticObjects which requires only one item on the server to be updated. Using a StaticObject you can set it's model to a certain name so that you know to operate on it accordingly. The collision can likewise be used to store permanent data or simply left blank. You can then set values for your dynamic data.

If you just need to store information I'd suggest an NO/SO/WNO.

Dev_34

  • Full Member
  • ***
  • Posts: 158
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #5 on: February 26, 2016, 09:02:49 pm »
I use StaticObjects to do what you are describing because I can't see when a WNO streams in nor can I iterate through it without manually handling a list of them.
Can't you see when one streams in with the WorldNetworkObjectCreate event?
I don't know. The event says Create, not Spawn and there is no note on the page about whether or not it fires on the client side each time it comes into stream. Can someone confirm this?

I've used WorldNetworkObjects quite a lot, and can confirm that the event fires client-side when a client streams one in.
The corresponding Destroy event also fires when a client leaves the streaming distance.


Do you know about how many objects that is?

Here is a little video that features around 5,000 StaticObjects all with a streaming distance of 5000.
Notice the initial FPS drop when streaming them in, and how the FPS returns to 60 for the most part.

https://www.youtube.com/watch?v=7FDdd7xemLM&feature=youtu.be

I just re-did the experiment with a streaming distance of 100, meaning there would be a lot of streaming in and out if I were moving around a lot, but it didn't seem to have an effect.
Not sure what to think  :-\
« Last Edit: February 26, 2016, 09:20:28 pm by Dev_34 »

Lord_Farquaad

  • Full Member
  • ***
  • Posts: 217
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #6 on: February 27, 2016, 02:43:58 am »
Lord Farquaad has recently put together a 'planet generator' script that spawns thousands of StaticObjects within very close proximity of each other, all with a streaming distance of 5000, meaning you'd stream that all in once.

On my computer, the initial streaming-in of these objects drops my FPS ~5-10 frames for a few seconds, then I get a solid 60 (my usual FPS) after that.

Maybe he can comment further on his findings regarding this.

From my investigations regarding the many objects that make up the planets, I can confirm that there is an FPS drop when you stream them in.  However, that's not the problem.  The problem is how they are spaced relative to each other (or so I think).  In earlier versions of the module, the terrain objects were able to sit right on top of each other, and this caused major FPS issues when looking at the cluster.  However, when you looked away from the tight cluster of objects, the FPS would rise quite significantly, as if there weren't any objects.

When I looked at one of the tight clusters of objects, my FPS was around 10-30.  When I looked away at the sky, my FPS jumped up to 60-80.  The interesting thing about this is when the object was changed (to whale in the tests), my FPS was stable around 50-60 when looking at what would have been the largest clusters before.  It's really strange that the distance of objects to each other would affect FPS.


SinisterRectus

  • JC2-MP Betatester
  • Sr. Member
  • *****
  • Posts: 451
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #7 on: February 27, 2016, 08:29:30 am »
What happens to FPS if you remove the collisions?

Darwood37

  • Donator
  • Hero Member
  • *****
  • Posts: 690
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #8 on: February 27, 2016, 02:59:33 pm »
Shadow quality and object detail settings if set to high or very high have a huge effect on FPS when looking at detailed objects.

Lord_Farquaad

  • Full Member
  • ***
  • Posts: 217
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #9 on: February 27, 2016, 06:22:20 pm »
What happens to FPS if you remove the collisions?
Still produces a large FPS drop.

Shadow quality and object detail settings if set to high or very high have a huge effect on FPS when looking at detailed objects.
My settings are at mostly low with a few mediums.

JasonMRC

  • Donator
  • Hero Member
  • *****
  • Posts: 601
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #10 on: February 27, 2016, 08:01:47 pm »
When I looked at one of the tight clusters of objects, my FPS was around 10-30.  When I looked away at the sky, my FPS jumped up to 60-80.  The interesting thing about this is when the object was changed (to whale in the tests), my FPS was stable around 50-60 when looking at what would have been the largest clusters before.  It's really strange that the distance of objects to each other would affect FPS.
What if you change it to something smaller, that has less surface texture?
Code: [Select]
Traffic Cone
"35x12.flz/go040-b.lod"  -- Model
"go040_lod1-b_col.pfx" -- Collision

Lord_Farquaad

  • Full Member
  • ***
  • Posts: 217
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #11 on: February 27, 2016, 09:01:58 pm »
The interesting thing about this is when the object was changed (to whale in the tests), my FPS was stable around 50-60 when looking at what would have been the largest clusters before.

So I did try it with the whale object Jason, and it caused very little frame drops (if any).  I expect that the traffic cone would cause even less drops, so it definitely has something to do with the amount of surface texture as you mentioned.

SinisterRectus

  • JC2-MP Betatester
  • Sr. Member
  • *****
  • Posts: 451
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #12 on: February 28, 2016, 04:03:29 pm »
Did some performance tests. Numbers are approximated averages.

Memory

Idle server with no scripts or objects: 25 MB

Code: [Select]
local tbl = {}
local pos = Vector3()
local ang = Angle()

Code: [Select]
for i = 1, 100000 do
local so = StaticObject.Create({
position = pos,
angle = ang,
model = "test1",
collision = "test2"
})
end
100k StaticObjects brings 25 MB to 94 MB

Code: [Select]
for i = 1, 100000 do
local so = StaticObject.Create({
position = pos,
angle = ang,
model = "test1",
collision = "test2"
})
tbl[so:GetId()] = so
end
100k StaticObjects with Lua refs brings 25 MB to 108 MB

Code: [Select]
for i = 1, 100000 do
local wno = WorldNetworkObject.Create({
position = pos,
angle = ang,
values = {
model = "test1",
collision = "test2"
}
})
end
100k WorldNetworkObjects brings 25 MB to 95 MB

Code: [Select]
for i = 1, 100000 do
local wno = WorldNetworkObject.Create({
position = pos,
angle = ang,
values = {
model = "test1",
collision = "test2"
}
})
tbl[wno:GetId()] = wno
end
100k WorldNetworkObjects with Lua refs brings 25 MB to 111 MB

Client at main screen: 680 MB
Client after connecting to server: 840 MB

Client after loading 100k StaticObjects defined above: 900 MB
Server after streaming 100k Static Objects: 137 MB (up from 108 MB)

Client after loading 100k WorldNetworkObjects defined above: 880 MB
Server after streaming 100k WorldNetworkObjects: 138 MB (up from 111 MB)

Conclusion: WorldNetworkObjects use slightly more server memory, but significantly less client memory than "blank" StaticObjects.

------

Function Calls

Code: [Select]
for _, so in pairs(tbl) do
local model = so:GetModel()
local collision = so:GetCollision()
end
70 ms to get model and collision of 100k StaticObjects

Code: [Select]
for _, wno in pairs(tbl) do
local model = wno:GetValue("model")
local collision = wno:GetValue("collision")
end
840 ms to get model and collision of 100k WorldNetworkObjects

Code: [Select]
for _, wno in pairs(tbl) do
local v = wno:GetValues()
local model = v.model
local collision = v.collision
end
490 ms to get both values and access the values tables

Conclusion: GetValue is a costly function for all StreamableObjects. It is considerably faster to access the model and collision of a StaticObject, which is comparable to other calls like GetPosition and GetAngle. GetValues takes the same amount of time to run as GetValue. Even with the extra time required to access the Lua table, use GetValues if more than one value is needed.

------

Network

Streaming 100k StaticObjects to one player: 10.4 MB sent / 31 kB received
Streaming 100k WorldNetworkObjects to one player: 11.0 MB sent / 35 kB received

Code: [Select]
for i = 1, 100000 do
Network:Send(Player.GetById(0), "Message", {model = "test1", collision = "test2"})
end
8.5 MB sent / 12 kB received

Code: [Select]
for i = 1, 100000 do
Network:Send(Player.GetById(0), "Message", {position = pos, angle = ang, model = "test1", collision = "test2"})
end
13.4 MB sent / 13 kB received

Conclusion: StaticObjects use slightly less bandwidth than WorldNetworkObjects, though the difference is negligible. Network events are reasonable alternatives for streaming data, but become more costly with more data.

------

Additionally, my client locked up twice, from 5 to 20 seconds, when the 100k StaticObjects were all streamed in at once. There was no delay with WorldNetworkObjects. Presumably, the StaticObjects are constructed by searching the client files for model and collision data.

You might see slight server performance increases using StaticObjects to stream data rather than WorldNetworkObjects (not sure why), and using the model and collision fields to store strings is clever, but the benefits are not enough to convince me to do it. I like to use WorldNetworkObjects as a base object.

Regarding the planet issue, I'd recommend using a single server object to construct a bunch of ClientStaticObjects like I do in my Maze module. I construct everything from a seed and a few dimensional variables.
« Last Edit: February 28, 2016, 04:38:10 pm by SinisterRectus »

Dev_34

  • Full Member
  • ***
  • Posts: 158
    • View Profile
Re: WorldNetworkObject vs. StaticObject
« Reply #13 on: February 28, 2016, 06:17:54 pm »
Thanks for taking the time to run these tests.

I think I'll end up using a StaticObject for my synced object since the streaming reliability is better and as you've shown, in terms of network usage and network speed, it's about the same as using a WorldNetworkObject or even very slightly better.

#TeamStaticObject