Tasharen Entertainment Forum

Support => TNet 3 Support => Topic started by: TheCodeTraveller on September 23, 2013, 04:15:09 AM

Title: Understanding the TNet model
Post by: TheCodeTraveller on September 23, 2013, 04:15:09 AM
Hi Guys,

Hoping you can help out with clarifying my high level understanding of TNet. Please correct my understanding below if I've made a mistake, omission or perhaps think that you could add some further value by adding to the points below:

1.) In order for TNet to function at all, a TNManager object needs to be part of the scene
ArenMook's Edit: This is no longer the case.
2.) Any network object i'm hoping to manage through TNet has to be added to the list prior to runtime. Is this correct? Is there no way to dynamically add new types? Or not yet known objects (for example, streamed items that do not exist ingame yet)
ArenMook's Edit: Can instantiate by string Resources name.
3.) The object added to the TNManager, has to be a prefab.
ArenMook's Edit: Yes, but not needed. Use string instantiation as per #2.
4.) This prefab has to contain a TNObject with a unique identifier.
5.) If the object is TNManger.CreateEx(...) I can leave the id 0 as it will be auto assigned. If the object is not being instantiated by TNet, I need to assign this id myself.
6.) In order to syncronise my prefab across the network, all I need to do is add the TNAutoSync object to the parent object of the prefab. Is this correct or does it belong on the object that contains the rigidbody.
7.) Following point 6, Only one TNAutoSync object is required per prefab to sync.
8.) All code relating to input and camera control needs to be controlled with own custom code, using the property TNManager.isMine?
ArenMook's Edit: tno.isMine
9.) By doing all of the above, to get two networked clients communicating. They join the same channel, then instantiate their own version of the prefab using TNManager.CreateEx(). In doing so, the first players create is buffered? For when the next player joins? The next player joining when their own player is instantiated, TNet automatically updates the host (and all other players) - without needing any additional code?
10.) When a player leaves the room, their instantiated object is automatically removed and all other clients are updated? Is this the case or does this code have to be written manually.
11.) Following on from 10. If the host leaves the room, all other player objects and their own are destroyed automatically? The rest of the players in the room only receive the destroy on the player leaving though?

I am asking all of the above, because based on the above, this is how I've implimented TNet in my game - however, all the assumptions above mostly do not work for me.

1.) When I join the channel and instantiate my local player, that works fine.
2.) When I load up another client and join the same one, they own player is instantiated.

However...

3.) the host (point 1) receives the instantiated object from (point 2), on the host there are now, 2 players
4.) the other client (point 2) never receives anything to tell it that the host is there. On this client, I have 1 player. As if they started the channel (they didn't because checking the channel list, shows 2 players).
5.) the host (point 3) if they leave, their local player is not automatically TNManager.Destroy(...)'d - neither is the other players (remember the host got the update that player 2 joined).
6.) the other client, (point 4) now becomes host, as he is the only player in the room. If he leaves, their object isn't destroyed either.

As you can see from the above recount of my own understanding of the framework. There are gaps - gaps which are resulting to me not understanding the outcome of my use case below it. Please add your comments to this thread to assist me and others in future.
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on September 23, 2013, 04:26:26 AM
To add to the above, none of the TNAutoSync properties work either for me, if I move the client around and their position, rotation and velocity changes - the server sees no positional update at all.

Are these updates meant to be sent manually, if so - why use TNAutoSync?

