Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Suvu

Pages: [1]
1
TNet 3 Support / Re: Manually Instantiating
« on: June 14, 2013, 01:36:29 AM »
Hey Aren!

Thanks for the reply, I got this working last night after having another look.

It's strange, there's the mDelayedCall list (In TNObject) to store a list of "calls that could not execute at the time of the call" as the comments say.
This list does get delayed calls added to it, but as far as I can tell, there's no code to execute these at any point. :/
So the delayed calls just sit in that list and no error/warning in Unity (which makes sense as it's not actually a problem... those calls should be executed in the future, when the correct TNO is available, it's just that this doesn't seem to happen)

So, my solution was to check the mDelayedCalls list, for any calls intended for this instance of TNObject (matching uid) at the end of the Register() Method.
If any calls are found, they are then executed using the appropriate FindAndExcecute() method, and then removed from mDelayedCalls

And that works just fine!

Anyways, hope this helps someone!

Cheers.

Owen

2
TNet 3 Support / Manually Instantiating
« on: June 13, 2013, 05:56:47 AM »
Hey all,

I've stumbled across an odd problem and can't seem to figure out whats going on here...

I need the ability to switch out part of my game logic at runtime into game modes (eg deathmatch, team deathmatch, capture the flag etc)

So here's a simplified version of the setup :


GameManager :
Contains core game logic and functionality that would be shared across all game modes.
Setup directly in the scene, with a TNO for network communication.
GameManager Script :
  1. public GameObject[] gameModePrefabs; //Drag gameMode prefabs here in the editor
  2. private GameObject mGameMode;
  3.  
  4. void Start()
  5. {
  6.    if(TNManager.isHosting)
  7.       tno.Send("StartGameMode", Target.AllSaved, 0); // 0 should really be the index/ID of the gameMode you want to instantiate
  8. }
  9.  
  10. [RFC]
  11. void StartGameMode(int modeID)
  12. {
  13.    mGameMode = Instantiate(gameModePrefabs[modeID]) as GameObject; // Yes, that is the unity Instantiate, but the prefab has a TNObject on it with the ID set manually
  14. }
  15.  

GameMode :
Contains logic and functionality specific to the gameMode.
NOT in the scene at startup, but instead stored as a prefab. Also has a TNObject with a manually set id (1000).
GameMode Script :
  1. void Start()
  2. {
  3.    if(TNManager.isHosting)
  4.       tno.Send("TestMessage", Target.AllSaved, "Message Received!");
  5. }
  6.  
  7. [RFC]
  8. void TestMessage(string msg)
  9. {
  10.    Debug.Log(msg);
  11. }
  12.  


What happens? :
Well, as the server, everything works as it should. The 'gameMode' is instantiated and the server get's the Debug.Log message.

Connecting as a client : the client gets the saved RFC to instantiate the 'gameMode' but, the saved RFC for the debug message doesn't trigger.
The strange thing is, the TNObjects on the runtime instantiated 'GameModes' do communicate (if you send a new message afterwards, it comes through as expected. it seems it's only the saved/buffered calls that don't get passed through for some reason...)

Any ideas as to whats happening here?

Cheers!

Update :
After doing a bit of poking around in the TNObject class, it looks like the client does in fact receive the "TestMessage" saved RFC... but before the TNObject has been registered.
It seems what happens is that the RFC call gets added to the delayed call list (mDelayed) until the corresponding TNObject exists/registers. But for some reason, these calls don't get excecuted even after the tno registers itself....

3
TNet 3 Support / Re: TNManager.Create Asynchronous call
« on: March 01, 2013, 01:54:32 PM »
Thanks for the input both! that's definitely given me something to think about.


I don't see sending input is a bad idea? As far as I know, that's how most modern multiplayer games work... I already have it running like this even with TNet for the player controlled entities.
  • Player samples their input and sends to Host. But ALSO, applies the Input locally (They get immediate response from their input)
  • Player is constantly sampling the entity state (if they are the owner) to a buffer (mLocalStateBuffer). (in my case, the entity state is just a struct containing timestamp, position, rotation, velocity and angularVelocity data)
  • Host applies input to the entity
  • Host samples the entity state and sends to all.
  • Client receives sample, and adds it to another buffer (mNetStateBuffer). (Client sets the timestamp of the incoming state to currentTime - (averagePing * 0.5)
  • If the client doesn't own this entity, it interpolates between two states in mNetStateBuffer that are ~50-100ms old (to allow for smooth interpolation even if minor network problems arise, can also extrapolate from the two most recent states as a fall-back solution for more serious network issues eg. multiple dropped packets)
  • If the client does own this entity, they find in their local state buffer (mLocalStateBuffer) the state with the timestamp closest to the most recent state in mNetStateBuffer. If these states differ by more that a threshold amount (in my case I just check difference in position being greater than some value) the client gradually applies corrections to the local entity.
This way the server can verify input, and the client has (what seems like) responsive controls (unless they have serious network problems... or they try to cheat :P )

4
TNet 3 Support / Re: TNManager.Create Asynchronous call
« on: March 01, 2013, 04:17:44 AM »
Hey guys,

I'm running into the same problem as you guys, I think it's a design issue as I have come from using the built-in networking as well...

This is a simplified version of what i'm working on :
  • Each player controls a ship (the player avatar)
  • The player can choose 2 weapons to attach to their ship
  • Each weapon fires a specific type of ammo
The point that i'm stuck on is when a player fires a weapon,
Using the built in networking I did it this way :
  • The player sends their control input on the ship to the server (host)
  • The server applies the input to the ship, and sends out the new position to the clients
  • If the one of the fire buttons was pressed, the ship (server side) 'checks' with the corresponding weapon that it can be fired.
  • If true, the server sends an RPC to all clients (on some kind of GameManager script), to spawn the correct ammo and passes a new NetworkViewID and ownerID with it.
  • The ammo is instantiated on all clients and uses the NetworkViewID to receive updates from the server.
But this design pattern doesn't work using TNet :(
If the server creates the ammo using TNManager.Create(ammoPrefab) then the server is always the 'owner' of the ammo, and as far as I can tell the 'ownerID' is the only indentifier for objects created in this way (because we can't pass extra parameters on Instantiation). So there's no way I can determine who the real owner was.

Another approach is to have the client spawn the ammo (TNManager.Create). But if that's the case, I would want the server/host to verify that this was allowed to happen (otherwise the client could easily cheat, spawning any ammo they want or adjusting refire rates etc).
So the server would somehow need to determine which player fired this Ammo (that's easy enough, with the TNManager.objectOwnerID called OnAwake()), get that player's ship and which weapon it came from (all I have to go on here is the ammo prefab?) and check with the weapon if the shot was allowed (x time has passed since the last shot). If it's not allowed then the server destroy's the Ammo.
But even if that was possible, this way probably wouldn't work because of fluctuations in latency (if i'm comaparing the time that the weapon was last fired)

I'm stumped here and it's really frustrating because I know it's just that i'm thinking in the wrong way....

Am I being too paranoid wanting the server to check everything? (From what I've read, you should never trust the clients)
Thanks!

5
TNet 3 Support / Re: Ownership OnNetworkPlayerLeave
« on: February 21, 2013, 04:02:32 AM »
But the code I pasted (from TNObject.cs) doesn't change the ownership of the TNObject back to the host, instead it changes the PlayerID of the passed Player parameter to the HostID...

For example :
  • Player "Dave" joins the game as Host (PlayerID 1)
  • Player "James" joins the game as Client (PlayerID 2)
  • James leaves the game
  • OnNetworkPlayerLeave(Player p) is called on all GameObjects
  • p.name = "James" which is correct, but! p.id = 1 (It should still be 2 right?)
Hope that makes sense, and thanks for the help Aren!

6
TNet 3 Support / Ownership OnNetworkPlayerLeave
« on: February 20, 2013, 10:59:58 AM »
I came across this issue when a player leaves the channel :

Each player that joins creates an instance of an object for managing some information about that player. (Each player 'owns' thier own InfoObject as they create it through TNManager.Create())
When a player leaves, the host tries to delete the InfoObject for the leaving player but ends up deleting it's own.
The problem seems to be that the Player returned by OnNetworkPlayerLeave(Player) always has the HostID.

I checked on TNObject.cs and saw this :

  1.     void OnNetworkPlayerLeave (Player p) { if (p.id == mOwner) p.id = TNManager.hostID; }
  2.  

Is that a bug? Should that be this instead?

  1.     void OnNetworkPlayerLeave (Player p) { if (p.id == mOwner) mOwner = TNManager.hostID; }
  2.  

Cheers

7
TNet 3 Support / Re: RFC question
« on: February 18, 2013, 10:33:53 AM »
Hey matis!

It doesn't work because you're sending a transform and then not applying it back to the gameObject,
If you just want to change the objects scale, try this instead :

  1. void Start ()
  2. {
  3.     test_transform.parent = cube_gen.transform.parent; //Set the parent if needed
  4.     if (TNManager.isHosting) // Only send the new scale if you are the host (or you could use TNManager.isThisMyObject but that needs to be checked on Awake!)
  5.     {
  6.         TNObject test = GetComponent <TNObject>();
  7.         test.Send ("SetScale", Target.AllSaved, new Vector3(0.5f, 0.5f, 0.5f));
  8.     }
  9. }
  10.  
  11. [RFC]
  12. void SetScale (Vector3 scale)
  13. {
  14.     gameObject.transform.localScale = scale; // apply the scale back to the gameObject
  15. }
  16.  

Hope that helps!

8
TNet 3 Support / Coming from built-in Unity networking
« on: February 18, 2013, 10:09:47 AM »
Hey guys,
I started my project using the built-in networking in Unity, I'm loving TNet so far but I've been having trouble getting my head around some the workflow/concepts.

Most logic in my game is authoritative, so for example when a player spawns :
  • Server checks that all conditions have been met (client has signaled that they want to spawn, respawn time has passed ... etc)
  • Server allocates a NetworkViewID (making it the owner) and sends an RPC to all (server and all clients) to spawn a player (with the parameters : PlayerID, networkViewID, initialPosition)
  • Server and Clients (on receiving the RPC) Instantiate the playerObject and assign it's NetworkViewID
  • Server can now communicate with that object on all clients.
Control is also applied authoritatively :
  • Client streams input to server, with timestamp (also applies input locally to reduce the appearance of latency, and corrects for prediction errors when server updates are received)
  • Server checks input is valid and applies it to the playerObject
  • Server sends updated position back to all clients
Questions I have about TNet :
  • Can you allocate unique TNObject id's at runtime? Or do they only allocate themselves through TNManager.Create()? Then how would you communicate on dynamically created objects?
  • On receiving an RFC, can you find out who sent it? (RPCs have an optional parameter : NetworkMessageInfo which contains which player sent it, network timestamp etc)
  • Is there an equivalent to Network.time? (a time value that is synchronised on all clients, used for timestamps etc)
  • For an authoritative setup, would you avoid using TNManager.Create? (Because then any client could create network objects)
I have a suspicion I'm looking at this is completely the wrong way and making it way to difficult for myself....

9
TNet 3 Support / Re: Confused by channels
« on: February 18, 2013, 09:30:55 AM »
Hey Kris, I think i've got my head around it now thanks :) but it might be worth posting an example for anyone else who has the same problem.
I still have a couple of other questions but i'll start a new thread about them.

Cheers!

10
TNet 3 Support / Re: Confused by channels
« on: February 17, 2013, 08:17:15 AM »
Ahhh ok, thanks for that Kris!
I should have tried that before posting ><
That makes much more sense now, I also read a post from Arenmook over on the Unity forums where he likened it to IRC.

Thanks again for the help!

11
TNet 3 Support / Confused by channels
« on: February 16, 2013, 11:57:03 AM »
Hey all,
I've run though the example scenes, documentation and 'getting started' page, but i'm still having a bit of trouble understanding how to get things setup or how things are SUPPOSED to be set up.

I've been working on a multiplayer game for a while but using Unity's built-in networking.
The way I started a server/connected to a game was pretty simple :

To create a server
  • Initialize server
  • OnServerInitialized - Load first level
  • OnPlayerConnected - Send netLoadLevel RPC with current levelName

To connect to a server
  • Connect(serverIP)
  • Waits for server to send current level
  • Loads level and receives current gameState

But now switching to TNet, I find it confusing....
I can start a server, and connect to it, just like the way it's shown in the ExampleMenu.
But then the channels throw me off. I previously had the server 'tell' newly joined clients which level to load, but with TNet, when you join a channel you need to specify the level to load. And no communication can take place before you join a channel.

I think i'm getting completley the wrong idea here >< How does the client know which level to load (the level the server is currently on)

Pages: [1]