浏览代码

2nd pass on action system. Not properly replicating to clients yet

/main
David Woodruff 3 年前
当前提交
574fd252
共有 13 个文件被更改,包括 288 次插入47 次删除
  1. 38
      Assets/BossRoom/Models/CharacterSetController.controller
  2. 17
      Assets/BossRoom/Scripts/Client/ClientCharacterVisualization.cs
  3. 11
      Assets/BossRoom/Scripts/Client/ClientInputSender.cs
  4. 6
      Assets/BossRoom/Scripts/Client/Game/Character/ClientCharacter.cs
  5. 72
      Assets/BossRoom/Scripts/Server/Game/Action/Action.cs
  6. 52
      Assets/BossRoom/Scripts/Server/Game/Character/ServerCharacter.cs
  7. 1
      Assets/BossRoom/Scripts/Server/ServerCharacterMovement.cs
  8. 2
      Assets/BossRoom/Scripts/Shared/Game/Action/ActionRequestData.cs
  9. 18
      Assets/BossRoom/Scripts/Shared/NetworkCharacterState.cs
  10. 74
      Assets/BossRoom/Scripts/Server/Game/Action/ActionPlayer.cs
  11. 11
      Assets/BossRoom/Scripts/Server/Game/Action/ActionPlayer.cs.meta
  12. 22
      Assets/BossRoom/Scripts/Server/Game/Action/MeleeAction.cs
  13. 11
      Assets/BossRoom/Scripts/Server/Game/Action/MeleeAction.cs.meta

38
Assets/BossRoom/Models/CharacterSetController.controller


m_Name: Blend Tree
m_Childs:
- serializedVersion: 2
m_Motion: {fileID: 1827226128182048838, guid: 2115c4661f55eff45a5a0f91fc0a12f0,
type: 3}
m_Motion: {fileID: 1827226128182048838, guid: 2115c4661f55eff45a5a0f91fc0a12f0, type: 3}
m_Threshold: 0
m_Position: {x: 0, y: 0}
m_TimeScale: 1

- serializedVersion: 2
m_Motion: {fileID: -3419257869308726280, guid: 2115c4661f55eff45a5a0f91fc0a12f0,
type: 3}
m_Motion: {fileID: -3419257869308726280, guid: 2115c4661f55eff45a5a0f91fc0a12f0, type: 3}
m_Threshold: 0.5
m_Position: {x: 0, y: 0}
m_TimeScale: 1

- serializedVersion: 2
m_Motion: {fileID: 6200578666267062213, guid: 2115c4661f55eff45a5a0f91fc0a12f0,
type: 3}
m_Motion: {fileID: 6200578666267062213, guid: 2115c4661f55eff45a5a0f91fc0a12f0, type: 3}
m_Threshold: 1
m_Position: {x: 0, y: 0}
m_TimeScale: 1

m_CanTransitionToSelf: 1
--- !u!1102 &-3516404760485336223
AnimatorState:
serializedVersion: 5
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}

m_BlendType: 0
--- !u!1101 &-2134875305200649429
AnimatorStateTransition:
m_ObjectHideFlags: 3
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}

m_CanTransitionToSelf: 1
--- !u!1102 &-1068572555509609370
AnimatorState:
serializedVersion: 5
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}

m_TimeParameter:
--- !u!1107 &-881976854541045011
AnimatorStateMachine:
serializedVersion: 5
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}

m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 9100000}
m_Controller: {fileID: 0}
m_Controller: {fileID: 9100000}
m_Controller: {fileID: 0}
m_Controller: {fileID: 9100000}
m_Controller: {fileID: 0}
m_Controller: {fileID: 9100000}
m_Controller: {fileID: 0}
m_AnimatorLayers:
- serializedVersion: 5
m_Name: Base Layer

m_Controller: {fileID: 9100000}
--- !u!1107 &2782526268344220699
AnimatorStateMachine:
serializedVersion: 5
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}

m_DefaultState: {fileID: 0}
--- !u!1101 &3218047883308753838
AnimatorStateTransition:
m_ObjectHideFlags: 3
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}

m_CanTransitionToSelf: 1
--- !u!1101 &5593412509193387231
AnimatorStateTransition:
m_ObjectHideFlags: 3
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}

serializedVersion: 1
--- !u!1102 &6299315480180736668
AnimatorState:
serializedVersion: 5
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}

m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: -6239216113759591374, guid: 2115c4661f55eff45a5a0f91fc0a12f0,
type: 3}
m_Motion: {fileID: -6239216113759591374, guid: 2115c4661f55eff45a5a0f91fc0a12f0, type: 3}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:

AnimatorStateMachine:
serializedVersion: 5
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}

17
Assets/BossRoom/Scripts/Client/ClientCharacterVisualization.cs


