So ; i’m here again and facing the same problem , after googling a lot to find a solution , i’m coming back to try to explain much better what’s going wrong :
i’m making a simple app for the place where i work , basically we have to face with covid constraint as we receive people inside a place where we need to stop people coming if there are too many …
For this i have to create an app working on two tablet /phone :one will be at the entry and the other at the exit
in the first tablet , after selecting the entry panel the admin enters a googlesheet id to get a list of users( only firstname and name ) and they have to appear in the scrollview content " player list" , when the person arrives and watches his name he clicks on the button and then it mooves to “present list” scrollview
It has to be synced with the exit tablet as the person will have to click again at the exit and then his name disappear from the present list to return at the playerlist ( i hope i am clearer … ) and once again sorry for my English .
Without networking , it works like a charm !
I copied the unity folder and opened with unityhub both project (original and the copy) when i run as a server the first one and client the second one i can and i import the sheet i can see playerbuttons appear in hierarchy , with the same position, but with no names and not under the parent transform ( the content of the scrollview)
I’m trying to figure out why it doesn’t work but i’m new to networking …
that’s my googledriveimportand spawning script :
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityGoogleDrive;
using UnityGoogleDrive.Data;
using MLAPI.Messaging;
using MLAPI.NetworkVariable;
using MLAPI;
using MLAPI.Spawning;
public class DriveManager : NetworkBehaviour
{
// the id of the googlesheet in google drive
[SerializeField] private string fileId ;
[SerializeField] InputField inputField;
// Prefab of playerbutton
[SerializeField] GameObject playerPrefab;
private GoogleDriveFiles.ExportRequest request;
GameObject playerGo;
[SerializeField] Transform playerList_Scroll_Transform;
//When we click on the validate button for the googlesheet
public void OnClick()
{
SetGoogleSheetId();
GetDataFromDrive();
}
// Methode pour aller chercher une liste sur google drive ( file id indiqué dans les paramètres
private void GetDataFromDrive()
{
Debug.Log("Get Data from Google Drive...");
if (fileId == "") { return; }
request = GoogleDriveFiles.Export(fileId, "text/csv");
request.Send().OnDone += SetResult;
}
// indique une id de google drive et entre l id comme parametre pour aller chercher le bon fichier
public void SetGoogleSheetId()
{
fileId = inputField.text;
}
//Make the list of button with google sheet params and spawn all objects in scene
private void SetResult(File file)
{
if(NetworkManager.Singleton.IsServer || NetworkManager.Singleton.IsHost) {
Debug.Log("GetResult from google Drive , waiting to encode and make prefab ");
// decode et transform le fichier téléchargé en une string
string eleveData = Encoding.UTF8.GetString(file.Content);
// transforme la string copntenant les données en caracteres UTF8 pour séparer les mots
string[] data = eleveData.Split(new char[] { '\n' });
// reads the first name from the first word and name from the second
for (int i = 1; i < data.Length - 1; i++)
{
string[] row = data[i].Split(new char[] { ',' });
//instantiate button on server
playerGo = Instantiate(playerPrefab, playerList_Scroll_Transform);
// set the player variables in player component
Player player = playerGo.GetComponent<Player>();
if (row[0] != "")
{
player.player_FirstName = row[0];
player.player_Name = row[1];
player.heureEntree = System.DateTime.MinValue;
player.heureSortie = System.DateTime.MinValue;
player.playerState = PlayerState.absent;
playerGo.name = "" + player.player_FirstName + player.player_Name;
GameManager.singleton.AddPlayerToList(player);
}
Debug.Log("Getting parentId ");
// Get the parent id of the player object
var transformParentId = playerList_Scroll_Transform.GetComponent<NetworkObject>().NetworkObjectId;
Debug.Log("adding parentId to playerScript ");
//put the parentid to the player component
player.parentNetId.Value = (int) transformParentId;
//Add the text to the button
playerGo.GetComponentInChildren<Text>().text = player.player_FirstName + " " + player.player_Name;
Debug.Log("Spawn network player object ");
//Spawn player network object
playerGo.GetComponent<NetworkObject>().Spawn();
}
}
}
}
And that’s my player’s script :
using MLAPI;
using MLAPI.NetworkVariable;
using UnityEngine;
public enum PlayerState { absent, present, enAttente }
[RequireComponent(typeof(NetworkObject))]
public class Player : NetworkBehaviour
{
//Player state ( presnt or missing or waiting )
public PlayerState playerState = PlayerState.absent;
// players name and surname and hours (at what time does he enter and leave
public string player_FirstName;
public string player_Name;
public System.DateTime heureEntree;
public System.DateTime heureSortie;
// the id of the parent object( the scroll view content )
public NetworkVariableInt parentNetId;
// Method to change playerbutton's list ( from playerlist to presentlist )
public void OnClick()
{
GameManager.singleton.ToggleList(this);
}
private void Start()
{
if (NetworkManager.Singleton.IsClient)
{
// When we are spawned on the client,
// find the parent object using its ID,
// and set it to be our transform's parent.
NetworkObject[] parentObjectArray = FindObjectsOfType<NetworkObject>();
for (int i = 0; i < parentObjectArray.Length; i++)
{
if ((int)parentObjectArray[i].NetworkObjectId == parentNetId.Value)
{
var parentObject = parentObjectArray[i];
transform.SetParent(parentObject.transform);
}
}
}
}
// TO DO implement the player variables over the network ( NOT sure if it can work like this )
//public void SetPlayerStat()
//{
// if (NetworkManager.Singleton.IsServer)
// {
// playerStats.Value = this;
// }
// playerState = playerStats.Value.playerState;
// player_FirstName = playerStats.Value.player_FirstName;
// player_Name = playerStats.Value.player_Name;
// heureEntree = playerStats.Value.heureEntree;
// heureSortie = playerStats.Value.heureSortie;
//}
//public NetworkVariable<Text> playerText = new NetworkVariable<Text>(new NetworkVariableSettings
//{
// WritePermission = NetworkVariablePermission.ServerOnly,
// ReadPermission = NetworkVariablePermission.Everyone
//});
}
in the two pictures you can see from the original that the server doesnt spawn any prefab on the screen
But in the client playerbutton spawn but not within the good parent tranqform
the error in the console say :[MLAPI] Cannot find parent. Parent objects always have to be spawned and replicated BEFORE the child
i don’t know if i have to spawn parent gameobject in the script ( actually i tried and i got an other error ) ; also i put the parent gameObject in the player prefab tab within the networkmanager but it doesn t change …
-
Do i have to put all possible parents transform ( my 2 scrollview contents) in this tab within Networkmanager component ?
-
Is that a simpler way to sync the prefab of a gameobject ?
-
is the fact that my player gameobject is a UIcompoonent (button ) a bad thing ?
Sorry for the long thread but i 'm learning how all these thing work at the same time and i feel i’m almost succeeding…