Tuesday, September 10, 2013

Server Updates

Temporary Login/Title Screen
So, after having good success moving the client to Unity, there were still some issues.

My primary concern was that there were now two physics engines involved:  BEPU on the server, and an old version of PhysX which Unity was running as the client.

Now, I wasn't certain that this would cause problems, but I'd done some fairly deep dives into the quirks and behaviors of BEPU, so it seemed pretty likely.

It would have been really nice to be able to use the Unity engine from the Zone Server.  If there was some way to simply include it as a DLL and run it, that would have been fantastic.  This is a familiar refrain you see all over the Unity forums, particularly the networking on.

Sadly you can't, of course, and I'm not surprised.  So, one would think that-would-be-that.

However, I had a bit of a thought.  I noticed that Unity can be passed command line parameters.  A couple of these caught my attention:

Run Unity in batch mode. This should always be used in conjunction with the other command line arguments as it ensures no pop up windows appear and eliminates the need for any human intervention. When an exception occurs during execution of script code, asset server updates fail or other operations fail Unity will immediately exit with return code 1. Note that in batch mode, Unity will send a minimal version of its log output to the console. However, the Log Files still contain the full log information. Note that opening a project in batch mode whilst the Editor has the same project open is not supported. Only a single instance of Unity can run at a time.

-nographics (Windows & Linux only)
When running in batch mode, do not initialize graphics device at all. This makes it possible to run your automated workflows on machines that don't even have a GPU (automated workflows only work, when you have a window in focus, otherwise you can't send simulated input commands). A standalone player generated with this option will not feature any graphics.

So I thought, "instead of running Unity in the server, what if I ran the server in Unity?".  This should clearly work.  The servers were designed to run from the command line, as services, or from a default shared UI (for dev/testing purposes).  I figured it should be fairly easy to get a simple Zone server running in a Unity project.

So, I stripped some things from the default ZoneServer project, put the DLL into a Unity project, and with a bit of work got it going.  Shortly I did away with using the DLL, and just moved ZoneServer.cs (and the DLLs it was depenent on, BaseServer, etc) into the Unity project.

As I noted in the last post, Unity essentially operates on an entity/component model, much like the system I was using.  Everything is a 'gameObject', which can contain multiple components (and indeed MUST contain a Transform component).

So to start, in the scene that will be loaded on startup, I created a MasterControl gameObject, which contains one component, the MasterControl script.  The MasterControl script is what kicks everything off and starts the server.  The Awake (called when a component is created) does the work:


 void Awake()
  //On scene change gameObjects are normally
  //destroyed.  This prevents that from occuring
  //on this object.
  //Add Unity vector3, quaternion, etc
  //to the object model for Protocol Buffers
  //so it knows how to serialize/deserialize
  //Find the config.ini file, looking in different
  //places (running from editor vs standalone)
  string configLoc;
  if (Application.dataPath.Contains("Assets"))
    configLoc = Application.dataPath.Replace("Assets","") + "Config.ini";
   configLoc = Application.dataPath.Replace("RogueMoonServer_Data","") + "Config.ini";
  // Sigh, the config was opened and read already in BaseServer.
  // But of course BaseServer is common to all server types and
  // thus doesn't look at type specific settings.  So I reopen and
  // get the setting needed here.
  IConfigSource source = new IniConfigSource(configLoc);
  //Get the desired target frame rate.  By default servers run at
  //10 fps.
  string targetFrameRateFromConfig = source.Configs["FrameRate"].Get("TargetFrameRate");
  if (targetFrameRateFromConfig != null && targetFrameRateFromConfig != "")
   Application.targetFrameRate = int.Parse(targetFrameRateFromConfig);
   Application.targetFrameRate = 10;
  //Get zone type to start from config file, if it is there.
  string startZoneFromConfig = source.Configs["Zone"].Get("Start");
  if (startZoneFromConfig != null && startZoneFromConfig != "")
   ZoneType = startZoneFromConfig;
  Debug.Log("Start zone type is "+ZoneType); 
  //Start the zoneserver, which runs on its own thread.
  zoneServer = new Naginata.ZoneServer(ServerTypeEnum.SERVER_TYPE_ZONE, -1);
 void Start () 
 void Update()
 void OnDestroy()

I did have to make a few changes to the zone server code.  Note in the Update() function, zoneServer.HandleMessageQueue() is called.  Originally the zone server started up it's own thread on startup, and handled calling its own event loop.  There was no real point in that here, so now it is just part of Unity's main thread (note the networkLayer and Dispatcher within the zone server still operate on their own threads).

This DID mean I threw away pretty much everything in the RogueMoonZoneServer, the subclass of the general ZoneServer dedicated to the Rogue Moon game.  Since everything was now running in the Unity paradigm, that meant I could chunk BEPU Physics, the Artemis framework, XNA/Monogame and several other things completely.  Granted, I did have to write some new zone control code to take over some of that functionality, but this allowed me to simply delete (it is still in older revisions in the repository of course) huge amounts of code.

So far this is working smashingly...

No comments:

Post a Comment