-
Notifications
You must be signed in to change notification settings - Fork 452
Description
Description
I'm trying to implement Anticipation to my game which features Player Characters that moves using rb.AddForce(). As such, I'm not using neither AnticipatedNetworkTransform nor the default NetworkTransform (I'm using AnticipatedNetworkVariable for the rotation and movement of the player character).
I'm running the following setup in my Player script:
Player.cs
public Vector3 position;
public override void OnReanticipate(double lastRoundTripTime)
{
base.OnReanticipate(lastRoundTripTime);
Debug.Log("Reanticipating");
SmoothAnticipateNetworkVariable(rbRotation, 0.25f, Quaternion.Slerp);
SmoothAnticipateNetworkVariable(rbPosition, 0.25f, Vector3.Slerp);
position = rbPosition.AuthoritativeValue;
//rb.rotation = rbRotation.Value;
//Rb.position = rbPosition.Value;
}
private void SmoothAnticipateNetworkVariable<T>(AnticipatedNetworkVariable<T> anticipatedNetworkVariable, float durationSeconds, AnticipatedNetworkVariable<T>.SmoothDelegate how)
{
if (anticipatedNetworkVariable.ShouldReanticipate)
{
anticipatedNetworkVariable.Smooth(anticipatedNetworkVariable.PreviousAnticipatedValue, anticipatedNetworkVariable.AuthoritativeValue, durationSeconds, how);
}
}
public override void FixedUpdate()
{
base.FixedUpdate();
if (IsLocalPlayer)
{
ClientFixedUpdate();
}
if (IsServer)
{
ServerFixedUpdate();
}
rb.rotation = rbRotation.Value;
Rb.position = rbPosition.Value;
}
private void ServerFixedUpdate()
{
if (moveDirection != Vector2.zero)
{
Quaternion targetRotation = Quaternion.LookRotation(new Vector3(moveDirection.x, 0, moveDirection.y));
//rbRotation.Anticipate(Quaternion.Slerp(rb.rotation, targetRotation, Time.deltaTime * 10f));
rbRotation.Anticipate(targetRotation);
rb.rotation = targetRotation;
//rb.rotation = rbRotation.Value;
}
}
void ClientFixedUpdate()
{
if (clientInputDirectionRelativeToCamera != Vector3.zero)
{
// Rotate towards movement direction
Quaternion targetRotation = Quaternion.LookRotation(clientInputDirectionRelativeToCamera);
rbRotation.Anticipate(targetRotation);
//rbRotation.Anticipate(Quaternion.Slerp(rb.rotation, targetRotation, Time.deltaTime * 10f));
}
}
PlayerMoveState (Runs on LocalClients and Server)
public override void OnFixedUpdate()
{
if (playerFiniteStateMachine.IsLocalPlayer)
{
playerFiniteStateMachine.Rb.CharacterMoveRelativeToCameraDirection(playerFiniteStateMachine.ClientInputDirectionRelativeToCamera, playerFiniteStateMachine.MovementSpeed, playerFiniteStateMachine.IsGrounded, ref previousTargetVelocity);
playerFiniteStateMachine.RPCAnimatorSetFloat(Player.AnimationParameters.horizontalVelocity.ToStringCached(), (playerFiniteStateMachine.ClientInputDirectionRelativeToCamera.magnitude > 0F) ? Math.Clamp(playerFiniteStateMachine.NormalizeMovementSpeed, 0.01F, 999F) : 0F);
}
else
{
playerFiniteStateMachine.Rb.CharacterMoveRelativeToCameraDirection(playerFiniteStateMachine.inputDirectionRelativeToCamera, playerFiniteStateMachine.MovementSpeed, playerFiniteStateMachine.IsGrounded, ref previousTargetVelocity);
playerFiniteStateMachine.RPCAnimatorSetFloat(Player.AnimationParameters.horizontalVelocity.ToStringCached(), (playerFiniteStateMachine.inputDirectionRelativeToCamera.magnitude > 0F) ? Math.Clamp(playerFiniteStateMachine.NormalizeMovementSpeed, 0.01F, 999F) : 0F);
}
//if (playerFiniteStateMachine.IsServer || playerFiniteStateMachine.IsLocalPlayer)
if (playerFiniteStateMachine.IsServer && !playerFiniteStateMachine.IsLocalPlayer)
Debug.Log(playerFiniteStateMachine.Rb.position);
playerFiniteStateMachine.rbPosition.Anticipate(playerFiniteStateMachine.Rb.position);
}
The issue is AnticipatedNetworkVariable.Smooth() in my example above, over time does not lerp towards the AuthoritativeValue. It happens on several scenarios, one of them when the player hits another player and tries to push the other player away.
As we can see from the screenshots below, the Server is sending the correct position data BUT when the client tries to Smooth() the data in OnReanticipation, the value is not the same. I've checked and AuthoratitativeValue is correct on the client side. So it's certainly the Smooth() on the client side that is not syncing and making AnticipatedNetworkVariable go towards the Authorative Value.
This seems very much like a breaking bug?
Reproduce Steps
- Do not attach AnticipatedNetworkTransform OR NetworkTransform to your player gameobject. Move & Rotate your player object with Rigidbody.AddForce & Sync over the network the position and rotation with AnticipatedNetworkVariable instead. Have a level and at least 2 players in the game. All Clients must only be sending inputs to the Server and the Server must be the only one that move the players using rb.AddForce.
I'm using this level assets (Though any level/3d models should be fine): https://assetstore.unity.com/packages/essentials/tutorial-projects/starter-pack-synty-polygon-stylized-low-poly-3d-art-156819?srsltid=AfmBOorri35RnAhfSmXrG20RSqmKrzXEjNApOCqUq4hMd4T0SOHrFVAN
Actual Outcome
AnticipatedNetworkVariable.Smooth does not sync with AnticipatedNetworkVariable.AuthoritativeValue, overtime the position goes incorrect. At the start there's no issues, move around with the players and gradually they will go out of sync in position.
Expected Outcome
AnticipatedNetworkVariable.Smooth should sync constantly to AnticipatedNetworkVariable.AuthoritativeValue.
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
Environment
- OS: Windows 11 64 bit
- Unity Version: Unity 6
- Netcode Version: 2.3.2
- Netcode Commit: Downloaded directly from PackageManager.
Additional Context
Add any other context about the problem here. Logs, code snippets would be useful here but please also consider attaching a minimal Unity project that reproduces the issue.