Author Topic: RFC Calls in Other Classes  (Read 1010 times)

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
RFC Calls in Other Classes
« on: June 13, 2017, 05:50:25 PM »
I think I'm misunderstanding the use of the RFC IDs. I had thought that if I tag a function with an ID, I can then call it even if it exists in another script. Is this correct?

  1. public class JoinMenu
  2. {
  3.     public void TogglePlayerReady()
  4.     {
  5.         bool readystate = true;
  6.         tno.Send(1, "PlayerReady", readyState);
  7.     }
  8.  
  9.     [RFC(2)]
  10.     public void SetClockTime(float time)
  11.     {
  12.         countdown.Text = time;
  13.     }
  14.  
  15. }
  16.  
  17. public class HostMenu
  18. {
  19.     [RFC(1)]
  20.     public void PlayerReady()
  21.     {
  22.        //Trigger countdown clock
  23.        tno.Send(2, "SetClockTime", timeValue);
  24.     }
  25. }
This doesnt seem to work however. Is this correct?
The tutorial doc for RFCs is pretty basic and I didn't see the kind of thing I'm doing in the StarLinkUI example.

WolfTechGames

  • Newbie
  • *
  • Thank You
  • -Given: 6
  • -Receive: 4
  • Posts: 35
    • View Profile
Re: RFC Calls in Other Classes
« Reply #1 on: June 13, 2017, 10:43:01 PM »
It works, as long as the script is on the same object as the other script as the RFCs link with the TNObject. So let's say class A has rfc with id 2 and class B calls send on id 2, as long as they are on the same object then it would work. If class A is on Object A and class B is on Object B it won't work.

It's mostly a feature to simplify sending RFCs as you don't have to type the whole method name.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: RFC Calls in Other Classes
« Reply #2 on: June 13, 2017, 10:49:15 PM »
RFCs are cached per-TNObject. TNObject's RebuildMethodList() function gets a list of all MonoBehaviours on its GameObject's hierarchy (using Unity's GetComponentsInChildren function), then for each MonoBehaviour it uses reflection to iterate through each Method and checks if a Method is decorated with the [RFC] attribute.

So it seems you can only use the [RFC] attribute on methods defined in classes that derive from MonoBehaviour, and each ID is unique to that TNObject (technically the top-most TNObject in that GameObject's hierarchy since it detects parenting using Unity's GetComponentInParent).

However, if you can get a reference to a TNObject you can use a known ID on that object rather than your own object. You can do this from non-MonoBehaviour classes, too.
There's a static function in TNObject to Find a specific TNObject, but it's not meant to be used for this as it requires knowing its UID.

I think caching RFCs globally could be better, and I wonder what ArenMook would think of this. TNet already iterates every Type of every Assembly when it caches RCC's, so in the same step it could cache RFCs too. Since an object instance is used in the invocation of the method already the methods don't even need to be bound to an instance. Could also speed up method invocation using something like this: https://stackoverflow.com/a/41516621. I think the RFC packet structure would need to be changed, though, and there might be some design issues with that. ArenMook is a design genius, so I trust his judgement!

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
Re: RFC Calls in Other Classes
« Reply #3 on: June 14, 2017, 12:17:16 AM »
Thanks, that makes it a lot more clear. So for my purposes, I guess the best thing to do is have the lobby players 'ready' state saved via PlayerData like:

  1. if (ready)
  2.   TNet.TNManager.SetPlayerData("LobbyReady", false);

Then just have the host system iterate over these every frame. As for the countdown clock however, I guess I could just have each client trigger their own countdown clock but that completely defeats the purpose of a network synced clock. Any suggestions on that?

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: RFC Calls in Other Classes
« Reply #4 on: June 14, 2017, 01:09:39 AM »
Maybe something like this?
  1. IEnumerator BeginCountdown()
  2. {
  3.         while ((TNManager.isTryingToConnect) || (TNManager.IsJoiningChannel(-1))) yield return null;
  4.         TNList<Player> players = TNManager.players;
  5.         bool bReady = false;
  6.         while (true)
  7.         {
  8.                 bReady = true;
  9.                 foreach (Player p in players)
  10.                 {
  11.                         if (!p.Get<bool>("LobbyReady", false))
  12.                                 bReady = false;
  13.                 }
  14.                 if (bReady)
  15.                         break;
  16.                 yield return null;
  17.         }
  18.         LocalCountdown();
  19. }
  20.  

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
Re: RFC Calls in Other Classes
« Reply #5 on: June 14, 2017, 01:21:45 AM »
cmifwdll, Thanks I've got that part down. It's just syncing a countdown clock to all connected clients. Without being a multiplayer networking expert, I don't know if its going to be safe to pass that many messages over the network for each frame update when the countdown timeout value changes.

cmifwdll

  • Global Moderator
  • Sr. Member
  • *****
  • Thank You
  • -Given: 0
  • -Receive: 149
  • Posts: 285
  • TNet Alchemist
    • View Profile
Re: RFC Calls in Other Classes
« Reply #6 on: June 14, 2017, 01:49:36 AM »
There are no network calls in the code I posted.

Maybe I'm misunderstanding, but you want your countdown clock to begin at the same time for everyone as soon as everyone is ready, right? The code I posted should do that.
Just make sure all the players are in the same channel, then begin calling TNet.TNManager.SetPlayerData("LobbyReady", true) on each client. Once all players have set their "LobbyReady" value to true then the countdown will begin for everyone.

I don't know where you plan on calling TNet.TNManager.SetPlayerData("LobbyReady", true), but StartCoroutine(BeginCountdown()) should immediately follow.

phil.atha

  • Newbie
  • *
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 18
    • View Profile
Re: RFC Calls in Other Classes
« Reply #7 on: June 14, 2017, 01:42:31 PM »
Understood, thanks.
I guess it's a design dilemma. I thought that maybe having a network-synced clock was the 'proper' way to do things, because it would guarantee the clock time is the same for all clients. On the other hand I don't see how that's possible without flooding messages to each client for every clock tick.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,154
  • Toronto, Canada
    • View Profile
Re: RFC Calls in Other Classes
« Reply #8 on: June 18, 2017, 08:07:42 PM »
  1. double mCountdown = 0.0;
  2.  
  3. [RFC] void StartCountdown (double time)
  4. {
  5.     mCountdown = time;
  6. }
  1. tno.Send("StartCountdown", Target.All, TNManager.time + 5.0);
Now you can check in Update() or somewhere -- if mCountdown is not 0.0, time remaining is (mCountdown - TNManager.time).

And for the record, Re: OP title -- to call an RFC on another object, just do otherClass.tno.Send(...);