Skip navigation

Category Archives: Networking

So Unity 3D is super easy to use and you can make really cool stuff rapidly.  The first “professional” release I am trying to do involves Unity’s networking layer because Tanks Online is a multi-player game.  For me, this is where Unity starts to stumble – or at least is not very developer friendly.  I got Tanks Online running a few weeks ago in a very alpha form with networking enabled – meaning multiple players could connect and shoot at each other.  That was the easy part.  I have spent about 25 hours since then ironing out the plethora of networking bugs.  Here is two of my “favorites” – meaning it took about 10 of those 25 hours to figure out and fix.

Who’s your daddy?

Hosts (players) can use Network.Instantiate(…) to create objects in the scene (world).  When Network.Instantiate(…) is used, all the hosts regardless of type (server or client, remote or local) create that object.  This works like a charm and in very little time I had tanks running around and shooting at each other.  Now, I needed to do a little bit of collision detection for when a projectile hits a tank.  It’s important to know who “owns” the tank and who “owns” the bullet so you can tally the correct stats on death and not register a “hit” when a tank is colliding with a projectile it created.  Unity offers this through the network information (NetworkView) of a object that was instantiated with Network.Instantiate(…).  I was doing this check on the collision of a projectile with a tank and getting good results on the server but not the client hosts.  It turns out that the server is the only host who really does know who the “owner” of each object is, but the other hosts all think that the server is the owner of the Network Instantiated object (tank).  I think this is because the server is the one to brodcast RPC calls (of which Network.Instantiate(…) is a special case) to all the other hosts, even when the RPC is called on a client host.

The solution was to add an OnNetworkInstantiate “callback” on the tank object that sends a RPC only to the server that asks for the NetworkPlayer who owns the newly created tank.  The server sends a RPC back that has the “owning” NetworkPlayer.  The tank object stores that away in a member variable.  Now when a projectile and a tank collide, each host can correctly check the owner.

This seems like quite a bit of overhead that could have been avoided if Unity would have correctly assigned the owner of the NetworkView on each host.  Hopefully they will correct that some day and this convoluted way to get the correct owner of a network object can go away.

Give up the ghosts

Network.Instantiate(…) is a buffered call, meaning new hosts will get these objects even if they are created before that new host joins the network game.  Cool!  When a tank dies in Tanks Online, the tank’s Game Object that represents that player is removed from the game using Network.Destroy.  Everything looks great when you are fooling around with a few players – everyone spawns correctly and when they die all the hosts see the player’s tank disappear.  However, Network.Destroy is apparently not a buffered call because if a player died and a new host shows up, that new host will create an instance of a tank (where it originally spawned) that was destroyed on the network before the new host showed up to the party.  And because no one is using that tank any more, it just sits there, un-moving and absorbing any project’s sent it’s way.  An indestructible ghost of a player’s past.

I looked online and the proscribed solution was to call Network.RemoveRPCs on the NetworkView associated with the tank that was about to be destroyed.  But that didn’t work – apparently more than a few people have run into this problem and there is no solution yet.  Luckily for me, the only buffered RPC’s I am using are creating a new tank when a player spawns – so they don’t need to there forever, I can clear all the RPC’s from that player when the tank dies.  Network.RemoveRPCs allows you to pass in a NetworkPlayer and it blasts away all the buffered calls on the network from that player.  So that’s what I did.    If I had a more complicated game this bug would have gotten in my way, but because spawning a tank is the only buffered call that is made, I lucked out and can brute force hack my my out of this one.