using BossRoom.Shared;
namespace BossRoom.Client
namespace BossRoom.Viz
{
/// <summary>
/// <see cref="ClientCharacterVisualization"/> is responsible for displaying a character on the client's screen based on state information sent by the server.

if (!IsClient && !IsHost)
{
enabled = false;
return;
else if (IsLocalPlayer)
networkCharacterState.DoActionEvent += this.PerformActionFX;
if (IsLocalPlayer)
}
private void PerformActionFX(ActionRequestData data )
{
//TODO: [GOMPS-13] break this method out into its own class, so we can drive multi-frame graphical effects.
//FIXME: [GOMPS-13] hook this up to information in the ActionDescription.
m_ClientVisualsAnimator.SetInteger("AttackID", 1);
m_ClientVisualsAnimator.SetTrigger("BeginAttack");
}
void Awake()

11
Assets/BossRoom/Scripts/Client/ClientInputSender.cs


using BossRoom.Shared;
using MLAPI;
using UnityEngine;

// The MLAPI_INTERNAL channel is a reliable sequenced channel. Inputs should always arrive and be in order that's why this channel is used.
networkCharacter.InvokeServerRpc(networkCharacter.SendCharacterInputServerRpc, hit.point, "MLAPI_INTERNAL");
}
}
}
private void Update()
{
if (Input.GetMouseButtonDown(1))
{
var data = new ActionRequestData();
data.ActionTypeEnum = Action.TANK_BASEATTACK;
networkCharacter.C2S_DoAction(ref data);
}
}
}

6
Assets/BossRoom/Scripts/Client/Game/Character/ClientCharacter.cs


namespace BossRoom.Client
{
[RequireComponent(typeof(BossRoom.Shared.NetworkCharacterState))]
[RequireComponent(typeof(BossRoom.NetworkCharacterState))]
public override void NetworkStart()
{
if( !IsClient ) { this.enabled = false; }
}
// Start is called before the first frame update

72
Assets/BossRoom/Scripts/Server/Game/Action/Action.cs


/// The Action System is a generalized mechanism for Characters to "do stuff" in a networked way. Actions
/// include everything from your basic character attack, to a fancy skill like the Archer's Volley Shot, but also
/// include more mundane things like pulling a lever.
/// For every ActionLogic enum, there will be one specialization of this class.
/// There is only ever one active Action at a time on a character, but multiple Actions may exist at once, with subsequent Actions
/// pending behind the currently playing one. See ActionPlayer.cs
protected ServerCharacter m_parent;
/// <summary>
/// The level this action plays back at. e.g. a weak "level 0" melee attack, vs a strong "level 3" melee attack.
/// </summary>
protected int m_level;
private ActionRequestData m_data;
/// <summary>
/// RequestData we were instantiated with. Value should be treated as readonly.
/// </summary>
public ref ActionRequestData Data { get { return ref m_data; } }
/// <summary>
/// Data Description for this action.
/// </summary>
public ActionDescription Description
{
get
{
var list = ActionDescriptionList.LIST[Data.ActionTypeEnum];
int level = Mathf.Min(m_level, list.Count - 1); //if we don't go up to the requested level, just cap at the max level.
return list[level];
}
}
/// <summary>
/// constructor. The "data" parameter should not be retained after passing in to this method, because we take ownership of its internal memory.
/// </summary>
public Action(ServerCharacter parent, ref ActionRequestData data, int level)
{
m_parent = parent;
m_level = level;
m_data = data; //do a shallow copy.
m_data.Level = level;
}
/// <summary>
/// Called when the Action starts actually playing (which may be after it is created, because of queueing).
/// </summary>
/// <returns>false if the action decided it doesn't want to run after all, true otherwise. </returns>
public abstract bool Start();
/// <summary>
/// Called each frame while the action is running.
/// </summary>
/// <returns>true to keep running, false to stop. The Action will stop by default when its duration expires, if it has a duration set. </returns>
public abstract bool Update();
/// <summary>
/// Factory method that creates Actions from their request data.
/// </summary>
/// <param name="state">the NetworkCharacterState of the character that owns our ActionPlayer</param>
/// <param name="data">the data to instantiate this skill from. </param>
/// <param name="level">the level to play the skill at. </param>
/// <returns>the newly created action. </returns>
public static Action MakeAction(ServerCharacter parent, ref ActionRequestData data, int level )
{
var logic = ActionDescriptionList.LIST[data.ActionTypeEnum][0].Logic;
switch(logic)
{
case ActionLogic.MELEE: return new MeleeAction(parent, ref data, level);
default: throw new System.NotImplementedException();
}
}
}

52
Assets/BossRoom/Scripts/Server/Game/Character/ServerCharacter.cs


