ProjectDDD/Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/Manager/ExtraDatabases.cs
2025-07-08 19:46:31 +09:00

345 lines
12 KiB
C#

// Copyright (c) Pixel Crushers. All rights reserved.
using UnityEngine;
using System.Collections;
namespace PixelCrushers.DialogueSystem
{
/// <summary>
/// Adds and removes extra dialogue databases.
/// </summary>
[AddComponentMenu("")] // Use wrapper.
public class ExtraDatabases : MonoBehaviour
{
/// <summary>
/// Add the databases when this trigger occurs.
/// </summary>
public DialogueTriggerEvent addTrigger = DialogueTriggerEvent.OnStart;
/// <summary>
/// Remove the databases when this trigger occurs.
/// </summary>
public DialogueTriggerEvent removeTrigger = DialogueTriggerEvent.None;
/// <summary>
/// The databases to add/remove.
/// </summary>
public DialogueDatabase[] databases = new DialogueDatabase[0];
/// <summary>
/// The condition that must be true for the trigger to fire.
/// </summary>
public Condition condition = new Condition();
/// <summary>
/// As soon as one event (add or remove) has occurred, destroy this component.
/// </summary>
[Tooltip("As soon as one event (add or remove) has occurred, destroy this component.")]
public bool once = false;
/// <summary>
/// Add/remove one database per frame instead of adding them all at the same time.
/// Useful to avoid stutter when adding several databases.
/// </summary>
[Tooltip("Add/remove one database per frame instead of adding them all at the same time. Useful to avoid stutter when adding several databases.")]
public bool onePerFrame = false;
/// <summary>
/// This event is called after ExtraDatabases has finished adding its list of databases
/// to the DialogueManager's MasterDatabase.
/// </summary>
public static event System.Action addedDatabases = delegate { };
/// <summary>
/// This event is called after ExtraDatabases has finished removing its list of databases
/// from the DialogueManager's MasterDatabase.
/// </summary>
public static event System.Action removedDatabases = delegate { };
#if UNITY_2019_3_OR_NEWER && UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void InitStaticVariables()
{
addedDatabases = delegate { };
removedDatabases = delegate { };
}
#endif
protected bool m_trying = false;
protected Coroutine m_destroyCoroutine = null;
protected int m_numActiveCoroutines = 0;
protected DialogueDatabase[] databaseInstances = null;
protected virtual void TryAddDatabases(Transform interactor, bool onePerFrame)
{
if (DialogueManager.instance == null) return;
if (!m_trying)
{
m_trying = true;
try
{
if ((condition == null) || condition.IsTrue(interactor))
{
AddDatabases(onePerFrame);
}
}
finally
{
m_trying = false;
}
}
}
public virtual void AddDatabases(bool onePerFrame)
{
if (DialogueManager.instance.instantiateDatabase)
{
if (databaseInstances != null && databaseInstances.Length != databases.Length)
{
foreach (var instance in databaseInstances)
{
Destroy(instance);
}
databaseInstances = null;
}
if (databaseInstances == null)
{
databaseInstances = new DialogueDatabase[databases.Length];
for (int i = 0; i < databases.Length; i++)
{
databaseInstances[i] = Instantiate(databases[i]);
}
}
}
if (onePerFrame)
{
StartCoroutine(AddDatabasesCoroutine());
}
else if (gameObject.activeInHierarchy && enabled)
{
AddDatabasesImmediate();
}
}
protected virtual void AddDatabasesImmediate()
{
for (int i = 0; i < databases.Length; i++)
{
if (DialogueManager.instance.instantiateDatabase)
{
AddDatabase(databaseInstances[i]);
}
else
{
AddDatabase(databases[i]);
}
}
addedDatabases();
if (once) Destroy(this);
}
protected virtual IEnumerator AddDatabasesCoroutine()
{
m_numActiveCoroutines++;
if (once && m_destroyCoroutine == null) m_destroyCoroutine = StartCoroutine(DestroyCoroutine());
for (int i = 0; i < databases.Length; i++)
{
if (DialogueManager.instance.instantiateDatabase)
{
AddDatabase(databaseInstances[i]);
}
else
{
AddDatabase(databases[i]);
}
yield return null;
}
addedDatabases();
m_numActiveCoroutines--;
}
protected virtual void AddDatabase(DialogueDatabase database)
{
if (database != null)
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: Adding database " + database.name, this);
DialogueManager.AddDatabase(database);
}
}
protected virtual void TryRemoveDatabases(Transform interactor, bool onePerFrame)
{
if (DialogueManager.instance == null) return;
if (!m_trying)
{
m_trying = true;
try
{
if ((condition == null) || condition.IsTrue(interactor))
{
RemoveDatabases(onePerFrame);
}
}
finally
{
m_trying = false;
}
}
}
public virtual void RemoveDatabases(bool onePerFrame)
{
if (onePerFrame)
{
StartCoroutine(RemoveDatabasesCoroutine());
}
else if (gameObject.activeInHierarchy && enabled)
{
RemoveDatabasesImmediate();
}
}
protected virtual void RemoveDatabasesImmediate()
{
foreach (var database in databases)
{
RemoveDatabase(database);
}
removedDatabases();
if (once) Destroy(this);
}
protected virtual IEnumerator RemoveDatabasesCoroutine()
{
m_numActiveCoroutines++;
if (once && m_destroyCoroutine == null) m_destroyCoroutine = StartCoroutine(DestroyCoroutine());
foreach (var database in databases)
{
RemoveDatabase(database);
yield return null;
}
removedDatabases();
m_numActiveCoroutines--;
}
protected virtual void RemoveDatabase(DialogueDatabase database)
{
if (database != null)
{
if (DialogueDebug.logInfo) Debug.Log("Dialogue System: Removing database " + database.name, this);
DialogueManager.RemoveDatabase(database);
}
}
protected virtual IEnumerator DestroyCoroutine()
{
// If Once is ticked and component both adds & removes databases, we need to wait for both to finish:
while (m_numActiveCoroutines > 0)
{
yield return null;
}
m_destroyCoroutine = null;
Destroy(this);
}
public virtual void Start()
{
if (addTrigger == DialogueTriggerEvent.OnStart || removeTrigger == DialogueTriggerEvent.OnStart)
{
StartCoroutine(StartEndOfFrame());
}
}
protected virtual IEnumerator StartEndOfFrame()
{
yield return CoroutineUtility.endOfFrame;
if (addTrigger == DialogueTriggerEvent.OnStart) TryAddDatabases(null, onePerFrame);
if (removeTrigger == DialogueTriggerEvent.OnStart) TryRemoveDatabases(null, onePerFrame);
}
public virtual void OnEnable()
{
if (addTrigger == DialogueTriggerEvent.OnEnable) TryAddDatabases(null, onePerFrame);
if (removeTrigger == DialogueTriggerEvent.OnEnable) TryRemoveDatabases(null, onePerFrame);
}
public virtual void OnDisable()
{
if (addTrigger == DialogueTriggerEvent.OnDisable) TryAddDatabases(null, false); // Can't run coroutine when disabled.
if (removeTrigger == DialogueTriggerEvent.OnDisable) TryRemoveDatabases(null, false);
}
public virtual void OnDestroy()
{
if (addTrigger == DialogueTriggerEvent.OnDestroy) TryAddDatabases(null, false); // Can't run coroutine when destroyed.
if (removeTrigger == DialogueTriggerEvent.OnDestroy) TryRemoveDatabases(null, false);
if (databaseInstances != null)
{
foreach (var databaseInstance in databaseInstances)
{
Destroy(databaseInstance);
}
}
}
public virtual void OnUse(Transform actor)
{
if (!enabled) return;
if (addTrigger == DialogueTriggerEvent.OnUse) TryAddDatabases(actor, onePerFrame);
if (removeTrigger == DialogueTriggerEvent.OnUse) TryRemoveDatabases(actor, onePerFrame);
}
public virtual void OnUse(string message)
{
if (!enabled) return;
if (addTrigger == DialogueTriggerEvent.OnUse) TryAddDatabases(null, onePerFrame);
if (removeTrigger == DialogueTriggerEvent.OnUse) TryRemoveDatabases(null, onePerFrame);
}
public virtual void OnUse()
{
if (!enabled) return;
if (addTrigger == DialogueTriggerEvent.OnUse) TryAddDatabases(null, onePerFrame);
if (removeTrigger == DialogueTriggerEvent.OnUse) TryRemoveDatabases(null, onePerFrame);
}
public virtual void OnTriggerEnter(Collider other)
{
if (!enabled) return;
if (addTrigger == DialogueTriggerEvent.OnTriggerEnter) TryAddDatabases(other.transform, onePerFrame);
if (removeTrigger == DialogueTriggerEvent.OnTriggerEnter) TryRemoveDatabases(other.transform, onePerFrame);
}
public virtual void OnTriggerExit(Collider other)
{
if (!enabled) return;
if (addTrigger == DialogueTriggerEvent.OnTriggerExit) TryAddDatabases(other.transform, onePerFrame);
if (removeTrigger == DialogueTriggerEvent.OnTriggerExit) TryRemoveDatabases(other.transform, onePerFrame);
}
#if USE_PHYSICS2D || !UNITY_2018_1_OR_NEWER
public virtual void OnTriggerEnter2D(Collider2D other)
{
if (!enabled) return;
if (addTrigger == DialogueTriggerEvent.OnTriggerEnter) TryAddDatabases(other.transform, onePerFrame);
if (removeTrigger == DialogueTriggerEvent.OnTriggerEnter) TryRemoveDatabases(other.transform, onePerFrame);
}
public virtual void OnTriggerExit2D(Collider2D other)
{
if (!enabled) return;
if (addTrigger == DialogueTriggerEvent.OnTriggerExit) TryAddDatabases(other.transform, onePerFrame);
if (removeTrigger == DialogueTriggerEvent.OnTriggerExit) TryRemoveDatabases(other.transform, onePerFrame);
}
#endif
}
}