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 - cmifwdll

Pages: 1 ... 11 12 [13] 14 15 ... 19
181
TNet 3 Support / Re: Host Change doesn't go well
« on: October 28, 2016, 12:12:03 AM »
I'm surprised the coroutine isn't overflowing the stack from infinite recursion. This *could* be your problem, but not very likely.

I don't have TNet3 so I can't check the params you're passing to TNManager.Instantiate, but make sure the objects are being marked as persistent.
There could be a bug with channels but it's doubtful. Place a Debug.Log n your object's OnDestroy function and examine the call stack.

To be clear (and to summarize for when Aren swoops in) this is what's happening:
1. Two players join
2. The Host begins instantiating network objects from a coroutine
3. The Host leaves
4. Some time later, the player that was previously hosting rejoins
5. The rejoining player does not see all of the network objects that the other player sees.

What happens if you completely restart the game before rejoining?
Also, perhaps you shouldn't instantiate objects in the coroutine? There could be a race condition during the disconnect process. Actually, a modification could solve that:
  1. // Spawn Timer
  2. IEnumerator spawnObjects(spawnableItem itemToSpawn)
  3. {
  4.         int lastCount;
  5.         // Make Sure Is Host
  6.         while ((TNManager.isConnected) && (TNManager.isInChannel) && (TNManager.isHosting))
  7.         {
  8.                 while (GlobalSettings.currentOptions == null) yield return null;
  9.                
  10.                 // Spawn Objects
  11.                 if ((spawnedObjects[itemToSpawn.objectPath].Count <  itemToSpawn.maxSpawn) && (spawnedObjects[itemToSpawn.objectPath].Count != lastCount))
  12.                 {
  13.                         lastCount = spawnedObjects[itemToSpawn.objectPath].Count;
  14.                         string go = itemToSpawn.objectPath;
  15.                         Vector3 spawnPointY = new Vector3(Random.Range(-(worldSize.x/2), (worldSize.x/2)), worldSize.y, Random.Range(-(worldSize.z/2), (worldSize.z/2)));
  16.                         RaycastHit hit = new RaycastHit();
  17.  
  18.                         if (Physics.Raycast(spawnPointY, Vector3.down, out hit))
  19.                         {
  20.                                 int objID = Random.Range(1, 99999);
  21.                                 if (go.Contains("Blob"))
  22.                                         TNManager.Instantiate(1, "CreateBlob", go, true, hit.point, transform.rotation, go, objID, true, 1);
  23.                                 else
  24.                                         TNManager.Instantiate(1, "CreateObject", go, true, hit.point, transform.rotation, go, objID);
  25.                         }
  26.                 }
  27.                 // Timer
  28.                 yield return new WaitForSeconds(itemToSpawn.spawnTimerInSeconds);
  29.         }
  30. }
  31.  

The above should only be called once per join per itemToSpawn. The coroutine will stop running if the player is not the host, is not in a channel, OR is not connected.
Additionally, I read somewhere that local variables are persistent throughout the coroutine's lifetime, so I'm assuming int lastCount will function properly.
This should eliminate race conditions and attempts to ensure objects are given enough time to instantiate fully.

Even with all this I don't know what exactly is going wrong. For player B to see the object means it's passed through the server which means it's been saved on the channel. Packets are kept in a queue and processed in order. If a player disconnects the queue is cleared. So when the Instantiate packet comes in it means the player currently exists on the server so it'll properly be assigned an owner. When the player disconnects any persistent object owned by that player is transferred to player[0] (this is done after the disconnecting player is removed from the list, so 0 would be player B in this case). Then the SetHost packet is sent out. Then the ResponsePlayerLeft packet is sent out. In this, every TNObject on every client that's owned by the disconnected player sets its owner to TNManager.hostID (which was set in response to the SetHost packet that preceded this one).
When a player joins, the channel's list of objects is iterated over and each object is created on the connecting client. The only way player B can see an object and player A can't is if player B ignored (or fails to execute) a networked Destroy call or player A ignored (or fails to execute) a networked Instantiate call.

Other than that, the only possible way I can see this happening is if the objects aren't being marked as persistent. Again, check your TNManager.Instantiate call to verify that the persistent flag is true.

182
TNet 3 Support / Re: Sound question
« on: October 27, 2016, 11:02:32 PM »
Only briefly skimmed the code you posted.

Typically you don't network sound, you network events that would cause sound to play. For example, instead of networking both a bullet and the bullet sound effect, you would just network the "player X fired this weapon". Other players then receive this message, instantiate the bullet on their client, and play the sound effect.

183
I've had the same exact problem! Even the editor completely froze. I don't remember exactly what I did to fix it, though... I think I wrapped all relevant functions in an if (TNManager.isInChannel) block.

184
TNet 3 Support / Re: Host Change doesn't go well
« on: October 24, 2016, 05:31:39 PM »
In your case I think it'd be best keeping it so the host spawns and updates the objects. Trying to sort out X clients all running their own spawn logic is needlessly complicated, so just keep it all on the host :)