using System.Collections.Generic;
using UnityEngine;
public class ServerCharacter : MLAPI.NetworkedBehaviour
namespace BossRoom.Server
// Start is called before the first frame update
void Start()
[RequireComponent(typeof(NetworkCharacterState))]
public class ServerCharacter : MLAPI.NetworkedBehaviour
}
public NetworkCharacterState NetState { get; private set; }
public override void NetworkStart()
{
if( !IsServer ) { this.enabled = false; }
}
private ActionPlayer m_actionPlayer;
// Update is called once per frame
void Update()
{
// Start is called before the first frame update
void Start()
{
NetState = GetComponent<NetworkCharacterState>();
m_actionPlayer = new ActionPlayer(this);
}
public override void NetworkStart()
{
if (!IsServer) { this.enabled = false; }
else
{
this.NetState.DoActionEvent += this.OnActionPlayRequest;
}
}
public void PlayAction(ref ActionRequestData data )
{
this.m_actionPlayer.PlayAction(ref data);
}
private void OnActionPlayRequest( ActionRequestData data )
{
Debug.Log("Server receiving action request for " + data.ActionTypeEnum);
this.PlayAction(ref data);
}
// Update is called once per frame
void Update()
{
m_actionPlayer.Update();
}
}
}

1
Assets/BossRoom/Scripts/Server/ServerCharacterMovement.cs


using System;
using System.Linq;
using BossRoom.Shared;
using MLAPI;
using UnityEngine;
using UnityEngine.AI;

2
Assets/BossRoom/Scripts/Shared/Game/Action/ActionRequestData.cs


public Vector3 Position; //center position of skill, e.g. "ground zero" of a fireball skill.
public Vector3 Direction; //direction of skill, if not inferrable from the character's current facing.
public int[] TargetIds; //networkIds of targets, or null if untargeted.
int Level; //what level the Action plays at (server->client only).
public int Level; //what level the Action plays at (server->client only). Levels are 0-based, with 0 being weakest.
}

18
Assets/BossRoom/Scripts/Shared/NetworkCharacterState.cs


using (PooledBitStream stream = PooledBitStream.Get())
{
SerializeAction(ref data, stream);
InvokeServerRpcPerformance(RecvDoAction, stream);
InvokeServerRpcPerformance(RecvDoActionServer, stream);
}
}

using (PooledBitStream stream = PooledBitStream.Get())
{
SerializeAction(ref data, stream);
InvokeClientRpcOnEveryonePerformance(RecvDoAction, stream);
InvokeClientRpcOnEveryonePerformance(RecvDoActionClient, stream);
}
}

}
}
[ServerRPC, ClientRPC]
[ClientRPC]
private void RecvDoActionClient(ulong clientId, Stream stream )
{
RecvDoAction(clientId, stream);
}
[ServerRPC]
private void RecvDoActionServer(ulong clientId, Stream stream)
{
RecvDoAction(clientId, stream);
}
private void RecvDoAction(ulong clientId, Stream stream )
{
ActionRequestData data = new ActionRequestData();

74
Assets/BossRoom/Scripts/Server/Game/Action/ActionPlayer.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BossRoom.Server
{
/// <summary>
/// Class responsible for playing back action inputs from user.
/// </summary>
public class ActionPlayer
{
private ServerCharacter m_parent;
private List<Action> m_queue;
private float m_actionStarted_s = 0f;
public ActionPlayer(ServerCharacter parent )
{
m_parent = parent;
m_queue = new List<Action>();
}
public void PlayAction(ref ActionRequestData data )
{
int level = 0; //todo, get this from parent's networked vars, maybe.
var new_action = Action.MakeAction(m_parent, ref data, level);
bool was_empty = m_queue.Count == 0;
m_queue.Add(new_action);
if( was_empty )
{
AdvanceQueue(false);
}
}
/// <summary>
/// Optionally end the currently playing action, and advance to the next Action that wants to play.
/// </summary>
/// <param name="expireFirstElement">Pass true to remove the first element and advance to the next element. Pass false to "advance" to the 0th element</param>
private void AdvanceQueue(bool expireFirstElement)
{
if( expireFirstElement && m_queue.Count > 0 )
{
m_queue.RemoveAt(0);
}
if( m_queue.Count > 0 )
{
m_actionStarted_s = Time.time;
bool play = m_queue[0].Start();
if( !play )
{
AdvanceQueue(true);
}
}
}
public void Update()
{
if( this.m_queue.Count > 0 )
{
bool keepgoing = this.m_queue[0].Update();
bool time_expired = (Time.time - this.m_actionStarted_s) >= this.m_queue[0].Description.Duration_s;
if ( !keepgoing || time_expired )
{
this.AdvanceQueue(true);
}
}
}
}
}

11
Assets/BossRoom/Scripts/Server/Game/Action/ActionPlayer.cs.meta


fileFormatVersion: 2
guid: cfede55de1de006448fa960048736574
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

22
Assets/BossRoom/Scripts/Server/Game/Action/MeleeAction.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BossRoom.Server
{
public class MeleeAction : Action
{
public MeleeAction(ServerCharacter parent, ref ActionRequestData data, int level) : base(parent, ref data, level)
{
}
public override bool Start()
{
//stub. For now, just relay the action to all clients.
m_parent.NetState.S2C_BroadcastAction(ref Data);
return true;
}
public override bool Update() { return true; }
}
}

11
Assets/BossRoom/Scripts/Server/Game/Action/MeleeAction.cs.meta


fileFormatVersion: 2
guid: 62b840a5705be5b4b9c5f9926aafcc85
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存