Also I put TNObject on the rigid body, which is a way down from the root game object in the prefab - this matters?
Title: Re: Understanding the TNet model
Post by: ArenMook on September 23, 2013, 05:04:31 AM
Quote
1.) In order for TNet to function at all, a TNManager object needs to be part of the scene
No, just your first scene should have a TNManager. Main menu would be the logical place for it.
Quote
2.) Any network object i'm hoping to manage through TNet has to be added to the list prior to runtime. Is this correct? Is there no way to dynamically add new types? Or not yet known objects (for example, streamed items that do not exist ingame yet)
Nope. Only objects you plan on instantiating quickly. You can still instantiate objects found in the Resources folder by their name, if you wish.
Quote
3.) The object added to the TNManager, has to be a prefab.
Yup.
Quote
4.) This prefab has to contain a TNObject with a unique identifier.
Nope. It should contain a TNObject only if you want to have this object synchronized on the network later -- for example the player's avatar. One-shot objects that get destroyed shortly (for example cannonballs, explosions, etc) don't need a TNObject on them. Lastly, you should leave the ID at '0' so that TNet assigns one for you when it instantiates the object.
Quote
5.) If the object is TNManger.CreateEx(...) I can leave the id 0 as it will be auto assigned. If the object is not being instantiated by TNet, I need to assign this id myself.
Correct, and this applies to Create as well, not just CreateEx.
Quote
6.) In order to syncronise my prefab across the network, all I need to do is add the TNAutoSync object to the parent object of the prefab. Is this correct or does it belong on the object that contains the rigidbody.
Parent object of the prefab? Auto sync goes on whichever object you want to synchronize -- generally on the same object that contains your TNObject script. Also, auto sync should be used liberally. It's better to do your own RFC calls instead. Lastly, you can only have one TNAutoSync per TNObject -- so only one per prefab. So again, be careful with it.
Quote
7.) Following point 6, Only one TNAutoSync object is required per prefab to sync.
Yup. But again, see the last part of #6.
Quote
8.) All code relating to input and camera control needs to be controlled with own custom code, using the property TNManager.isMine?
TNObject.isMine is the property that tells you if you own the object or not. You should only control the objects you own.
Quote
9.) By doing all of the above, to get two networked clients communicating. They join the same channel, then instantiate their own version of the prefab using TNManager.CreateEx(). In doing so, the first players create is buffered? For when the next player joins? The next player joining when their own player is instantiated, TNet automatically updates the host (and all other players) - without needing any additional code?
All create calls that created an object with a TNObject script on them get buffered, yes. Unless you destroy them later. Then they get removed.
Quote
10.) When a player leaves the room, their instantiated object is automatically removed and all other clients are updated? Is this the case or does this code have to be written manually.
Correct, but that's assuming you specified 'false' for the 'persistent' flag for TNManager.Create / TNManager.CreateEx.
Quote
11.) Following on from 10. If the host leaves the room, all other player objects and their own are destroyed automatically? The rest of the players in the room only receive the destroy on the player leaving though?
No, if a host leaves, another player is chosen to be the host. This is why you should be using TNObject.isMine. Host doesn't own everything. Host is just like any other player. The "host" status is just to make it so that only one player does the "generic" logic -- such as AI, pathfinding, etc, rather than having everyone do it.

Hope this helps!
Title: Re: Understanding the TNet model
Post by: Notepid on September 23, 2013, 06:26:26 AM
5.) If the object is TNManger.CreateEx(...) I can leave the id 0 as it will be auto assigned. If the object is not being instantiated by TNet, I need to assign this id myself.
Correct, and this applies to Create as well, not just CreateEx.

What, wait!!

So if I create an object that is part of the scene and is not instantiated by the TNManager, I need to set the TNObject ID manually? How? Just assign it a random number?
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on September 23, 2013, 06:38:38 AM
Thanks for the responses Aren, I will check that false flag on the manager, maybe I have it set to persistent state and accounts for why objects are not destroyed.

Appreciate the time taken to answer. More input welcome of course! Good thread for guys starting out with TNet.
Title: Re: Understanding the TNet model
Post by: ArenMook on September 23, 2013, 06:49:55 AM
@Notepid: You can choose a numer, or normalize the IDs via the menu. I advise keeping the numbers low though. Under 255 ideally, and under 32767 as beyond that means the ID was dynamically assigned. It won't break TNet if you go past it, but some future behaviour may be... undefined.
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on September 23, 2013, 02:34:22 PM
You can still instantiate objects found in the Resources folder by their name, if you wish.

