Hello guys.
I faced same problem with this issue. I cannot find good answer.
connectionToClient of ServerHandleUnitSpawned always return null so unit color does not change on minimap.
Below is my RTSPlayer code.
using System;
using System.Collections;
using System.Collections.Generic;
using Mirror;
using UnityEngine;
public class RTSPlayer : NetworkBehaviour
{
[SerializeField] private LayerMask buildingBlockLayer;
[SerializeField] private float buildingLimit = 5f;
[SerializeField] private Building[] buildings = new Building[0];
[SerializeField] private Color teamColor;
[SyncVar(hook = nameof(ClientHandleResourcesUpdated))]
private int resources = 500;
private List<Unit> unitList = new List<Unit>();
private List<Building> buildingList = new List<Building>();
public event Action<int> ClientOnResourcesUpdated;
public List<Unit> GetMyUnits()
{
return unitList;
}
public List<Building> GetMyBuilding()
{
return buildingList;
}
public int GetResources()
{
return resources;
}
public Color GetColor()
{
return teamColor;
}
public bool CanPlaceBuilding(BoxCollider buildingCollider, Vector3 position)
{
if (Physics.CheckBox(
position + buildingCollider.center,
buildingCollider.size / 2,
Quaternion.identity,
buildingBlockLayer))
{
return false;
}
foreach (var building in buildingList)
{
if ((position - building.transform.position).sqrMagnitude
<= buildingLimit * buildingLimit)
{
return true;
}
}
return false;
}
#region Server
public override void OnStartServer()
{
Unit.ServerOnUnitSpawned += ServerHandleUnitSpawned;
Unit.ServerOnUnitDespawned += ServerHandleUnitDespawned;
Building.ServerOnBuildingSpawned += ServerHandleBuildingSpawned;
Building.ServerOnBuildingDespawned += ServerHandleBuildingDespawned;
}
public override void OnStopServer()
{
Unit.ServerOnUnitSpawned -= ServerHandleUnitSpawned;
Unit.ServerOnUnitDespawned -= ServerHandleUnitDespawned;
Building.ServerOnBuildingSpawned -= ServerHandleBuildingSpawned;
Building.ServerOnBuildingDespawned -= ServerHandleBuildingDespawned;
}
private void ServerHandleUnitSpawned(Unit unit)
{
if (unit.connectionToClient.connectionId != connectionToClient.connectionId)
{
return;
}
unitList.Add(unit);
}
private void ServerHandleUnitDespawned(Unit unit)
{
if (unit.connectionToClient.connectionId != connectionToClient.connectionId)
{
return;
}
unitList.Remove(unit);
}
private void ServerHandleBuildingSpawned(Building building)
{
if (building.connectionToClient.connectionId != connectionToClient.connectionId)
{
return;
}
buildingList.Add(building);
}
private void ServerHandleBuildingDespawned(Building building)
{
if (building.connectionToClient.connectionId != connectionToClient.connectionId)
{
return;
}
buildingList.Remove(building);
}
[Command]
public void CmdTryPlaceBuilding(int id, Vector3 position)
{
Building buildingToPlace = null;
foreach (var building in buildings)
{
if (building.GetId() == id)
{
buildingToPlace = building;
break;
}
}
if (buildingToPlace == null)
{
return;
}
if (resources < buildingToPlace.GetPrice())
{
return;
}
BoxCollider buildingCollider = buildingToPlace.GetComponent<BoxCollider>();
if (!CanPlaceBuilding(buildingCollider, position))
{
return;
}
GameObject buildingInstance =
Instantiate(buildingToPlace.gameObject, position, buildingToPlace.transform.rotation);
NetworkServer.Spawn(buildingInstance, connectionToClient);
SetResources(resources - buildingToPlace.GetPrice());
}
[Server]
public void SetResources(int resources)
{
this.resources = resources;
}
[Server]
public void SetTeamColor(Color teamColor)
{
this.teamColor = teamColor;
}
#endregion
#region Client
public Color GetTeamColor()
{
return teamColor;
}
public override void OnStartAuthority()
{
if (NetworkServer.active)
{
return;
}
Unit.AuthorityOnUnitSpawned += AuthorityHandleUnitSpawned;
Unit.AuthorityOnUnitDespawned += AuthorityHandleUnitDespawned;
Building.AuthorityOnBuildingSpawned += AuthorityHandleBuildingSpawned;
Building.AuthorityOnBuildingDespawned += AuthorityHandleBuildingDespawned;
}
public override void OnStopClient()
{
if (!isClientOnly || !hasAuthority)
{
return;
}
Unit.AuthorityOnUnitSpawned -= AuthorityHandleUnitSpawned;
Unit.AuthorityOnUnitDespawned -= AuthorityHandleUnitDespawned;
}
private void AuthorityHandleUnitSpawned(Unit unit)
{
unitList.Add(unit);
}
private void AuthorityHandleUnitDespawned(Unit unit)
{
unitList.Remove(unit);
}
private void AuthorityHandleBuildingSpawned(Building building)
{
buildingList.Add(building);
}
private void AuthorityHandleBuildingDespawned(Building building)
{
buildingList.Remove(building);
}
private void ClientHandleResourcesUpdated(int oldResources, int newResources)
{
ClientOnResourcesUpdated?.Invoke(newResources);
}
#endregion
}
Below is Unit code.
using System;
using System.Collections;
using System.Collections.Generic;
using Mirror;
using UnityEngine;
using UnityEngine.Events;
public class Unit : NetworkBehaviour
{
[SerializeField] private UnitMovement unitMovement;
[SerializeField] private Targeter targeter;
[SerializeField] private UnityEvent OnSelected;
[SerializeField] private UnityEvent OnDeselected;
[SerializeField] private Health health;
[SerializeField] private int resourceCost = 10;
public static event Action<Unit> ServerOnUnitSpawned;
public static event Action<Unit> ServerOnUnitDespawned;
public static event Action<Unit> AuthorityOnUnitSpawned;
public static event Action<Unit> AuthorityOnUnitDespawned;
public UnitMovement GetUnitMovement()
{
return unitMovement;
}
public int GetResourceCost()
{
return resourceCost;
}
public Targeter GetTargeter()
{
return targeter;
}
#region Server
public override void OnStartServer()
{
ServerOnUnitSpawned?.Invoke(this);
health.ServerOnDie += ServerHandleDie;
}
public override void OnStopServer()
{
ServerOnUnitDespawned?.Invoke(this);
health.ServerOnDie -= ServerHandleDie;
}
[Server]
private void ServerHandleDie()
{
NetworkServer.Destroy(gameObject);
}
#endregion
#region client
// https://edom18.hateblo.jp/entry/2017/05/30/120811
public override void OnStartAuthority()
{
AuthorityOnUnitSpawned?.Invoke(this);
}
public override void OnStopClient()
{
if (!hasAuthority)
{
return;
}
AuthorityOnUnitDespawned?.Invoke(this);
}
[Client]
public void Select()
{
if (!hasAuthority)
{
return;
}
OnSelected?.Invoke();
}
[Client]
public void Deselect()
{
if (!hasAuthority)
{
return;
}
OnDeselected?.Invoke();
}
#endregion
}