305 lines
12 KiB (Stored with Git LFS)
C#
305 lines
12 KiB (Stored with Git LFS)
C#
// Copyright (c) Pixel Crushers. All rights reserved.
|
|
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace PixelCrushers.DialogueSystem
|
|
{
|
|
|
|
public enum BarkGroupQueueLimitMode { NoLimit, StopAtLimit, DropOldestAtLimit }
|
|
|
|
/// <summary>
|
|
/// Manages bark groups specified by BarkGroupMember.
|
|
/// Adds itself to the Dialogue Manager.
|
|
/// </summary>
|
|
[AddComponentMenu("")] // Added automatically at runtime.
|
|
public class BarkGroupManager : MonoBehaviour
|
|
{
|
|
|
|
public BarkGroupQueueLimitMode queueLimitMode = BarkGroupQueueLimitMode.NoLimit;
|
|
|
|
[Tooltip("Only used if mode is Stop At Limit or Drop Oldest At Limit")]
|
|
public int queueLimit = 256;
|
|
|
|
private static bool s_applicationIsQuitting = false;
|
|
private static BarkGroupManager s_instance = null;
|
|
public static BarkGroupManager instance
|
|
{
|
|
get
|
|
{
|
|
if (s_applicationIsQuitting) return null;
|
|
if (s_instance == null)
|
|
{
|
|
s_instance = DialogueManager.instance.GetComponent<BarkGroupManager>();
|
|
if (s_instance == null)
|
|
{
|
|
s_instance = DialogueManager.instance.gameObject.AddComponent<BarkGroupManager>();
|
|
}
|
|
}
|
|
return s_instance;
|
|
}
|
|
}
|
|
|
|
#if UNITY_2019_3_OR_NEWER && UNITY_EDITOR
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
|
static void InitStaticVariables()
|
|
{
|
|
s_applicationIsQuitting = false;
|
|
s_instance = null;
|
|
}
|
|
#endif
|
|
|
|
public Dictionary<string, HashSet<BarkGroupMember>> groups = new Dictionary<string, HashSet<BarkGroupMember>>();
|
|
|
|
private class BarkRequest
|
|
{
|
|
public BarkGroupMember member;
|
|
public Transform listener;
|
|
public string conversation;
|
|
public BarkHistory barkHistory;
|
|
public int entryID;
|
|
public string barkText;
|
|
public string sequence;
|
|
public AbstractBarkUI barkUI;
|
|
public float delayTime;
|
|
public bool isPlaying = false;
|
|
|
|
public BarkRequest(string conversation, BarkGroupMember member, Transform listener, BarkHistory barkHistory, int entryID = -1, float delayTime = -1)
|
|
{
|
|
this.member = member;
|
|
this.listener = listener;
|
|
this.conversation = conversation;
|
|
this.barkHistory = barkHistory;
|
|
this.entryID = entryID;
|
|
this.barkText = null;
|
|
this.sequence = null;
|
|
this.barkUI = GetBarkUI(member);
|
|
this.delayTime = GetDelayTime(member, delayTime);
|
|
}
|
|
|
|
public BarkRequest(string barkText, BarkGroupMember member, Transform listener, string sequence, float delayTime = -1)
|
|
{
|
|
this.member = member;
|
|
this.listener = listener;
|
|
this.conversation = null;
|
|
this.barkHistory = null;
|
|
this.entryID = -1;
|
|
this.barkText = barkText;
|
|
this.sequence = sequence;
|
|
this.barkUI = GetBarkUI(member);
|
|
this.delayTime = GetDelayTime(member, delayTime);
|
|
}
|
|
|
|
private AbstractBarkUI GetBarkUI(BarkGroupMember member)
|
|
{
|
|
if (member == null) return null;
|
|
var dialogueActor = member.GetComponentInChildren<DialogueActor>();
|
|
if (dialogueActor != null && dialogueActor.barkUISettings.barkUI != null) return dialogueActor.barkUISettings.barkUI;
|
|
return member.GetComponentInChildren<AbstractBarkUI>();
|
|
}
|
|
|
|
private float GetDelayTime(BarkGroupMember member, float delayTime)
|
|
{
|
|
if (delayTime >= 0) return delayTime;
|
|
return (member == null) ? 0 : Random.Range(member.minDelayBetweenQueuedBarks, member.maxDelayBetweenQueuedBarks);
|
|
}
|
|
}
|
|
|
|
private Dictionary<string, Queue<BarkRequest>> queues = new Dictionary<string, Queue<BarkRequest>>();
|
|
|
|
private void OnApplicationQuit()
|
|
{
|
|
s_applicationIsQuitting = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Registers a bark group member.
|
|
/// </summary>
|
|
public void AddToGroup(string groupId, BarkGroupMember member)
|
|
{
|
|
if (string.IsNullOrEmpty(groupId) || member == null) return;
|
|
if (!groups.ContainsKey(groupId)) groups.Add(groupId, new HashSet<BarkGroupMember>());
|
|
groups[groupId].Add(member);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unregisters a bark group member.
|
|
/// </summary>
|
|
public void RemoveFromGroup(string groupId, BarkGroupMember member)
|
|
{
|
|
if (string.IsNullOrEmpty(groupId) || member == null) return;
|
|
if (!groups.ContainsKey(groupId)) return;
|
|
if (!groups[groupId].Contains(member)) return;
|
|
groups[groupId].Remove(member);
|
|
if (groups[groupId].Count == 0) groups.Remove(groupId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hides all bark members' bark UIs and clears any queued barks.
|
|
/// </summary>
|
|
public void CancelAllBarks()
|
|
{
|
|
foreach (var queue in queues.Values)
|
|
{
|
|
queue.Clear();
|
|
}
|
|
foreach (var group in groups.Values)
|
|
{
|
|
foreach (var member in group)
|
|
{
|
|
if (member != null) member.CancelBark();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hides other members' barks if they're playing.
|
|
/// Pass null to hide all members' barks.
|
|
/// </summary>
|
|
public void MutexBark(string groupId, BarkGroupMember member)
|
|
{
|
|
if (string.IsNullOrEmpty(groupId)) return;
|
|
if (!groups.ContainsKey(groupId)) return;
|
|
foreach (var other in groups[groupId])
|
|
{
|
|
if (other == member) continue;
|
|
other.CancelBark();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Barks with group awareness.
|
|
/// </summary>
|
|
/// <param name="conversation">Conversation to bark from.</param>
|
|
/// <param name="member">Barker.</param>
|
|
/// <param name="listener">Bark target.</param>
|
|
/// <param name="barkHistory">Bark history.</param>
|
|
/// <param name="delayTime">Omit/zero to use the member's random delay settings; if nonzero, use this delay time.</param>
|
|
public void GroupBark(string conversation, BarkGroupMember member, Transform listener, BarkHistory barkHistory, float delayTime = 0)
|
|
{
|
|
if (member == null || !member.queueBarks)
|
|
{
|
|
DialogueManager.Bark(conversation, (member != null) ? member.transform : null, listener, barkHistory);
|
|
}
|
|
else
|
|
{
|
|
Enqueue(new BarkRequest(conversation, member, listener, barkHistory, -1, delayTime));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Barks with group awareness.
|
|
/// </summary>
|
|
/// <param name="conversation">Conversation to bark from.</param>
|
|
/// <param name="member">Barker.</param>
|
|
/// <param name="listener">Bark target.</param>
|
|
/// <param name="barkHistory">Bark history.</param>
|
|
/// <param name="delayTime">Omit/zero to use the member's random delay settings; if nonzero, use this delay time.</param>
|
|
public void GroupBark(string conversation, BarkGroupMember member, Transform listener, int entryID, float delayTime = 0)
|
|
{
|
|
if (member == null || !member.queueBarks)
|
|
{
|
|
DialogueManager.Bark(conversation, (member != null) ? member.transform : null, listener, entryID);
|
|
}
|
|
else
|
|
{
|
|
Enqueue(new BarkRequest(conversation, member, listener, null, entryID, delayTime));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Barks with group awareness.
|
|
/// </summary>
|
|
/// <param name="barkText">Text to bark.</param>
|
|
/// <param name="member">Barker.</param>
|
|
/// <param name="listener">Bark target.</param>
|
|
/// <param name="sequence">Optional sequence to play during the bark.</param>
|
|
/// <param name="delayTime">Omit/zero to use the member's random delay settings; if nonzero, use this delay time.</param>
|
|
public void GroupBarkString(string barkText, BarkGroupMember member, Transform listener, string sequence, float delayTime = 0)
|
|
{
|
|
if (member == null || !member.queueBarks)
|
|
{
|
|
DialogueManager.BarkString(barkText, (member != null) ? member.transform : null, listener, sequence);
|
|
}
|
|
else
|
|
{
|
|
Enqueue(new BarkRequest(barkText, member, listener, sequence, delayTime));
|
|
}
|
|
}
|
|
|
|
private void Enqueue(BarkRequest barkRequest)
|
|
{
|
|
var member = barkRequest.member;
|
|
if (member.evaluateIdEveryBark) member.UpdateMembership();
|
|
var groupId = member.currentIdValue;
|
|
if (!queues.ContainsKey(groupId)) queues.Add(groupId, new Queue<BarkRequest>());
|
|
var queue = queues[groupId];
|
|
if (queueLimitMode != BarkGroupQueueLimitMode.NoLimit && queue.Count > queueLimit)
|
|
{
|
|
switch (queueLimitMode)
|
|
{
|
|
case BarkGroupQueueLimitMode.StopAtLimit:
|
|
return;
|
|
case BarkGroupQueueLimitMode.DropOldestAtLimit:
|
|
queue.Dequeue();
|
|
break;
|
|
}
|
|
}
|
|
queue.Enqueue(barkRequest);
|
|
if (queue.Count == 1) barkRequest.delayTime = 0; // Play immediately.
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
// Check each group's queue:
|
|
var enumerator = queues.GetEnumerator(); // Enumerates manually to avoid garbage.
|
|
while (enumerator.MoveNext())
|
|
{
|
|
var queue = enumerator.Current.Value;
|
|
if (queue.Count == 0) continue;
|
|
var barkRequest = queue.Peek();
|
|
if (!barkRequest.isPlaying)
|
|
{
|
|
// If request at front of queue isn't playing yet, update time left:
|
|
barkRequest.delayTime -= Time.deltaTime;
|
|
if (barkRequest.delayTime <= 0)
|
|
{
|
|
// If it's now time, play the bark:
|
|
if (barkRequest.member == null || barkRequest.barkUI == null || (string.IsNullOrEmpty(barkRequest.conversation) && string.IsNullOrEmpty(barkRequest.barkText)))
|
|
{
|
|
queue.Dequeue();
|
|
}
|
|
else if (!string.IsNullOrEmpty(barkRequest.conversation))
|
|
{
|
|
if (barkRequest.entryID == -1)
|
|
{
|
|
DialogueManager.Bark(barkRequest.conversation, barkRequest.member.transform, barkRequest.listener, barkRequest.barkHistory);
|
|
}
|
|
else
|
|
{
|
|
DialogueManager.Bark(barkRequest.conversation, barkRequest.member.transform, barkRequest.listener, barkRequest.entryID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DialogueManager.BarkString(barkRequest.barkText, barkRequest.member.transform, barkRequest.listener, barkRequest.sequence);
|
|
}
|
|
barkRequest.isPlaying = true;
|
|
barkRequest.delayTime = 0.5f; // Wait a little for bark to set up before checking if it's done playing.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
barkRequest.delayTime -= Time.deltaTime;
|
|
if (barkRequest.delayTime <= 0 && !barkRequest.barkUI.isPlaying)
|
|
{
|
|
|
|
// If request at front of queue is playing but bark UI is done playing, dequeue:
|
|
queue.Dequeue();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|