I tried this, I removed the prefab from the TNManager (so now it's size is zero). In doing so, when I call a CreateEx(...)

I get the following error:

The game object was not found in the TNManager's list of objects. Did you forget to add it?
UnityEngine.Debug:LogError(Object, Object)
TNManager:IndexOf(GameObject) (at Assets/TNet/Client/TNManager.cs:693)

This is the reason I initially said - it looks like anything you want to instantiate for network play needs to be added to that list. Perhaps I am missing something?

Am I meant to (GameObject)Instantiate(Resources.Load(..))

As normal just with a TNObject on the unit / player?
Title: Re: Understanding the TNet model
Post by: ArenMook on September 24, 2013, 07:12:48 PM
Yes, you misunderstood me. Don't pass Resources.Load. Pass the string inside your (..) brackets.
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on September 25, 2013, 03:12:14 AM
Hi All,

Thanks Aren, I've managed to come right  8) I just wanted to update this thread with the biggest stumbling block I had.

You see, my load sequence on prefabs are very important - the player object for example has close on 40 different scripts attached, each of which have some dependency on one another - so order of execution is important to me. Long story short, this means I do a fair bit of footwork to enable, disable things on load - in a certain order.

What happened was one of the objects contained the TNObject, which is not by default enabled immediately on load. I would guess you're looking at the prefab when loading to find the TNObject, of which you wont because technically it isn't enabled yet.

What I did to get around this was place the TNObject on my root node, the first item in the prefab (which is always enabled on load). TNManger / TNet assigns the ID automagically and then my syncing script picks this object up from the hierrarchy root (for example, my rigidbody is very low level in the tree).

This way I can still send my RPC's etc through the correct tno.

New question.

Is sendquickly definitely UDP or is there an additional setting I need to enable first for this to switch from TCP to UDP for sendquickly use.

I've also worked on my custom interpolation (and even extrapolation) algorithm and on lan play, I have quaternion rotations super smooth, vector placement was of no issue to me.

Also anyone know of a good network emulator I can run within the lan to slow down traffic? Currently I've rolled my own on the client side, delaying packet transmission.

I'd like to simulate server side too for when the clients connection is fine but the server is battling.
Title: Re: Understanding the TNet model
Post by: ArenMook on September 25, 2013, 05:43:40 PM
SendQuickly sends via UDP if UDP communication has been proven to be operational. Otherwise it uses TCP.
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on September 26, 2013, 01:23:06 AM
Thanks for the confirmation and good job with the framework. It's been a breeze to customize server side - really enjoying the experience.
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on September 26, 2013, 02:07:12 PM
 :o I'm stuck on this one.

-Host starts channel, no issue there. Host leaves channel, TNObject / instantiated prefab removed.
-Host starts channel, no issue there. Client joins channel no issue there. Client leave channel, Hosts TNObject / instantiated prefab remains but clients has been removed as expected.
-Host starts channel, no issue there. Client joins channel no issue there. Host leaves channel, Hosts TNObject / instantiated prefab remains but clients has been removed as expected.

Are you guys sure I don't have to somehow destroy these objects myself? Something isn't right here. I leave the channel i'm in like so:

  1. TNManager.LeaveChannel();
  2. TNManager.JoinChannel(1905, null);

Also this is not a persistent channel. Does it matter that my project is not structured as Main Menu scene and Level scene? I instantiate levels live in the same scene as the TNManager lives.

Any help appreciated here :(
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on September 26, 2013, 02:09:23 PM
To add. I receive these when clients leave:

  1.     void OnNetworkPlayerLeave(Player p)
  2.     {
  3.         Debug.Log(p.name + p.id + " has left");
  4.     }

But I never receive this: This seems to be working now. Odd.

  1.     void OnNetworkLeaveChannel(Player p)
  2.     {
  3.         Debug.Log(p.name + p.id + " we have left");
  4.     }
Title: Re: Understanding the TNet model
Post by: ArenMook on September 26, 2013, 04:35:52 PM
There is no difference between the host and non-host players in terms of object instantiation. The server doesn't care. If the object was created without the persistent flag, then it will be destroyed when the player that created it leaves.
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on September 27, 2013, 04:04:58 AM
Definitely not the way it's working currently for me. I'm going to break away from the current project and prepare a smaller solution alongside to test out this issue. If you're will I can forward the demo project on after for you to take a look at if I haven't already solved by then.

It's most definitely down to my usage/implementation, the release is fairly mature now.
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on September 27, 2013, 04:37:09 AM
Also to add to above posts, my project is structured as:

NetManager
\- TNManager
\- TNObject
\- PlayerManager - Something similar to the GameUnitManager I saw around here a while ago (CreateEx example)

MenuManager

- When the MenuManager receives an instruction to start up the game, I call my PlayerManager.CreatePlayer (static function), which returns an RCC which kicks off a TNManager.Instantiate
- What happens next is the MenuManager has some load step logic so it finds the Player that was created by TNManager. I do this because I set certain parameters on the player. This is essentially the same as if I was doing in the RCC just more specific to disabling the menu system and setting up the game level.
- Every player has their own TNObject which I use to drive controller / gui logic
- When the MenuManager listener receives a level end command, the player is instructed to TNManager.LeaveChannel and the entire menu is reloaded.

Is there anything other than the above to do to get these objects to remove themselves? Am I meant to be checking in my PlayerManagers received RCC that the receive is for me? If I do this only, no other player will TNManager.Instantiate. Must the host only call TNManager.Instantiate in the RCC? If I must, should I be checking the TNManager of isHost? Or something else.
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on September 27, 2013, 12:39:50 PM
Cool so I've made progress. I've decided to manage players actively and have solved the problem with objects being left behind. Still need to battle test this with a few more clients open but two player games seem to be working just perfectly.

I've also starting playing around with UDP a little more, first thing I got stuck on is testing two clients, as they originally bound to the same port to listen on these UDP packets. I've not got rolling code per client for local testing so that these ports don't conflict with one another.

Here's a question though, SendQuickly sends via UDP when available but falls back to TCP - correct? The very nature of UDP is zero ACK., just assumes the packet arrived etc.

Now if I'm starting a UDP up on my local manager say port 6777 or whatever, how do you know that the UDP wasnt started in first place. What I'm trying to say is how do you know to send TCP without an ACK from the UDP side which goes against what UDP is.

Or are you sending another packet via TCP to say the first packet arrived, continue sending regardless via UDP (because it's up).
Title: Re: Understanding the TNet model
Post by: ArenMook on September 27, 2013, 06:56:44 PM
Whatever implements an RCC function needs to be defined on the same game object as TNManager, or one of its children. In your diagram you have it beside the TNManager, which would be wrong.

You can have two UDP game clients on the same machine, but you can't have two UDP listeners on the same machine (lobby Yes, if UDP is not available, TCP is used.

You should be starting UDP on a random port, not on a specific one. Only the server should be using a specific port. Check the example that comes with TNet.
Title: Re: Understanding the TNet model
Post by: TheCodeTraveller on October 30, 2013, 03:56:27 PM
Thanks for the reply, in the end I hunt for the next available port open  8)
Title: Re: Understanding the TNet model
Post by: danfoo on March 04, 2014, 01:02:45 PM
A few fundamental questions relating to ownership:

- Is ownership of an object determined by which client sends the RCC?
- Can an ownership change be performed at any time using tno.ownerID?

- In the case of a game hosted by a player via starting a local server instance, is there any distinction at all between the server and the host (I keep seeing both words used in documentation)?
- In the above case, if the hosting player disconnects will the session still live on? Ie. will another client instantiate a server and take over the responsibility, or does this transfer only apply to remote servers and independent clients?

TIA!
Title: Re: Understanding the TNet model
Post by: ArenMook on March 05, 2014, 08:46:02 AM
Ownership is determined by whomever sends the Create call, yes.

Yes, you can change the ownerID at any time.

Server is just a process that everyone connects to. IRC server is also a "server" for example. Host is a player -- usually the first player to join the channel. Just like a channel operator in IRC. The first person to join a channel in IRC is its operator and can boot people and do other administrative things.

If the host disconnects, a new player gets to become a host. Server does not migrate. If a server goes down, that's it. Everyone will be disconnected.
Title: Re: Understanding the TNet model
Post by: danfoo on March 17, 2014, 07:36:16 AM
Thanks for the reply! Have been on vacation but back to tackle this now. :)

If the host disconnects, a new player gets to become a host. Server does not migrate. If a server goes down, that's it. Everyone will be disconnected.

The planned model for our title is a locally hosted server model where players themselves will take responsibility for running a server and hosting. So, would this approach be recommended:

- The game allows players to start a local server. Connects to a lobby server hosted by us. Local server can be private/public.
- The player can (but does not have to) start a game on his local server.
- Other players can connect to the server and can (but do not have to) join the session run by the player owning the server.

The alternative would be game servers hosted by us, but that comes with scalability issues / cost. Thanks in advance for confirming the above!

Edit: Another related question: Per your recommendations, much of our code is written with multiplayer in mind and as such much of the communication will be routed through Tnet even when in single player mode. Does this mean that a local server has to be started for this to work - or will TNet still route RCCs/RFCs?
Title: Re: Understanding the TNet model
Post by: ArenMook on March 18, 2014, 10:08:21 PM
No need to start a local server. TNet's functionality will work the same whether you are connected or not. If you are offline it will behave as if you were connected in a channel by yourself (TNManager.isConnected will be false however).

Your model seems fine, and is ideal for TNet.
Title: Re: Understanding the TNet model
Post by: danfoo on March 19, 2014, 10:54:48 AM
Thank you!