Tasharen Entertainment Forum

Support => TNet 3 Support => Topic started by: ArenMook on August 15, 2013, 12:36:08 PM

Title: Custom Object Creation functions (TNet 2)
Post by: ArenMook on August 15, 2013, 12:36:08 PM
Let's face it -- sometimes the generic TNManager.Create functions aren't enough. Sometimes it's useful to be able to pass custom data along. For example, creating a unit and wanting to assign its team. With Unity's objects it's easy -- Instantiate returns a game object that you can then modify, but with the creation having to go through proper synchronization, things get... tricky.

Well, TNet 1.8.0 aims to change that.

Adding a custom creation callback is now as simple as adding a new RFC call. In fact, the syntax is very similar as well.

The first thing you will want to do is to have a MonoBehaviour script attached to the same game object as your TNManager, or one of its children. This way TNManager will be able to find the function you are about to add. If you have a Game Manager, I'd suggest you add the following code there.

If you don't want to add the script under your TNManager, then you will need to register it with the TNManager by calling TNManager.AddRCCs<YourScriptType>();. TNet will check the script and add all of its RCCs automatically.

Next, add the actual RCC (remote creation call) function to your script. To do that, simply create a prototype for it. The function prototype for it is: [RCC(#)] GameObject FunctionName (GameObject prefab, ...); -- where "#" is the ID (10 to 255 range, inclusive), and "..." can be your custom parameters -- whatever you want them to be. For example, here's a function that expects a name to be passed along with position and rotation:
  1.         [RCC(10)]
  2.         static GameObject OnCreate (GameObject prefab, Vector3 pos, Quaternion rot, string unitName)
  3.         {
  4.                 GameObject go = Instantiate(prefab, pos, rot) as GameObject;
  5.                 go.name = unitName;
  6.                 return go;
  7.         }
Note that the function then returns the game object you've created so that TNet can do some other work with it (namely setting the TNObject IDs, if needed).

The last step is to call the new TNManager.CreateEx function somewhere. You can call it directly if you wish, but it's probably easier to create a wrapper function for it next to your RCC call and so that it's easy to find later:
  1.         static public void Create (GameObject prefab, Vector3 pos, Quaternion rot, string unitName, bool persistent = true)
  2.         {
  3.                 TNManager.CreateEx(10, persistent, prefab, pos, rot, unitName);
  4.         }
Note that the first 2 parameters passed to TNManager.CreateEx must be the ID of your RCC function and the persistent flag (whether the object will remain behind if the player leaves). The following parameters should match your RCC function's parameters.

As you probably guessed, calling your custom GameUnitManager.Create(...) function will indeed create your object as if you called TNManager.Create, except that your custom function will be doing the work -- including setting the name of the object.

Here is the complete script, for your convenience:
  1. using UnityEngine;
  2. using TNet;
  3.  
  4. public class GameUnitManager : MonoBehaviour
  5. {
  6.         /// <summary>
  7.         /// Step 1: Use this function instead of TNManager.Create when you want to create a new unit.
  8.         /// </summary>
  9.  
  10.         static public void Create (GameObject prefab, Vector3 pos, Quaternion rot, string unitName, bool persistent = true)
  11.         {
  12.                 TNManager.CreateEx(10, persistent, prefab, pos, rot, unitName);
  13.         }
  14.  
  15.         /// <summary>
  16.         /// Step 2: Create a function that will be called when the unit creation packet arrives.
  17.         /// Make sure that this script is attached to the same game object as TNManager or one of its children,
  18.         /// or that you registered this MonoBehaviour by calling TNManager.AddRCCs!
  19.         /// </summary>
  20.  
  21.         [RCC(10)]
  22.         static GameObject OnCreate (GameObject prefab, Vector3 pos, Quaternion rot, string unitName)
  23.         {
  24.                 GameObject go = Instantiate(prefab, pos, rot) as GameObject;
  25.                 go.name = unitName;
  26.                 return go;
  27.         }
  28. }
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: hippocoder on August 15, 2013, 07:07:08 PM
Hiya, I meant to purchase over the weekend but got too busy. I saw you are mentioning a pro version now, do I buy that instead? is there a link to the new version?
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on August 16, 2013, 12:10:19 AM
Pro version is just $30 more right now ($95 total). Like NGUI Pro it comes with access to the git-based source code repository. Two ways of getting it right now -- just with a direct PayPal of $95 to support at tasharen.com (for a brand-new license), or upgrade of $30 to the same address, with an email mentioning your OR# on the Asset Store for TNet standard.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: hippocoder on August 16, 2013, 07:05:40 AM
May I know what the differences between standard and pro are? I was unable to find the pro version on unity asset store.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on August 16, 2013, 07:14:14 AM
It's the same as NGUI -- Pro comes in the form of original source code repository access which gives you access to the latest changes sooner than you would otherwise, the ability to submit your own patches, and just overall much easier way to stay up to date if you plan on changing the library.

You won't find it on the Asset Store due to its delivery method (repo access).
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: pyscho2day on August 17, 2013, 10:03:18 PM
Aren,

Will standard get the same functionality as pro at some point but with out the repo access?
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on August 18, 2013, 06:35:31 AM
Yes, of course. Just wait a bit and when I ensure that there are no issues with it, it will be pushed to the Asset Store.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: pyscho2day on August 19, 2013, 10:52:39 AM
OK, I figured as much but wanted to make sure.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: jn5414 on September 12, 2013, 04:40:58 AM
can rcc be used depart from TNManager?
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on September 12, 2013, 07:58:57 AM
RCC functions must be on a script that's attached either to the same object as the TNManager or one of its children.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: andrew on October 10, 2013, 09:59:49 PM
Nice stuff...

Say I want to launch off a projectile with this code... and I want to pass in the GameObject owner of the projectile so that I can turn off collision between the owner and the projectile.  I can't serialize a GameObject for this, how would you go about doing that?

thanks
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: andrew on October 10, 2013, 11:04:25 PM
Think I answered my own question.. keep a static list around and update it when creating/removing players using tno.ownerID for lookup.

  1. public class PlayerID {
  2.         public PlayerID( GameObject _go, int _id ) {
  3.                 go = _go;
  4.                 id = _id;
  5.         }
  6.         public GameObject       go;
  7.         public int                      id;
  8. }
  9. private static BetterList<PlayerID> players = new BetterList<PlayerID>();
  10.        
  11. public static GameObject Find( int objID ) {
  12.         for ( int i = 0; i < players.size; i++ ) {
  13.                 if ( players[i].id == objID ) {
  14.                         return players[i].go;
  15.                 }
  16.         }
  17.         return null;
  18. }
  19.  
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: pyscho2day on October 11, 2013, 07:55:59 AM
This is how i do it

  1. [RCC(10)]      
  2. static GameObject myMethod(GameObject prefab, Vector3 pos, Quaternion rot, string someStringValue, int someIntValue)
  3. {
  4.         GameObject go = Instantiate(prefab, pos, rot) as GameObject;    //creates the object
  5.         go.name = someStringValue;                                     //Names the object
  6.         ScriptName sn = go.GetComponent<ScriptName>();    //Gets the script you want to add info to
  7.         sn.property    //Add info to the script such as name or team.
  8.         return go;
  9. }
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: case on February 05, 2014, 02:18:22 PM
First, this is a great package, I've used a lot of Tasharen's sets from the space game, NGUI, and now TNET. However, I wasn't sure why TNManager requires a list of object prefabs set for creation. Most of the time this is handled by a scene/game manager, and I didn't want to have to redefine it in more than one place any time I make a change. Is it purely for the purpose of standalone servers?
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on February 05, 2014, 05:01:19 PM
It needs to know what the objects are. There are only two ways of doing this in Unity. You can either reference them directly, or you can Resources.Load them by name. TNet supports both -- so you don't need to add objects to TNManager's list if you want to create them by their prefab's name instead (assuming you placed them in the Resources folder, of course).
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: case on February 05, 2014, 10:06:50 PM
Okay, I think I understand. Can the TNManager.objects list can be populated at runtime somehow? Thanks for the answers. :)
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on February 06, 2014, 10:50:59 PM
It shouldn't be populated at run-time, as it expects the list to match on all clients before the object instantiation begins.

If your list is dynamic, then just instantiate from the Resources folder by name.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: mohydine on May 14, 2014, 01:13:42 PM
Hello ArenMook,

Does the OnCreate Method require to be static?


Thanks
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on May 15, 2014, 12:19:47 AM
No, it doesn't. But in most cases you will want it to be.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: danfoo on August 29, 2014, 03:39:51 AM
Hi,

I have a problem with custom RCCs. I call TNManager without error, but the RCC never fires.
The only difference compared to your examples is that the RCC function is not static, does it have to be?
  1. TNManager.CreateEx(10, true, patchPrefab, tid, coordSpan, TNManager.playerID);
  1. [TNet.RCC(10)]
  2.         public GameObject OnCreate (GameObject prefab, int mastertile, int[] coordspan, int reqPlayer) {....}

Thanks in advance!

Update:
CreateEx does fire, but since the passed gameobject was null (my mistake) it returns without an error (maybe it should at least log something).
Anyway, looking at the TNManager code it seems that if you pass a GO to the CreateEx function it assumes it is one of TNManagers "known" objects, and will not accept just any prefab. Correct?
I am assuming that passing a string path instead leads to it being loaded from Resources regardless of whether it is in the TNManager list or not?

TIA!
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on August 30, 2014, 09:53:41 AM
Yup. It's generally best to pass a string in its place that you would normally pass to Resources.Load.

TNet handles prefab instantiation using its Resources.Load string instead of the prefab game object.

P.S. Also... the RCC should ideally be a static function.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: viri on February 22, 2015, 09:02:56 PM
It would be kinda nice to have immediate access to the gameobjects. Kindof like
  1. class SpawnerButton :MonoBehavior
  2. {
  3.          void OnMouseDown()
  4.          {
  5.                 GameObject go=TNManager.Create ("Token",Vector3.zero,Quaternion.identity,false);
  6.                 Random r=new Random();
  7.                 //yield new WaitForSeconds(1);
  8.                 go.GetComponent<Token>().SetName("Random name "+r.Next(100).ToString());
  9.          }
  10. }
  11.  

  1. public class Token:TNBehavior
  2. {
  3.         public void SetName(string newname)
  4.         {
  5.                 tno.Send ("SetNameRFC",Target.AllSaved,newname);
  6.         }
  7.         [RFC]
  8.         public void SetNameRFC(string newname)
  9.         {
  10.                 name=newname;
  11.         }
  12. }
  13.  

Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on February 24, 2015, 12:03:01 PM
That's impossible. Game objects are created by sending a request to the server, the server sending it back to everyone at the same time. It's a delayed call. Sending is done by specific object IDs which are generated by the server. They are not available immediately, so sending of immediate RFCs wouldn't be possible.

As this thread explains if you need to pass arguments along with your create call, create an RCC function and use it.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: Shifty Geezer on July 02, 2015, 05:30:28 AM
What's the syntax for passing a string reference to the RCC?

I can't get this or variations of it to work:
  1.     [RCC(10)]
  2.     static GameObject OnCreate (string prefabName, Vector3 pos, Quaternion rot, string unitName)
  3.     {
  4.         GameObject go = Instantiate(Resources.Load (prefabName) as GameObject);
  5.         go.transform.position = pos;
  6.         go.transform.rotation = rot;
  7.         go.name = unitName;
  8.         return go;
  9.     }
  10.  
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on July 02, 2015, 09:27:43 PM
I see nothing wrong with that. What's the actual error you're running into? Did you actually register your RCC(10)? Note TNManager.AddRCCs.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: Shifty Geezer on July 03, 2015, 04:01:54 AM
My script, GameControl:
  1.         void Awake(){
  2.                 Instance = this;
  3.                 TNManager.AddRCCs<GameControl>();
  4.                 ...
  5.         }
  6.  
  7.         TNManager.CreateEx ((byte)GLOBAL.RFCs.CREATE_ACTIONABLE, true, prefabName, (Vector3)pos, Quaternion.Euler (0,0,0));
  8.  
  9.         [RCC((byte)GLOBAL.RFCs.CREATE_ACTIONABLE)]
  10.         static GameObject CreateActionable (string prefabName, Vector3 pos, Quaternion rot){
  11.                 GameObject go = Instantiate(Resources.Load (prefabName) as GameObject);
  12.                 go.transform.position = pos;
  13.                 go.transform.rotation = rot;
  14.                 return go;
  15.         }
  16.  

Error:
  1. [TNet] Failed to call RFC #10 on <null>: failed to convert parameters
  2.   Expected args: System.String, UnityEngine.Vector3, UnityEngine.Quaternion
  3.   Received args: UnityEngine.GameObject, UnityEngine.Vector3, UnityEngine.Quaternion
  4.  
  5.   at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00063] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:192
  6.   at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115
  7.   at TNet.UnityTools.ExecuteFirst (TNet.List`1 rfcs, Byte funcID, System.Object& retVal, System.Object[] parameters) [0x0003e] in D:\_Programming Stuff\Unity\AiaVG\Assets\TNet\Client\TNUnityTools.cs:103
  8.  
  9. UnityEngine.Debug:LogError(Object, Object)
  10. TNet.UnityTools:PrintException(Exception, CachedFunc, Int32, String, Object[]) (at Assets/TNet/Client/TNUnityTools.cs:81)
  11. TNet.UnityTools:ExecuteFirst(List`1, Byte, Object&, Object[]) (at Assets/TNet/Client/TNUnityTools.cs:111)
  12. TNManager:CreateEx(Int32, Boolean, String, Object[]) (at Assets/TNet/Client/TNManager.cs:884)
  13. GameControl:DEV_AddObjective(String, TIME_TYPE, Int32, OBJECTIVE_TYPE, Int32, Vector2, Vector2, Vector2) (at Assets/_Scripts/GameControl.cs:430)
  14. GameControl:HOST_CreateLevel() (at Assets/_Scripts/GameControl.cs:412)
  15. <Start>c__Iterator33:MoveNext() (at Assets/_Scripts/GameControl.cs:163)
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on July 03, 2015, 11:49:51 AM
It's telling you what's wrong. You have "string prefabName", but it expects a Game Object. TNet finds the game object for you and passes a reference to the prefab for you. You don't need to Resources.Load. TNet does it for you.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: Shifty Geezer on July 03, 2015, 12:08:25 PM
If I pass the prefab as a GameObject, TNManager complains that the object isn't in its list.

