Jgn & mmorpg

To synchronize server and clients in an MMORPG I currently use JGN but not a synchronization manager. Instead I keep lists of characters that are near enough to see each other. That way I tried to reduce the number of synchronization packages so that only visible objects are synchronized. The planned MMORPG will have a quite huge world so this will become an issue once there are thousands of NPCs running around.



My approach has some problems with keeping the objects in sync (not sure what the problem is, the characters sometimes are  teleporting around). I think using the synchronization manager will save me some work.



Can I have both, i.e. using the JGN synchronization and keep the number of messages at a minimum? What is a reasonable approach for a big virtual world?


hmm from reading some of Darkfrog and Jeff's heated debates and this thread: http://www.jmonkeyengine.com/jmeforum/index.php?topic=7923.0 it seems JGN is quite scalable. Your approach of keeping a list of nearby characters and synching only the visible objects is similar to what Synch Manager does. In JGN (correct me if I'm wrong) Clients are registered to a priority queue and distance based synchronization is provided out of the box.



To minimize the messages to a minimum, You might need to split your world into smaller zones or tiles where each Synch Manager is responsible for it's own zone but is aware of the surrounding zones to pass clients to when they step out of the current zone. There's a detailed thread on this approach in the Darkstar (SGS) forums: http://www.projectdarkstar.com/index.php?option=com_smf&Itemid=120&topic=621.msg4140#msg4140. I think the idea is good, and can definitely be implemented a lot easier using JGN Synch than SGS listeners.



But ultimately in a large MMO it's likely the persistences layer that will cause bottlenecks more than the networking.

