using System.Collections.Generic;
using UnityEngine;
namespace Unity.Cinemachine
{
///
/// Base class for a CinemachineCamera extension module.
/// Hooks into the Cinemachine Pipeline. Use this to add extra processing
/// to the vcam, modifying its generated state
///
public abstract class CinemachineExtension : MonoBehaviour
{
///
/// Extensions that need to save per-vcam state should inherit from this class and add
/// appropriate member variables. Use GetExtraState() to access.
///
protected class VcamExtraStateBase
{
/// The virtual camera being modified by the extension
public CinemachineVirtualCameraBase Vcam;
}
CinemachineVirtualCameraBase m_VcamOwner;
Dictionary m_ExtraState;
/// Useful constant for very small floats
protected const float Epsilon = UnityVectorExtensions.Epsilon;
/// Get the CinemachineVirtualCamera to which this extension is attached.
/// This is distinct from the CinemachineCameras that the extension will modify,
/// as extensions owned by manager cameras will be applied to all the CinemachineCamera children.
public CinemachineVirtualCameraBase ComponentOwner
{
get
{
if (m_VcamOwner == null)
TryGetComponent(out m_VcamOwner);
return m_VcamOwner;
}
}
/// Connect to virtual camera pipeline.
/// Override implementations must call this base implementation
protected virtual void Awake() => ConnectToVcam(true);
/// Disconnect from virtual camera pipeline.
/// Override implementations must call this base implementation
protected virtual void OnDestroy() => ConnectToVcam(false);
/// Does nothing. It's here for the little checkbox in the inspector.
protected virtual void OnEnable() {}
#if UNITY_EDITOR
[UnityEditor.Callbacks.DidReloadScripts]
static void OnScriptReload()
{
var extensions = Resources.FindObjectsOfTypeAll();
// Sort by execution order
System.Array.Sort(extensions, (x, y) =>
UnityEditor.MonoImporter.GetExecutionOrder(UnityEditor.MonoScript.FromMonoBehaviour(y))
- UnityEditor.MonoImporter.GetExecutionOrder(UnityEditor.MonoScript.FromMonoBehaviour(x)));
for (int i = 0; i < extensions.Length; ++i)
extensions[i].ConnectToVcam(true);
}
#endif
internal void EnsureStarted() => ConnectToVcam(true);
/// Connect to virtual camera. Implementation must be safe to be called
/// redundantly. Override implementations must call this base implementation
/// True if connecting, false if disconnecting
protected virtual void ConnectToVcam(bool connect)
{
if (ComponentOwner != null)
{
if (connect)
ComponentOwner.AddExtension(this);
else
ComponentOwner.RemoveExtension(this);
}
m_ExtraState = null;
}
/// Override this to do such things as offset the ReferenceLookAt.
/// Base class implementation does nothing.
/// The virtual camera being processed
/// Input state that must be mutated
/// The current applicable deltaTime
public virtual void PrePipelineMutateCameraStateCallback(
CinemachineVirtualCameraBase vcam, ref CameraState curState, float deltaTime) {}
/// Legacy support. This is only here to avoid changing the API
/// to make PostPipelineStageCallback() public
/// The virtual camera being processed
/// The current pipeline stage
/// The current virtual camera state
/// The current applicable deltaTime
public void InvokePostPipelineStageCallback(
CinemachineVirtualCameraBase vcam,
CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
{
PostPipelineStageCallback(vcam, stage, ref state, deltaTime);
}
///
/// This callback will be called after the virtual camera has implemented
/// each stage in the pipeline. This method may modify the referenced state.
/// If deltaTime less than 0, reset all state info and perform no damping.
///
/// The virtual camera being processed
/// The current pipeline stage
/// The current virtual camera state
/// The current applicable deltaTime
protected abstract void PostPipelineStageCallback(
CinemachineVirtualCameraBase vcam,
CinemachineCore.Stage stage, ref CameraState state, float deltaTime);
/// This is called to notify the extension that a target got warped,
/// so that the extension can update its internal state to make the camera
/// also warp seamlessly. Base class implementation does nothing.
/// Virtual camera to warp
/// The object that was warped
/// The amount the target's position changed
public virtual void OnTargetObjectWarped(
CinemachineVirtualCameraBase vcam, Transform target, Vector3 positionDelta) {}
///
/// Force the virtual camera to assume a given position and orientation
///
/// World-space position to take
/// World-space orientation to take
public virtual void ForceCameraPosition(Vector3 pos, Quaternion rot) {}
/// Notification that this virtual camera is going live.
/// Base class implementation must be called by any overridden method.
/// The camera being deactivated. May be null.
/// Default world Up, set by the CinemachineBrain
/// Delta time for time-based effects (ignore if less than or equal to 0)
/// True to request a vcam update of internal state
public virtual bool OnTransitionFromCamera(
ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime) => false;
///
/// Report maximum damping time needed for this extension.
/// Only used in editor for timeline scrubbing.
///
/// Highest damping setting in this extension
public virtual float GetMaxDampTime() => 0;
/// Because extensions can be placed on manager cams and will in that
/// case be called for all the vcam children, vcam-specific state information
/// should be stored here. Just define a class to hold your state info
/// and use it exclusively when calling this.
/// /// The type of the extra state class
/// The virtual camera being processed
/// The extra state, cast as type T
protected T GetExtraState(CinemachineVirtualCameraBase vcam) where T : VcamExtraStateBase, new()
{
if (m_ExtraState == null)
m_ExtraState = new ();
if (!m_ExtraState.TryGetValue(vcam, out var extra))
extra = m_ExtraState[vcam] = new T { Vcam = vcam};
return extra as T;
}
/// Get all extra state info for all vcams.
/// The extra state type
/// The list that will get populated with the extra states.
protected void GetAllExtraStates(List list) where T : VcamExtraStateBase, new()
{
list.Clear();
if (m_ExtraState != null)
{
var iter = m_ExtraState.GetEnumerator();
while (iter.MoveNext())
list.Add(iter.Current.Value as T);
}
}
}
}