Skip to content

fix: performance improvements (CPU-only) #590

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using UnityEngine;
using UnityEngine.Assertions;

namespace Unity.Multiplayer.Samples.BossRoom.Visual
{
Expand Down Expand Up @@ -63,6 +64,8 @@ public class AnimatorFootstepSounds : MonoBehaviour
[Tooltip("If the speed variable is between WalkSpeedThreshold and this, we're running. (Higher than this means no sound)")]
private float m_RunSpeedThreshold = 1.2f;

float m_LastSpeed;

void Awake()
{
if (!m_Animator)
Expand All @@ -73,17 +76,24 @@ void Awake()

private void Update()
{
if (!m_Animator || !m_AudioSource || !m_WalkFootstepAudioClip || !m_RunFootstepAudioClip || m_AnimatorVariableHash == 0)
if (!m_Animator)
{
// we can't actually run since we don't have the stuff we need. So just stop updating
enabled = false;
return;
}

var speed = m_Animator.GetFloat(m_AnimatorVariableHash);

if (Mathf.Approximately(speed, m_LastSpeed))
{
return;
}

// choose which sound effect to use based on how fast we're walking
AudioClip clipToUse = null;
float volume = 0;
float speed = m_Animator.GetFloat(m_AnimatorVariableHash);

if (speed <= m_TooSlowThreshold)
{
// we could have a "VERY slow walk" sound... but we don't, so just play nothing
Expand Down Expand Up @@ -117,6 +127,8 @@ private void Update()
m_AudioSource.loop = true;
m_AudioSource.Play();
}

m_LastSpeed = speed;
}

#if UNITY_EDITOR
Expand All @@ -128,9 +140,17 @@ private void Update()
private void OnValidate()
{
m_AnimatorVariableHash = Animator.StringToHash(m_AnimatorVariable);
Assert.IsTrue(m_AnimatorVariableHash != 0);

if (m_AudioSource == null)
{
m_AudioSource = GetComponent<AudioSource>();
}
Assert.IsNotNull(m_AudioSource);

Assert.IsNotNull(m_WalkFootstepAudioClip);

Assert.IsNotNull(m_RunFootstepAudioClip);
}
#endif
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Assertions;
using Unity.Multiplayer.Samples.BossRoom.Client;

namespace Unity.Multiplayer.Samples.BossRoom.Visual
Expand Down Expand Up @@ -60,6 +59,10 @@ public class ClientCharacterVisualization : NetworkBehaviour

Quaternion m_LerpedRotation;

bool m_IsHost;

float m_CurrentSpeed;

void Awake()
{
enabled = false;
Expand All @@ -74,6 +77,8 @@ public override void OnNetworkSpawn()

enabled = true;

m_IsHost = IsHost;

m_ActionViz = new ActionVisualization(this);

m_NetState = GetComponentInParent<NetworkCharacterState>();
Expand All @@ -85,6 +90,8 @@ public override void OnNetworkSpawn()
m_NetState.CancelActionsByTypeEventClient += CancelActionFXByType;
m_NetState.OnStopChargingUpClient += OnStoppedChargingUp;
m_NetState.IsStealthy.OnValueChanged += OnStealthyChanged;
m_NetState.MovementStatus.OnValueChanged += OnMovementStatusChanged;
OnMovementStatusChanged(MovementStatus.Normal,m_NetState.MovementStatus.Value);

// sync our visualization position & rotation to the most up to date version received from server
transform.SetPositionAndRotation(m_PhysicsWrapper.Transform.position, m_PhysicsWrapper.Transform.rotation);
Expand Down Expand Up @@ -210,15 +217,14 @@ void SetAppearanceSwap()
/// <summary>
/// Returns the value we should set the Animator's "Speed" variable, given current gameplay conditions.
/// </summary>
float GetVisualMovementSpeed()
float GetVisualMovementSpeed(MovementStatus movementStatus)
{
Assert.IsNotNull(m_VisualizationConfiguration);
if (m_NetState.NetworkLifeState.LifeState.Value != LifeState.Alive)
{
return m_VisualizationConfiguration.SpeedDead;
}

switch (m_NetState.MovementStatus.Value)
switch (movementStatus)
{
case MovementStatus.Idle:
return m_VisualizationConfiguration.SpeedIdle;
Expand All @@ -233,17 +239,22 @@ float GetVisualMovementSpeed()
case MovementStatus.Walking:
return m_VisualizationConfiguration.SpeedWalking;
default:
throw new Exception($"Unknown MovementStatus {m_NetState.MovementStatus.Value}");
throw new Exception($"Unknown MovementStatus {movementStatus}");
}
}

void OnMovementStatusChanged(MovementStatus previousValue, MovementStatus newValue)
{
m_CurrentSpeed = GetVisualMovementSpeed(newValue);
}

void Update()
{
// On the host, Characters are translated via ServerCharacterMovement's FixedUpdate method. To ensure that
// the game camera tracks a GameObject moving in the Update loop and therefore eliminate any camera jitter,
// this graphics GameObject's position is smoothed over time on the host. Clients do not need to perform any
// positional smoothing since NetworkTransform will interpolate position updates on the root GameObject.
if (IsHost)
if (m_IsHost)
{
// Note: a cached position (m_LerpedPosition) and rotation (m_LerpedRotation) are created and used as
// the starting point for each interpolation since the root's position and rotation are modified in
Expand All @@ -258,7 +269,7 @@ void Update()
if (m_ClientVisualsAnimator)
{
// set Animator variables here
OurAnimator.SetFloat(m_VisualizationConfiguration.SpeedVariableID, GetVisualMovementSpeed());
OurAnimator.SetFloat(m_VisualizationConfiguration.SpeedVariableID, m_CurrentSpeed);
}

m_ActionViz.Update();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public class ServerCharacterMovement : NetworkBehaviour

private MovementState m_MovementState;

MovementStatus m_PreviousState;

[SerializeField]
private ServerCharacter m_CharLogic;

Expand Down Expand Up @@ -169,7 +171,12 @@ private void FixedUpdate()
{
PerformMovement();

m_NetworkCharacterState.MovementStatus.Value = GetMovementStatus();
var currentState = GetMovementStatus(m_MovementState);
if (m_PreviousState != currentState)
{
m_NetworkCharacterState.MovementStatus.Value = currentState;
m_PreviousState = currentState;
}
}

public override void OnNetworkDespawn()
Expand Down Expand Up @@ -259,9 +266,9 @@ private float GetBaseMovementSpeed()
/// Determines the appropriate MovementStatus for the character. The
/// MovementStatus is used by the client code when animating the character.
/// </summary>
private MovementStatus GetMovementStatus()
private MovementStatus GetMovementStatus(MovementState movementState)
{
switch (m_MovementState)
switch (movementState)
{
case MovementState.Idle:
return MovementStatus.Idle;
Expand Down
7 changes: 5 additions & 2 deletions Assets/BossRoom/Scripts/Shared/Game/Action/ActionBase.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using UnityEngine;

namespace Unity.Multiplayer.Samples.BossRoom
Expand Down Expand Up @@ -31,8 +32,10 @@ public ActionDescription Description
{
get
{
var found = GameDataSource.Instance.ActionDataByType.TryGetValue(Data.ActionTypeEnum, out var result);
Debug.AssertFormat(found, "Tried to find ActionType %s but it was missing from GameDataSource!", Data.ActionTypeEnum);
if (!GameDataSource.Instance.ActionDataByType.TryGetValue(Data.ActionTypeEnum, out var result))
{
throw new KeyNotFoundException($"Tried to find ActionType {Data.ActionTypeEnum} but it was missing from GameDataSource!");
}

return result;
}
Expand Down
18 changes: 11 additions & 7 deletions Assets/BossRoom/Scripts/Shared/Net/NetworkStats.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,14 @@ public ExponentialMovingAverageCalculator(float average)

ClientRpcParams m_PongClientParams;

bool m_IsServer;

string m_TextToDisplay;

public override void OnNetworkSpawn()
{
m_IsServer = IsServer;

bool isClientOnly = IsClient && !IsServer;
if (!IsOwner && isClientOnly) // we don't want to track player ghost stats, only our own
{
Expand Down Expand Up @@ -101,8 +107,7 @@ void InitializeTextLine(string defaultText, out TextMeshProUGUI textComponent)

void FixedUpdate()
{
var textToDisplay = string.Empty;
if (!IsServer)
if (!m_IsServer)
{
if (Time.realtimeSinceStartup - m_LastPingTime > k_PingIntervalSeconds)
{
Expand All @@ -118,18 +123,17 @@ void FixedUpdate()

if (m_TextStat != null)
{
textToDisplay = $"{textToDisplay}RTT: {(m_BossRoomRTT.Average * 1000).ToString("0")} ms;\nUTP RTT {m_UtpRTT.Average.ToString("0")} ms";
m_TextToDisplay = $"RTT: {(m_BossRoomRTT.Average * 1000).ToString("0")} ms;\nUTP RTT {m_UtpRTT.Average.ToString("0")} ms";
}
}

if (IsServer)
else
{
textToDisplay = $"{textToDisplay}Connected players: {NetworkManager.Singleton.ConnectedClients.Count.ToString()} ";
m_TextToDisplay = $"Connected players: {NetworkManager.Singleton.ConnectedClients.Count.ToString()}";
}

if (m_TextStat)
{
m_TextStat.text = textToDisplay;
m_TextStat.text = m_TextToDisplay;
}
}

Expand Down