x


Clearing out buffered RPC calls from old Network.Instantiate() calls?

OK, I know that Network.Instantiate() works using buffered RPC calls; does anyone have a recommended system for getting rid of those buffered calls after they're no longer needed?

The issue, as I'm sure many of you have come across, is that those buffered RPCs can stack up after they're useful. The symptom that brought this to our attention is that, because Network.Destroy() doesn't use buffered RPC calls, new clients get the calls to Instantiate already-destroyed objects and don't get corresponding messages to destroy them. This results in ghost copies of whatever it is you instantiate and destroy.

Now, one solution would be to add a buffered RPC call that destroys the objects. Which would work, but the RPC buffer could get really bloated with unnecessary calls, and we'd need to be careful about initialization--we wouldn't really want clients to load models, animations, etc. for things that don't really exist anymore.

So we're thinking we'd like to use Network.RemoveRPCsInGroup() to get rid of the RPCs (reserving a bunch of communication groups to be claimed by each Network.Instantiate() call). Has anyone tried this, who can share their experiences/pitfalls encountered? The other option I can think of would be to make explicit all of the RPC calls included in Network.Instantiate(), which seems less ideal...

more ▼

asked Apr 07 '11 at 07:49 PM

Steve 9 gravatar image

Steve 9
255 3 4 12

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

6 answers: sort voted first

Didn't they fix this in 3.2? What's new in Unity 3.2

Networking: It's now possible to remove Network.Instantiate calls from the RPC buffer by calling Network.RemoveRPCs on the first NetworkView in the instantiated object.

So, right before you destroy your Network.Instantiated object, I imagine you do something like:

Network.RemoveRPCs(objectImDestroying.GetComponent(NetworkView)); 

(I think. If the object has multiple networkViews you might need to use GetComponents and call RemoveRPCs on the first entry in the array it returns).

more ▼

answered May 03 '11 at 06:03 PM

PrimeDerektive gravatar image

PrimeDerektive
3.4k 59 70 88

Hot diggity! That sounds like exactly what I wanted! I will definitely try this...

May 03 '11 at 07:39 PM Steve 9

Not working... at least not for me, i used it like this.

@RPC function DestroyBuffered(ObjectToDestroy : GameObject) { Network.RemoveRPCs(ObjectToDestroy.GetComponent(NetworkView)); Network.Destroy(ObjectToDestroy); }

May 04 '11 at 12:49 PM Zhapness

It works for me. Much better than our convoluted stuff; thanks a ton! Zaphness: I'm sure it needs to be done on the same machine that initiated the instantiation; when you call DestroyBuffered(), do you RPC it to everyone?.

May 04 '11 at 03:49 PM Steve 9

Glad to help! That issue was one of my longstanding irks with the built-in networking; I was very pleased when I saw they fixed it.

May 04 '11 at 04:02 PM PrimeDerektive

Whoah, actually I have to add a big caveat: this doesn't look like it works as completely as the gross remove-by-group solution, which causes occasional strangeness if (like us, so far) you don't use the levelPrefix. In most cases, yes, it gets rid of ghost players who disconnected; but this solution leaves some things reappearing in later levels for late joiners. I could be mistaken, but I'm afraid I won't have time to investigate much further for a while...

May 04 '11 at 06:22 PM Steve 9
(comments are locked)
10|3000 characters needed characters left

You would use RemoveRPCS and give it the Netowork.player that you want to remove the buffered stuff for. So if you know you used Network.Instantiate() or your own instantiate from a specific client that disconnected all you need to do is call RemoveRPCS(Network.player) for which ever network player disconnected and you shouldn't see their buffered RPCs anymore.

This works for me.

In code it would look like this.

function OnPlayerDisconnected(player: NetworkPlayer) {
    //Destroy all the objects currently in the scene created by this player and remove his info from the list
    Network.RemoveRPCs(player);
    Network.DestroyPlayerObjects(player);
}

This should do the trick.

more ▼

answered Apr 18 '11 at 09:59 PM

AKAssassin gravatar image

AKAssassin
363 2 2 9

Thanks! Unfortunately, in our situation this isn't enough for two reasons. First, our server is authoritative for everything (except input, of course); so when players disconnect, we have to recall which server-owned objects were created for that player and net-destroy them as well (switching to a client-authoritative architecture would work for players, but add action-resolution complexity). Second and more importantly, we net-instantiate non-player things; for those, destroying-by-player just wouldn't be possible. Anyway, the destroying-by-group seems to be working for us so far...

