#GameObject/Prefab becomes null when passed into a [Command]

18 messages · Page 1 of 1 (latest)

alpine crag
#

Hi, I am creating an RTS, and the BuildingPlacer script gets created as a player in Mirror for every client.
But, executing a Command called private void CmdPlaceBuilding(GameObject building, Vector3 position), the GameObject becomes null, even though it is not null before passing it. Can someone help me?

using UnityEngine;
using Mirror;
using UnityEngine.InputSystem;
using UnityEngine.UI;


public class BuildingPlacement : NetworkBehaviour
{
    [Header("Building options")]
    public Building[] buildingPrefabs;
    private Building currentBuilding;
    private bool isClickPressed = false;
    public Button buildingButton;
    public string buildingButtonContainer;
    [Header("Placement options")]
    public LayerMask groundLayer;
    private Vector3 hitPoint;

    private void Start()
    {
        currentBuilding = buildingPrefabs[0];
        foreach (Building building in buildingPrefabs)
        {
            GenerateButton(building);
        }
    }

    void Update()
    {

        if (isLocalPlayer)
        {
            Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
            RaycastHit hit;

            if (Physics.Raycast(ray, out hit, Mathf.Infinity, groundLayer))
            {
                if (isClickPressed)
                {
                    Debug.Log(hit.point);
                    hitPoint = hit.point;
                    //CmdPlaceBuilding(hit.point);
                }
            }
        }
    }

    [Command]
    private void CmdPlaceBuilding(GameObject building, Vector3 position)
    {
        Debug.Log(building);
        GameObject buildingInstance = Instantiate(building, position, Quaternion.identity);
        NetworkServer.Spawn(buildingInstance);
        RpcOnPlaceBuilding();
    }

    [ClientRpc]
    private void RpcOnPlaceBuilding()
    {
        //Debug.Log("Called on client!");
    }

    private void GenerateButton(Building building)
    {
        Button newButton = Instantiate(buildingButton, GameObject.Find(buildingButtonContainer).transform);
        newButton.transform.Find("Icon").GetComponent<Image>().sprite = building.icon;
        newButton.transform.Find("Data").transform.Find("Name").GetComponent<TMPro.TextMeshProUGUI>().text = building.displayName;

        Debug.Log(building.prefab);
        newButton.onClick.AddListener(() => CmdPlaceBuilding(building.prefab, hitPoint));
    }

    public void OnClick(InputAction.CallbackContext context)
    {
        isClickPressed = context.ReadValueAsButton();
    }
}
frosty timber
#

Public GameObject[] buildingObjects;

Cmd( buildingNumber );

Instantiate( buildingObjects[ buildingNumber] );

#

No need to send whole objects (you can only do this for pre-spawned networked objects), send an id of which to choose from a list/array

#

@alpine crag

alpine crag
#

would that buildingNumber synchronize?

#

I added private int i = 0;
Modified Start: private void Start() { currentBuilding = buildingPrefabs[0]; foreach (Building building in buildingPrefabs) { buildingObjects[i] = building.prefab; GenerateButton(building); Debug.Log(i); i++; } }
CmdPlaceBuilding: ```
[Command]
private void CmdPlaceBuilding(int buildingNumber, Vector3 position)
{
//Debug.Log(buildingObjects[buildingNumber]);
GameObject buildingInstance = Instantiate(buildingObjects[buildingNumber], position, Quaternion.identity);
NetworkServer.Spawn(buildingInstance);
RpcOnPlaceBuilding();
}

And

private void GenerateButton(Building building)
{
Button newButton = Instantiate(buildingButton, GameObject.Find(buildingButtonContainer).transform);
newButton.transform.Find("Icon").GetComponent<Image>().sprite = building.icon;
newButton.transform.Find("Data").transform.Find("Name").GetComponent<TMPro.TextMeshProUGUI>().text = building.displayName;

    //Debug.Log(building.prefab);

    newButton.onClick.AddListener(() => CmdPlaceBuilding(i, hitPoint));
}
And I still get ```Disconnecting connId=0 to prevent exploits from an Exception in MessageHandler: IndexOutOfRangeException Index was outside the bounds of the array.
  at BuildingPlacement.UserCode_CmdPlaceBuilding__Int32__Vector3 (System.Int32 buildingNumber, UnityEngine.Vector3 position) [0x00000] in /Users/kyandesutter/development/ocean-game/Assets/Code/Scripts/Core/BuildingPlacement.cs:57 ```
#

This is my full code ```using UnityEngine;
using Mirror;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class BuildingPlacement : NetworkBehaviour
{
[Header("Building options")]
public Building[] buildingPrefabs;
private Building currentBuilding;
private bool isClickPressed = false;
public Button buildingButton;
public string buildingButtonContainer;
[Header("Placement options")]
public LayerMask groundLayer;
private Vector3 hitPoint;
public GameObject[] buildingObjects;
private int i = 0;

private void Start()
{
    currentBuilding = buildingPrefabs[0];
    foreach (Building building in buildingPrefabs)
    {
        buildingObjects[i] = building.prefab;
        GenerateButton(building);
        Debug.Log(i);
        i++;
    }
}

void Update()
{

    if (isLocalPlayer)
    {
        Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit, Mathf.Infinity, groundLayer))
        {
            if (isClickPressed)
            {
                Debug.Log(hit.point);
                hitPoint = hit.point;
                //CmdPlaceBuilding(hit.point);
            }
        }
    }
}

[Command]
private void CmdPlaceBuilding(int buildingNumber, Vector3 position)
{
    //Debug.Log(buildingObjects[buildingNumber]);
    GameObject buildingInstance = Instantiate(buildingObjects[buildingNumber], position, Quaternion.identity);
    NetworkServer.Spawn(buildingInstance);
    RpcOnPlaceBuilding();
}

[ClientRpc]
private void RpcOnPlaceBuilding()
{
    //Debug.Log("Called on client!");
}

private void GenerateButton(Building building)
{
    Button newButton = Instantiate(buildingButton, GameObject.Find(buildingButtonContainer).transform);
    newButton.transform.Find("Icon").GetComponent<Image>().sprite = building.icon;
    newButton.transform.Find("Data").transform.Find("Name").GetComponent<TMPro.TextMeshProUGUI>().text = building.displayName;

    //Debug.Log(building.prefab);

    newButton.onClick.AddListener(() => CmdPlaceBuilding(i, hitPoint));
}

public void OnClick(InputAction.CallbackContext context)
{
    isClickPressed = context.ReadValueAsButton();
}

}

alpine crag
#

can anyone help?

hard flax
#

hard

alpine crag
tranquil stone
#

Hi, Did you get an error at this line NetworkServer.Spawn(buildingInstance); ?

#

if its the case maybe you have to had your prefab building to the network manager array registered spawnable prefab

alpine crag
#

it spawned perfectly until I introduced buttons that spawn different buildings

#

before it just was buildingPrefabs[0]

tranquil stone
#

can you log buildingObjects count in CmdPlaceBuilding

#

And buildingObjects[i] = building.prefab; building.prefab is a gameObject ?

#

did u assign the gameObject in prefab ?