- Home /
Network RPC buffer issue
Hello Unitypeople,
I have been struggeling with an issue in Unity's Network system for a long time now that I cannot seem to fix.
I have specially created a stripped down version of my project to demonstrate the issue, which can be downloaded here.
The following project consists of a "game" in which one server and multiple clients can engage in a battle of cube instantiation. These cubes are to represent actual game elements such as player characters and projectiles. Note that clients Instantiate their own objects to make sure that the movement of these objects runs smooth on their side, and smooth with prediction and interpolation on other sides.
The issue that I am facing is when I have a server and one client, and a second client connects, that last client can see loads of objects that should have been destroyed. I suspect that the Instantiation of that object remains in the RPC buffer even though I have tried to remove it.
I give the cubes a red color by default on start, to mark these as cubes that are unowned by any network player. Then, once OnSerializeNetworkView() is called, that would imply that someone somewhere wrote into the stream because he owns the cube, which makes the cube turn green. Cubes that remain red don't have any owner and should be destroyed.
In order to reproduce the issue:
It is rather simple to reproduce the issue. All you have to do is start the "game" three times. Start one as server, and one as client. Let them have their cube-war for aproximatically 10 seconds, and then use the third game to connect aswell. That client will have loads of unowned red cubes that shouldnt be there. This can be done from editor aswell as from standalone builds.
The entire project consists of two scripts, a game controller that manages the network and the cubes, and a cube script that synchronizes its data through the network stream.
I would be really happy if someone spots the problem of what I am doing wrong, because I am almost 100% certain that I have understood Unity's documentation of Networking, and I am unable to find what is causing the issue.
Here be code:
using UnityEngine;
public class GameController : MonoBehaviour
{
private static GameController s_main = null;
public static GameController main
{
get
{
if (!s_main)
return null;
return s_main;
}
}
private void Awake()
{
//Ensure that only one GameController is active in the game, and destroy duplicates when returning to menu scene
if (s_main == null)
{
s_main = this;
//Make the GameController persistant
GameObject.DontDestroyOnLoad(gameObject);
}
else
{
GameObject.Destroy(gameObject);
}
}
private float cubeTimer = 0;
private void Update()
{
//Exit application
if (Input.GetKeyDown(KeyCode.Escape))
Application.Quit();
//Return if we are not in the game scene
if (Application.loadedLevel != 1)
return;
//Return when we are not connected
if (Network.peerType != NetworkPeerType.Server && Network.peerType != NetworkPeerType.Client)
return;
//Create a cube every tenth of a second
cubeTimer -= Time.deltaTime;
while (cubeTimer <= 0)
{
cubeTimer += 0.1f;
Network.Instantiate(Resources.Load("NetworkCube"), new Vector3(Random.Range(-5f, 5f), Random.Range(-5f, 5f), 0), Quaternion.identity, 0);
}
}
private void OnGUI()
{
//Connect/disconnect GUI
if (Network.peerType != NetworkPeerType.Disconnected)
{
if (Network.isServer)
{
GUI.Box(new Rect(50, 50, 120, 30), "Playing as server");
if (GUI.Button(new Rect(180, 50, 120, 30), "Disconnect"))
Disconnect();
}
else if (Network.isClient)
{
GUI.Box(new Rect(50, 50, 120, 30), "Playing as client");
if (GUI.Button(new Rect(180, 50, 120, 30), "Disconnect"))
Disconnect();
}
}
else
{
if (GUI.Button(new Rect(50, 50, 120, 30), "Start as server"))
Network.InitializeServer(32, 2302, false);
else if (GUI.Button(new Rect(180, 50, 120, 30), "Start as client"))
Network.Connect("127.0.0.1", 2302);
}
}
private void OnServerInitialized()
{
//Force clients to load the following level upon connecting
networkView.RPC("ClientLoadLevel", RPCMode.OthersBuffered);
Application.LoadLevel(1);
}
private void OnPlayerDisconnected(NetworkPlayer player)
{
//When a player disconnects, destroy his objects
Network.RemoveRPCs(player, 0);
Network.DestroyPlayerObjects(player);
}
private void OnDisconnectedFromServer()
{
//Return to the menu on disconnect
if (Application.loadedLevel != 0)
Application.LoadLevel(0);
}
[RPC]
private void ClientLoadLevel()
{
//Stop the message queue and load the game level
Network.isMessageQueueRunning = false;
Network.SetLevelPrefix(1);
Application.LoadLevel(1);
}
private void OnLevelWasLoaded(int level)
{
//Resume the message queue upon loading the game scene
Network.isMessageQueueRunning = true;
}
internal static void Disconnect()
{
//Disconnect from the server
Network.Disconnect();
//Return to the menu if neccesairy
if (Application.loadedLevel != 0)
Application.LoadLevel(0);
}
}
And cube:
using UnityEngine;
public class NetworkCube : MonoBehaviour
{
private Vector3 orbitPoint;
private float angle;
private float lifeTime = 1f;
private void Start()
{
if (networkView.isMine)
{
orbitPoint = transform.position;
angle = Random.Range(60f, 120f);
transform.Translate(0, 1, 0);
//Set the color to red to mark this as an invalid object
renderer.material.color = Color.green;
}
else
{
//Set the color to red to mark this as an invalid object
renderer.material.color = Color.red;
}
}
private void Update()
{
if (networkView.isMine)
{
//Rotate the cube around a point
transform.position = orbitPoint;
transform.Rotate(0, 0, -angle * Time.deltaTime);
transform.Translate(0, 1, 0);
//Destroy after one second
lifeTime -= Time.deltaTime;
if (lifeTime <= 0)
NetworkDestroy();
}
}
private void NetworkDestroy()
{
//Remove RPC calls related to this object
Network.RemoveRPCs(networkView.viewID);
//Destroy this object over network
Network.Destroy(networkView.viewID);
}
private void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
if (stream.isWriting)
{
//Set the color to green once the owner of this cube has started streaming/receiving
//Cubes that are not owned by anyone will not turn green
renderer.material.color = Color.green;
//Stream the cube position/rotation
Vector3 position = transform.position;
Quaternion rotation = transform.rotation;
stream.Serialize(ref position);
stream.Serialize(ref rotation);
}
else
{
//Set the color to green once the owner of this cube has started streaming/receiving
//Cubes that are not owned by anyone will not turn green
renderer.material.color = Color.green;
//Receive the cube position/rotation
Vector3 position = transform.position;
Quaternion rotation = transform.rotation;
stream.Serialize(ref position);
stream.Serialize(ref rotation);
transform.position = position;
transform.rotation = rotation;
}
}
}
Kind regards, Romenski
Your answer
Follow this Question
Related Questions
Set unity process as server and client? 0 Answers
How can I delete or destroy an instance of an object IN A MULTIPLAYER GAME?. 2 Answers
Network Game - all players respond to same input 0 Answers
How to apply damage to raycast hitten object's Networkview? 2 Answers
Player not deleting on server exit 1 Answer