x


How do I use yield in a C# RPC function?

Hi. I tried to convert javascript to C# with Networking sample.

My code almost works, but some code doesn't work in NetworkLevelLoad.js (RPC function).

//NetworkLevelLoad.js

@RPC
function LoadLevel (level : String, levelPrefix : int)
{
    // omitted code

    Application.LoadLevel(level);
    yield;
    yield;

    // Allow receiving data again
    Network.isMessageQueueRunning = true;
    // Now the level has been loaded and we can start sending out data
    Network.SetSendingEnabled(0, true);

    // Notify our objects that the level and the network is ready
    for (var go in FindObjectsOfType(GameObject))
        go.SendMessage("OnNetworkLoadedLevel", SendMessageOptions.DontRequireReceiver); 
}

I convert yield; to yield return 0;, and edited LoadLevel function to IEnumerator LoadLevel. (Of course I converted other lines to C# too.)

But at runtime, after first yield return 0, script is ended and Network.IsMessageQueueRunning is not performed. How can I edit this script for work fine?

Thanks.

more ▼

asked Nov 17 '10 at 09:24 AM

Kichang Kim gravatar image

Kichang Kim
50 6 8 16

Are you getting any errors in your debugger?

Nov 17 '10 at 10:24 AM denewbie

no error. but MessageQueining after yield is not excuted.

Dec 01 '10 at 08:37 AM Kichang Kim

I also want to know how to make yield work in RPC calls. It looks like they are not called if the return type of the RPC function is not void.

Jul 16 '11 at 11:15 AM Herman Tulleken
(comments are locked)
10|3000 characters needed characters left

3 answers: sort voted first

I'm currently struggling with the same task of converting the networking example to C#

The problem is that yield containing functions must return an Enumerator but RPC functions must return void.

The following code works for me.

[RPC]
public void LoadLevel(string level, int levelPrefix)
{
  StartCoroutine(loadLevel(level, levelPrefix));
}

private IEnumerator loadLevel(string level, int levelPrefix)
{
  // omitted code

  Application.LoadLevel(level);
  yield return new WaitForEndOfFrame();
  yield return new WaitForEndOfFrame();

  // Allow receiving data again
  Network.isMessageQueueRunning = true;
  // Now the level has been loaded and we can start sending out data
  Network.SetSendingEnabled(0, true);

  // Notify our objects that the level and the network is ready
  foreach (GameObject go in FindObjectsOfType(typeof(GameObject)))
    go.SendMessage("OnNetworkLoadedLevel", SendMessageOptions.DontRequireReceiver);
}
more ▼

answered Nov 05 '11 at 01:31 PM

Azzara. gravatar image

Azzara.
101 3 5 6

(comments are locked)
10|3000 characters needed characters left

this is one major mind fuck thanks to c# being nearly useless, and javascript being well, javascript.

so i'm assuming we're all working off of the same code, and in order to fix the problem you need to make the following changes:

[RPC]
public void LoadLevel(string level, int levelPrefix)
{
  StartCoroutine(loadLevel(level, levelPrefix));
}

private IEnumerator loadLevel (string level, int levelPrefix)
{

    showLobby = false;
    Debug.Log("Loading level " + level + " with prefix " + levelPrefix);
    lastLevelPrefix = levelPrefix;

    // There is no reason to send any more data over the network on the default channel,
    // because we are about to load the level, thus all those objects will get deleted anyway
    Network.SetSendingEnabled(0, false);   

    // We need to stop receiving because first the level must be loaded.
    // Once the level is loaded, RPC's and other state update attached to objects in the level are allowed to fire
    Network.isMessageQueueRunning = false;

    // All network views loaded from a level will get a prefix into their NetworkViewID.
    // This will prevent old updates from clients leaking into a newly created scene.
    Network.SetLevelPrefix(levelPrefix);
    Application.LoadLevelAdditive(level);
    yield return new WaitForEndOfFrame();
    yield return new WaitForEndOfFrame();
    Debug.Log("Loading complete");



    Debug.Log("load level DONE");
    // Allow receiving data again
    Network.isMessageQueueRunning = true;
    // Now the level has been loaded and we can start sending out data
    Network.SetSendingEnabled(0, true);

    Debug.Log("sending load msg");
    // Notify our objects that the level and the network is ready
    foreach (GameObject go  in FindObjectsOfType(typeof(GameObject)) )
    {
         Debug.Log("sending load msg");
         go.SendMessage("OnNetworkLoadedLevel", SendMessageOptions.DontRequireReceiver);  
    }
}

so level additive works and i dont know exactly why, but you need to change your function to a non RPC with return type IEnumerator so that yield will work properly. and in order to call as a RPC, make a dummy function with return type void. and start a coroutine so yield can work its magic.

more ▼

answered May 15 '12 at 07:51 PM

kajjait gravatar image

kajjait
15

What's the point in answering a 2 years old question with the same answer that is already there (Azzara) ?

Btw you posted the answer two times. I deleted your second one since you had all your text bold and it's the same again ...

Why do you complain about C#? Generator functions always work this way, even before Unity came out.

I guess you just didn't used DontDestroyOnLoad on this gameobject, right? So if you load a new level this gameobject + script + coroutine is wiped out.

May 15 '12 at 08:18 PM Bunny83

i dunno why it posted twice or in bold, but thanks for your answer. i probably didnt do that! just trying to adjust to this magical world of managed code. i'm used to having full control of how my program runs. my bad!?

May 26 '12 at 02:23 AM kajjait

DontDestroyOnLoad ! I don't know that method until now! Very thanks.

Jul 05 '12 at 04:33 AM Kichang Kim

And thanks for reply kajjait

Jul 05 '12 at 04:37 AM Kichang Kim
(comments are locked)
10|3000 characters needed characters left

Meantime, I dont have my debugger with me now but I'll convert it to something like this. Does it look similar to yours?

public void LoadLevel (string level, int levelPrefix)
{
    // omitted code

    Application.LoadLevel(level);
    yield;
    yield;

    // Allow receiving data again
    Network.isMessageQueueRunning = true;
    // Now the level has been loaded and we can start sending out data
    Network.SetSendingEnabled(0, true);

    // Notify our objects that the level and the network is ready
    foreach (GameObject go in FindObjectsOfType(GameObject))
        go.SendMessage("OnNetworkLoadedLevel", SendMessageOptions.DontRequireReceiver); 
}
more ▼

answered Nov 17 '10 at 10:28 AM

denewbie gravatar image

denewbie
717 3 3 17

thanks for reply. but "yield;" occured error in C#.

Nov 19 '10 at 07:51 AM Kichang Kim

You cannot do coroutines like that in C#. You must return IEnumerator and the yield syntax is as follows "yield return 'value';" And, never "yield return 0;". There is an unnecessary memory allocation. Return null instead.

Feb 12 '11 at 02:21 PM Peter G

Thanks Peter G

Jul 05 '12 at 04:38 AM Kichang Kim
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x333
x225

asked: Nov 17 '10 at 09:24 AM

Seen: 2632 times

Last Updated: Jul 05 '12 at 04:38 AM