I currently use Create("String") to instantiate from Resources. How do I do the same with CreateEx()?
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on July 03, 2015, 12:13:06 PM
TNManager.CreateEx needs the string. The RCC needs a GameObject.

TNet takes the string, does Resources.Load, then passes the game object to your RCC.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: Shifty Geezer on July 03, 2015, 02:12:10 PM
Okay, thanks. To clarify, the syntax is exactly the same as the first post, only the call uses a string instead of a GameObject. The GameObject parameter of the RCC is created and passed via TNet. It's also only a reference - that object itself doesn't exist in the game and we need the Instantiation of it to create an in-game version.

It's a very simple, effective solution.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on July 03, 2015, 02:13:17 PM
That's correct. TNet gives you a reference to the loaded prefab that you will then instantiate.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: Shifty Geezer on July 11, 2015, 10:57:55 AM
I'm finding calls after CreateEx are executing before the CreateEx is complete. Is there a callback or something to get when a CreateEx is complete? Or should I implement a handshake via RFCs?

Edit: Sorry, complete nonsense on my part. Can't remember the fault now but my interpretation of the situation was wrong. It was some dumb implementation error on my end!
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on July 12, 2015, 08:11:23 PM
What calls? When you instantiate an object, its Awake() and OnEnable() will trigger before the creation completes. Is this what you're seeing? If so, that's just how Unity works.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on July 15, 2015, 12:51:18 AM
You shouldn't be doing any RFCs in Start() of a created object. You can't send RFCs while the channel is being joined, and joining operation can stretch across several frames, meaning your Start() will most likely execute before you finish joining the channel.

