UpdateFromCompressedFlags in network gameplay repeatedly being called

Hey all,

I’ve recently come across odd behaviour in my network code.
I have a custom MovementComponent that I use, I’ve not overriden UpdateFromCompressedFlags at all. Infact a bug has led me to this function.

On a network game, player 2 would join - as a client - and their StopJumping() would keep being called on repeat.
I’ve found it this is being caused in MovementComponent::UpdateFromCompressedFlags



void MyMovementComponent::UpdateFromCompressedFlags(uint8 Flags)
{
    if (!CharacterOwner)
    {
        return;
    }

    const bool bWasPressingJump = CharacterOwner->bPressedJump;

    CharacterOwner->bPressedJump = ((Flags & FSavedMove_Character::FLAG_JumpPressed) != 0);
    bWantsToCrouch = ((Flags & FSavedMove_Character::FLAG_WantsToCrouch) != 0);

    // Detect change in jump press on the server
    if (CharacterOwner->GetLocalRole() == ROLE_Authority)
    {
        const bool bIsPressingJump = CharacterOwner->bPressedJump;
        if (bIsPressingJump && !bWasPressingJump)
        {
            CharacterOwner->Jump();
        }
        else if (!bIsPressingJump)
        {
            CharacterOwner->StopJumping();
        }
    }

}


Both vars bIsPressingJump and bWasPressingJump are False, which would suggest to me they’ve not changed.
This function is only called for clients, and it’s every tick - it seems.

Should this function be called all the time? If not, what could I look for as the reason why it is happening?

Cheers for any ideas

I would replicate this bool so the client can see it and use it in the if checks.


bIsPressingJump

Beings the client is the one running this. Any if checks where you have a bool or what ever your checking with in the ifs. The client must have a copy of them in order to read them right or you end up with a false. Any ifs that you are checking from the client must be replicated to the client from the server.

ooooohhhhhhhhh why isnt bPressedJump replicated ?? I’d have thought the Server would need to tell clients that a Character is jumping…
Ah I guess this is an interal variable that only the Client needs to care about ? The Server knows a character is jumping due to other vars/funcs ?
cheers !

I assume I’ve done something wrong somewhere then…?
As this would mean the base code for the ue4 MovementComponent is always calling StopJumping() on network clients. (Which I assume it’s not)

  • Edit:
    Just looking at the code, is it not correct both variables are “false”? My client hasnt pressed jump, and UpdateFromCompressedFlags() is always being called…
    And the “if ROLE_Authority” is saying this block of code is only running on server right ?

Replication on a var happens when the var changes its values and if you have the replication code in to make it happen.

That is server driven, it does not tell the client anything about bIsPressingJump only the server. If the server makes that true the client did not get a replication about it because you never told the server to tell the client about it, so the client will always see that as a false until the server replicates it to the client.

If you want to replicate that. Do this in your .h file where you defined your var add above it



//needed to help replication happen
void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const override;

UPROPERTY(Replicated, ReplicatedUsing = OnRep_IsPressingJump)//set it up for replication.
bool bIsPressingJump;//lets replicate this var

UFUNCTION()
void OnRep_IsPressingJump();//define client function to be used.


Then in your .cpp file add in

That will replicate the var and let the client get a copy of it and run what he needs.

Ok cool, il add that in now !

I just dont get why the function UpdateFromCompressedFlags is always being called… The level starts, I press no buttons, and it’s already firing 1000s of times.
Is that correct ?

Oh, wait … “bIsPressingJump” isnt my variable… it’s in the ue4 code :



const bool bIsPressingJump = CharacterOwner->bPressedJump;


My example at the top - I just copied and pasted the code for UpdateFromCompressedFlag from the base class MovementComponent - and changed none of it.

ohh i thought you wrote that, yeah ignore what i put above then. I am just assuming here, but i bet that function is on tick. What are you trying to do?

Ok so my plan was to have the concept of Press Jump Button (start jump) and on Release of Jump Button stop and return to earth.
So I did this:

MyCharacter:



PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AWaterproofCharacter::Jump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &AWaterproofCharacter::StopJumping);



void AWaterproofCharacter::StopJumping()
{       
    Super::StopJumping();
    
    GetCharacterMovement()->Velocity.Z /= 2;
    GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, "StopJumping");    

    if (!bDoExtendJump) bCanDoextendedJump = false;
}


