Is object retexturing data supposed to be sent this way?
#1

Retexturing RPCs format seems to be VERY, VERY unefficient and bandwidth consuming.

Bug 1:

Let's consider the following snippet:
Код:
main()
{
	new handle = CreateObject(19371, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0);
	for(new idx; idx < 8; ++idx)
	{
		SetObjectMaterial(handle, idx, 19341, "egg_texts", "easter_egg01", -1);
		SetObjectMaterialText(handle, "2048 characters string", idx, OBJECT_MATERIAL_SIZE_256x128, "Arial", 28, 1, 0xFFFF8200, 0xFF000000, 2);
	}
}
At a first view, this code should send to client the following info:
- 1x CreateObject + parameters
- 8x SetObjectMaterial + parameters
- 8x SetObjectMaterialText + parameters

This is what a player receives from server:
1) RPC: CreateObject() parameters
2) RPC: CreateObject() parameters + all SetObjectMaterial() parameters (for material index 'idx' = 0)
3) RPC: CreateObject() parameters + all SetObjectMaterial() parameters (for material index 'idx' = 0) + all SetObjectMaterialText() parameters (for material index 'idx = 0')
4) RPC: CreateObject() parameters + all SetObjectMaterial() parameters (for material index 'idx' = 0) + all SetObjectMaterialText() parameters (for material index 'idx = 0') + all SetObjectMaterial() parameters (for material index 'idx' = 1)
5) RPC: CreateObject() parameters + all SetObjectMaterial() parameters (for material index 'idx' = 0) + all SetObjectMaterialText() parameters (for material index 'idx = 0') + all SetObjectMaterial() parameters (for material index 'idx' = 1) + all SetObjectMaterialText() parameters (for material index 'idx = 1')
6) RPC: CreateObject() parameters + all SetObjectMaterial() parameters (for material index 'idx' = 0) + all SetObjectMaterialText() parameters (for material index 'idx = 0') + all SetObjectMaterial() parameters (for material index 'idx' = 1) + all SetObjectMaterialText() parameters (for material index 'idx = 1') + all SetObjectMaterial() parameters (for material index 'idx' = 2) + all SetObjectMaterialText() parameters (for material index 'idx = 2')

...

17) ...

So, for each subsequent SetObjectMaterial(Text) call, server sends all previous material(text) data + current call data (+ initial CreateObject parameters + some extra bytes)

In case of our code snippet:
- object data is being sent 17 times
- material data is being sent 72 times
- text data is being sent 64 times

Size of data:
- for object: ~32 bytes each time
- for material: ~75 bytes each time
- for material text: ~2000 bytes each time (calculated for worst case = 2048 length text string)

Total size of data:
- for object: 17 * 32 = 544 Bytes
- for material: 72 * 75 = 5400 Bytes = ~= 5KB
- for material text: 64 * 2000 = 128,000 Bytes = ~128 KB (which is a lot for only 1 object per player)
- TOTAL: ~134 KB/object/player

Things get a lot worse when there are a lot of players to send data to and/or a streamer is used since objects are created, textured and destroyed very often, especially if there are lots of objects with small stream distances in very 'popular' areas.

------------------

Bug 2:

It states on wiki page that there are 16 (0-15) material indexes that can be used.

Let's consider the following snippet:
Код:
main()
{
	new handle = CreateObject(19371, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0);
	for(new idx; idx < 16; ++idx) // 8 -> 16
	{
		SetObjectMaterial(handle, idx, 19341, "egg_texts", "easter_egg01", -1);
		SetObjectMaterialText(handle, "Hello there", idx, OBJECT_MATERIAL_SIZE_256x128, "Arial", 28, 1, 0xFFFF8200, 0xFF000000, 2);
	}
}
Server will stop sending new data when idx >= 8. I guess there is a hardcoded limit of 16 material changes and the counter is increased by both material and material text function calls.




// I am aware that no-one would ever has a reason neither to send 2048 length strings for material retexturing, nor to call retexturing functions so often as I presented.
// But, heavily mapped servers that use streamer and lots of retextured objects would certainly benefit from optimizing these RPCs.

// Later edit: I forgot to mention that all my tests were made on global objects only (CreateObject) and everything I said about streamer plugin is based on assumptions. I did not test how player objects (or streamer objects, since streamer plugin is based on them) are sent to clients. I will post data usage for player objects in the following days.
Reply
#2

