Search Unity

Third Party Mirror MMO enemies, what approach should I use?

Discussion in 'Multiplayer' started by Varga87, Nov 7, 2022.

  1. Varga87

    Varga87

    Joined:
    Jun 3, 2019
    Posts:
    6
    HI all! Im making a MMO using Mirror networking and have some thoughts and questions about how to do the AI- enemies. I cant really get it to work as i want for my clients.

    My approach right now is to use a stateMachine and have separate states for the server and client. The server is in charge of switching state and I have a syncVar hook who switches the client state when server changes. I'm beginning tho think that maybe I should let the client handle all the logic and states and only update SyncVars via commands to the server, and get rid of the server states all along.

    Heres an example of how it looks in my Idle states:
    Code (CSharp):
    1.   void Update()
    2.     {
    3.         if (isClient)
    4.         {
    5.             ClientState.Tick(Time.deltaTime);
    6.         }
    7.  
    8.         if (isServer) && IsWorthUpdating())
    9.         {
    10.             ServerState.Tick(Time.deltaTime);
    11.         }
    12.     }
    Code (CSharp):
    1.  public class ServerEnemyIdleState : NetworkEnemyBaseState
    2. {
    3.     private float roamTimer;
    4.  
    5.     public ServerEnemyIdleState(NetworkEnemyStateMachine stateMachine) : base(stateMachine) {}
    6.  
    7.     public override void Enter() {
    8.         stateMachine.health.regenerateHealth = true;
    9.         roamTimer = UnityEngine.Random.Range(10f, 20f);
    10.     }
    11.  
    12.     public override void Tick(float deltaTime)
    13.     {
    14.         if (stateMachine.target != null) {
    15.             stateMachine.SwitchServerState(new ServerEnemyChaseState(stateMachine), NetworkEnemyStateMachine.EState.Chase);
    16.         }
    17.  
    18.         if (stateMachine.Roaming) {
    19.             roamTimer -= deltaTime;
    20.             if (roamTimer <= 0f) {
    21.                 stateMachine.SwitchServerState(new ServerEnemyRoamingState(stateMachine), NetworkEnemyStateMachine.EState.Roam);
    22.             }
    23.         }
    24.  
    25.         Move(deltaTime);
    26.     }
    27.  
    28.     public override void Exit() {
    29.         stateMachine.health.regenerateHealth = false;
    30.     }
    31. }
    Code (CSharp):
    1.  public class ClientEnemyIdleState : NetworkEnemyBaseState
    2. {
    3.     private readonly int LocomotionBlendTreeHash = Animator.StringToHash("Locomotion");
    4.     private readonly int SpeedHash = Animator.StringToHash("Speed");
    5.     private const float CrossFadeDureation = 0.1f;
    6.     private const float AnimatorDampTime = 0.1f;
    7.  
    8.     public ClientEnemyIdleState(NetworkEnemyStateMachine stateMachine) : base(stateMachine) {}
    9.  
    10.     public override void Enter()
    11.     {
    12.       stateMachine.Animator.CrossFadeInFixedTime(LocomotionBlendTreeHash, CrossFadeDureation);
    13.     }
    14.  
    15.     public override void Tick(float deltaTime)
    16.     {
    17.       stateMachine.Animator.SetFloat(SpeedHash, 0f, AnimatorDampTime, deltaTime);
    18.     }
    19.  
    20.     public override void Exit() {}
    21. }
    22.  
    23.  
    Would love some useful input on this approach because I'm starting to think I might be complicating things for me a little too much.