[Advanced] Sign Lag (Clientside) and Proxmity Hiding

Discussion in 'Plugin Development' started by hellboyPS, Dec 22, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    hellboyPS

    Greetings,

    on our server we have a rather big shop area where players use the ChestShop plugin to build custom shops. Basically for every thing you want to sell you have to put up (atleast) one sign in your shop.

    As it turns out, signs produce quite a heavy client-lag, especially if there are around 2000 signs in the loaded chunks. I did this quick test with first 1 and then 400 signs:
    2013-12-22_22.28.17.png 2013-12-22_22.28.57.png

    I think 400 (or even 2000) signs isn't all that much if you have a shop area with ~30 shops or so.
    The lag probably comes from the rendering of the text itself. The client could generate a cached texture with the text already on, and project it on the sign, but that is client handling and doesn't concern us here...

    I was looking for a practical server-side solution to fix this issue. In our shop center most players get a fps of under 5 and this is, obviously, not acceptable or even playable.
    Because of this we would actually be willing to switch to another playershop plugin which doesn't require signs. But even then most of the players would want to put up a lot of signs anyway to advertise their products, so this is probably only a temporary fix.

    My next thought was to hide signs which are not in the proximity (maybe 32 blocks) of the player. To do this I started reading some more into ProtocolLib (even though 1.7 doesn't make this easy) and try to find out how to intersect these packets. Maybe I wasn't trying hard enough, but I couldn't get it to work. I think PacketWrapper is not 1.7-ready and even when I just did a simple sysout whenever a MAP_CHUNK or MAP_CHUNK_BULK packet was sent all of the players received (in a spamming fashion) "Unable to locate sign (x,y,z)" messages in chat. So this won't work this way.
    I then installed Orebfuscator because of the proximity hider feature. I disabled every other feature and only put signs on the proximity hider list. It actually worked (easy 30fps in shop area, and far away signs where displayed as air!) BUT I, again, received the "Unable to locate sign" messages. Also, as soon as the signs where displayed as signs the first time, they wouldn't turn back to air, when out of range. So I cannot use this either.

    I'm a bit out of ideas what to do here. There must be a way to fix this.
    Maybe some of you even have a whole new idea of tackleing the problem?
    If OptiFine was out, this would maybe be acceptable, but I can't really rely on that.

    What do you guys think?
    Regards, hellboyPS
     
  2. Offline

    Chlorek

    I would use sendBlockChange() method (no need for Orebfuscato that makes many other things and it might be a little heavy). When player is far from a sign I would send sign replacement with air, and of course when he is near I would send this sign back.

    Also signs are heavy because of text and that what they really are, they are a bit more complicated than other blocks.
     
  3. Offline

    Garris0n

    I'd set up some sort of system that uses inventory GUIs instead of signs everywhere. Also, the chests as well as signs are contributing to the lag.
     
  4. Offline

    Chlorek

    Garris0n
    It's true, but as you probably read, players will post signs to advertise their products, so no matter what kind of shopping system you use it will lead to same result.
     
  5. Offline

    Garris0n

    Chlorek Perhaps it could be set up so only one sign could be placed on the shop, or even none.

    Also, perhaps Comphenix would know how to hide the signs in a radius? I'd think you could do it with a lot of sendBlockChange spam as well, but if you wanted to hide it as the chunks load...
     
  6. Offline

    hellboyPS

    I actually wasn't quite aware of the sendBlockChange() method. I previously build my own NMS code for that (broken in 1.7, didn't yet bother to fix) or used ProtocolLib.
    Gonna try it with that later today.
    It's quite okay if it is (a bit) more cpu heavy on server side. We have plently of cycles left.

    Edit: Well, I did try it with this. Works quite good in theory (lag is actually gone!). But it's certainly not feasible with sendBlockChange(). Client then starts to lag behind quite much (too much packets in queue for sending those signs). I should try it next with sendChunkChange(). I actually didn't find any good examples of how to use it. The information how to fill the data array probably is somewhere here to be found. Does someone know what exactly sendChunkChange() needs in order to function properly? Does the data array has to be deflate()'d? It's not quite clear, because actually the packet numbers changed and the references on the site are not accurate.

    Oh - also does anyone have an even better idea than sendChunkChange?

    Thanks for all the help.
     
  7. Offline

    Chlorek

    hellboyPS
    I don't understand why some packets would lag server, you receive and send many all the time and it's not going to lag as long as you send REALLY much data - just think, you receive whole world chunks (they are compressed but it's still so much data). Also block change packet contains not that much informations. If your problem still appears it might be something else? Maybe you spam client with these block changes (you send it many more times than needed). So check it, do some debugs, it should work fine.
     
  8. Offline

    blablubbabc

    The "Unable to locate sign x y z" message pop up if the client receives a Sign_Update packet for a block which isn't of type "sign" (at least for the client). Those packets are sent just like the chunk data when the player shall load the sign. So you have to intercept those packets as well and stop them from passing if the signs are hidden to the client, and instead send them when the signs shall become visble.
     
    Chlorek and hellboyPS like this.
  9. Offline

    hellboyPS

    Chlorek I was sending some unnessecary packets. I still think the difference between sending whole chunks and sending blocks one by one is immense. The packets don't contain much data, but the overhead sums up pretty fast.
    I once sent a whole chunk with single BlockChangePackets this actually kicked the player from the server. It matters greatly.
    After some additional tests I deceided that it was worth trying to optimize. I now interpolate the chunks which should update if the player moves dependent of the players direction. This works pretty darn well, altough there are some cases where the player may stand before an invisible sign etc. etc. Not all that bad.
    I still think I should do it with sendChunkData() because it will be quite near O(1) instead of O(n) where n is number of signs.
    I also need to send a UpdateSignPacket if the sign should display again.
    blablubbabc thanks for the clarification. Didn't know what exacly causes this.
    I probably can't solve this problem if I frequently send packets with (sign)block changes and sign updates. Is there a Packet which contains both, block change and content (prob. not)?
    Otherwise if the player moves, like, back and forth, there will be messing up with the order of the arrival of these packets and the error message is sure to occur. Well, can't have everything.
    Thanks everyone. I'm still looking for optimization advice, so I will report back when I had the plugin running for a few days.
     
  10. Offline

    Comphenix

    If you look in the source code, you'll see that sendChunkData() is not (and have never been) implemented:
    Code:java
    1. public boolean sendChunkChange(Location loc, int sx, int sy, int sz, byte[] data) {
    2. if (getHandle().playerConnection == null) return false;
    3.  
    4. throw new NotImplementedException("Chunk changes do not yet work");
    5. }

    I suppose it's too tied to the underlying protocol and implementation to be exposed reliably in the API.

    But you can get Minecraft to send these packets for you, and intercept them with ProtocolLib. That's what I do in BlockPatcher - I just schedule the chunk to be resent, and intercept the resulting MAP_CHUNK or MAP_CHUNK_BULK packet.

    In your case, I think I would try delaying tile update packets based on their chunk coordinate (or segment coordinate, 16x16x16, if your shops are more tall than wide). I suggest using a SphericalBuffer of some sort, essentially just a grid that wraps around. Then you just remove tile update packets that "fall off" the grid, ensuring that they don't stay loaded forever. You should also make sure more recent packets overwrite old packets.

    I would have written a test plugin, but it's Christmas. :p
     
Thread Status:
Not open for further replies.

Share This Page