This is why I yield in all my Start() calls like so:
  1. IEnumerator Start()
  2. {
  3.     while (TNManager.isJoiningChannel) yield return null;
  4.     // .. do stuff
  5. }
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: blueagardq15 on July 24, 2015, 10:29:58 AM
Does the script have to be attached to TNManager?
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on July 24, 2015, 11:00:25 AM
No, just be sure to register it with TNManager in your script's Awake(), and make sure that this script exists as a part of your scene.
  1. TNManager.AddRCCs<YourScript>();
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: Doomlazy on October 20, 2015, 08:29:28 AM
Is there any easier way of Instantiating a player.
I tried using TNManager.Create today and got the error:
"[TNet] Failed to call RCC #1. Did you forget to register it in Awake() via TNManager.AddRCCs?"
Do I seriously have to set all this stuff up just to instantiate a player?
In Unity all I would need to do is Network.Instantiate and that worked fine for me.
Is there an easier way of instantiating gameobjects Unity-style?
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on October 24, 2015, 05:17:07 AM
RCC #1 is a part of TNet. It's bound to OnCreate1 function in TNManager. It doesn't need to be registered because it gets registered automatically on line 951 of TNManager.cs:
  1.                                 // Add the built-in remote creation calls
  2.                                 AddRCCs<TNManager>();
