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
}
}