bDoExtendJump - is basically if you press and continue to hold the jump button, when you reach the apex of the normal jump height, it gives a lil extra boost (so it feels like youve jumped a bit higher)

So I only noticed this issue (bug ?) of StopJumping() always firing for clients as I added the “vel.z /= 2”, which basically just did a quick ease on slowing/stopping the jump and forcing the player back to earth.

On server this works fine as this function ONLY calls on “release”, but for Clients that MovementComponent function UpdateFromCompressedFlags() is always being fired, and those 2 variables (checking if jump pressed) are always “false” - which seems to trick it into calling “StopJumping”.
I assume this function should only be called if client’s Character has changed… but I can’t work it out at all, and it’s hard to find specific informaiton about it.
That’s why I tried commenting out all my Binding(s) to see if one of those was accidentally firing, and changing my Character’s state. But it wasnt this either.



CharacterOwner->StopJumping();

So this is getting called constantly on the client? If you log this, CharacterOwner->GetLocalRole() < what is it? Is it ROLE_Authority? while your at it log your players GetNetMode() what is that?

This is the function I copied from MovementComponent to my custom MovementComponent, I added the UE_LOG() to see what was happening, and it’s always printing False , False, which is why it’s always calling StopJumping() (which I have a print() in too - in my custom character)



void UWPMovementComponent::UpdateFromCompressedFlags(uint8 Flags)
{
	if (!CharacterOwner)
	{
		return;
	}

	const bool bWasPressingJump = CharacterOwner->bPressedJump;

	CharacterOwner->bPressedJump = ((Flags & FSavedMove_Character::FLAG_JumpPressed) != 0);
	bWantsToCrouch = ((Flags & FSavedMove_Character::FLAG_WantsToCrouch) != 0);

	// Detect change in jump press on the server
	if (CharacterOwner->GetLocalRole() == ROLE_Authority)
	{
		
		const bool bIsPressingJump = CharacterOwner->bPressedJump;
		
		UE_LOG(LogTemp, Warning, TEXT("bIsPressingJump: %s, bWasPressingJump: %s"), bIsPressingJump ? TEXT("true") : TEXT("false"), bWasPressingJump ? TEXT("true") : TEXT("false"));

		if (bIsPressingJump && !bWasPressingJump)
		{
			CharacterOwner->Jump();
		}
		else if (!bIsPressingJump)
		{
			
			CharacterOwner->StopJumping();
		}
	}

}


“CharacterOwner->GetLocalRole()” this must be ROLE_Authority as it’s getting into the IF statement all the time.
So this is always running on server, I think, and then telling the client(s)

What you thinking I should be looking for?
My concern here is this is always being called on server for my client - and should only be called IF client Character has updated in someway.

I had a go at this, but my prints kept failing.



	ENetRole role = CharacterOwner->GetLocalRole();	
	const TCHAR* name = *UEnum::GetValueAsString<ENetRole>(role);
	UE_LOG(LogTemp, Warning, TEXT("CharacterOwner->GetLocalRole(): %s"), name)


This gave me symbols lol. But using breakpoints, I can see it’s always Role_Authority.



ENetMode netrole = GetNetMode();


I couldn’t get this to print at all. Always errored with “null” reference in run time. Using breakpoints, the variable never showed anything - which I’ve never seen before :S :S
So I don’t know what that means/how to get this info

Got an idea, try this. In your if try putting this see what happens



if(GetNetMode() != NM_Client )

//replace this

if (CharacterOwner->GetLocalRole() == ROLE_Authority)


I’ve heard there is an Authority bug that makes the client authority when he should’nt be

When you test the game. what server are you running on a dedicated or listen or standalone?

Ah yeah, I’ve read about that in a couple of places - but it never seems to be 100% confirmed (unless you;ve got a link?)
I always assume it’s a miss understanding, as a Client can have authority over actors in some cases.
But I guess with a network pawn the a client doesnt have auth?
I keep referencing in this : http://cedric-neukirchen.net/Downloa…kirchen_BW.pdf

Did you mean to replace like this:



