Resources generator works only for the host

Hi,

For some reason, the resources generator is working only for the host. When the client places the building with the resource generator class, it cannot find the RTS player to call the method to add the resources. Everything else is working; the client can place buildings, create units, and move them; the only thing is the resource generator. I copied the script:

‘’’
public class CrystalGenerator : NetworkBehaviour

{

[SerializeField] Health health = null;

[SerializeField] int crystalPerInterval = 10;

[SerializeField] float interval = 2f;

[SerializeField] RTSPlayer player;

float timer;

   

public override void OnStartServer()

{

    timer = interval;

    player = connectionToClient.identity.GetComponent<RTSPlayer>();

    print(player);

    health.ServerOnDie += ServerHandleDie;

    GameOverHandle.ServerOnGameOver += ServerHandleGameOver;

}

public override void OnStopServer()

{

    health.ServerOnDie -= ServerHandleDie;

    GameOverHandle.ServerOnGameOver -= ServerHandleGameOver;

}

[ServerCallback]

void Update()

{

    if(!hasAuthority) { return;}

   timer -= Time.deltaTime;

   if(timer <=0 && hasAuthority)

   {

   

     player.AddCrystal(player.GetCrystals() + crystalPerInterval);

     timer += interval;

   }

}

void ServerHandleDie()

{

    NetworkServer.Destroy(gameObject);  

}

void ServerHandleGameOver()

{

    enabled = false;

}

}
‘’’

The player = connectionToClient.identity.GetComponent(); is in the start rather than the update, because I’m at the end of course, where we have a working lobby.
Thank you for the help.

The error I get, when I join from Unity, is a NullReferenceException for Player.AddCrystal(), it seems that OnStartServer() I’m not able to get the RTSPlayer component.

OnStartServer is only run on the server/host. It’s not going to run on a client, so a client will never have `player’ set to anything.

Hi,

Thank you for the answer.

I just tried to call it in Start () like

‘’’
void Start()

{

    player = connectionToClient.identity.GetComponent<RTSPlayer>();

}

‘’’

However I get the Null reference :

NullReferenceException: Object reference not set to an instance of an object
CrystalGenerator.Start ()

Try OnStartClient()

I just tried, same issue.

I don’t know if it can help, but when using OnStartClient(), even the host gets the Null reference when trying to get the RTSPlayer component, but this is only on the start() in the update the host is still able to call AddCrystal on the player.

So I think I kind of fixed it. What I did was to us OnStartClient() as you suggested, then I used a SerializeField to check if both host and client had the player reference, and once I noticed that both of them had it, I removed the hasAuthority checks from the update, and it works. I still get the null reference on the start(), but both client and host generate crystals now. I wonder what causes the null reference on the Start(). This is the script if someone has the same issue.

‘’’
public class CrystalGenerator : NetworkBehaviour

{

[SerializeField] Health health = null;

[SerializeField] int crystalPerInterval = 10;

[SerializeField] float interval = 2f;

[SerializeField] RTSPlayer player;

float timer;

public override void OnStartClient()

{

    timer = interval;

    player = connectionToClient.identity.GetComponent<RTSPlayer>();

    health.ServerOnDie += ServerHandleDie;

    GameOverHandle.ServerOnGameOver += ServerHandleGameOver;

}

public override void OnStopServer()

{

    health.ServerOnDie -= ServerHandleDie;

    GameOverHandle.ServerOnGameOver -= ServerHandleGameOver;

}

public override void OnStopClient()

{

         health.ServerOnDie -= ServerHandleDie;

         GameOverHandle.ServerOnGameOver -= ServerHandleGameOver;

}

[ServerCallback]

void Update()

{



    // if (!isOwned) { return;}

   timer -= Time.deltaTime;

   if(timer <=0) //isOwned)

   {

   

     player.AddCrystal(player.GetCrystals() + crystalPerInterval);

     timer += interval;

   }

}

void ServerHandleDie()

{

    NetworkServer.Destroy(gameObject);  

}

void ServerHandleGameOver()

{

    enabled = false;

}

}

‘’’

The other thing I want to check, I’m unsubscribing from the two events both in OnStopServer() and in OnStopClient(), because OnStopServer() works only for the server and host, is this correct or should I unsubscribe only in one of them?

Afaik, you shouldn’t use Start and Awake in network behaviours. The stuff that would usually go in there will need to move to OnStartClient and OnStartServer etc. I believe this is because those are called by Unity before the network behaviour has had time to set itself up. That’s why we use the OnStart... callbacks. They get executed once the network behaviour has completed its own setup.

This is fine. Only one of those callbacks will be executed anyway and even if both get executed, only one of them will unsubscribe. The other one will find that the handlers aren’t there anymore and just do nothing. It won’t break anything

1 Like

I see, the Null reference comes up with OnStartClient() as well, it looks like only for that frame the the Crystal generator cannot access to the RTSPlayer, but in the frame after it is able to access to it and it works without problems, at least with only two players. I will keep testing and if it breaks the game I will open a new topic. Thank you very much for the help.

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

Privacy & Terms