Author Topic: Objects Instantiate with No Owner  (Read 11190 times)

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
Objects Instantiate with No Owner
« on: October 29, 2017, 10:54:08 PM »
I'm seeing this happen on player objects AFTER I've switched to my 'Game' scene. I'm keeping alive all of the objects that should carry over between scenes, and these objects that don't work (player home bases for an RTS game) do not have any other dependencies tied to them, just a simple dynamic TNObject.

Under what conditions might a TNO instantiate without an owner?

GabaLaba

  • Newbie
  • *
  • Thank You
  • -Given: 4
  • -Receive: 0
  • Posts: 11
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #1 on: October 30, 2017, 01:57:18 PM »
Had the same exact problem.

Fixed it by joining a channel. Not sure if it matters whether you do it before or after you join the scene, but just make sure you are connected to a channel.

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #2 on: November 02, 2017, 03:50:10 PM »
That might be my issue. I've noticed that TNManager.players.Count becomes zero when changing scenes. So will I have to rejoin a channel for every scene change? That doesnt make much sense. Even more strange, I can see position and rotation updates on my client system (laptop) despite the player count resetting. It would be nice if there was more information in the TNManager about connected players and their state.

Test: I have a server and client connected via local LAN. Both systems show connectivity to the same channel, however the host system shows Players: 1, while the client system shows Players: 2. Why the discrepancy? It almost seems like the client still thinks its connected, but the host isnt.

Image 1
Image 2

Edit: Okay so I proved myself wrong. I stopped changing scenes and I found that my problem still exists. Might help to mention that the host can spawn objects properly on both host and client systems, but when the client spawns the object it only appears on his local system and, again, has no owner.
« Last Edit: November 02, 2017, 10:15:54 PM by phil.atha »

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #3 on: November 04, 2017, 01:45:01 AM »
Anyone have any ideas? This is holding up progress.  :-\

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #4 on: November 04, 2017, 03:50:06 AM »
What version of TNet? Are you connecting to the same server on both clients? Are you joining the same channel on both clients? Are you sure there isn't some piece of code calling TNManager.Disconnect (or similar) for one client but not the other? Are you switching scenes using TNManager.LoadLevel? Do your networked objects have a TNObject component attached with an ID of 0? Are you instantiating objects via TNManager.Instantiate? What is the minimum set of features you can get working and what are the steps you're taking to achieve that?

Have you tried spamming Debug.Log's everywhere in your code? Could reveal something executing that shouldn't be executing, or some strange parameters, or something else. Usually every Unity dev's last resort :)

If you can reproduce this in a blank Unity project I could debug it for you, just PM the link and be sure to omit TNet's source code.

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #5 on: November 05, 2017, 01:42:36 AM »
I'm using the asset store version.

Edit: ARG!! I think I figured it out. All of the RCC events MUST be under the TNEventReceiver class unlike RFC's which apparently can be called from any TNBehavior.

@ArenMook is that correct? If so is that documented anywhere?
« Last Edit: November 06, 2017, 01:14:13 AM by phil.atha »

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #6 on: November 06, 2017, 01:37:19 AM »
RCCs (and RFCs) must be within a class that derives from MonoBehaviour. TNet uses reflection to cache all RCCs at startup. This reflection process first gets all Type's from all Assemblies in the current AppDomain (excluding some built-in ones). Then it narrows this further by checking if the Type derives from MonoBehaviour. Then it checks if the Type has the RCC attribute, whether the return type is GameObject, and if the optional RCC ID is within 1-255.

RFCs are cached similarly, except this is done on each TNObject instance, and instead of getting all Type's from all Assemblies, it simply calls GetComponentsInChildren. You probably didn't notice this because TNObject itself is a MonoBehaviour.

It doesn't look like this is mentioned in the tutorials on google docs, but I believe I made a post about it some time ago. Intuitively, though, you wouldn't have an RCC on a non-MonoBehaviour class because you wouldn't instantiate a non-MonoBehaviour class using Unity's Instantiate function and the RCC return type must be a GameObject.