// Detect change in jump press on the server
if (GetNetMode() != NM_Client) // if (CharacterOwner->GetLocalRole() == ROLE_Authority)
{

const bool bIsPressingJump = CharacterOwner->bPressedJump;

UE_LOG(LogTemp, Warning, TEXT("bIsPressingJump: %s, bWasPressingJump: %s"), bIsPressingJump ? TEXT("true") : TEXT("false"), bWasPressingJump ? TEXT("true") : TEXT("false"));
ENetMode const netrole = GetNetMode();

//UE_LOG(LogTemp, Warning, TEXT("GetNetMode(): %s"), netrole);


if (bIsPressingJump && !bWasPressingJump)
{
CharacterOwner->Jump();
}
else if (!bIsPressingJump)
{

CharacterOwner->StopJumping();
}
}


or did you mean:




if (GetNetMode() != NM_Client)
{
// Detect change in jump press on the server
if (CharacterOwner->GetLocalRole() == ROLE_Authority)
{
// everything else here
}
}


** Edit
Adding the if check for GetNetMode() didn’t help :frowning:
Keeps calling StopJumping still

But I still dont think this function should be getting called ever tick … I’d love for someone who knows more about the inner workings of all this to say yes/no on this…

Forgot to say, I added my own “fix”. Original code, that kept calling StopJumping() was this:



if (bIsPressingJump && !bWasPressingJump)
{
CharacterOwner->Jump();
}
else if (!bIsPressingJump)
{

CharacterOwner->StopJumping();
}


Which would obviously always fall into that “else if” statement - hence I assume something is broken/wrong somewhere else…

But i’ve now got this:



if (bIsPressingJump && !bWasPressingJump)
{
CharacterOwner->Jump();
}
else if (!bIsPressingJump && bWasPressingJump)
{

CharacterOwner->StopJumping();
}


Which doesnt call “stopjumping” all the time now… but it feels weird changing the base functionality of MovementComponent.

This doesn’t feel “correct” to me…

if it is on tick which i’m assuming it is. It will run over and over and over to check did you hit the button. Then it will run that function every time it is ticked. Yeah i read where the client can have
ROLE_Authority over the over actors in some cases. This must be the case as that how your code is acting.

Why would you want a client having authority over a function when it should be server controlled. If you are wanting the client to just run stop jump one time not over and over and over, then i would try this. This is your original code from epic, ok



// Detect change in jump press on the server <I'M ASSUMING THIS IS EPICS COMMENT?
if (CharacterOwner->GetLocalRole() == ROLE_Authority)// This is not doing what they are wanting the client has authority
{
        const bool bIsPressingJump = CharacterOwner->bPressedJump;
       UE_LOG(LogTemp, Warning, TEXT("bIsPressingJump: %s, bWasPressingJump: %s"), bIsPressingJump ? TEXT("true") : TEXT("false"), bWasPressingJump ? TEXT("true") : TEXT("false"));
       if (bIsPressingJump && !bWasPressingJump)
       {
          CharacterOwner->Jump();
       }
       else if (!bIsPressingJump)
       {
           CharacterOwner->StopJumping();
        }
}

If you read their comment it suppose to be server controlled. But its not. So Lets try this.



// Detect change in jump press on the server
if (GetNetMode() != NM_Client)//SHOULD ONLY LET THE SERVERS THRU
{
      const bool bIsPressingJump = CharacterOwner->bPressedJump;//WHEN THIS CHANGES REPLICATE IT TO THE CLIENT
      UE_LOG(LogTemp, Warning, TEXT("bIsPressingJump: %s, bWasPressingJump: %s"), bIsPressingJump ? TEXT("true") : TEXT("false"), bWasPressingJump ? TEXT("true") : TEXT("false"));
      if (bIsPressingJump && !bWasPressingJump) //SERVER SHOULD RUN THIS NOT NO CLIENTS, LET CLIENTS RUN THE REPLICATION SECTION SO THEY GET ONE RUN NOT MULTIPLE
      {
          CharacterOwner->Jump();
       }
       else if (!bIsPressingJump)
       {
           CharacterOwner->StopJumping();
       }
}


Then add in the replication code from above and if that if (GetNetMode() != NM_Client) works right the client will not get into it, but when the server rolls thru and changes that bool bIsPressingJump then the client should get his copy and run the function void YOURCLASS::OnRep_IsPressingJump() and the client should run it once.

Which ever way the var has been set it should run function void YOURCLASS::OnRep_IsPressingJump() then run its if or else to determine what the clients going to do. This is if the if (GetNetMode() != NM_Client) code works like it should.

