samp-incognito / samp-streamer-plugin

Streamer Plugin for SA-MP (San Andreas Multiplayer)
Apache License 2.0
229 stars 90 forks source link

Limit packets sent per tick #104

Closed oscar-broman closed 7 years ago

oscar-broman commented 8 years ago

When a player teleports or spawns in a new area, it's hard to maintain a stable connection until all objects have streamed in. 900 object create, destroy (from prev) and texture information takes quite some bandwidth, especially when players have slight packet loss.

Would it be possible tonstream in new objects in smaller pieces (e.g. 15 chunks with 60 objects each) to avoid the lag issues?

ghost commented 8 years ago

Yes, this would be very good. This needed.

samp-incognito commented 8 years ago

It would be possible, though I would need to think of a good system for this first, otherwise there might not be much of a benefit to be gained.

Some questions I'd have: how many "chunks" would be appropriate, and how far apart they should be spaced? Should it be something like 15 chunks across 15 consecutive server ticks? Would that significantly impact the amount of time it takes to stream everything? I don't really have any empirical data for any of this. I suppose the options could be customizable, though.

oscar-broman commented 8 years ago

It would be best if those 2 parameters could be tweaked (chunk size and ticks).

It's hard to approximate without testing it in different areas of the map.

I realize functionality like this will beg the question of which object to stream in first.

Being able to set priority per object or per model along with this would be incredibly powerful - one could prioritize large objects and set things such as grass and small objects at a low priority.

Another way this could be approached is to read from the server how many RPCs are waiting for ack from the client, and only send more objects if that number is below X.

Related: https://github.com/kurta999/YSF/issues/8 @kurta999 may have some useful input.

samp-incognito commented 8 years ago

Right, that could be useful in combination with #86.

oscar-broman commented 7 years ago

I see you implemented #86 now. What about this? The two in combination will be invaluable for those with both bad connections.

samp-incognito commented 7 years ago

I'll see about adding it soon. It will just require some thought and refactoring, so I've put it off, admittedly.

oscar-broman commented 7 years ago

I could help out with this, if you can just give me a few hints as to what I should be refactoring.

I think this could really reduce lag spikes and timeouts!

samp-incognito commented 7 years ago

Basically, this bit of code just needs to be refactored. It could just be put in a separate function inside of a player loop. There should be a check that limits the number of iterations through discoveredObjects on each tick. Of course, discoveredObjects and existingObjects also need to be cached for each player.

I guess I could just go ahead and do this, actually, but I don't really have time to test it properly right now.

oscar-broman commented 7 years ago

Cool! I'll give it a try shortly.

oscar-broman commented 7 years ago

Not sure what goes wrong, but I don't see any objects at all.. How should I approach debugging this?

Edit: Using CreateDynamicObject rather than CreateDynamicObjectEx worked. I'll look into what went wrong.

oscar-broman commented 7 years ago

If I set the tick rate to 1000 and the chunk size to 1, it does not behave as expected.

I'm guessing object deletion is not taken into account.

samp-incognito commented 7 years ago

Using CreateDynamicObject rather than CreateDynamicObjectEx worked. I'll look into what went wrong.

Hm, strange that CreateDynamicObjectEx isn't working. I don't see how these changes would affect that.

If I set the tick rate to 1000 and the chunk size to 1, it does not behave as expected.

Could you elaborate?

oscar-broman commented 7 years ago

I would expect it to stream in one object/second, but watching object count in F5 showed objects are destroyed/created much faster. It seemed as if it disregarded the chunk size completely.

samp-incognito commented 7 years ago

If the chunk size is set to 1, it should only create one object (and also possibly destroy the farthest object if no room is left) before the next tick. There are usually only a few milliseconds between each tick, though, so it would move to the next object much faster than just one second. (That's for the best. If it were only streaming one object per second, it would take over 8 minutes for 500 objects to be created.)

However, if any objects are completely out of range, then they're destroyed all at once. Maybe that's what you're seeing? I suppose this also needs to be staggered in some way.

oscar-broman commented 7 years ago

Here's what it looks like. Have a look at ObjectSlotsUsed.

Tick rate 1000, chunk size 1: https://youtu.be/xeDe_q9qEvk

Tick rate 1, chunk size 1: https://youtu.be/r8FSCIRqJgM

I realize now I thought you meant streamer tick, when it appears the chunk streaming happens each server tick. I suppose what's missing is a way to configure how often the chunk streaming happens, in a similar way the tick rate is configured.

samp-incognito commented 7 years ago

Oh, I see what you mean. That could be easily configured.

samp-incognito commented 7 years ago

You can configure the "chunk tick rate" now. Objects should be destroyed in chunks now as well.