I’ve been wracking my brain trying to figure this out.
I am creating a board game where each player object must be able to spawn board pieces with local client authority. I’m trying to use NetworkServer.SpawnWithClientAuthority() to handle this. I have created a [command] for spawning such objects.
[Command] void CmdLoadUnit(string prefabName)
{
prefab = Resources.Load<GameObject>("Units/" + prefabName);
prefab = Instantiate(prefab, prefab.transform.position, prefab.transform.rotation) as GameObject;
NetworkServer.SpawnWithClientAuthority(prefab, connectionToClient);
}
I am trying to test this out by spawning a single unit per player, all sharing a single prefab, at the start of the game. After spawning I want to pass a reference of the unit object to a script attached to the player object, the player who has authority. I look for this player in the Start() function on a script attached to the unit object.
public void Start()
{
foreach (GameObject player in GameObject.FindGameObjectsWithTag("Player"))
{
PlayerUnitManager playerUnitScript = player.GetComponent<PlayerUnitManager>();
if (playerUnitScript.hasAuthority && playerUnitScript.isLocalPlayer)
{
Debug.Log("Authority Here");
playerUnitScript.SendUnit(this, out tileIndex1, out tileIndex2);
}
}
Init();
}
The Debug.Log statement is printing on every client, a number of times equal to the number of player objects in the game! How can this be? I expect it to print exactly once per client, only for the player object which is the local player and has authority over exactly one unit object.
This is only the first of many problems I’m having just trying to set up the most basic of multiplayer functions for my game idea. I’m starting to feel like I should just give up. The documentation on spawning non-player objects with local authority is so sparse. I just can’t get anything to work.
I can’t add a comment for some reason. Here’s the script.
using UnityEngine;
using UnityEngine.Networking;
using System.Collections.Generic;
public class PlayerUnitManager : NetworkBehaviour
{
List<Unit> unitsOnBoard = new List<Unit>();
TurnManager turn;
Board board;
public Unit CurrentUnit { get; private set; }
bool allUnitsMoved = false;
Tile spawnTile;
GameObject prefab;
// Use this for initialization
void Start()
{
if (!isLocalPlayer) return;
turn = GameObject.Find("HUDCanvas/TurnStatus").GetComponent<TurnManager>();
board = GameObject.Find("Board").GetComponent<Board>();
TurnManager.RegisterStartAttack(ResetUnits);
TurnManager.RegisterStartAttack(StartAttackPhase);
TurnManager.RegisterStartMove(ResetUnits);
TurnManager.RegisterStartMove(StartMovePhase);
spawnTile = board.GetTile((int)Random.Range(0, 10), (int)Random.Range(0, 10));
CmdLoadUnit("CubeHero");
//turn.InitGame();
}
void Update()
{
if (!isLocalPlayer) return;
switch (turn.state)
{
case TurnManager.TurnState.Move:
if (CurrentUnit != null) { if (CurrentUnit.Moved) FocusNextUnit(); }
else { turn.EndPhase(); }
break;
case TurnManager.TurnState.Attack:
break;
}
}
void Init()
{
}
[Command] void CmdLoadUnit(string prefabName)
{
prefab = Resources.Load<GameObject>("Units/" + prefabName);
prefab = Instantiate(prefab, prefab.transform.position, prefab.transform.rotation) as GameObject;
NetworkServer.SpawnWithClientAuthority(prefab, connectionToClient);
}
void StartMovePhase()
{
allUnitsMoved = false;
FocusNextUnit();
}
void StartAttackPhase()
{
}
void FocusNextUnit()
{
CurrentUnit = FirstUnitNotMoved();
if (CurrentUnit != null)
{
board.FocusCameraToTile(board.GetTile(CurrentUnit.tileIndex1, CurrentUnit.tileIndex2));
CurrentUnit.Selected = true;
}
else
{
allUnitsMoved = true;
}
}
Unit FirstUnitNotMoved()
{
foreach (Unit unit in unitsOnBoard) { if (!unit.Moved) return unit; }
return null;
}
void ResetUnits()
{
foreach (Unit unit in unitsOnBoard)
{
unit.Moved = false;
unit.Attacked = false;
unit.Selected = false;
}
}
public void SendUnit(Unit unit, out int i1, out int i2)
{
unitsOnBoard.Add(unit);
i1 = spawnTile.Index1;
i2 = spawnTile.Index2;
unit.SetTileVision();
}
}
I’m also getting a NRE at line 107 (on the client side only), which suggests to me that the spawnTile variable is never initialized because isLocalPlayer is false. This is as it should be, but when I check isLocalPlayer from the unit script it is true for some reason even on the host, and the SendUnit() function gets called for the client’s cubehero object. That would trigger the NRE. I just don’t know why it would get called. I can’t find my error.