I would have to make a test project to verify this all. I’m in the middle of moving over around 10k lines of code and debugging them. So i can not add this into my project yet and try it.

If what you are saying is true. I do not believe you need to be running stop jump after it has ran once. That is all its doing it just setting it to false which does not change that vars value. It stays the same so it just running code that really does not need rerun.

Just remember this. Any time you replicate a var the value must change for it to actually replicate to the client. If it is a false and you set it to false again it will not replicate again as the value did not change, It is the same. It will replicate when it goes to true. < different value.

This needs fixed, i have a bunch of code that uses this check. if(GetLocalRole() == ROLE_Authority) and none of it is working right as it thinks the client should have authority when he should not have it. OMG this is just wonderful.

I just peeked at the define of GetLocalRole() there is also a GetRemoteRole().

/** Returns whether this actor has network authority */
bool HasAuthority()

/** Returns how much control the local machine has over this actor. */
GetLocalRole()

/** Returns how much control the remote machine has over this actor. */
GetRemoteRole().

you can use this to test what your net mode is bool IsNetMode(ENetMode Mode)

You can use this to find out if the function is ticked bool IsActorTickEnabled()//forget this it is for an actor and yours is a extension of uobject

Edit: add these log lines into the function right above the if


if (CharacterOwner->GetLocalRole() == ROLE_Authority)
//or this one which ever you are using.
if (GetNetMode() != NM_Client)/


ADD THESE LOGS



UE_LOG(LogCharacterMovement, Log, TEXT("UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_Client = %s"), IsNetMode(NM_Client) ? TEXT("TRUE") : TEXT("FALSE"));
UE_LOG(LogCharacterMovement, Log, TEXT("UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_ListenServer = %s"), IsNetMode(NM_ListenServer) ? TEXT("TRUE") : TEXT("FALSE"));
UE_LOG(LogCharacterMovement, Log, TEXT("UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_Standalone = %s"), IsNetMode(NM_Standalone) ? TEXT("TRUE") : TEXT("FALSE"));
UE_LOG(LogCharacterMovement, Log, TEXT("UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_DedicatedServer = %s"), IsNetMode(NM_DedicatedServer) ? TEXT("TRUE") : TEXT("FALSE"));

UE_LOG(LogCharacterMovement, Log, TEXT("UCharacterMovementComponent::UpdateFromCompressedFlags CharacterOwner->HasAuthority() = %s"), CharacterOwner->HasAuthority() ? TEXT("TRUE") : TEXT("FALSE"));


from all this you should be able to solve this and get it running like you want.
I am very curious to see what your logs show.

Here is a link to Character Movement Component | Unreal Engine Documentation

Hey @gamepainters , thanks for all of this !

I’m gna try and reply to each bit as best as I can !

It appears to be happening every tick.

I think it is only running on the server, but the StopJumping() is being called on the client.

The thing for me is, IF it is happening every tick - and IF that is normal behaviour - it WILL always get through to the if statements and land at StopJumping().



	// always False because I wasnt pressing jump
	const bool bWasPressingJump = CharacterOwner->bPressedJump;

	// always False because I havent pressed Jump
	CharacterOwner->bPressedJump = ((Flags & FSavedMove_Character::FLAG_JumpPressed) != 0);
	
	// we are server so we always go into this IF{} block
	if (CharacterOwner->GetLocalRole() == ROLE_Authority)
	{
		
		// always False because I havent pressed jump
		const bool bIsPressingJump = CharacterOwner->bPressedJump;

		// never go in here to do a jump because i havent pressed Jump
		if (bIsPressingJump && !bWasPressingJump)
		{
			CharacterOwner->Jump();
		}		
		else if (!bIsPressingJump)
		{
			// always come in here because everything is False
			CharacterOwner->StopJumping();
		}
	}


I feel this function should only fire IF one of the Compressed Flags has changed, otherwise it will always get to StopJumping()
Right ?

Your prints gave me:



LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_Client = FALSE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_ListenServer = FALSE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_Standalone = FALSE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_DedicatedServer = TRUE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags CharacterOwner->HasAuthority() = TRUE


lol oh man, you dont have to do that ! But thanks for the offer ! This is my odd bug to deal with…

Yea yea. I think what is happening here though, is the server is specifically calling StopJumping() which is replicated and ran on server and client Pawn ?

