Download

How is this not an infinite loop?

So I was studying the Shootergame code and was wondering about this:



void AShooterCharacter::SetRunning(bool bNewRunning, bool bToggle){
	bWantsToRun = bNewRunning;
	bWantsToRunToggled = bNewRunning && bToggle;

	if (Role < ROLE_Authority){
		ServerSetRunning(bNewRunning, bToggle);
	}
	UpdateRunSounds(bNewRunning);
}

bool AShooterCharacter::ServerSetRunning_Validate(bool bNewRunning, bool bToggle){
	return true;
}

void AShooterCharacter::ServerSetRunning_Implementation(bool bNewRunning, bool bToggle){
	SetRunning(bNewRunning, bToggle);
}


If ServerSetRunning_Implementation() is called, which calls SetRunning(), which calls ServerSetRunning(), wouldn’t that cause an infinite loop?

Second question:
Is there a Blueprint equivalent to these _Implementation/_Validate functions?

Thank you.

Hello!

I am also studying the shooter code to learn this engine, and already checked this little part of the code and made my guesses:

The thing in this code is that some methods will run only in the server, some others only in the client and the rest in both instances of the game. For the methods that run in both, there’s also a way to control which pieces of code will run only in the client and which in the server.

Said that, from what I can see the first method (SetRunning) will run in both cases, it will be called from several possible places. But there’s the check for the authority, which makes sure that the call will be made only if the code is running from an instance without authority (client). And why the client can call a server’s function? Well, what ServerSetRunning does is not calling ServerSetRunning_Implementation directly; from what I can see, this is a way to call a function of the server’s instance from a client instance.

So let’s imagine a client started running by pressing a key. The SetRunning function will be called (in client); then it will make the authority check and see it’s not an authority, so it will call the ServerSetRunning function. This, internally, will send a network packet and let this client’s execution continue. Then, when the server receives the packet, it will respond by executing the SetRunning function too, but this time since it’s the authority it won’t join the code within the if statement.

Summarizing, the SetRunning function does what its name says, plus when its execution is in a client it notifies the server about that and makes it call the same function.

But as I said, these are only guesses, I’m a newbie in this engine too…

Having done some replication in C++ I can confirm this. If SetRunning is first executed client-side, then because it does not have net authority over the character, it calls ServerSetRunning which is actually a request to server and executed server-side only (both due to UFUNCTION(Server, …)). When the server calls SetRunning, it has network authority so it does not call ServerSetRunning again.

If SetRunning is first called server-side (for example, listen server or single player) then ServerSetRunning is never called.

You may wonder whether SetRunning shouldn’t also be executed on connected clients. I don’t have the ShooterGame source locally, but what I’m guessing is that when the server calls UpdateSounds, those sounds are replicated already. As for bWantsToRun, its probably a replicated variable so the value updates to other clients already. Then, the other clients notice the desired effects without having to call SetRunning themselves.

About blueprint equivalent, it would be by creating a custom event anywhere such as the Level Blueprint or any Blueprint’s event graph and setting Replicates to ‘Run on Server’. Then when a client calls that event, it is actually run on server. You can do the validation as first part of the event. See attachment.repevent.png

Ah, it makes sense now.
Thank you both :).

Answer to Your Question

Hi there!

There’s actually a really simple reason its not an infinite loop:



if (Role < ROLE_Authority)
{
	ServerSetRunning(bNewRunning, bToggle);
}


Role < ROLE_Authority means this code only runs if you’re not the server.

The server calls the code, and skips that line, so its not an infinite loop

The purpose of the code structure is to say

"if you are not the server, then make sure the server does this too"


**Restructured Code For Clarity**

Personally I'd restructure the code to make the above sentence more clear



```


void AShooterCharacter::SetRunning(bool bNewRunning, bool bToggle)
{
        //Set!
	bWantsToRun = bNewRunning;
	bWantsToRunToggled = bNewRunning && bToggle;
	
        //Update!
        UpdateRunSounds(bNewRunning);

        //Make sure the server proxy runs this code too!
        if (Role < ROLE_Authority)
        {
		ServerSetRunning(bNewRunning, bToggle);
	}

      //♥ Rama
}


```



Network Summary

This code basically lets the locally controlled proxy update itself via the server for all its other proxies on other people’s machines.

Rather than having the server calculate and know to tell everyone, the locally controlled proxy, who first calls SetRunning, then tells everyone over the network to update their version of the local proxy.

So if you are the player as client 3 and you set yourself to running, this code tells the rest of the network to update their version of your player character proxy.

This avoids the server having to calculate setRunning for everyone, which is impossible for locally controlled characters because only you as the player know when you want to SetRunning to be true so you can run!

This code structure puts you in control as a client and uses the server to tell everyone else that you’ve chosen to start running.

:heart:

Rama