Tuesday, July 17, 2012

Unity Scripts & Network Management

Hi. Today I'm going more in depth with Unity development by adding some important information for managing you network and players. SmartFox connections can be very delicate, and a program that closes without properly disconnecting from SmartFox will crash Unity nearly every time.

First, here a few simple tips for designing the script that connects you to SmartFox. This pertains to people who debug on a localhost and also on a remote connection. Save your remote connection and 127.0.0.1 in strings and then add a public bool variable so that your program will switch between Local and Remote Connection in Start. Then you can tick the checkmark in Unity's inspector whenever you want to switch between your different SmartFoxServer instances. You can do something similar with a guest boolto change the user name to guest if you have allowed a guest to log into your server. Lastly, be sure that debugging information is always sent on bad connections. In my connector, I have a status message that is updated based upon how things are going with the three phases: Connection, Login, and Joining the Room. After logging in, I show the client a list of each of the rooms in the zone, so that they can choose which one they want to join. A client should be alerted of the status of all these things as they go along.

Make sure your database is configured the way you want it and that your zone and room connection scripts should be connecting to it as you intend. You can sett a zone variable using the SmartFoxServer admin tool to allow guests to log in. Their name will  always start with Guest. You could keep this disabled and manually assign a name, but I find this automatic way to be much simpler. In your Unity Script that connects to the server, you need to send a keyword in your login request.  I'd suggest setting the user name to "Guest" or "" (null), and then in your zone extension->OnLoginHandler add in the code below to avoid triggering an error message for a login request that intentionally will not be in the database.

if(clientName.compareToIgnoreCase("Guest")==0 
    || clientName.compareTo("")==0)
{
    //Guest login code
} 
else try 
{
    //Your Normal Login Code;
}

In my game before each user is sent the reply for the "spawn me" request, my room extension retrieves a specific model name which is stored in the database. You'll have to ensure that a default model name is returned for guests. In your room's "Spawn Me Handler",  I'd suggest doing this without querying the database so that your team can typically run the game without having to start WAMP or have the database locally installed.

if(user.getName().startsWith("Guest"))
{
    model="Guest"
} 
else try 
{
    //db query...
}

In your Unity Player Manager, check for this and load a generic prefab, or you could even generate a random model if you are up to the challenge.

There are a lot more things you should do to your Unity code. Now that we have discussed adding a player, let's make sure that your game knows how to remove one. Make sure that your users have a way that they can request to log out of the zone and disconnect from the server. The room extension that you built should have this:
addEventHandler(SFSEventType.USER_LEAVE_ROOM, OnUserGoneHandler.class);

However, it's come to my attention that the USER_LEAVE_ROOM event is not called when you send a logout request to the server. A logout only occurs in the zone, so your room will not be notified. This will cause a lot of problems because you have to access your world class and remove the leaving player so that their model is removed from the list of players and from each client's instantiated guests. Do this when a user activates logout. I'd also suggest placing this inside of OnApplicationQuit in SmartFoxConnection before the smartFox.disconnect. That way the users will be gracefully removed even if they don't log out. There is a lot of messaging among users, so make sure to broadcast a leaving message.
smartFox.Send (new PublicMessageRequest(userName + " left"));
smartFox.Send (new LeaveRoomRequest());
smartFox.Send (new LogoutRequest());

Look here for more information on leaving the room. http://www.smartfoxserver.com/forums/viewtopic.php?t=12524

I find it necessary to store my id within network manager so that if it happens to be me that is logging out, I don't erroneously try to remove my id from the guests dictionary.
// When a user leaves room destroy his object
private void OnUserLeaveRoom(BaseEvent evt)
{
 User user = (User)evt.Params["user"];
 if(user.Id != smartFox.myself.Id)
 {
      PlayerManager.Instance.RemoveGuest(user.Id);
 }
 Debug.Log("User "+ user.Name+ " left");
}

Then place this in your Player Manager.
public void removeGuest(int id)
{ 
    receivers.Remove(id);
    Destroy(guests[id]);
    guests.Remove(id); 
}

No comments:

Post a Comment