Fully agreed
And it’s why I wrote my “fix” as just simply doing:



 	if (CharacterOwner->GetLocalRole() == ROLE_Authority)
	{
		
		const bool bIsPressingJump = CharacterOwner->bPressedJump;
		
		if (bIsPressingJump && !bWasPressingJump)
		{
			CharacterOwner->Jump();
		}
		/*
			******* My fix *****
			check both bools
		*/		
		else if (!bIsPressingJump && bWasPressingJump)
		{			
			CharacterOwner->StopJumping();
		}
	}


But I say “fix” as I think this function is being called incorrectly in Tick() - due to an incorrect change in Character CompressedFlag(s)



void UWPMovementComponent::UpdateFromCompressedFlags(uint8 Flags)


What ever “Flags” are. Though I’m struggling to prove/disprove this

Yes sir.

It is on tick. It will fire every time tick fires it.

Right.

yes but no,
The server is running it yes. As you can see from the dedicated log saying true to it, but so is the client as he is getting thru the if check to run stopjump() on him self as the client. By seeing the HASAUTHORITY() set to true. Amazing client has authority on a dedicated server? looks like a place to inject a hack. man oh man.

Stopjump() is not replicated. each runs same version of it. If the if will let each in to run it. Something to remember is you have 2 things being sent thru the function. One is the server and one is the client. You must figure out how to deal with both at the same time.

It is no big deal it is on tick. You just need to deal with what is in that if to get the results you are wanting. As i said before, if you want it to run one time you will need to change the if to let only the server thru then replicated the bool to let client run it one time. Then when its value changes on the server it will replicated the bool and run the client side function one time until it gets a new value to do it again. Server side will still be on tick but no big deal. like i was saying once your a false you can set it server side to false tons times nothing changing until it goes true. Now that you have shown me this. i’m going to probably rewrite it to suit my needs to fire one time only by replicating the bool.

Your flags below.


 // Bit masks used by GetCompressedFlags() to encode movement information.
enum CompressedFlags
{
FLAG_JumpPressed = 0x01, // Jump pressed
FLAG_WantsToCrouch = 0x02, // Wants to crouch
FLAG_Reserved_1 = 0x04, // Reserved for future use
FLAG_Reserved_2 = 0x08, // Reserved for future use
// Remaining bit masks are available for custom flags.
FLAG_Custom_0 = 0x10,
FLAG_Custom_1 = 0x20,
FLAG_Custom_2 = 0x40,
FLAG_Custom_3 = 0x80,
};

Yeah good point! I just don’t get it, seems like quite a big miss for the unreal boys that this is running incorrectly. I assume I’m miss understanding the prints, or what’s really going on behind the scenes during PIE network tests

Weirdly, and I don’t know if this makes things better/worse…
I just tested it with different Play settings in editor:

Num Players: 1
Net Mode: Play as client



LogTemp: Warning: Start UpdateFromCompressedFlags
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_Client = FALSE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_ListenServer = FALSE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_Standalone = FALSE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_DedicatedServer = TRUE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags CharacterOwner->HasAuthority() = TRUE
LogTemp: Warning: bIsPressingJump: false, bWasPressingJump: false


Then I did:
Num Players: 1
Net Mode: Play as Listener Server



Nothing


Then I did:
Num Players: 2
Net Mode: Play as Listener Server



LogTemp: Warning: Start UpdateFromCompressedFlags
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_Client = FALSE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_ListenServer = TRUE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_Standalone = FALSE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags are we NM_DedicatedServer = FALSE
LogTemp: Warning: UCharacterMovementComponent::UpdateFromCompressedFlags CharacterOwner->HasAuthority() = TRUE


So when I say “play as client” it think it is Dedicated Server and prints.
When I “play as Listener server” with 1 player I get ListenServer and no prints.
But when I “play as Listener server” with 2 players I get ListenServer and prints

Yeah fair, that sounds good to me.
And to be honest, I’m quite happy with my current fix…Just wasnt expecting a function like this to run every tick.
Seems a waste of power right ? If nothing in the Flag(s) has changed, why call this function…


Epilogue
So checking MovementComponent, and tracing the function backwards, I’ve discovered this is the path it’s going on:



