2
\$\begingroup\$

We're developing a 2D PvP online action game. You can think of it like Super Smash Bros. We have a function call tree for characters like below:

CharacterInput.Update()
|-- CharacterController.StartJump()
    |-- CharacterMovement.TranslateState( "Jump" )
        |-- CharacterJumpState.OnEnter()
            |-- CustomRigidbody2D.Move( delta )

I think the pseudo-code above is kinda straight forward. It's a typical Controller-Movement structure where the Movement part is made using several character states. Also, the Movement part is responsible for animations, physics, visual effects and sound effects.

So, to make this networked, we need to replicate some values over the network.

To make it clear, we're using Photon Bolt for Unity, which provide a ExecuteCommand way to deal with server authority and client prediction. You can check it out here.

So in terms of replication, we realized that according to the structure, we should decide which part to replicate. According to the call tree above, we can split our character logic into these layers:

  • Input Layer: LeftStick, RightStick, A, B, X, Y, ...
  • Controller Layer: MovementDirection, ShootDirection, IsJump, IsShoot, IsMelee, ...
  • Movement Layer: CurrentState and all of its member variables
  • Rigidbody, Animation Layer: Velocity, GravityScale, CurrentAnimationState

Theoretically, replicate any of these layers can make it work because the process of higher layer to lower layer is deterministic. Once the higher layer is replicated, lower layers should be the same across the network.

Sadly, this is just theory. In reality, you must deal with lag, and unreliable packet delivery.

For example, if you only replicate the inputs, an unstable network may make it out of sync because state A may transit itself to state B if animation ends, but actually it should be transitted to state C if player presses some button.

However, if you only replicate rigidbody and animation, all the visual effect or audio effect triggered by CharacterState can't work, because CharacterMovement doesn't even know which state it is in...

So, my question is, how do other games replicate their character? Especially in a PvP game?

\$\endgroup\$
  • \$\begingroup\$ Sorry, I will not answer correctly to your question, but I think that you should transfer to the server the only data it needs, for example, it do not care about animations or input at all (because every client has it's own settings). You should send to it somethink like "Hey, I want to move to the left" and it will response you like: "Okay, bro, no problems". When your character walk to the wall, the server should response "No, you can't". With included client-predictions you can implement commands with Undo-logic on such answer. Only if validation on client fails, ofcourse. \$\endgroup\$ – Joshua Light Feb 13 '17 at 9:35
1
\$\begingroup\$

Thanks for your answers. I've found a perfect answer for my question. I looked up the UE4 source code and found this:

// CharacterMovementComponent.h
virtual void ReplicateMoveToServer(float DeltaTime, const FVector& NewAcceleration);

// In ReplicateMoveToServer(), FSavedMove_Character::SetMoveFor() is invoked.
void FSavedMove_Character::SetMoveFor(ACharacter* Character, float InDeltaTime, FVector const& NewAccel, class FNetworkPredictionData_Client_Character & ClientData)
{
    DeltaTime = InDeltaTime;

    SetInitialPosition(Character);

    AccelMag = NewAccel.Size();
    AccelNormal = (AccelMag > SMALL_NUMBER ? NewAccel / AccelMag : FVector::ZeroVector);

    // Round value, so that client and server match exactly (and so we can send with less bandwidth). This rounded value is copied back to the client in ReplicateMoveToServer.
    // This is done after the AccelMag and AccelNormal are computed above, because those are only used client-side for combining move logic and need to remain accurate.
    Acceleration = Character->GetCharacterMovement()->RoundAcceleration(NewAccel);

    bPressedJump = Character->bPressedJump;
    JumpKeyHoldTime = Character->JumpKeyHoldTime;
    JumpMaxCount = Character->JumpMaxCount;

    // CheckJumpInput will increment JumpCurrentCount.
    // Therefore, for replicated moves we want it to set it at 1 less to properly
    // handle the change.
    JumpCurrentCount = Character->JumpCurrentCount > 0 ? Character->JumpCurrentCount - 1 : 0;
    bWantsToCrouch = Character->GetCharacterMovement()->bWantsToCrouch;
    bForceMaxAccel = Character->GetCharacterMovement()->bForceMaxAccel;
    MovementMode = Character->GetCharacterMovement()->PackNetworkMovementMode();

    // Root motion source-containing moves should never be combined
    // Main discovered issue being a move without root motion combining with
    // a move with it will cause the DeltaTime for that next move to be larger than
    // intended (effectively root motion applies to movement that happened prior to its activation)
    if (Character->GetCharacterMovement()->CurrentRootMotion.HasActiveRootMotionSources())
    {
        bForceNoCombine = true;
    }

    TimeStamp = ClientData.CurrentTimeStamp;
}

Turns out that UE4 replicates CharacterMovement with all its state variables to make it work.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Like Ashkariel Eter suggested in his comment, in a pure client/server model client sends only his inputs such as key presses, mouse movement, clicks to the server. In response the server updates the state of your character in the world and replies with a packet containing the state of your character and other players near you.

Such approach resolves the problem of unreliable network. If some packets get lost, some of your inputs won't go through and your local state and server state will desynchronize - whoops! But wait, it is not such a big deal, the server will send you near world state in next snapshot and your client will be able to correct any resulting differences. Such unreliable network tends to generate strange artifacts on client-side like running into walls and sudden teleportation when server snapshot is received - sounds familiar?

Also you should definitely take a look on lag compensation techniques and communication system based on unreliable network and unreliable protocol. Photon Bolt for Unity takes care for most of these issues for you, leaving you only to decide whether to use those features for your game or not, in PVP online action game you would want to use those perks.

  1. Networking for game programmers, what every programmer needs to know about game networking.
  2. Lag compensation techniques
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.