Inheritable RPC Calls

suFFer
edited November 2012 in DotNet
Hey,

is it possible to make RPC Calls able to acess other scripts? For instance am I trying to use a list in my RPC function which was added via AddCompontent, yet Unity can not use this reference. It seems like it can't acess inherited classes. There is a solution for normal unity RPC calls (http://whydoidoit.com/2012/06/29/inheri ... for-unity/) but is there one for Photon RPC calls too?

Thank you very much

Greetings,

Alex

Comments

  • The link describes how to call RPCs that should normally be overridden by some extending class. How does this relate to the problem you describe?

    Access to properties and fields is defined by the access modifiers and by knowing the objects you need for this.
    If you want access to some specific list, you could refactor the project to make the objects known to each other instead of modifying RPCs.
    You could also GetComponent when you add a RPC script to get access to other components and scripts. Do this once and cache the result to save performance.
    You could also use SendMonoMessage. But this is also performance hungry.
  • We tried to use GetComponent and AddComponent, but there is still the same error.

    I added the part of the code with the problem, i can't explain it adequate.

    It is all from one script.
    We are adding one List in the "spellList" in line 26 and its fine. It has one item and it works perfectly if we call the "SpellHitManager" method local from our own client. When the method is called from another client the "spellList" is empty (there should still be the one List) and the function in line 6 in the last code cast a NullReference exception.

    When we integrated the whole "Slow" script into this one it is working.
    But we need a way to get access to another script.

    [code2=csharp]Dictionary<string, Dictionary<string,Spell>> spellList = new Dictionary<string, Dictionary<string, Spell>>();

    W001 w001;
    W001 w001Test;

    Slow slow;
    Slow slowTest;

    IEnumerator Start ()
    {
    slow = gameObject.AddComponent<Slow>();
    w001 = gameObject.AddComponent<W001>();

    slowTest = GetComponent<Slow>();
    w001Test = GetComponent<W001>();

    Debug.Log(slowTest);
    Debug.Log(w001Test.effects);


    distToGround = collider.bounds.extents.y;
    rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;
    transform.localEulerAngles = new Vector3(transform.localRotation.x,0.0f,transform.localRotation.z); //Replaced with an animation!
    transform.rigidbody.useGravity = true;
    yield return 0;
    spellList.Add("W001",w0012.effects);
    }[/code2]


    [code2=csharp]photonView.RPC("SpellHitManager",PhotonTargets.All,"W001");[/code2]


    [code2=csharp][RPC]

    public void SpellHitManager(string spellname){

    //This part is just for test purposes
    slowTest.SlowEffect("WupWup",5f,-0.1f,true,true,5,ref moveSpeedEffects); //Nullreference Exception

    Debug.Log(spellList.Count); //It's empty count = 0 but it should have 1 item
    //


    Dictionary<string,Spell> tempEffects;
    if(spellList.TryGetValue(spellname,out tempEffects))
    {
    foreach(KeyValuePair<string,Spell> tempEffect in tempEffects)
    {
    switch(tempEffect.Key)
    {
    case "slow":
    if(tempEffect.Value.Stack)
    {
    slow.SlowEffect(tempEffect.Value.Name,tempEffect.Value.Duration,tempEffect.Value.Efficiency,tempEffect.Value.ProcentDmg,tempEffect.Value.Stack,tempEffect.Value.StackTimes,ref moveSpeedEffects);
    }
    else
    {
    slow.SlowEffect(tempEffect.Value.Name,tempEffect.Value.Duration,tempEffect.Value.Efficiency,tempEffect.Value.ProcentDmg,ref moveSpeedEffects);
    }
    break;[/code2]

    greets

    Max
  • "...tThe same error"?
    You mean that the list is not filled?
    That's not really a networking/Photon related issue and I don't have the time to check this at the moment :(

    Does anyone from the community know what's up?
  • I don't know anything about Unity's built in networking or the recent Photon integration with it. You are saying that you want a list you populated on one client to be automagically sent to the other clients by way of the Unity [RPC]?
  • No the List is populated on the own client/pc. We just want to send a (string) name with the RPC and search for this in the Dictionary. This Dictionary is filled with information from many scripts (our classes), in this case our spell information. But it seems that if this List is called via RPC this List is a new one with no elements. Furthermore we can't access methods in other scripts like:

    [code2=csharp][RPC]

    public Method(string name)
    {
    //The otherMethod is no RPC Method
    otherscript.otherMethod(); //NullReference Exception
    }[/code2]

    There is allways a NullReference Exepction. It could be that we are just too stupid and overseen some little issues, but i have not a single idea what to do.
  • The RPC really has nothing to do with accessing the other script.
    You could do a check if otherscript is null and if so, try to find the object that has the script.
    How are you accessing the otherscript in .. other scripts? :)
  • The funny thing is that if we access slow.Sloweffect without the RP Call then the sloweffect works _perfectly_ but using the RPC, Unity says "NullReference"....does RPC create a new instance or something like that? Locally the "spellList" is filled but if the RPC accesses it it responds with "NullReference" :?

    And otherscirpt is being accessed by

    [code2=csharp]Otherscript otherscript;

    void Start()
    {
    otherscript = gameObject.AddComponent<Otherscript>();
    }[/code2]
  • Can you strip down the project and share it with me somehow? I might take a look next week.
    I don't see what's happening just by descriptions.
  • okay, we made a strip version and suddenly its working, if we know why i will post the solution. But thanks for the time.
  • ok now we did a ton of debugging and eventually we found out that the reason for not sending the RPC properly seems to have something to do with the instantiating the players. So what we essentially found out is that if both players have a scene photonID it works. If one has a scene photonID and the other one is instantiated it's not working. So basically the RPC is being received but the List is still empty so no effect happening. Everything is fine if both players are not instantiated, which isn't good because of course we need to identify them by their unique PhotonViews. Are we doing the Player Instantiation wrong? We see the Players Ingame + it correctly updates position and rotation. We think that the RPC is not working correctly (it is being received but it can't access the List) because the players have been instantiated. We are kind of stuck here because it doesn't really make sense :s

    here is the Instantiation Code:

    [code2=csharp]playerClone = PhotonNetwork.Instantiate("3rdPersonPlayer",transform.position,Quaternion.identity,0);[/code2]


    Thanks in advance!

    Alex

    EDIT/ if we manually delete the photonView during runtime and then add it again (becoming a scene photonView) it works, too.
  • I think the problem is that you somehow remove a scene view. Otherwise, I don't see how one player has a scene view and the other has an instanced one.
    This is never a good idea. Don't delete scene views. They should always stay untouched. They are useful if you want to send RPCs to the scene instead of to someone/something instantiated in particular.
    Instantiate your avatars at runtime from prefabs and they get a user-specific ID and can be targets of RPCs as well.
  • haha no we don't delete it. It was just a test! We do instantiate our characters at runtime and with that comes the error :/ But we will strip down the project and upload it asap
  • The problem was, that the RPC created a new instans of the gerneric Lists and Dictionaries. So it wasn't possible to call it by reference in the other scripts or use it in the same where the rpc function was. The solution is simple but to find it was hard. You just have to make the Lists and Dictonaries static and it works.
  • Ah, cool you found it. Mean stuff!
    Thanks for the head up.
  • By the way: In the next PUN update (1.18) we will also call RPC methods that are inherited.
  • brainversation
    edited October 2015
    Tobias said:

    By the way: In the next PUN update (1.18) we will also call RPC methods that are inherited.

    Is there documentation on this because when I try and do this I get an error that there are 2 of the same function??

    PhotonView with ID 14 has 2 methods "setSizeRPC" that takes 1 argument(s): Vector3. Should be just one?
    UnityEngine.Debug:LogError(Object)

    I am using virtual and override.
  • There is nothing special to document for this case.
    We will have to take another look, it seems.
    Which version of PUN and Unity do you use?
  • brainversation
    edited October 2015
    Hello @Tobias ,

    Ya how can I help resolve this!!

    I am using v1.62.

    Thanks!
  • I think it should be easy to test. One class with RPC and one that extends it, right?
    You could send me a minimal class which shows the behaviour, if you like. Else, I will try early next week.
    (sorry, didn't fit in before the weekend)
  • Do you mean like this?

    ------------------------------------------------------

    public class Parent : MonoBehaviour {
    protected int ID;

    void Start () {
    ID = gameObject.GetInstanceID();
    print(ID);
    }

    [PunRPC]
    public virtual void sendID(int newID){
    ID = newID;
    }
    }

    public class Child : Parent {
    const int ChildOffset = 1;

    void Start () {
    ID = gameObject.GetInstanceID() + ChildOffset;
    print(ID);
    }

    [PunRPC]
    public override void sendID(int newID){
    base.sendID(newID);
    }
    }


    ---------------------------------------OR------------------------------------------

    public class Parent : MonoBehaviour {
    protected int ID;

    void Start () {
    ID = gameObject.GetInstanceID();
    print(ID);
    }

    [PunRPC]
    public virtual void sendID(int newID){
    ID = newID;
    }
    }

    public class Child : Parent {
    const int ChildOffset = 1;

    void Start () {
    ID = gameObject.GetInstanceID() + ChildOffset;
    print(ID);
    }
    }

    ------------------------------------------------------

    And the second will have the RPC work?

    Because I have tried both and the first one says there no RPC sendID in this class and the second one says there are 2 functions called sendID that take 1 argument(s): int.

    P.S. Also sorry for the bad format of my code, I can not figure out the syntax highlighting.
  • Both sets of classes are fine for me. In Unity 4.3.4 and 5.2 as well.
    Of course, only the extending component gets placed on a game object. In my case, I don't instantiate that GO but place it in the scene at edit time.

  • Hello @Tobias ,

    I guess the Update to v1.62 fixed that issue. We were on v1.52 and I had just messaged you after I did the update with out testing it, enough.

    Sorry and thank you for your help! I will reply to this post if I have anymore problems.