Teleporting around? Does that happen on all clients? I assume you are running several clients on one physical machine for testing… right? I think I had the same thing, even with FlagRush. Some screens (client / server don't know which) were running smoothly but some remote objects' movement was very choppy and they seemed to teleport. Anyways as yunspace said, JGN is pretty scalable and all these problems can probably be fixed. I personally never bothered however, as my game does not require this type of synchronization.

Thanks for your replies, guys.



The problem with out-of-sync teleporting is most probably in my code and not in JGN and happens when there is a change in the direction or speed.

Currently I only use one PC for a dedicated server (Linux) and one for the client (Windows). The server is not loaded much yet so it's not (yet) a bottleneck but my logic that is the reason for the bad sync.



I was not aware that the sync manager already takes a distance into account. I haven't seen a setting for that.

If it does it will be perfect for my needs I think.



In my previous approach using the MMOKIT and TGE there was no other way than splitting the terrain into zones. As long as I can find a solution without zones I will try that as I want the world being seamless if possible (at least it should look and feel seamless).

There is a grid however but that is just to speed up the distance calculation server-side. I think that's more or less what you suggest.



Just to let you know why I don't like zones: In MMOKIT zones are loaded and unloaded and you cannot look beyond the zone borders. There was even a loading screen and that was one of the reasons I discarded this engine. This is just too unflexible for my taste.



The persistence layer is something like a poor man's hibernation. It persists objects using settings in annotations and I only persist them then and now - not with every change. I know this could lead to data corruption when the server dies but I dont want to kill my database with too many updates. The authority will be the in-memory objects in the server and the DB is the storage for master data and persistence layer over server restarts.


There used to be a lot of support for priority based on distance, but because of some optimizations I made I ended up temporarily disabling that functionality.  It wouldn't be too difficult to re-enable it as all the stubs are still there.  The idea is that the GraphicalController implementation has a method:


public float proximity(T object, short playerId)



That determines the proximity to that player of the object referenced.  If it returns 1.0f it will send synchronization messages at normal speed.  If it's set to 0.5f it will send at half speed. 0.0f will stop sending synchronization messages (for objects out of range).  Currently the jME-Networking implementation always returns 1.0f.

Feel free to help get this working again and post a fix on the JGN forums.

OK, the proximity is fine and for the time being I'll compare the distance to the sight distance and set it to either 1 or 0.



Another thing I miss is: How can I send additional info to the clients so that they know what to add to the scene? All examples I found just create a fixed object (JPanel or a model) but what if I need to supply an NPC id and a type.

I must overlook something very basic here. Extending JMEGraphicController and Synchronize3DMessage should work but is that the preferred way?


You need to extend the SynchronizeCreateMessage and add any additional fields you want, then use that custom SynchronizeCreateMessage when you are registering the object. The create message is sent to all clients and then just add support to your SyncObjectManager to handle the new values.



If you mean for specific synchronization messages then you do need to extend JMEGraphicController and Synchronize3DMessage.

public float proximity(T object, short playerId)



I haven't found any code calling this function. I change the value in the GraphicalController but I just saw there is more needed to reimplement this feature. Can you give me some hints where the logic was? ( SynchronizationManager? SyncWrapper? )

It really should be in the relaying aspect that calls it.  At the moment synchronization data is sent to the server and the server re-sends the message to all subscribed clients.  It is at this point in time that there needs to be an asynchronous system to decide how long to delay per client based on proximity before sending.



So what would need to happen is creation of an outbound queue for the message to each client and based on proximity a timeout would be assigned and once that timeout has elapsed it would send the message (or a newer message if a newer message has arrived since the last send).  It would be relatively easy to just manage a "lastUpdated" time that keys to the client and to the most recent message.  Then you'd decide the amount of time to delay between updates based on proximity from the Object to the player.

I think you had other things in mind with the proximity function to what I would like to achieve. Maybe I just haven't understood what you wanted to do with the mentioned delay.

A priority based on the proximity would be nice but what I want to achieve is that moving objects are not synchronized to clients which are too far away to see that object. I may have hundreds or thousands of objects and would like to send the sync packages only to those clients near enough.

I thought about adding that in SynchronizationManager but you may have other ideas.


Well, what I suggest is similar but encapsulates much more.  The idea is that objects further away are updated at a lower rate than objects up close and if something has a proximity of…I think 0.0f it will no longer send updates for that object, so you'd essentially do the same thing except that if all you care about is an "on/off mode" then just alternate between 0.0f and 1.0f depending.

That sounds good but before I refactor it too much (and maybe to death) I did a very simple on/off using that in SyncWrapper:



   protected void update(SynchronizationManager manager, JGNServer server, GraphicalController controller) {
      if (lastUpdate + rate < System.nanoTime()) {
         if (server.getConnections().length > 0) {
            SynchronizeMessage message = controller.createSynchronizationMessage(getObject());
            message.setSyncManagerId(manager.getId());
            message.setSyncObjectId(getId());
            // this would send the message to all connected clients
            //server.sendToAll(message);
            // this sends the message to all connected clients for which the controller's
            // proximity function returns a value bigger than a certain margin (in the range of 0.0 to 1.0)
            JGNConnection[] connections = server.getConnections();
            for (JGNConnection conn : connections) {
               if (conn.isConnected() && controller.proximity(object, conn.getPlayerId()) > epsilon)
                  server.sendToPlayer(message, conn.getPlayerId());
            }
         }

         lastUpdate = System.nanoTime();
      }
   }


I set epsilon to 0.0f.
Though there is one thing in it I don't like: It creates an array in the getConnections() call copying the JGNConnection from the linked queue.

But the more important point is that I'd like to do something similar with the sync create messages. I don't want to send all synchronized objects to all clients. Assuming a big virtual world it would not make sense to announce everything to everyone.
This could get more tricky. I may have to keep track of the objects announced to each client. Otherwise the server sends sync messages for objects which are unknown to clients approaching a synchronized object.
An alternative could work like that: If a client receives a sync message for an unknown object it could send a message to the server asking for a create message. Then I could set an expiry on synchronized objects and the clients just remove objects far away and without any sync messages for a certain time.

What do you think?

seems like an okay intermediate solution, but does end up creating a lot more communication from each client, who doesn't usually have the bandwidth to spare.

take a look at this about synchronization  :slight_smile:



http://forum.captiveimagination.com/index.php/topic,667.0.html


Kine