OnStartClient() vs OnStartAuthority()

When setting up the Unit storing for the player only, the way it’s implemented in the course is by using

OnStartClient()

and then checking if we have authority.

Wouldn’t it also work - and be easier - to just use

OnStartAuthority()

directly? Since it’s the same, but only called if we have authority, we wouldn’t have to worry about checking via an if statement, whether or not we have authority.

Or am I missing something here?

So after experimenting a bit, I’ve noticed that there’s a difference, but I’m not entirely sure what the difference is.

So on the course the code used, is:

public override void OnStartClient() {
    if (!isClientOnly || !hasAuthority) { return; }
    AuthorityOnUnitSpawned?.Invoke(this);
}

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

What I tried is doing the exact same, just using OnStartAuthority(), to only have to do one if Statement, rather than checking for authority too.

public override void OnStartAuthority() {
    if (!isClientOnly) { return; }

    AuthorityOnUnitSpawned?.Invoke(this);
}


public override void OnStopAuthority() {
    if (!isClientOnly) { return; }
    AuthorityOnUnitDespawned?.Invoke(this);
} 

While this worked the same as the code from the lecture, this also resulted in the list only being updated on the Server/Host side, and never on the side of a client that just joined the server.
Removing the if statement would however cause duplicates to appear.
Now I’m confused over the “isClientOnly” bool, or rather why it’s apparently false for both the unit on the client, as well as the unit on the host/server.

With experimenting a bit, I figured out that replacing the “!isClientOnly” with “isServer” would result in the same behaviour as in the lecture.

public override void OnStartAuthority() {
    if (isServer) { return; }

    AuthorityOnUnitSpawned?.Invoke(this);
}


public override void OnStopAuthority() {
    if (isServer) { return; }
    AuthorityOnUnitDespawned?.Invoke(this);
}

So while it works, I’m not sure why it works, or rather what the difference is.
Basically why does checking “isClientOnly” work if we’re starting in the OnStartClient method, but not when starting in the OnStartAuthority method?
Also the exact difference between isClientOnly, isClient, isServer and isServerOnly.

Cause while I’m happy I got it to work, it would help if I understood why it’s working with the changes I made, and didn’t work before, as that would make tracking down issues easier for me in the future.

2 Likes

Hi there, glad you are working through each of these and learning more about them. I think what a lot of people miss when asking about these statements, is that the Server has authority over all of the clients by default. So you need to think about who has authority when using authority statements.

Otherwise, I believe isClientOnly, isClient, isServer and isServerOnly would work as you expect. In our game, no one isServerOnly. The server is a server and a client and the clients are clients and isClientOnly.

We use a lot of “!” and return statements, so it’s also important to follow the logic. For example:

public override void OnStartClient() {
    if (!isClientOnly || !hasAuthority) { return; }
    AuthorityOnUnitSpawned?.Invoke(this);
}

OnStartClient() limits this code to clients and not servers. Then we have an if statement with an or inside.
!isClientOnly excludes the server which is not only a client.
!hasAuthority excludes clients who aren’t the authority, for example the instance of other client’s units on your client. This would not exclude the server’s units because they have authority. The server has authority by default.
This leaves only the units on your client who are owned by that client.

Hope this helps!

Right.

But what confused me, was that it also excluded the client. Checking the same bool, in the same way, had two different behaviours, depending on whether I did so in
OnStartClient, or OnStartAuthority.

When on paper, OnStartAuthority would exclude the clients that don’t have authority, so you could just check if it’s the server or not, by checking if it’s a clientOnly.

Like…on paper “isClientOnly” should always be the opposite of “isServer”.
Because if it’s a server, it’s either a client and a server (in the case of a host), or only a server. So if isServer is true, I’d expect isClientOnly to always be false in the same instance.

So checking “! isClientOnly” should always give the same result as “isServer”, at least from what I understand. But that wasn’t the case. So what am I missing here?

I’m not sure about the first part, for OnStartClient() !isClientOnly should exclude the server’s client. For OnStartAuthroity(), !isClientOnly should exclude the server’s client also.

The second part you said:

So checking “! isClientOnly” should always give the same result as “isServer”, at least from what I understand. But that wasn’t the case. So what am I missing here?

After thinking this through I can see one edge case missing. The server’s client is not included in the isServer logic. The server’s client does not include the server it’s just running on the same hardware as it. So while !isClientOnly excludes the server’s client, isServer would not exclude the server’s client. (I think…)

Okay, adding this in case someone else is wondering the same thing as me.

A later lecture actually brings up one of those things, more specifically why the “isClientOnly” check doesn’t work in OnStartAuthority
According to that lecture OnStartAuthority is called much earlier than OnStartClient, and is called before the “isClientOnly” bool is set correctly.

Which explains why it was still set to false in my case, even on an instance that was the client only

2 Likes

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

Privacy & Terms