Apr 19 '11 at 02:06 PM Steve 9
(comments are locked)
10|3000 characters needed characters left

Hi I am a bit new to programming, so can you show or explain how to add the Buffered Network.Destroy RPC Call?

Really need this.

Thanks.

more ▼

answered May 02 '11 at 11:18 PM

Zhapness gravatar image

Zhapness
101 9 10 17

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

I'd like to add a note to this thread.

I just spent the whole day struggling with this issue (sidetracked by this issue, rather), because the RemoveRPCs call didn't appear to be working correctly.

What I instead discovered was that when I call an RPC on the SERVER and perform Network.Instantiate, it actually ends up creating a separate instance of a network-instantiated object FROM EACH CONNECTED PLAYER. (I confirmed that there were multiple instances of the same object being instantiated right on top of each other, all with their own unique viewIDs belonging to each player; I confirmed it with their Network.Player as well)

I don't know if this is a bug or intended behavior (I don't see why it should behave this way, TBH), but due to this I was not able to remove the RPC(s) correctly from the buffer for the longest time.

In the end, what I did was:

  • Instead of Network.Instantiating the object from within an RPC on the server,
  • I called Network.Instantiate directly from the server

That did the trick for me. No more duplicate copies of the object, and RemoveRPCs started behaving "correctly" as well.

I guess the point I'm trying to make is, if you are having ghost objects even after RemoveRPC-ing, check to see how many instances are actually spawned before you try Network.Destroy or RemoveRPC. If you have multiple copies, you could be having similar issues of RPC-induced server-side Network.Instantiations actually instantiating on the Client(s) side.

If I'm not making sense, I apologize. I literally spent 8 hours cutting this issue from every angle and am not sure if I'm even thinking straight anymore. ;D-

more ▼

answered May 29 '11 at 08:54 AM

orakga gravatar image

orakga
1

sounds like it was expected behavior if I understand what you did. If you did:

void Somewherincode() { . . networkView.RPC("dosomething", RPCMode.All); . . )

void dosomething() { Network.Instantiate(....) }

Then yes, you'll end up having every client run a Network.Instantiate and create the same object on top of itself. This is because Network.Instantiate already does an RPC call to all clients so you're double dipping if you will.

Instead you have two options:

  1. Just call Network.Instantiate and that's it. It'll create one copy on every client and also add the object to the server buffer to create the object on any new clients that join

  2. alternatively use your RPC call, but in the remote function just do an Instantiate without the "Network." in front of it. But if you do it this way you first have to create a viewid and pass it in, so all the remote objects share the same network id, like this:

void Somewherincode() { . . NetworkViewID _nvid = Network.AllocateViewID(); networkView.RPC("dosomething", RPCMode.All, _nvid); . . )

void dosomething(NetworkViewID _nvid ) { GameObject _go = Instantiate(....); NetworkView _nv = (NetworkView)_go.GetComponent(typeod(NetworkView)); _nv.viewID = _nvid; }

Note: In my final version I'm using RPCMode.All, not a buffered mode. This is my preference so I can control when things are instantiated and destroyed, but you might want to use AllBuffered.

Oct 13 '12 at 04:26 AM Quadgnim
(comments are locked)
10|3000 characters needed characters left

Like PrimeDerektive says in the "accepted" answer, you should use Network.RemoveRPCs. One subtlety that isn't clear is that the RPCs are buffered on the server, even if you call Network.Instantiate on one of the clients. This means that you should use a method like this:

[RPC]
void RemoveBufferedInstantiate (NetworkViewID viewID) {
    if (Network.isServer) {
        Network.RemoveRPCs (viewID);
    } else {
        networkView.RPC ("RemoveBufferedInstantiate", RPCMode.Server, viewID);
    }
}

With this code, you can call `RemoveBufferedInstantiate (networkView.viewID);` without having to consider if you're on the server or the client.

Your code would then look like:

RemoveBufferedInstantiate (someObject.networkView.viewID);
Network.Destroy (someObject);
more ▼

answered Oct 07 '12 at 06:15 AM

jorgenpt gravatar image

jorgenpt
79 4 4 7

(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:

x1030
x399
x77

asked: Apr 07 '11 at 07:49 PM

Seen: 5534 times

Last Updated: Oct 13 '12 at 04:26 AM