185
TNet 3 Support / Re: Host Change doesn't go well
« on: October 23, 2016, 11:04:24 PM »
It's hard to tell exactly what's going on without seeing all of your code. Why exactly are you calling initSpawners() on every host change?
Also:
  1. if (go.Contains("Blob"))
  2.     TNManager.Instantiate(1, "CreateBlob", go, true, hit.point, transform.rotation, go, objID, true, 1);
  3. else
  4.     TNManager.Instantiate(1, "CreateObject", go, true, hit.point, transform.rotation, go, objID);
  5.  
This implies a GO already exists before you instantiate it through TNet, why is that?

Typically you don't need to do anything special on host change, TNet will automatically take care of everything (transferring ownership of objects and privileges). If you have some code that you need your host to run then simply put
  1. if (!TNManager.isHosting) return;
  2.  
at the top of the function and call it like normal. Doesn't have to be done on host change, and doesn't have to be ran more than once unless you need it to.

186
TNet 3 Support / Re: Not able to obtain unique playerID
« on: October 23, 2016, 10:55:55 PM »
tno.uid works as well. ownerID is just the uid of the player that owns that object, so if a player owns more than one object you'll have duplicates. tno.uid is guaranteed unique and is assigned by the server.

187
TNet 3 Support / Re: How to simulate latency and packet loss?
« on: October 21, 2016, 07:17:33 PM »
This is a really complicated question. TNet primarily uses TCP. TCP will re-transmit lost packets in order to ensure reliable transmission. So to realistically simulate packet loss using TCP I think you'd need to use a raw socket and mimic the behaviour of TCP. This would then give you control over retransmissions and a nice test bed to work with.

Latency, I think, is slightly easier to simulate, but I can't wrap my head around it at the moment. I don't think a stack + delayed popping would work, but you could try it.

Maybe I'm over-thinking it and there's a far simpler approach, like simulating the *effects* of latency and packet loss without actually simulating latency and packet loss. Who knows :-\

188
TNet 3 Support / Re: How to see stats like incoming and outgoing bytes?
« on: October 21, 2016, 07:03:41 PM »
Add a public int BytesReceived to the top of TNGameClient.cs, then in the ProcessPacket function add: BytesReceived += buffer.size;
Now, in TNManager add a float BPSTimer = 0f, and an int BytesPerSecond. In TNManager's Update function, add this AFTER the call to mClient.ProcessPackets():
  1. BPSTimer += Time.deltaTime;
  2. if (BPSTimer >= 1f)
  3. {
  4.         BPSTimer = 0f;
  5.         BytesPerSecond = mClient.BytesReceived;
  6.         mClient.BytesReceived = 0;
  7. }
  8.  

That'll get you incoming bytes per second on the client. Outgoing bytes could follow the same process, except you'd be looking into TNTcpProtocol::OnSend and TNUdpProtocol::OnSend functions. Stats on the server would, again, follow the same process, but you'd look into TNGameServer.cs::ThreadFunction for incoming bytes. Outgoing bytes on the server could use the same OnSend functions as the client. Timing bytes/sec on the standalone server is slightly more involved as you don't have Unity calling the Update function every frame, but for the sake of brevity I'll let you figure it out :P

189
TNet 3 Support / Re: Send RFC Error on manuel added TNObject
« on: October 18, 2016, 01:58:02 AM »
You shouldn't change those values at runtime. You can add the TNObject in the editor and assign its ID field in the Inspector. This will in turn change the uid as well (the uid is just a getter/setter for the ID). I don't know about the channelID, but I imagine there's some function to change channels instead of modifying the channelID directly.

It's interesting that it only errors out the first time, though. From what I can tell, it shouldn't be able to get past the TNObject.Find call within TNObject.FindAndExecute but it does. Can't see how a null object reference could be thrown in RebuildMethodList() either. Only reference that could be null would be mRFCs and that's instantiated at declaration.

Anyway, change those fields within the Unity editor (not at runtime) and you should be good to go.