Finally an interesting topic about object materials.... I've been thinking that object material data using a number of bandwidth that is not small, i can see the total byte size from client F5 key, sometimes it just go peak at 60KB/s at a server with a dense object full material textures (no text) when streamed in, i noticed the object being drawn slowly like after 2 seconds i can see all texture of all (around 300) objects clearly, ofcourse the one which is closest drawn first since it uses streamer. If there are no objects, normally it's just around 1~3KB/s upload/download rate (or peak at 10KB/s for download when there are some players/vehicle around). Yea i'm aware that is relative to my internet speed rate is not good, it's just around 1Mb/s, also the server location distance is far and i got 300ms ping average. And no, it's not the hardware lag (that 2 seconds), since i don't get fps drop (stream memory is also enough), neither the server since it has good connection, don't know much about the script. The object are mostly tubes and ramps (since it's a stunt map) with only around 2 material textures.
Just i didn't know about how the SA-MP packets being send with it, from your experiment now i found out that the server always telling the client re-create the object data every time the object is modified, isn't it? In this case, probably using streamer requires higher bandwidth usage for server, since it's being re-created and destroyed when player is going near/far from the object.
But I'm wondering if the same method is used for TextDraw, any comparison you did test?
If what i'm trying to understand is true, then i think sa-mp need a "Builder" function for Objects/TextDraw to initialize the object properties before it's being send to the client to create (so it's being sent at once per object), not sure if that's possible.
Are these data actually being packed (compressed) when sent? or the test you did with RPC already decompress them? or maybe these object data are being cached into client memory? Well that's the optimization idea here, right? Not sure why you post it in Bug Reports section. Another idea is to encrypt these data, i know it does not really needed and it wont be much secure/reliable for the client sync but it's useful to avoid (decrease chance) the Map stealer hacks.


Oh also from what i know, you cannot place texture and text at same index at same time. You can only place one of them. Applying texture with text doesn't allow you to make it appear on client to have textured background for text, as it's being replaced with the background color parameter from Material Text. It should answer the reason why it stop sending new data when idx is >= 8. Did you try to send object material texture at index 0-7 and then text at index 8-15?

Well i'm sure a mapper should be experienced and know how to optimize their number of objects and the textures... They should know to not apply material texture on index that is not even available in the Object Model in the client, like you did with a wall object that only has 1 object material texture.

Well i'm not really expert on this, but just want to point what i know so far that you are probably not aware yet/sharing my opinion. Sorry for my bad english.
Reply
#3

Quote:
Originally Posted by RoboN1X
Посмотреть сообщение
Oh also from what i know, you cannot place texture and text at same index at same time. You can only place one of them. Applying texture with text doesn't allow you to make it appear on client to have textured background for text, as it's being replaced with the background color parameter from Material Text. It should answer the reason why it stop sending new data when idx is >= 8. Did you try to send object material texture at index 0-7 and then text at index 8-15?
He knows you can put both a texture and a text on the same index at once... They replace one another so setting the same index is perfectly fine for this example. He could've set them on separate indexes but the results WILL be the same, trust me, I have experience with this issue. Setting the material (with texture or text) can only be done 16 times before an object bugs out. This is why Texture Studio completely destroys objects each time the text or texture is set, so it never reaches that '16'.

Quote:
Originally Posted by RoboN1X
Посмотреть сообщение
Well i'm sure a mapper should be experienced and know how to optimize their number of objects and the textures... They should know to not apply material texture on index that is not even available in the Object Model in the client, like you did with a wall object that only has 1 object material texture.
This is a good point mostly. Optimizing the stream is pretty much the best we can do for now. In fact, optimizing the stream with the streamer plugin is better than using CreateObject, since the objects are destroyed and recreated as they stream in and out. And now that we have some new features in streamer made specifically for optimizing this can be even better.

We still need to have the RPC's fixed though.
Reply
#4

I forgot to mention that all my tests were made on global objects only (CreateObject) and everything I said about streamer plugin is based on assumptions. I did not test how player objects (or streamer objects, since streamer plugin is based on them) are sent to clients. I will post data usage for player objects in the following days.

Quote:
Originally Posted by RoboN1X
Посмотреть сообщение
the server always telling the client re-create the object data every time the object is modified, isn't it
Yes, it seems so.

Quote:
Originally Posted by RoboN1X
Посмотреть сообщение
But I'm wondering if the same method is used for TextDraw, any comparison you did test?
Textdraws work in a unique way. New data is sent only when textdraw is shown to player, so every TextDrawSet* functions have no impact to network usage unless TextDrawShowForPlayer/All is used. I've posted more information here: https://sampforum.blast.hk/showthread.php?tid=614050
I did not mention there that all properties are sent at Show function call, not only those that were edited/changed.

So that object builder feature you mention already exists and is used for textdraws.

Quote:
Originally Posted by RoboN1X
Посмотреть сообщение
Are these data actually being packed (compressed) when sent? or the test you did with RPC already decompress them? or maybe these object data are being cached into client memory?
I've used YSF code base to check what data is being sent through RakServer. I used functions provided by RakNet to read bitstreams' size and data and there is no compression applied at high level, otherwise I would have mentioned that in my first post. Anyway, RakNet can't compress data so much before it hits network, this optimization must be done by SA-MP server before it writes data to bitstream.
Regarding caching, it doesn't matter if data is being cached or not. I'm measuring network usage, not memory usage.

Quote:
Originally Posted by RoboN1X
Посмотреть сообщение
Another idea is to encrypt these data, i know it does not really needed and it wont be much secure/reliable for the client sync but it's useful to avoid (decrease chance) the Map stealer hacks.
It won't make a difference since most hacks read data from GTA memory, not SA-MP.
Reply
#5

Everything works fine on my texture studio
Reply
#6

Quote:
Originally Posted by n0minal
Посмотреть сообщение
Everything works fine on my texture studio
TS isn't relative to this problem at all...
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)