TNet also automatically registers any RCCs it finds on scripts underneath its instance object (assuming you have a TNManager script present in the scene rather than having it instantiate itself dynamically). The rest you need to register in Awake() when first starting up your application.

This is only for custom RCCs, mind you -- that is RCCs that involve passing custom data during the creation.
Title: Re: Custom Object Creation functions (1.8.0+)
Post by: ArenMook on January 28, 2016, 03:06:42 PM
As of TNet 3, it's no longer necessary to call TNManager.AddRCCs<T>(), and the syntax of RCCs changed. They can be called by name, just like RFCs (the ID is no longer needed). Instantiation is done via TNManager.Instantiate, or TNBehaviour's Instantiate() functions (there for convenience).

Examining the ExampleCreate.cs script shows both steps needed -- creating the RFC and instantiating an object. As such, this topic is now obsolete.
  1. using UnityEngine;
  2. using TNet;
  3.  
  4. public class ExampleCreate : MonoBehaviour
  5. {
  6.         /// <summary>
  7.         /// Create a new object above the clicked position
  8.         /// </summary>
  9.  
  10.         void OnClick ()
  11.         {
  12.                 // Object's position will be up in the air so that it can fall down
  13.                 Vector3 pos = TouchHandler.worldPos + Vector3.up * 3f;
  14.  
  15.                 // Object's rotation is completely random
  16.                 Quaternion rot = Quaternion.Euler(Random.value * 180f, Random.value * 180f, Random.value * 180f);
  17.  
  18.                 // Object's color is completely random
  19.                 Color color = new Color(Random.value, Random.value, Random.value, 1f);
  20.  
  21.                 // Create the object using a custom creation function defined below
  22.                 TNManager.Instantiate("ColoredObject", "Created Cube", true, pos, rot, color);
  23.         }
  24.  
  25.         /// <summary>
  26.         /// RCCs (Remote Creation Calls) allow you to pass arbitrary amount of parameters to the object you are creating.
  27.         /// TNManager will call this function, passing a prefab to it that you should then instantiate.
  28.         /// </summary>
  29.  
  30.         [RCC]
  31.         static GameObject ColoredObject (GameObject prefab, Vector3 pos, Quaternion rot, Color c)
  32.         {
  33.                 // Instantiate the prefab
  34.                 GameObject go = Object.Instantiate(prefab) as GameObject;
  35.  
  36.                 // Set the position and rotation based on the passed values
  37.                 Transform t = go.transform;
  38.                 t.position = pos;
  39.                 t.rotation = rot;
  40.  
  41.                 // Set the renderer's color as well
  42.                 go.GetComponentInChildren<Renderer>().material.color = c;
  43.                 return go;
  44.         }
  45. }