using System; using System.Collections.Generic; using System.Threading.Tasks; using AudioSystem.Runtime; using FinTOKMAK.EventSystem.Runtime; using FinTOKMAK.TimelineSystem.Runtime; using UnityEngine; using UnityEngine.Serialization; namespace FinTOKMAK.WeaponSystem.Runtime { [System.Serializable] public class WeaponAudioEventConfig { /// /// The timeline event that trigger the audio. /// [TimelineEvent] public string eventName; /// /// The audio config of the audio to play. /// public AudioConfig audioConfig; } public class Weapon : ScriptableObject, IWeapon> where ConfigType : WeaponConfigData where RuntimeType : WeaponRuntimeData { #region Hide Public Field public string id => _configData.id; public int index { get; set; } public IWeaponData configData => _configData; public IWeaponData runtimeData => _runtimeData; public IWeaponManager> weaponManager { get => _weaponManager; set => _weaponManager = (WeaponManager)value; } public TimelineSystem.Runtime.TimelineSystem timelineSystem { get => _timelineSystem; set => _timelineSystem = value; } public TimelineEventManager timelineEventManager { get => _timelineEventManager; set => _timelineEventManager = value; } #endregion #region Protected Field #region Weapon Data [SerializeField] protected ConfigType _configData; protected RuntimeType _runtimeData; protected WeaponManager _weaponManager; protected TimelineSystem.Runtime.TimelineSystem _timelineSystem; protected TimelineEventManager _timelineEventManager; #endregion #region Weapon Events /// /// The TSC for finish put out event /// private TaskCompletionSource _finishPutoutSource; /// /// The TSC for finish put in event /// private TaskCompletionSource _finishPutinSource; #endregion #endregion #region Private Field private Dictionary> _audioActions = new Dictionary>(); #endregion #region Protected Methods /// /// Call this method to initialize all the TaskCompletionSource. /// protected virtual void InitTSC() { _finishPutoutSource = new TaskCompletionSource(); _finishPutinSource = new TaskCompletionSource(); } /// /// Call this method to register all the timeline events with corresponding weapon events. /// protected virtual void RegisterTimelineEvents() { foreach (string eventNames in _audioActions.Keys) { _timelineEventManager.RegisterEvent(eventNames, _audioActions[eventNames]); } _timelineEventManager.RegisterEvent(_configData.finishPutoutEvent, WeaponPutoutEvent); _timelineEventManager.RegisterEvent(_configData.finishPutinEvent, WeaponPutinEvent); } /// /// Call this method to unregister the timeline events with corresponding weapon events. /// protected virtual void UnregisterTimelineEvents() { foreach (string eventNames in _audioActions.Keys) { _timelineEventManager.UnRegisterEvent(eventNames, _audioActions[eventNames]); } _timelineEventManager.UnRegisterEvent(_configData.finishPutoutEvent, WeaponPutoutEvent); _timelineEventManager.UnRegisterEvent(_configData.finishPutinEvent, WeaponPutinEvent); } /// /// The method to call a Weapon RPC method. /// /// The method name. /// The method parameters. protected void CallRPC(string methodName, params object[] methodParams) { _weaponManager.weaponAgent.CallRPC(index, methodName, methodParams); } #endregion #region Audio Player private void InitAudioPlayers() { foreach (WeaponAudioEventConfig config in _configData.audioEventConfigs) { _configData.audioPlayerPrefab.audioConfig = config.audioConfig; AudioPlayer playerInstance = Instantiate(_configData.audioPlayerPrefab, _weaponManager.weaponMountPoint[_configData.audioMountPoint]); _audioActions.Add(config.eventName, data => { playerInstance.Play(); CallRPC("InvokeAudioEvent", config.eventName); }); } } /// /// The RPC method to invoke an audio event. /// /// the name of the audio event. public void InvokeAudioEvent(string eventName) { // Play the fire audio _timelineEventManager.InvokeEvent(eventName, new EventData()); } #endregion #region Timeline Events /// /// Timeline event invoked when the weapon finish put out. /// /// EventData private void WeaponPutoutEvent(IEventData data) { _finishPutoutSource.SetResult(true); } /// /// Timeline event invoked when the weapon finish put in. /// /// EventData private void WeaponPutinEvent(IEventData data) { _finishPutinSource.SetResult(true); } #endregion #region Life Cycle public virtual void OnInitialize() { InitTSC(); InitAudioPlayers(); // Convert the WeaponConfigData to the WeaponRuntimeData _runtimeData = (RuntimeType) _configData.ToRuntime(); // Change the using status. _runtimeData.usingStatus = WeaponUsingStatus.Background; } public virtual void OnUpdate() { } #endregion #region Put In And Put Out public virtual void OnPutOut() { // Register event listening. RegisterTimelineEvents(); // Play the put out timeline. _timelineSystem.PlayTimeline(_runtimeData.putoutTimline); // Change the using status. _runtimeData.usingStatus = WeaponUsingStatus.Using; } public virtual void OnFinishPutOut() { } public async Task OnPutOutAsync() { OnPutOut(); // Wait until the weapon finish put out. await _finishPutoutSource.Task; // Reset the _finishPutoutSource _finishPutoutSource = new TaskCompletionSource(); OnFinishPutOut(); } public virtual void OnPutIn() { // Play the put in Timeline _timelineSystem.PlayTimeline(_runtimeData.putinTimeline); } public virtual void OnFinishPutIn() { // Unregister event listening UnregisterTimelineEvents(); // Change the using status. _runtimeData.usingStatus = WeaponUsingStatus.Background; } public async Task OnPutInAsync() { OnPutIn(); // Wait until the weapon finish put in. await _finishPutinSource.Task; // Reset the _finishPutinSource _finishPutinSource = new TaskCompletionSource(); OnFinishPutIn(); } #endregion #region Weapon Operation public void Mount(GameObject instance, string mountPoint) { if (!_weaponManager.weaponMountPoint.ContainsKey(mountPoint)) { throw new InvalidOperationException($"No mount point name {mountPoint}"); } instance.transform.SetParent(_weaponManager.weaponMountPoint[mountPoint]); instance.transform.localScale = new Vector3(1, 1, 1); } public virtual void OnTriggerDown() { } public virtual void OnTriggerUp() { } public virtual void OnShootEnableChanged(bool enable) { } public virtual void OnReloadDown() { } public virtual void OnReloadUp() { } public virtual void OnReloadEnableChanged(bool enable) { } public virtual void OnAimDown() { } public virtual void OnAimUp() { } public virtual void OnAimEnableChanged(bool enable) { } #endregion } }