After quit some research on multiplayer network gaming I concluded U net is the most painless way to integrate such a multi play system and avoid NAT punching problems. However, I encounter some problems when trying to get the data synced to all clients, due to authority problems I guess.
I’m currently building some sort of chat test and want to make use of syncvar and hook. Since I found this is easier than using the command and clientRPC.
My setup in unity is as follow:
I have two scenes:
UNET_menu
Contains a gameobject with a NetworkManager and networkHUD component added
UNET_game
Contains 2 buttons (send data and erase data) and a text UI component to show the send messages
Those two scenes are added to the NetworkManager online and offline reference.
I have made a prefab called communicationPlug which hold a custom script called NetworkPlug.cs and added a NetworkIdentity component with local player authority set true. This prefab is then added to the NetworkManager component in the UNET_menu scene to spawn on all clients.
When I run the scene and set up a host and client, only the messages from the host sync to all clients pressing on the data send button. When I do the same on the client nothing syncs. So I have no idea what I’m doing wrong.
I found a way to make the setup work. By changing the code as follow:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class NetworkPlug : NetworkBehaviour {
private Button btnSend, btnErase;
private Text txt;
[SyncVar (hook = "OnIncommingData")]
private string data;
private void Awake()
{
txt = GameObject.FindWithTag ("messageField").GetComponent<Text> ();
btnSend = GameObject.FindWithTag("btnSend").GetComponent<Button>();
btnErase = GameObject.FindWithTag("btnErased").GetComponent<Button>();
}
private void Start()
{
btnSend.onClick.AddListener(() => CmdSend("Send clicked!"));
btnErase.onClick.AddListener(() => CmdSend("Erased"));
}
//COMMAND TO SERVER OBJECT
[Command]
private void CmdSend(string data)
{
//if (!isServer)
// return;
this.data = data;
}
//RPC RECEIVE FROM SERVER
private void OnIncommingData(string data)
{
this.data = data;
txt.text = this.data;
}
}
I only get this warning in Unity in the console when clicking on the button of the client side. The host side doesn’t give this warning.
Trying to send command for object without authority.
UnityEngine.Networking.NetworkBehaviour:SendCommandInternal(NetworkWriter, Int32, String)
NetworkPlug:CallCmdSend(String)
NetworkPlug:m__0() (at Assets/UNET_CONNECTIE/NetworkPlug.cs:24)
UnityEngine.EventSystems.EventSystem:Update()
I don’t understand why there is no authority? The script is running on the spawned GameObject which contains a NetworkIdentity and set to local player authority. I also wonder why the code of my first post doesn’t work with the syncvar only.
To make things clear I added a package of the working test. (Add the two scenes to build settings and in player settings set “play in background” to true for testing in unity in conjunction with a build .exe
The command method is located in the NetworkPlug.cs script which is added on the playerPrefab named communicationPlug. Then the code searches for the buttons and add the click events to call the command.
So it shouldn’t showing that warning message in my oppinion?
This is how I think it works:
When you have three instances of the project running (A, B, C) and you click on the button of A, A calls the command function and adjusts it’s brother A (sA) on the server. Then the sA sends out a RPC notification to B and C but not A, to let them know that their local instance of bA has changed.
Just to come back on my first syncvar problem post and finalize this topic, this is how I understand it:
(correct me if I’m wrong)
In my first post I used a sync var with a hook attached to it. What I now understand from the documentation is that a syncvar exists on the server, and when called, it’s updating all his clones on the other clients. So I needed to use the command attribute from my localclient to access the syncvar on the server and tell it has changed in order to push the changes through to the clones using the hooked function.
First I thought the syncvar existed on the client only and when I changed the value, it automatically updated to all the clones. So in short, you have to use an command to update a syncvar
[SyncVar (hook = "OnReceive")]
private string data;
//Update syncvar on server
[Command]
private void CmdSend(string data)
{
this.data = data;
}
//Call of hooked funtion on clone clients (rpc)
private void OnReceive(string data)
{
this.data = data;
}
}