TickComponent()
...
if (CharacterOwner->GetLocalRole() > ROLE_SimulatedProxy)
{
SCOPE_CYCLE_COUNTER(STAT_CharacterMovementNonSimulated);

// If we are a client we might have received an update from the server.
const bool bIsClient = (CharacterOwner->GetLocalRole() == ROLE_AutonomousProxy && IsNetMode(NM_Client));
if (bIsClient)
{
FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character();
if (ClientData && ClientData->bUpdatePosition)
{
ClientUpdatePositionAfterServerUpdate();
}
}
...

ClientUpdatePositionAfterServerUpdate()
...
FNetworkPredictionData_Client_Character* ClientData = GetPredictionData_Client_Character();
check(ClientData);

if (!ClientData->bUpdatePosition)
{
return false;
}

ClientData->bUpdatePosition = false;

for (int32 i=0; i<ClientData->SavedMoves.Num(); i++)
{
FSavedMove_Character* const CurrentMove = ClientData->SavedMoves*.Get();
checkSlow(CurrentMove != nullptr);
CurrentMove->PrepMoveFor(CharacterOwner);
MoveAutonomous(CurrentMove->TimeStamp, CurrentMove->DeltaTime, CurrentMove->GetCompressedFlags(), CurrentMove->Acceleration);
CurrentMove->PostUpdate(CharacterOwner, FSavedMove_Character::PostUpdate_Replay);
}
...


MoveAutonomous()
...
UpdateFromCompressedFlags(CompressedFlags);
...


The function GetPredictionData_Client_Character:



FNetworkPredictionData_Client_Character* UCharacterMovementComponent::GetPredictionData_Client_Character() const
{
// Should only be called on client or listen server (for remote clients) in network games


This says to me that whole stack of functions i’ve been looking at to run on client pawn (role_simualtedproxy)
I think by the time we get to our function UpdateFromCompressedFlags() we are running on a character spawned client side - which would mean it can be Authoritative ( right ?).
This would explain why the CharacterOwner->GetLocalRole() is Role_Auth, but NetMode is Server.

This function is to playback data sent from the server ?
** Edit, still confused, everywhere I read “role_authority” is to mean “definitely server”… I don’t understand this function

For what it’s worth, I’m going to keep my current fix and forget this lol
I need brain power for work code, let alone home code

With the default CharacterMovementComponent the listen server does this as well despite not jumping with any of the characters. I’ve only briefly tested with PIE, 3 players and Use Single Process active. It happens as soon as a client has its Character spawned. In this case StopJumping seems to never be called on the client itself though. The Character spawned for the listenserver does not cause this at all even if that Character jumps (breakpoint in ACharacter::StopJumping does not trigger here). The callstack on the listenserver is the following (UE4.24):



UE4Editor-Engine-Win64-Debug.dll!UCharacterMovementComponent::UpdateFromCompressedFlags(unsigned char Flags)
UE4Editor-Engine-Win64-Debug.dll!UCharacterMovementComponent::MoveAutonomous(float ClientTimeStamp, float DeltaTime, unsigned char CompressedFlags, const FVector & NewAccel)
UE4Editor-Engine-Win64-Debug.dll!UCharacterMovementComponent::ServerMove_Implementation(float TimeStamp, FVector_NetQuantize10 InAccel, FVector_NetQuantize100 ClientLoc, unsigned char MoveFlags, unsigned char ClientRoll, unsigned int View, UPrimitiveComponent * ClientMovementBase, FName ClientBaseBoneName, unsigned char ClientMovementMode)
UE4Editor-Engine-Win64-Debug.dll!ACharacter::ServerMoveNoBase_Implementation(float TimeStamp, FVector_NetQuantize10 InAccel, FVector_NetQuantize100 ClientLoc, unsigned char CompressedMoveFlags, unsigned char ClientRoll, unsigned int View, unsigned char ClientMovementMode)
UE4Editor-Engine-Win64-Debug.dll!ACharacter::execServerMoveNoBase(UObject * Context, FFrame & Stack, void * const Z_Param__Result)
UE4Editor-CoreUObject-Win64-Debug.dll!UFunction::Invoke(UObject * Obj, FFrame & Stack, void * const Z_Param__Result)
UE4Editor-CoreUObject-Win64-Debug.dll!UObject::ProcessEvent(UFunction * Function, void * Parms)
UE4Editor-Engine-Win64-Debug.dll!AActor::ProcessEvent(UFunction * Function, void * Parameters)
UE4Editor-Engine-Win64-Debug.dll!FObjectReplicator::ReceivedRPC(FNetBitReader & Reader, const FReplicationFlags & RepFlags, const FFieldNetCache * FieldCache, const bool bCanDelayRPC, bool & bOutDelayRPC, TSet<FNetworkGUID,DefaultKeyFuncs<FNetworkGUID,0>,FDefaultSetAllocator> & UnmappedGuids)
UE4Editor-Engine-Win64-Debug.dll!FObjectReplicator::ReceivedBunch(FNetBitReader & Bunch, const FReplicationFlags & RepFlags, const bool bHasRepLayout, bool & bOutHasUnmapped)
UE4Editor-Engine-Win64-Debug.dll!UActorChannel::ProcessBunch(FInBunch & Bunch)
UE4Editor-Engine-Win64-Debug.dll!UActorChannel::ReceivedBunch(FInBunch & Bunch)
UE4Editor-Engine-Win64-Debug.dll!UChannel::ReceivedSequencedBunch(FInBunch & Bunch)
UE4Editor-Engine-Win64-Debug.dll!UChannel::ReceivedNextBunch(FInBunch & Bunch, bool & bOutSkipAck)
UE4Editor-Engine-Win64-Debug.dll!UChannel::ReceivedRawBunch(FInBunch & Bunch, bool & bOutSkipAck)
UE4Editor-Engine-Win64-Debug.dll!UNetConnection::ReceivedPacket(FBitReader & Reader)
UE4Editor-Engine-Win64-Debug.dll!UNetConnection::ReceivedRawPacket(void * InData, int Count)
UE4Editor-OnlineSubsystemUtils-Win64-Debug.dll!UIpConnection::ReceivedRawPacket(void * Data, int Count)
UE4Editor-OnlineSubsystemUtils-Win64-Debug.dll!UIpNetDriver::TickDispatch(float DeltaTime)
UE4Editor-Engine-Win64-Debug.dll!TBaseUObjectMethodDelegateInstance<0,UNetDriver,TTypeWrapper<void> __cdecl(float)>::Execute(float <Params_0>)
UE4Editor-Engine-Win64-Debug.dll!TBaseUObjectMethodDelegateInstance<0,UNetDriver,void __cdecl(float)>::ExecuteIfSafe(float <Params_0>)
UE4Editor-Engine-Win64-Debug.dll!TBaseMulticastDelegate<void,float>::Broadcast(float <Params_0>)
UE4Editor-Engine-Win64-Debug.dll!UWorld::Tick(ELevelTick TickType, float DeltaSeconds)
UE4Editor-UnrealEd-Win64-Debug.dll!UEditorEngine::Tick(float DeltaSeconds, bool bIdleMode)
UE4Editor-UnrealEd-Win64-Debug.dll!UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode)
UE4Editor-Win64-Debug.exe!FEngineLoop::Tick()
UE4Editor-Win64-Debug.exe!EngineTick()


Your fix actually seems like a good solution, but I wonder whether the check for the second bool was missing intentionally.

Maybe there are alternative solutions to the problem? What are you trying to achieve?

That is because of this, when you play as a dedicated server. It is only clients joining, it has to print. You have a client, as you are the client, everyone is a client on dedicated servers…

Listen server with 1 player will not print as you are the server you are the host you are not a client, everyone after the 1st player is a client on listen server. So it prints to the clients 2nd guy makes that happen beings its on tick for the clients.

look at the flags. Its jump or crouch, that would be a bad check because lets say your doing the jump thing it does not know if your jumping or stopping the flag just sets that its in jump it just does not know what state of jump your in. So checking if the flag changes would not be a good idea unless it is rewrote to check for flags jumping or not jumping.

Same got to get my head wrapped around their way of doing this. Just seems weird a client is “role_authority” over anything, Just seems the server should be telling the client go do this, not the client saying i have authority i will go do this.

Cool, np.
Same, i have some pain in the *** bugs i have to solve. Couple bugs i tackled, i just rewrote everything totally different to fix. I’m adding in an inventory with weapons. What my biggest issue is how i am going to do states. Do i make a state system similar to udk or do i just eliminate the need for states period.

Anyways hope you have a better understanding what is going on there.