190
I think what's happening is your camera is on the player prefab, and so when the second player joins Unity starts rendering the newly-spawned second camera. If that's correct then you've got a few options:
1. Decouple the camera from the player prefab (you'd have to write some code to position the camera accordingly, probably not ideal)
2. Delete the camera from the prefab on spawn if tno.isMine is false (make the camera its own child gameobject so you can do this in one simple Destroy() call from the Awake event)
3. Adjust the camera's depth property (this controls the order cameras are rendered in)

Keep in mind that each camera in the scene is rendered at all times, so option 3 probably isn't ideal. I personally go with option 2, but it feels wrong so maybe someone else has a better solution?

191
TNet 3 Support / Re: Check players in trigger
« on: October 11, 2016, 02:34:50 AM »
You should rethink your design.
For an immediate fix (but not the best):
  1. void OnTriggerEnter(Collider col)
  2. {
  3.         if (col.gameObject.CompareTag("Player"))
  4.         {
  5.                 if (!col.gameObject.GetComponentInChildren<TNObject>().isMine)
  6.                         return;
  7.                 ShopWallBase.SetActive(true);
  8.         }
  9. }
  10.  

192
TNet 3 Support / Re: Check players in trigger
« on: October 11, 2016, 01:52:00 AM »
Opening your shop is a network call? GUI elements like a shop GUI don't have to be driven by the network. Make opening the shop GUI driven by the client and purchasing or selling items network calls.

An immediate fix for your problem, though, could be instead to place your OnTriggerEnter logic in your player script and check if it enters a Shop tag. Then you can use tno.isMine so that it's only ran on the local client.

193
TNet 3 Support / Re: Stand-alone Server DataNode Error
« on: September 30, 2016, 06:21:01 PM »
Well the error seems to be because the serializer thinks it's an unsigned long instead of a signed long. I don't have code so I can't give line numbers, but I'm sure you can make the appropriate fixes (or wait for Aren to weigh in).

Regardless, though, why rely on TNet serialization when the class you're working with has built-in serialization? ;)

194
TNet 3 Support / Re: Stand-alone Server DataNode Error
« on: September 30, 2016, 10:38:59 AM »
Try this:
  1. // serializing
  2. resptotarget.AddChild("last_active", DateTime.UtcNow.Ticks);
  3. // deserializing
  4. DateTime last_active = new DateTime(data.GetChild<long>("last_active"), DateTimeKind.Utc);
  5.  

I'm not too familiar with the DataNode class, so perhaps there's a different way of doing this, but this should certainly fix the serialization error. The Ticks property returns a signed long (Int64) representing the DateTime object. The DateTime class has a constructor that accepts this value. Additionally, you specify that the ticks represent a UTC formatted object.

195
TNet 3 Support / Re: AutoSync
« on: September 19, 2016, 04:24:14 PM »
It's possible your Update() loop is causing an FPS decrease. I believe Physics.Raycast expense increases with distance, and NavMeshAgent.SetDestination is rather expensive as well (it's been a while since I benchmarked it though). I made some optimizations here (won't fix the jittery movement though, more on that later):
  1. void Update()
  2. {
  3.         if (Input.GetMouseButtonDown(0))
  4.         {
  5.                 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
  6.                 RaycastHit hit;
  7.                 // 500f might still be too much, adjust as needed
  8.                 if (Physics.Raycast(ray, out hit, 500f)
  9.                 {
  10.                         float distance = nav.destination.DistanceTo(hit.point, true);
  11.                         // adjust the 1f as needed
  12.                         if (distance > 1f)
  13.                         {
  14.                                 if (!nav.SetDestination(hit.point))
  15.                                 {
  16.                                         Debug.LogWarning("Could not find valid path to target");
  17.                                         return;
  18.                                 }
  19.                         }
  20.                 }
  21.         }
  22. }
  23.  

You'll need this extension method:
  1. public static class ExtensionMethods
  2. {
  3.         // credit: Unity Engine
  4.         public static float DistanceTo(this Vector3 a, Vector3 b, bool ignoreHeight = false)
  5.         {
  6.                 Vector3 vec3 = new Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
  7.                 if (ignoreHeight)
  8.                         vec3.y = 0f;
  9.                 return Mathf.Sqrt((float)((double)vec3.x * (double)vec3.x + (double)vec3.y * (double)vec3.y + (double)vec3.z * (double)vec3.z));
  10.         }
  11. }
  12.  

Making networked movement appear smooth is quite difficult and depends a lot on your specific needs. The AutoSync script is included more as an example than a final solution. It's always been recommended that you write your own movement code. Here are the two major approaches:
1. Sync input
   * In your case, you could sync every button click (with rate limiting to avoid those ultra-fast clickers :))
2. Sync the transform (this is what the AutoSync script does, but in the least efficient way :P)
   * Deltas (sync only what has changed and the amount it changed)
   * Float compression (this comes with a loss of precision, but in most cases not significant. 4 bytes reduced to 1 byte)
   
In both cases you'll have to deal with ping (this is what causes the jittery appearance). Easiest way to solve this is interpolating between movement updates. Aren has explained this really well, so I'll just paste those links here:
http://www.tasharen.com/forum/index.php?topic=6538.msg33291#msg33291
The LagPosition script (that performs the interpolation) can be found here:
http://www.tasharen.com/forum/index.php?topic=11830.msg54898#msg54898

In short you'll want to split your networked objects into two parts: the "real" transform, and the "display" transform. From a user perspective, you'll be seeing the "display" transform. The "display" transform is constantly chasing after the "real" transform via linear interpolation. The "real" transform is what receives and processes the movement update.

Pages: 1 ... 11 12 [13] 14 15 ... 19