Problem with client adding building multiple times

So i followed along and now have a problem where in the editor if im the server, each player will have a building in myBuildings list as intended, but when i run the Client the myBuildings list adds the same building 4 times.

I have tried to go through the code all the way from the point a building is added on the client side list, but can only see that it is called once. Anyone who maybe can help point out my mistake?

Picture of the problem:
image
Only supposed to have a base and resource generator in the list as they are the only 2 buildings the player has.

RTSPlayer client code looks like this.

public override void OnStartAuthority()
    {
        if (NetworkServer.active) { return; }

        Unit.AuthorityOnUnitSpawned += clientHandleUnitSpawned;
        Unit.AuthorityOnUnitDeSpawned += clientHandleUnitDeSpawned;
        Building.AuthorityOnBuildingSpawned += clientHandleBuildingSpawned;
        Building.AuthorityOnBuildingDeSpawned += clientHandleBuildingDeSpawned;
    }

    public override void OnStopClient()
    {
        if (!isClientOnly || !hasAuthority) { return; }

        Unit.AuthorityOnUnitSpawned -= clientHandleUnitSpawned;
        Unit.AuthorityOnUnitDeSpawned -= clientHandleUnitDeSpawned;
        Building.AuthorityOnBuildingSpawned -= clientHandleBuildingSpawned;
        Building.AuthorityOnBuildingDeSpawned -= clientHandleBuildingDeSpawned;
    }

private void clientHandleBuildingSpawned(Building building)
    {
        myBuildings.Add(building);
    }

    private void clientHandleBuildingDeSpawned(Building building)
    {
        myBuildings.Remove(building);
    }

Building Auth call:

public override void OnStartAuthority()
    {
        AuthorityOnBuildingSpawned?.Invoke(this);
    }

    public override void OnStopClient()
    {
        if (!hasAuthority) { return; }
        AuthorityOnBuildingDeSpawned?.Invoke(this);

    }

On the server side everything works as it should.

Hi there, it could be some server code is running on the client. Are you able to post the whole RTSPlayer script including the server side?

Yes ofcause.

using Mirror;
using System;
using System.Collections.Generic;
using UnityEngine;

public class RTSPlayer : NetworkBehaviour
{

    [SerializeField] private Building[] buildings = new Building[0];
    [SerializeField] private LayerMask buildingBlockLayer = new LayerMask();
    [SerializeField] private float buildingRangeLimit = 5f;

    [SyncVar(hook = nameof(clientHandleResourcesChanged))]
    private int resources = 200;


    private Color teamColor = new Color();
    private List<Unit> myUnits = new List<Unit>();
    [SerializeField]
    private List<Building> myBuildings = new List<Building>();
    
    public event Action<int> ClientOnResourcesChanged;
    
    public Color GetTeamColor { get => teamColor; }
    public int GetResources()
    {
        return resources;
    }
    public List<Unit> MyUnits { get => myUnits;}
    public List<Building> MyBuildings { get => myBuildings; }
    

    public bool CanPlaceBuilding(BoxCollider buildingCollider, Vector3 point)
    {
        if (Physics.CheckBox(point + buildingCollider.center, buildingCollider.size / 2, Quaternion.identity, buildingBlockLayer))
        {
            return false;
        }

        foreach (var building in myBuildings)
        {
            if ((point - building.transform.position).sqrMagnitude <= buildingRangeLimit * buildingRangeLimit)
            {
                return true;
            }
        }
        return false;
    }

    #region ServerSide

    [Server]
    public void SetTeamColor(Color newTeamColor)
    {
        teamColor = newTeamColor;
    }

    [Server]
    public void SetResources(int newResources)
    {
        resources = newResources;
    }
    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;
    }

    [Command]
    public void CmdTryPlaceBuilding(int buildingId, Vector3 position)
    {
        Building buildingToPlace = null;

        foreach (var building in buildings)
        {
            if (building.GetId == buildingId) 
            {
                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);

    }

    private void ServerHandleUnitSpawned(Unit unit)
    {
        if(unit.connectionToClient.connectionId != connectionToClient.connectionId) { return; }
        myUnits.Add(unit);
    }
    private void ServerHandleUnitDeSpawned(Unit unit)
    {
        if (unit.connectionToClient.connectionId != connectionToClient.connectionId) { return; }
        myUnits.Remove(unit);
    }

    private void ServerHandleBuildingSpawned(Building building)
    {
        if (building.connectionToClient.connectionId != connectionToClient.connectionId) { return; }
        myBuildings.Add(building);
    }
    private void ServerHandleBuildingDeSpawned(Building building)
    {
        if (building.connectionToClient.connectionId != connectionToClient.connectionId) { return; }
        myBuildings.Remove(building);
    }
    #endregion

    #region ClientSide
    public override void OnStartAuthority()
    {
        if (NetworkServer.active) { return; }

        Unit.AuthorityOnUnitSpawned += clientHandleUnitSpawned;
        Unit.AuthorityOnUnitDeSpawned += clientHandleUnitDeSpawned;
        Building.AuthorityOnBuildingSpawned += clientHandleBuildingSpawned;
        Building.AuthorityOnBuildingDeSpawned += clientHandleBuildingDeSpawned;
    }

    public override void OnStopClient()
    {
        if (!isClientOnly || !hasAuthority) { return; }

        Unit.AuthorityOnUnitSpawned -= clientHandleUnitSpawned;
        Unit.AuthorityOnUnitDeSpawned -= clientHandleUnitDeSpawned;
        Building.AuthorityOnBuildingSpawned -= clientHandleBuildingSpawned;
        Building.AuthorityOnBuildingDeSpawned -= clientHandleBuildingDeSpawned;
    }

    private void clientHandleUnitSpawned(Unit unit)
    {
        myUnits.Add(unit);
    }

    private void clientHandleUnitDeSpawned(Unit unit)
    {
        myUnits.Remove(unit);
    }
    private void clientHandleBuildingSpawned(Building building)
    {
        myBuildings.Add(building);
    }

    private void clientHandleBuildingDeSpawned(Building building)
    {
        myBuildings.Remove(building);
    }

    private void clientHandleResourcesChanged(int oldValue, int newValue)
    {
        ClientOnResourcesChanged?.Invoke(newValue);
    }

    #endregion
}

Hi there, so your code here seems fine.

Can you place some debug.log statements and see if the AuthorityOnBuildingSpawned is being invoked more than once? Try and trace it back to see if something is being called 4 times. Also maybe show your hierarchy from the scene when this happens.

Will do

The hierarchy looks like this
image

and the callback is somehow called 7 times,

They are split in a weird way, and it seems the first one is called from OnStartClient and the next 3 are OnStartAuthority, and the last 3 are also OnStartClient.

I think im going to try reimport Mirror to see if i migt have made a mistake when renaming a method at some point with Ctrl + r + r in VS studio. <<< Fixed my problem, i must have by accident renamed a method all the way back to NetworkBehavior through an overrideded method.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms