Wednesday, August 20, 2008

Playing Nice with Lag

Preface: New method of interpolation and "slack" to minimize "hitching" (suddenly jumping location while walking because of a lag spike.)

Every online gamer at one point or another will experience LAG. It is sadly a fact of life.
Although I've been busy trying to minimize bandwidth and packet exchange where-ever possible until this point, delays in a network router somewhere between the server and the clients could cause a sudden lack of communication. If that delay is even half a second, players may notice a "jolt" in their movement as they resynchronize with the server. This in inevitable playing over a network as large as the internet.

So I began looking at ways to minimize the effects of this; and came up with the concept of "movement slack". Basically, when moving between tiles, the client and server generally don't have to agree on the exact location of the client at the exact moment. In fact, even without changing any code, it is impossible to have PERFECT synchronization. What is important however, is the location where the client is going - ie; their destination.

So, to use this in our advantage I have changed the synchronization routines a little, and it looks something like these 2 flow-charts (click to enlarge):




As you can see, the server now has a "tollerance" for the client to choose the stop location, but to avoid exploits being made of this, there are a number of guarding factors in place:

I add speed-hack proofing server side. So, although it "trusts" the client's "stop location" (the location of your char whenever you let up on the movement keys) within 2 tiles (value can be changed in the INI but 2 is the best), it only trusts stop-location packets that arrived more than xms apart or so.

to test it out, i actually modified client code to add a "speed hack" and if i remove the check the speed-hack works, by basically bombarding the server with UserPosition+StopAtPos packets (a kind of modified version of the Server_SetUserPosition packet)

Sure enough, without any checks, the player can zoom around the map at insane speed (illegally)

So this check is necessary, after applying the speedhack check I tested again; With the checks in place, only legal movements are allowed

The nice thing about this new feature (the new StopAtPos packet) is it keeps the client + server more synced up, but places trust on the clients location by x tiles (default is 2; loads from Server.ini), but does so in a secure way, AND sometimes saves a packet from being sent when the user lets up on the movement keys. It is like win-win-win situation

Also note that it does not add any bandwidth, as the StopAtPos packet is basically just a replacement for the SetUserPosition packet in a specific situation (when the player stands still after moving)
and on client side, when moving, it doesn't "jump" the client around when an update is recieved from the server about location and the client location is less than 2 tiles off, it more fluently remains synced. To test it, I set the Packet_WaitTime to 600 to simulate a ping of 600+

Drasil Tech - Chat Compression

Drasil Tech.
Welcome to the first post of a section I will call 'Drasil Tech' where we'll explore some technical feature of Drasil.

As an introduction, I will point out that drasil is based on an increasingly heavily modified version of the vbGore engine - but is quickly beginning to look like it's own unique platform as myself and Tyler (another programmer) re-write entire sections of the engine to fit the needs of Drasil or to optimize performance or stability.

vbGore is a Visual Basic 6 based game engine, and as such Drasil is primary written in VB6. However, some performance intensive parts of the game are being ported to C++ (esspeciall server side) and integrated as DLLs, to take advantage of C++'s superior performance.

Saving Bandwidth - vbGore's engine does a great job of minimizing bandwidth right out of the box by using an optimized binary based datastream protocal. There was however, still room for improvment. For starters a lot of strings (text) are sent from the server during game-play - Player names, Item names, Quest info, NPC chat dialog, Descriptions of game elements or players, Mailbox messages, the MOTD, and of course chat text shared between users. If we want to have the ability to have global chat, we might end up quickly running up the bandwidth meter / causing network performance issues on the game server if people start to actively engage in chat. Thus, I designed a compression scheme that is not only fast, but is designed specifically to compress strings of English text using a common dictionary that will be built in to the client. Now our NPC messages and global (shout) chat don't have to cause potentially lag-inducing spikes in bandwidth. See a screenshot demonstrating a test of the compression algorithm at work:


Demonstrating compression of example MOTD text - 37 bytes may not seem like much but it adds up when these types of strings are being passed to and from the server many times per second to many different users.

Features & Bug fixes-some big, some small

Yesterday was mostly a day of adding features, testing, and polishing/optimizing.

I have almost completed the status window which displays the user's health/mp/exp til next level.
Note that as the stats system evolves, this may very well change as Stamina may become just as important as Mana (more on this later). This window is still a work in progress (anyone notice the X and Y being switched around to read 'y x'?)


Another big feature that has been added (and although sounds simple was kind of a pain to code), was a Double Click event. So basically now we are able to write code that is triggered when the user double-clicks on something (I know, whoop-tee-doo right? But really this will add a lot more usability to the game). This will come in extremely handy though as we develop the UI, Items, and stats systems. For example a small but very useful little feature that was added: when you double-click on your character, your inventory pops up. This is pretty much the norm for PC based RPGs, so why should Drasil lack this luxury?

We are completely overhauling the Stats system and the associated user interface. There are going to be a lot of big changes in this regard.

Also, double clicking on any Item, Player, or NPC, etc. will bring up an information box giving a quick overview of relative attributes.

Big Bug Fixed - I have found the cause of one of the random "phantom bugs" that plagues the vbGore engine, and fixed it. If you ever got a Run Time Error 9 OR Run Time Error 91 when trying to use an inventory item such as a potion etc. before, you have seen this bug in action. It occured seemingly randomly; none-the-less, it is history now.

Optimizations - I'll overview the optimizations in list form:
  • Decreased server memory footprint by moving Errcode strings and SQL query strings to external files rather than being hard-coded into the EXE and thus taking up memory when not needed.
  • Optimized one of the server subroutines that is used to send update info about user stats.
  • Tweaked some of the client's setting-loading related routines to work a little faster and at the same time reduced the memory footprint of the client.
  • Misc. tweaks to the graphics.