And just to avoid any future issues: your custom RCC IDs should be between 4 and 255 as TNManager uses 1-3 for default fallbacks. I don't think many people use the IDs though. Even though it's faster and results in smaller packets :(

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #7 on: November 06, 2017, 08:02:08 AM »
I never use IDs. Really no reason to. :P

And what cmifwdll said: RCCs must be on a MonoBehaviour, not a random class. Even receiver class doesn't have anything to do with this.

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #8 on: November 06, 2017, 05:17:28 PM »
My class that calls scene building functions derives from TNBehavior like so:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5.  
  6. public class GameBuilder : TNet.TNBehaviour
  7. {
  8.         public void SpawnPlayer()
  9.         {
  10.             Debug.Log("Spawning Player");
  11.             FactionName f = TNet.TNManager.player.Get<FactionName>("PlayerFaction");
  12.             string apath = fDB.GetFactionPath(f);
  13.             TNet.TNManager.Instantiate(channelID, "GeneratePlayerCore", apath, true);
  14.         }
  15.  
  16.         [TNet.RCC]
  17.         public static GameObject GeneratePlayerCore(GameObject prefab)
  18.         {
  19.             Debug.Log("GeneratePlayerCore");
  20.             GameObject _mainCore = Instantiate(prefab) as GameObject;
  21.             Vector3 position = GetSpawnPoint();
  22.             _mainCore.transform.localPosition = position;
  23.             GamePlay.game.myCore = _mainCore;
  24.             Controller.instance.FocusMainCore();
  25.             return _mainCore;
  26.         }
  27. .....
  28. }
  29.  

If I change it to a Monobehavior, it doesn't appear to make any difference which is not at all surprising since TNBehaviour derives from Mono already. As of now, if I run this code on each client I get a player core instantiated BUT only locally, not remotely. But if I simply move both of those functions to my TNEventReceiver inherited subclass, they instantiate both locally and remotely.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #9 on: November 06, 2017, 06:41:53 PM »
I'm not able to reproduce your problem. Do you have any functions that override the TNEventReceiver functions? Maybe one of the overrides is causing the discrepancy. TNEventReceiver definitely shouldn't effect anything in this case.

Is one of the clients hitting an exception in GeneratePlayerCore? You're calling some external functions, so maybe the error is occurring there? Still doesn't explain why TNEventReceiver makes it work (unless there is an override).

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #10 on: November 07, 2017, 02:29:48 AM »
Where is SpawnPlayer called from? Wherever it is, it must be done after joining your "channelID" channel.

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #11 on: November 07, 2017, 02:17:19 PM »
  1.     public class LoadingScreen : UIState
  2.     {
  3.         ..........
  4.  
  5.         [TNet.RFC]
  6.         public void CloseLoader()
  7.         {
  8.             StartCoroutine(Hold()); //All players are ready - Fade Out Screen Effect
  9.             GameBuilder.builder.SpawnPlayer();
  10.         }
  11.     }

So I have it called from the tail end of a loading screen. Not the best place, but it ensures it happens after I'm done loading the rest of the scene assets. I have all of my UI screens inherit from UIState, which is a custom GUI class that inherits from TNBehaviour. The reason for this is most of my UI overlays are required to be in sync across players.

The loading screen is displayed while the scene is changed from 'MainMenu' to 'Game.'
Just before we exit MainMenu we are sitting in the lobby waiting for players to be ready and the game to start.

I think the next thing for me to do is just sit down and strip everything out of the TNEventReceiver and see where I'm going wrong. All the example projects I've tried work properly, so its gotta be something I'm doing.
« Last Edit: November 07, 2017, 02:45:34 PM by phil.atha »

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #12 on: November 07, 2017, 11:54:52 PM »
I don't see anything immediately wrong. All my previous suggestions are still valid. Good luck and keep us updated :D

And to expand on ArenMook's advice: TNManager.JoinChannel returns immediately, but that doesn't mean you've joined the channel yet. The TNManager.onJoinChannel callback will fire when the join channel process is complete (whether it's a success or failure). So you may want to move some of your initialization code there (including spawning objects - as you need to be in a channel for TNManager.Instantiate to work).

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #13 on: November 09, 2017, 01:22:26 AM »
Figured it out.  So I was storing channel.id as a global variable in my TNEventReceiver-inherited class after I joined the channel, for convenience purposes I guess? This value was exposed and passed to my GameBuilder class on Awake. Evidently something was wrong with it however. Once I directly referenced TNManager.channel.id in the Instantiate calls directly they worked and created both player prefabs with the correct owners set.

But.. I haven't the slightest idea why this was the case. In my design the player can only ever connect to one channel at a time.  ???

On that note, it would be a little easier/cleaner if we could pass the Channel object as a variable into the Instantiate method rather than the ID int.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Objects Instantiate with No Owner
« Reply #14 on: November 09, 2017, 08:03:08 PM »
Because Awake() is the wrong place to interact with other components. Awake() is basically the constructor -- it runs as soon as the component gets added. Channel ID is not yet set at this point. You had to wait for it to be set.