(Unet) Issue with Sending a TargetRPC
Hello,
i have a problem sending data from my Server to Clients. This should happen: On Start the Server generates positions and stores them in a position storage. After this happened, the Server generates Cubes at the generated positions.
When a client connects to the Server, it is supposed to fetch the position Info and also generate Cubes at this position. However the data transferred from my server to my client by a targetRPC is null, and i cannot understand what i am doing wrong.
This is the code:
private PositionStorage positionStorage;
private int[,] positionInfo;
void Start()
{
positionStorage = GameObject.Find("PositionContainer").GetComponent<PositionStorage>();
if (isServer)
{
positionStorage.GeneratePositions();
positionInfo = positionStorage.GetPositionInfo();
positionStorage.GenerateCubesAtPosition(positionInfo);
}
else
{
CmdGetPositionInfo();
}
}
[Command]
void CmdGetPositionInfo()
{
TargetSendPositionToClient(connectionToClient, positionInfo);
}
[TargetRpc]
public void TargetSendPositionToClient(NetworkConnection target, int[,] info)
{
positionStorage.GenerateCubesAtPosition(info);
}
Am i doing a fundemental mistake somewhere? Thanks for your help!
I believe TargetRPC only accepts certain parameters, e.g. "array of basic types". Your int[,] however, is an array of integer arrays, which is not a basic type. Thus, the reference is lost on the client and it becomes null.
Thanks for your answer. Do you know how i can send information from array over the network?
Well, you could flatten your 2D-Array into a 1D-Array, if all your arrays-within-the-array are of the same length. If you pass the length of the sub arrays, then you can rebuild a 2D array. Something like this (not tested):
int[] flatArray (int[,] input)
{
int[] flatArray = new int[input.GetLength (0) * input.GetLength (1)]; //likely IndexOutOfArrayException if array length differs
for (int i = 0; i < input.GetLength (0); i++) {
for (int j = 0; j < input.GetLength (1); j++) {
flatArray [i * input.GetLength (0) + j] = input [i, j];
}
}
return flatArray;
}
int[,] to2DArray(int[] input, int subArrayLength){
int[,] inflateArray = new int[input.Length / subArrayLength, subArrayLength];
for (int i = 0; i < inflateArray.GetLength (0); i++) {
for (int j = 0; j < inflateArray.GetLength (1); j++) {
inflateArray [i,j] = input [i * inflateArray.GetLength (0) + j];
}
}
}
I am guessing that you have that object A in which you assign positionInfo (only if isServer). If you have a host and a client, you have three copies of A. Now the positionInfo has been set on object A on the server. A_server has that info.
Now you are sending a Command (most likely from a player object, as that's what commands are for). That command is executed on the server but in the client object on the server. That object does not have the positionInfo - remember, you only set that on the serverObject, not in the playerObject on the server. ;) That's why positionInfo is now null.
If you reveal more of your code, maybe we can figure something out.
Thanks for that explanation, i understand the issue now. There is not more code pretty much. Ins$$anonymous$$d of generating an array i just tried it with an array filled with ones, i recieve zeros.
Is there a way to get the "correct" server object? I mean the client object that sits on the server
Here is an example of what does not work:
private int[] testArray = new int[2];
void Start(){
if(isServer){
testArray[0] = 1;
testArray[1] = 1;
}
else {
CmdTestCommand();
}
[Command]
void CmdTestCommand(){
Debug.Log(testArray[0] + " " + testArray[1]);
}
What kind of data does PositionStorage store?
$$anonymous$$aybe you can convert PositionStorage in a struct ins$$anonymous$$d of a class. Then, you can use a SyncListStruct. You can add to it on the server and it automatically syncs to the client. https://docs.unity3d.com/ScriptReference/Networking.SyncListStruct_1.html
Edit: It might also work to make a SyncListStruct of int array. Then, you can reuse your 2D-Array [,] info
by putting every sub-array into the list.
Answer by Chikari · Feb 13, 2017 at 07:20 PM
This might be a way to sync your info to the client:
private PositionStorage positionStorage;
private int[,] positionInfo;
private SyncListStruct<int[]> positionList;
void Start()
{
positionList = new SyncListStruct<int[]> ();
positionList.Callback = processPositions;
positionStorage = GameObject.Find("PositionContainer").GetComponent<PositionStorage>();
if (isServer)
{
positionStorage.GeneratePositions();
positionInfo = positionStorage.GetPositionInfo();
positionStorage.GenerateCubesAtPosition(positionInfo);
for (int i = 0; i < positionInfo.GetLength (0); i++) {
positionList.Add (positionInfo [i]);
}
}
}
void processPositions(SyncListStruct<int[]>.Operation op, int item)
{
//this is called on the client when positionList updates
}
Thanks for that but thats sadly not what i need for my issue i think.
I have managed to isolate my problem now. This is the simplest code i could write that still does not work:
using UnityEngine;
using UnityEngine.Networking;
public class TestClass : NetworkBehaviour {
int x;
void Start()
{
if (isServer)
{
x = 1;
Debug.Log("x value: " + x); // x = 1
}
else
{
CmdTestCommand();
}
}
[Command]
void CmdTestCommand()
{
Debug.Log("x value: " + x); // x = 0
}
}
Is there no way to access the correct object when using [Command]?