text:
using UnityEditor;
using UnityEditorInternal;

namespace DialogSystem.ScriptObject.Editor
{
    [CustomEditor(typeof(DialogProgressAsset))]
    public class DialogProgressAssetEditor:UnityEditor.Editor
    {
        [MenuItem("ReadyGamerOne/DialogSystem/ShowDialogProgressPoints")]
        public static void CreateAsset()
        {
            Selection.activeInstanceID = DialogProgressAsset.Instance.GetInstanceID();
        }

        private SerializedProperty progressPointProp;
        private ReorderableList progressPointList;
        private DialogProgressAsset _dialogProgressAsset;
        private SerializedProperty currentProgressValueProp;
        private void OnEnable()
        {
            this._dialogProgressAsset=target as DialogProgressAsset;
            this.progressPointProp = serializedObject.FindProperty("DialogProgressPoints");
            this.currentProgressValueProp = serializedObject.FindProperty("currentProgress");
            this.progressPointList = new ReorderableList(serializedObject, progressPointProp, false, true, true, true);

            this.progressPointList.elementHeight = 2 * EditorGUIUtility.singleLineHeight;

            this.progressPointList.drawElementCallback = (rect, index, isActive, isFocus) =>
            {
                EditorGUI.PropertyField(rect, progressPointProp.GetArrayElementAtIndex(index));
            };

            this.progressPointList.drawHeaderCallback = (rect) => { EditorGUI.LabelField(rect, "剧情关键点"); };

            this.progressPointList.onAddCallback = (list) =>
            {
                var index = progressPointProp.arraySize;
                progressPointProp.InsertArrayElementAtIndex(index);
                var ele = progressPointProp.GetArrayElementAtIndex(index);
                ele.FindPropertyRelative("index").intValue = index;
                ele.FindPropertyRelative("name").stringValue = "";
                ele.FindPropertyRelative("value").floatValue = 0f;
            };
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            EditorGUILayout.PropertyField(currentProgressValueProp);
            progressPointList.DoLayoutList();
            foreach (var VARIABLE in _dialogProgressAsset.DialogProgressPoints)
            {
                if (string.IsNullOrEmpty(VARIABLE.name))
                {
                    EditorGUILayout.HelpBox("进度关键点名字不能为空！！", MessageType.Error);
                    break;
                }
            }
            serializedObject.ApplyModifiedProperties();
        }
    }
}


text:
using UnityEditor;

namespace DialogSystem.ScriptObject.Editor
{
    [CustomEditor(typeof(DialogSettings))]
    public class DialogSettingsEditor:UnityEditor.Editor
    {
        [MenuItem("ReadyGamerOne/DialogSystem/ShowDialogSettings")]
        public static void CreateAsset()
        {
            Selection.activeInstanceID = DialogSettings.Instance.GetInstanceID();
        }

        private SerializedProperty showDialogStackInfoProp;

        private void OnEnable()
        {
            showDialogStackInfoProp = serializedObject.FindProperty("ShowDialogStackInfo");
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            EditorGUILayout.Separator();
            EditorGUILayout.Separator();
            EditorGUILayout.LabelField("请注意！！！");
            EditorGUILayout.Separator();
            EditorGUILayout.LabelField("1、切换Scene的时候不能调用CEventCenter.Clear");
            EditorGUILayout.Separator();
            EditorGUILayout.Separator();
            EditorGUILayout.PropertyField(showDialogStackInfoProp);
            serializedObject.ApplyModifiedProperties();
        }
    }
}

mime_type: text/plain


text:
fileFormatVersion: 2
guid: 29916c46746ef134dab97ab9bdeaed6a
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: dafcdbdb88494e16a6f8bddf586a8c6a
timeCreated: 1618499773


text:
using System;
using System.Collections;
using DialogSystem.ScriptObject;
using UnityEngine;
using UnityEngine.UI;

namespace DialogSystem.Scripts
{
    /// <summary>
    /// 打字机效果
    /// </summary>
    [RequireComponent(typeof(Text))]
    public class TypeWriterEffect : MonoBehaviour
    {
        private Text thisText;

        private string fullWords;

        private Coroutine writerCoroutine;

        private Func<bool> pushFunc;

        private event Action onFinally;

        private void Update()
        {
            if (writerCoroutine != null)
            {
                if (pushFunc != null && pushFunc())
                {
                    if(DialogSettings.Instance.ShowDialogStackInfo)
                        print("打字机被打断");
                    StopCoroutine(writerCoroutine);
                    this.thisText.text = this.fullWords;
                    Finally();
                }
            }
        }

        private void Init()
        {
            if (thisText == null)
                this.thisText = GetComponent<Text>();
            if (string.IsNullOrEmpty(fullWords))
            {
                this.fullWords = thisText.text;
            }

            this.thisText.text = "";
        }

        public void StartWriter( float timeToEnd, Action endCall = null, Func<bool> pushFunc = null,
            bool affectedByTimeScale = true)
        {
            this.pushFunc = pushFunc;
            onFinally += endCall;
            Init();
            this.writerCoroutine = StartCoroutine(TypeWriter(this.fullWords.Length / timeToEnd, affectedByTimeScale));
        }

        private IEnumerator TypeWriter(float charPerSecond, bool affectedByTimeScale = true)
        {
            for (int i = 0; i < this.fullWords.Length; i++)
            {
                this.thisText.text = this.fullWords.Substring(0, i + 1);
                if (affectedByTimeScale)
                    yield return new WaitForSeconds(1 / charPerSecond);
                else
                {
                    for (var j = 0; j < 30 / charPerSecond; j++)
                        yield return 0;
                }
            }

            Finally();
        }

        private void Finally()
        {
            this.writerCoroutine = null;
            this.fullWords = null;
            onFinally?.Invoke();
            onFinally = null;
        }
    }
}


text:
using System;
using System.Collections.Generic;
using DialogSystem.Model;
using DialogSystem.ScriptObject;

namespace DialogSystem.Scripts
{
    public class ActivateWithBoolVars : UnityEngine.MonoBehaviour
    {
        protected virtual Action<float> howActivateGameObject => process => gameObject.SetActive(true);
        protected virtual Action<float> howDisactivateGameObject => process => gameObject.SetActive(false);

        public List<BoolVarChooser> enableConditions = new List<BoolVarChooser>();

        protected virtual void Awake()
        {
            TriggerWithConditions(DialogProgressAsset.Instance.CurrentProgress);
            DialogProgressAsset.Instance.onProgressChanged += TriggerWithConditions;
        }

        protected virtual void OnDestroy()
        {
            DialogProgressAsset.Instance.onProgressChanged -= TriggerWithConditions;
        }

        private void TriggerWithConditions(float progress)
        {
            if (enableConditions.Count == 0)
            {
                //没有条件，直接调用
                howActivateGameObject(progress);
            }
            else
            {
                foreach (var VARIABLE in enableConditions)
                {
                    if (!VARIABLE.Value)
                    {
                        //有一个条件不满足，都不调用，直接禁用
                        howDisactivateGameObject(progress);
                        return;
                    }
                }

                howActivateGameObject(progress);
            }
        }
    }
}


text:
using UnityEngine;

namespace DialogSystem.Scripts
{
    public class DialogData : UnityEngine.MonoBehaviour
    {
        public Vector3 offect=new Vector3(-1,1.58f,0);
        public float yWeight = 0.3f;

        public Vector3 GetSuitPos(Transform targetPos)
        {
            return
                targetPos.position+new Vector3(this.offect.x,this.offect.y + targetPos.transform.localScale.y*yWeight,0);
        }

        public Vector3 GetSuitPos()
        {
            return transform.position;
        }
    }
}


text:
fileFormatVersion: 2
guid: a0211f9ec18a91a4dad54a4333051735
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: bd02f6d294e9a634e940d2f65084b352
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using DialogSystem.Model;

namespace DialogSystem.Scripts
{
    /// <summary>
    /// 角色脚本
    /// 通过这个脚本维护角色名字和GameObject之间的映射
    /// </summary>
    public class DialogCharacter : UnityEngine.MonoBehaviour
    {
        public CharacterChooser CharacterChooser;

        private void OnEnable()
        {
            DialogSystem.RefreshCharacterObj(CharacterChooser.CharacterName, transform.gameObject);
        }

    }
}


text:
using System;
using UnityEngine;

namespace DialogSystem.Scripts
{
    public class InteractableFlag : MonoBehaviour
    {
        private Transform mainCamera;
        public GameObject characterGameObject;
        public void SetInteractable(bool value)
        {
            gameObject.SetActive(value);
        }

        private void Start()
        {
            mainCamera = Camera.main?.transform;
        }

        private void Update()
        {
            if (!mainCamera)
                return;

            var pos = new Vector3(mainCamera.position.x, transform.position.y, mainCamera.position.z);
            transform.LookAt(pos);
        }
    }
}


text:
fileFormatVersion: 2
guid: d58cc219bb3dda94ab3c22774a37f2e6
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using System;
using DialogSystem.Model;

namespace DialogSystem.Scripts
{
    public class ActivateBetweenProgressRange : ActivateWithBoolVars
    {
        public ProgressPointRange ProgressPointRange;

        protected override Action<float> howActivateGameObject => (value) =>
        {
            if (value > ProgressPointRange.Min && value < ProgressPointRange.Max)
            {
                this.gameObject.SetActive(true);
            }
            else
                this.gameObject.SetActive(false);
        };
    }
}


text:
fileFormatVersion: 2
guid: bb768c229e9b4f1c9fd20bb434bcea9d
timeCreated: 1564125935


text:
fileFormatVersion: 2
guid: 0754fa9c3a1349f2b8c332ddfd3c33d7
timeCreated: 1617888505


text:
using System;
using System.Collections;
using System.Collections.Generic;
using DialogSystem.Model;
using DialogSystem.ScriptObject;
using ReadyGamerOne.Common;
using ReadyGamerOne.Script;
using UnityEngine;

namespace DialogSystem.Scripts
{
    /// <summary>
    /// 对话系统
    /// </summary>
    public class DialogSystem : MonoBehaviour
    {
        #region Static

        #region Const_Messages

        /// <summary>
        /// 用于DialogSystem内部
        /// <DialogUnitInfo>资源</DialogUnitInfo>
        /// </summary>
        public static readonly string ExternWord = "__ew";

        /// <summary>
        /// 用于DialogSystem内部
        /// <string>assetName</string>
        /// </summary>
        public static readonly string EndThisDialogUnit = "__etdu";

        /// <summary>
        /// 用于DialogSystem内部
        /// </summary>
        public static readonly string CanGoNext = "__cgn";

        /// <summary>
        /// 开始对话
        /// <string>对话单元名字</string>
        /// </summary>
        public static readonly string BeginDialog = "__bdg";

        /// <summary>
        /// Choose单元的分支不会返回
        /// <string>AssetName</string>
        /// </summary>
        public static readonly string ChooseNotBack = "__cnb";

        #region 监听多资源消息

        private static Dictionary<string, List<string>> messageCache = new Dictionary<string, List<string>>();
        private static void AddAssetMessage(string message,string assetName)
        {
            if (!messageCache.ContainsKey(message))
            {
                messageCache.Add(message,new List<string>());
            }

            if (!messageCache[message].Contains(assetName))
                messageCache[message].Add(assetName);
        }
        public static bool GetAssetMessage(string message, string assetName,bool reset=true)
        {
            if (!messageCache.ContainsKey(message))
            {
                return false;
            }

            if (!messageCache[message].Contains(assetName))
                return false;

            if(reset)
                messageCache[message].Remove(assetName);
            return true;
        }

        #endregion

        #endregion

        #region 维护Character名字和GameObject的映射

        // 所有DialogCharacter需要在全局窗口中添加好，并且，每个角色都需要挂上DialogCharacter脚本用于维护和更新其位置信息
        // 用于在角色头顶产生对话气泡
        private static Dictionary<string, GameObject> nameToGameObject = new Dictionary<string, GameObject>();
        /// <summary>
        /// 根据角色名字获取角色GameObject
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static GameObject GetCharacterObj(string name)
        {
            if (nameToGameObject.ContainsKey(name) == false)
                throw new Exception("DialogSystem 不包含这个名字：name:" + name);
            return nameToGameObject[name];
        }
        /// <summary>
        /// 更新角色的位置
        /// </summary>
        /// <param name="name"></param>
        /// <param name="obj"></param>
        public static void RefreshCharacterObj(string name, GameObject obj)
        {
            if (nameToGameObject.ContainsKey(name))
            {
                nameToGameObject[name] = obj;
            }
            else
                nameToGameObject.Add(name, obj);
        }

        #endregion

        #region 开启对话的API

        /// <summary>
        /// 开始谈话实践
        /// </summary>
        public static event Action onStartDialog;

        /// <summary>
        /// 结束谈话事件
        /// </summary>
        public static event Action onEndDialog;

        /// <summary>
        /// 运行DialogInfoAsset资源
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        public static IEnumerator RunDialog(AbstractDialogInfoAsset info,Action endCall=null)
        {
            #region 对话开始事件

            if(!IsRunningAll && stackSize==0)
                onStartDialog?.Invoke();
            if (DialogSettings.Instance.ShowDialogStackInfo)
            {
                var text = "对话开始-";
                for (var i = 0; i < stackSize; i++)
                    text += "-";
                print(text+info.name);
            }

            #endregion

            stackSize++;

            var DialogUnits = info.DialogUnits;

            var ifConditions=new Stack<bool>();
            var ifTrue = false;

            var currentIndex = 0;

            if (!info.canMoveOnTalking)
                info.SetPlayerMovable(false);

            while (currentIndex<DialogUnits.Count)
            {

                var dialogUnitInfo = DialogUnits[currentIndex];

//                Debug.Log(dialogUnitInfo.UnitType);
//                Debug.Log(info.name+":"+ dialogUnitInfo.id);

                switch (dialogUnitInfo.UnitType)
                {
                    case UnitType.Word:
//                        Debug.Log("DialogSystem_RunDialog_Switch_UnitType.Word_Start");
                        yield return dialogUnitInfo.RunWordUnit();
//                        Debug.Log("DialogSystem_RunDialog_Switch_UnitType.Word_end");
                        break;
                    case UnitType.Choose:
                        yield return dialogUnitInfo.RunChooseUnit();

                        if (GetAssetMessage(ChooseNotBack,info.name))
                        {
                            endCall?.Invoke();
                            EndRunningDialog("End by ChooseNotBack",info.name);
                            yield break;
                        }
                        break;

                    case UnitType.Narrator:
                        yield return dialogUnitInfo.RunNarratorUnit();
                        break;

                    case UnitType.ExWord:
                        yield return dialogUnitInfo.RunExWordUnit();
                        break;

                    case UnitType.If:

                        ifTrue = dialogUnitInfo.Complare();
                        ifConditions.Push(ifTrue);

                        if (!ifTrue)//如果不满足IF条件，IF到Else或者EndIF之间不执行
                        {
                            //寻找Else
                            var id = FindUnitFromIndex(info, currentIndex, UnitType.Else);
                            if (id != -1)
                            {
                                //找到Else
                                currentIndex = id - 1;
                            }
                            else//没找到Else，查找EndIF
                            {
                                id = FindUnitFromIndex(info, currentIndex, UnitType.EndIf);

                                if (-1 == id)
                                {
                                    endCall?.Invoke();
                                    EndRunningDialog("End by 在IF处， if 条件不满足，同时没有EndIf",info.name);
                                    yield break;
                                }
                                else
                                {
                                    //找到EndIf
                                    currentIndex = id - 1;
                                }
                            }
                        }

                        break;
                    case UnitType.Else:

                        if (ifConditions.Peek())//如果满足条件，Else到EndIF不执行
                        {
                            //寻找下一个EndIF
                            var id = FindUnitFromIndex(info, currentIndex, UnitType.EndIf);
                            if (-1 == id)
                            {
                                //没找到
                                endCall?.Invoke();
                                EndRunningDialog("End by 在Else处， if 条件满足，同时没有EndIf",info.name);
                                yield break;
                            }
                            else
                            {
                                //找到了
                                currentIndex = id - 1;
                            }
                        }

                        break;
                    case UnitType.EndIf:
                        ifConditions.Pop();
                        break;
                    case UnitType.Message:
                        dialogUnitInfo.RunMessageUnit();
                        break;
                    case UnitType.SetVar:
                        dialogUnitInfo.RunSetVarUnit();
                        break;
                    case UnitType.End:
                        endCall?.Invoke();
                        EndRunningDialog("End By UnitType.End",info.name);
                        yield break;
                    case UnitType.Skip:
                        currentIndex += dialogUnitInfo.skipNum;
                        break;
                    case UnitType.Event:
                        dialogUnitInfo.RunEventUnit();
                        break;
                    case UnitType.Print:
                        dialogUnitInfo.RunPrintUnit();
                        break;
                    case UnitType.VarInfo:
                        dialogUnitInfo.ShowVarInfo();
                        break;
                    case UnitType.Wait:
                        yield return dialogUnitInfo.WaitForTime();
                        break;
                    case UnitType.Jump:
                        yield return dialogUnitInfo.RunJumpUnit();
                        if (GetAssetMessage(ChooseNotBack,info.name))
                        {
                            endCall?.Invoke();
                            EndRunningDialog("End by JumpNotBack",info.name);
                            yield break;
                        }

                        break;
                    case UnitType.Shining:
                        yield return dialogUnitInfo.Shining();
                        break;
                    case UnitType.FadeIn:
                        yield return dialogUnitInfo.FadeIn();
                        break;
                    case UnitType.FadeOut:
                        yield return dialogUnitInfo.FadeOut();
                        break;
                    case UnitType.Audio:
                        dialogUnitInfo.RunAudio();
                        break;
                    case UnitType.Panel:
//                        Debug.Log("DialogSystem_RunDialog_Switch_UnitType_Panel");
                        dialogUnitInfo.RunPanelUnit();
                        break;
                    case UnitType.Scene:
                        yield return dialogUnitInfo.RunSceneUnit();
//                        Debug.Log("DialogSystem_RunDialog_Switch_UnitType.Scene_end");
                        break;
                    case UnitType.Progress:
                        dialogUnitInfo.RunProgressUnit();
                        break;
                    case UnitType.ProcessInfo:
                        dialogUnitInfo.RunProgressInfoUnit();
                        break;
                    case UnitType.Camera:
                        yield return dialogUnitInfo.RunCameraUnit();
                        break;
                }

                currentIndex++;
            }

            if (!info.canMoveOnTalking)
                info.SetPlayerMovable(true);
            endCall?.Invoke();
            EndRunningDialog("End by normalEnd",info.name);

        }

        /// <summary>
        /// 顺次运行DialogSystem所有DialogInfoAsset资源
        /// </summary>
        /// <param name="dialogSystem"></param>
        /// <returns></returns>
        public static IEnumerator RunAllDialog(DialogSystem dialogSystem,bool await=false)
        {
            IsRunningAll = true;
            if(stackSize==0)
                onStartDialog?.Invoke();

            foreach (var asset in dialogSystem.DialogInfoAssets)
            {
                if(asset==null)
                    continue;
                if (await)
                    yield return RunDialogAwait(asset);
                else
                    yield return RunDialog(asset);
            }

            onEndDialog?.Invoke();

            IsRunningAll = false;
        }

        /// <summary>
        /// 运行对话资源，会等待所有对话结束才会开始
        /// </summary>
        /// <param name="info"></param>
        /// <param name="callBack"></param>
        /// <returns></returns>
        public static IEnumerator RunDialogAwait(AbstractDialogInfoAsset info, Action callBack = null)
        {
            while (stackSize != 0)
                yield return null;
            yield return RunDialog(info, callBack);
        }

        #endregion

        #region Private

        private static int stackSize = 0;
        private static bool IsRunningAll = false;
        private static int FindUnitFromIndex(AbstractDialogInfoAsset asset, int index, UnitType type)
         {
             bool skip = false || (type == UnitType.Else || type == UnitType.EndIf);

             int ifCount = 0;

             var DialogUnits = asset.DialogUnits;

             for (var i = index+1; i < DialogUnits.Count; i++)
             {
                 if (skip && DialogUnits[i].UnitType == UnitType.If)
                 {
 //                    print("执行ifCount++");
                     ifCount++;
                 }

                 if (DialogUnits[i].UnitType == type)
                 {
                     if (skip)
                     {
                         if (ifCount <= 0)
                             return i;
                         else
                         {
                             ifCount--;
                         }
                     }
                     else
                         return i;
                 }
             }

             return -1;
         }

        static DialogSystem()
         {
             //监听选择语句不再返回的消息
             CEventCenter.AddListener<string>(ChooseNotBack,(assetName)=>AddAssetMessage(ChooseNotBack,assetName));
         }
        /// <summary>
        /// 结束对话调用此函数
        /// </summary>
        /// <param name="endStatement"></param>
        /// <param name="assetName"></param>
        private static void EndRunningDialog(string endStatement, string assetName)
        {

            stackSize--;
            if(!IsRunningAll && stackSize==0)
                onEndDialog?.Invoke();

            if (DialogSettings.Instance.ShowDialogStackInfo)
            {
                var text = "对话结束-";
                for (var i = 0; i < stackSize; i++)
                    text += "-";
                print($"{text}{assetName}【{endStatement}】");
            }

        }

        #endregion

        #endregion

        #region MonoBehavior

        private void OnEnable()
        {
            CEventCenter.AddListener<string>(BeginDialog, OnStartDialogOnMessage);
        }

        private void OnDisable()
        {
            CEventCenter.RemoveListener<string>(BeginDialog,OnStartDialogOnMessage);
        }

        protected virtual void Update()
        {
            if(DialogInfoAssets.Count>0 && DialogInfoAssets[0].CanGoToNext())
                CEventCenter.BroadMessage(Scripts.DialogSystem.CanGoNext);
        }

        #endregion

        #region Public

        public List<AbstractDialogInfoAsset> DialogInfoAssets=new List<AbstractDialogInfoAsset>();

        public Func<bool> IfInteract => DialogInfoAssets[0].IfInteract;

        /// <summary>
        /// 根据名字开始某个对话
        /// </summary>
        /// <param name="name">对话资源名，这个名字需要是列表中的一个</param>
        /// <param name="endCall">对话结束时的回调</param>
        /// <param name="await">是否等待正在进行的对话结束</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public Coroutine StartDialog(string name,Action endCall=null,bool await=false)
        {
            foreach (var asset in DialogInfoAssets)
            {
                if (asset && asset.name == name)
                    if (await)
                        return MainLoop.Instance.StartCoroutine(RunDialogAwait(asset, endCall));
                    else
                        return MainLoop.Instance.StartCoroutine(RunDialog(asset,endCall));
            }

            throw  new Exception("对话资源名字不对:" + name);
        }

        /// <summary>
        /// 根据Index开启某个对话
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public Coroutine StartDialog(int index,Action endCall=null,bool await=false)
        {
            if (index >= DialogInfoAssets.Count)
                throw new Exception("StartDialog超出索引范围：index:" + index);
            if (await)
                return MainLoop.Instance.StartCoroutine(RunDialogAwait(DialogInfoAssets[index], endCall));
            else
                return MainLoop.Instance.StartCoroutine(RunDialog(DialogInfoAssets[index],endCall));
        }

        /// <summary>
        /// 顺次开启所有对话
        /// </summary>
        /// <returns></returns>
        public Coroutine StartDialog(bool await=false)
        {
            return MainLoop.Instance.StartCoroutine(RunAllDialog(this,await));
        }

        /// <summary>
        /// 获取列表所有对话资源名字
        /// </summary>
        /// <returns></returns>
        public List<string> GetAssetNames()
        {
            var names = new List<string>();
            foreach (var asset in DialogInfoAssets)
            {
                //print(asset.name);
                if (asset == null)
                    continue;
                names.Add(asset.name);
            }
            if (names.Count == 0)
                print("没有对话资源");
            return names;
        }

        #endregion

        #region Native

        private void OnStartDialogOnMessage(string assetName)
        {
            if (GetAssetNames().Contains(name))
                StartDialog(name);
        }

        #endregion

    }
}


text:
using System;
using DialogSystem.Model;
using DialogSystem.ScriptObject;
using ReadyGamerOne.Common;
using UnityEngine;
using ReadyGamerOne.EditorExtension;
using ReadyGamerOne.Script;
using UnityEngine.Events;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace DialogSystem.Scripts
{
    /// <summary>
    /// 开启类型
    /// </summary>
    public enum StartType
    {
        StartOnAwake,    //场景Awake时开启
        AutoStart,       //触发器碰到后自动开启
        InteractStart,   //在触发器范围内按交互键开启
        MessageStart,    //接收到指定消息后开启
        ClickStart,      //点击此物体开启
        AppearStart,     //出现在屏幕中后开始对话
    }

    /// <summary>
    /// 如何开启DialogSystem中的对话
    /// </summary>
    public enum TriggerType
    {
        Single,        //只开启你指定的DialogInfoAsset
        Sequence,      //会依次调用DialogSystem中指定范围的DialogInfoAsset,每调用一次触发一个
        All            //一次性全部顺次开启DialogSystem中的DialogInfoAsset
    }

    /// <summary>
    /// 工作模式
    /// </summary>
    public enum WorkType
    {
        WorkAlways,        //始终工作，一直在检测有没有触发
        WorkAfterMessage,  //接收到指定消息后再开始工作
        WorkBetweenProgress     //在指定游戏进度中间工作
    }

    /// <summary>
    /// 对话触发器
    /// </summary>
    public class DialogTrigger : MonoBehaviour
    {
        #region UsedDialogSystem

        public DialogSystem targetDialogSystem;

        private DialogSystem _dialogSystem;
        public DialogSystem UsedDialogSystem
        {
            get
            {
                _dialogSystem = targetDialogSystem ? targetDialogSystem : GetComponent<DialogSystem>();

                if (_dialogSystem == null)
                    Debug.LogError("获取DialogSystem失败");
                return _dialogSystem;
            }
        }

        #endregion

        #region Fields

        [Header("如何使用DialogSystem中的对话")]
        [Tooltip("Single\t只使用你指定的DialogInfoAsset\n"+
                 "Sequence\t会依次调用DialogSystem中指定范围的DialogInfoAsset,每调用一次触发一个\n"+
                 "All\t一次性全部顺次开启DialogSystem中的DialogInfoAsset")]
        public TriggerType triggerType=TriggerType.Single;

        [Header("工作模式：什么情况下本触发器是正常工作的")]
        [Tooltip( "WorkAlways\t始终工作，持续在检测有没有触发\n"+
                 "WorkAfterMessage\t接收到指定消息后再开始工作\n"+
                 "WorkBetweenProgress\t在指定游戏进度中间工作")]
        public WorkType workType = WorkType.WorkAlways;

        [Header("开启工作的消息")]
        public StringChooser messageToEnableThis;
        [Header("如何开启DialogSystem中的对话")]
        [Tooltip( "StartOnAwake\t场景Awake时开启\n"+
                 "AutoStart\t\t触发器碰到后自动开启\n"+
                 "InteractStart\t在触发器范围内按交互键开启\n"+"" +
                 "MessageStart\t接收到指定消息后开启\n"+"" +
                 "ClickStart\t\t点击此物体开启\n" +
                 "AppearStart\t出现在屏幕中后开始对话")]
        public StartType startType = StartType.AutoStart;

        [Tooltip("待触发的对话资源")]
        public StringChooser dialogNameToTrigger=null;

        [Header("开启对话的消息")]
        public StringChooser messageToStart;

        [Header("依次开启DialogSystem中从哪里到哪里的对话资源")]
        public Vector2Int sequenceRange = new Vector2Int(0, 0);

        [Header("是否只触发一次")]
        public bool triggerOnlyOnce = true;

        [Header("是否在触发后设置此物体不可见")]
        public bool disableThisGameObjectOnEnd = false;

        [Header("在这样的进度区间内触发器是工作的")]
        public ProgressPointRange allowProgressRange;

        [SerializeField] public UnityEvent<bool> onInteractableChanged;

        #region Private

        private bool enableTrigger_WorkAfterMsg = false;

        private bool _triggered = false;

        private int currentDialogIndex=0;

        private bool close=false;

        #endregion

        #endregion

        #region CEventCenter消息响应

        private void OnEnableTrigger() => enableTrigger_WorkAfterMsg = true;

        #endregion

        #region MonoBehavior

        // Use this for initialization
        private void Start()
        {
//            Debug.Log(gameObject.name+ " Start:"+gameObject.activeSelf);
            if(workType==WorkType.WorkAfterMessage)
                CEventCenter.AddListener(messageToEnableThis.StringValue,OnEnableTrigger);

            if (startType == StartType.MessageStart)
                CEventCenter.AddListener(messageToStart.StringValue,TriggerDialog);
            else if (startType == StartType.ClickStart)
            {
                if (this.gameObject.layer == LayerMask.NameToLayer("UI"))
                {
                    this.gameObject.AddComponent<UIInputer>().eventOnPointerClick += (obj) =>
                    {
                        switch (workType)
                        {
                            case WorkType.WorkAlways:
                                TriggerDialog();
                                break;
                            case WorkType.WorkAfterMessage:
                                if (enableTrigger_WorkAfterMsg)
                                    TriggerDialog();
                                break;
                            case WorkType.WorkBetweenProgress:
                                if(DialogProgressAsset.Instance.CurrentProgress>allowProgressRange.Min
                                   && DialogProgressAsset.Instance.CurrentProgress<allowProgressRange.Max)
                                TriggerDialog();
                                break;
                        }
                    };
                }
                else
                {
                    Debug.Log("添加eventOnCLickObj监听");
                    this.gameObject.AddComponent<UIInputer>().eventOnClickObj += (obj) =>
                    {
                        Debug.Log("点击");
                        switch (workType)
                        {
                            case WorkType.WorkAlways:
                                TriggerDialog();
                                break;
                            case WorkType.WorkAfterMessage:
                                if (enableTrigger_WorkAfterMsg)
                                    TriggerDialog();
                                break;
                            case WorkType.WorkBetweenProgress:
                                if(DialogProgressAsset.Instance.CurrentProgress>allowProgressRange.Min
                                   && DialogProgressAsset.Instance.CurrentProgress<allowProgressRange.Max)
                                    TriggerDialog();
                                break;
                        }
                    };
                }

            }
            else if(startType==StartType.StartOnAwake)
            {
                switch (workType)
                {
                    case WorkType.WorkAlways:
                        TriggerDialog();
                        break;
                    case WorkType.WorkAfterMessage:
                        if(enableTrigger_WorkAfterMsg)
                            TriggerDialog();
                        break;
                    case WorkType.WorkBetweenProgress:
                        if(DialogProgressAsset.Instance.CurrentProgress>allowProgressRange.Min
                           && DialogProgressAsset.Instance.CurrentProgress<allowProgressRange.Max)
                            TriggerDialog();
                        break;
                }
            }
            else if (startType == StartType.InteractStart)
            {
                switch (workType)
                {
                    case WorkType.WorkAlways:
                        onInteractableChanged?.Invoke(true);
                        break;
                    case WorkType.WorkAfterMessage:
                        onInteractableChanged?.Invoke(true);
                        break;
                    case WorkType.WorkBetweenProgress:
                        if(DialogProgressAsset.Instance.CurrentProgress>allowProgressRange.Min
                           && DialogProgressAsset.Instance.CurrentProgress<allowProgressRange.Max)
                        {
                            onInteractableChanged?.Invoke(true);
                        }
                        else
                        {
                            onInteractableChanged?.Invoke(false);
                        }
                        break;
                }
            }
        }

        private void Update()
        {
            if(!close)
                return;
            if(startType==StartType.InteractStart && UsedDialogSystem.IfInteract())
                switch (workType)
                {
                    case WorkType.WorkAlways:
                        TriggerDialog();
                        break;
                    case WorkType.WorkAfterMessage:
                        if(enableTrigger_WorkAfterMsg)
                            TriggerDialog();
                        break;
                    case WorkType.WorkBetweenProgress:
                        if(DialogProgressAsset.Instance.CurrentProgress>allowProgressRange.Min
                           && DialogProgressAsset.Instance.CurrentProgress<allowProgressRange.Max)
                            TriggerDialog();
                        break;
                }
        }

        private void OnDestroy()
        {
            if(workType==WorkType.WorkAfterMessage)
                CEventCenter.RemoveListener(messageToEnableThis.StringValue,OnEnableTrigger);
            if (startType == StartType.MessageStart)
                CEventCenter.RemoveListener(messageToStart.StringValue,TriggerDialog);
        }

#if UNITY_EDITOR
        private GUIStyle style;
        private GUIStyle Style
        {
            get
            {
                if (null == style)
                {
                    style = new GUIStyle();
                    style.alignment = TextAnchor.MiddleCenter;
                    style.fontStyle = FontStyle.Italic;
                    style.normal.textColor=new Color(1f, 0.42f, 0.81f);
                }

                return style;
            }
        }
#endif

        private void OnDrawGizmos()
        {
            if (!gameObject.activeSelf || !enabled)
                return;

#if UNITY_EDITOR
            Handles.Label(transform.position,$"[DialogTrigger:{name}]\n({startType})",Style);
#endif

        }
        #endregion

        #region Unity_Trigger

        private void OnBecameVisible()
        {
            if (!Application.isPlaying)
                return;
            if (!enabled)
                return;
            if(startType==StartType.AppearStart)
                switch (workType)
                {
                    case WorkType.WorkAlways:
                        TriggerDialog();
                        break;
                    case WorkType.WorkAfterMessage:
                        if(enableTrigger_WorkAfterMsg)
                            TriggerDialog();
                        break;
                    case WorkType.WorkBetweenProgress:
                        if(DialogProgressAsset.Instance.CurrentProgress>allowProgressRange.Min
                           && DialogProgressAsset.Instance.CurrentProgress<allowProgressRange.Max)
                            TriggerDialog();
                        break;
                }
        }

        private void OnTriggerEnter(Collider other)
        {
            if (!other.CompareTag("Player"))
                return;
            close=true;
            if (!this.enabled)
                return;
            if(startType==StartType.AutoStart)
                switch (workType)
                {
                    case WorkType.WorkAlways:
                        TriggerDialog();
                        break;
                    case WorkType.WorkAfterMessage:
                        if(enableTrigger_WorkAfterMsg)
                            TriggerDialog();
                        break;
                    case WorkType.WorkBetweenProgress:
                        if(DialogProgressAsset.Instance.CurrentProgress>allowProgressRange.Min
                           && DialogProgressAsset.Instance.CurrentProgress<allowProgressRange.Max)
                            TriggerDialog();
                        break;
                }
        }

        private void OnTriggerExit(Collider other)
        {
            if (!other.CompareTag("Player"))
                return;
            close=false;
        }

        private void OnTriggerExit2D(Collider2D collider){
            if (!collider.CompareTag("Player"))
                return;
            close=false;
        }

        private void OnTriggerEnter2D(Collider2D collision)
        {
            if (!collision.CompareTag("Player"))
                return;
            close=true;
            if (!this.enabled)
                return;
            if(startType==StartType.AutoStart)
                switch (workType)
                {
                    case WorkType.WorkAlways:
                        TriggerDialog();
                        break;
                    case WorkType.WorkAfterMessage:
                        if(enableTrigger_WorkAfterMsg)
                            TriggerDialog();
                        break;
                    case WorkType.WorkBetweenProgress:
                        if(DialogProgressAsset.Instance.CurrentProgress>allowProgressRange.Min
                           && DialogProgressAsset.Instance.CurrentProgress<allowProgressRange.Max)
                            TriggerDialog();
                        break;
                }
        }

        #endregion

        #region Private_Functions

        private void TriggerDialog()
        {
            if(triggerOnlyOnce && _triggered)
                return;

            //每次开始对话时就不再需要显示flag
            onInteractableChanged?.Invoke(false);
            StartDialog(this.triggerType);
        }

        private Coroutine StartDialog(TriggerType triggerType)
        {
            switch (triggerType)
            {
                case TriggerType.All:
                    _triggered = true;
                    return UsedDialogSystem.StartDialog(startType==StartType.MessageStart);
                case TriggerType.Single:
                    _triggered = true;
                    return UsedDialogSystem.StartDialog(dialogNameToTrigger.StringValue,null,startType==StartType.MessageStart);
                case TriggerType.Sequence:

                    var c = UsedDialogSystem.StartDialog(sequenceRange.x + currentDialogIndex++, () =>
                    {
                        // 所有对话全都结束
                        if (currentDialogIndex > sequenceRange.y)
                        {
                            _triggered = true;
                            if(disableThisGameObjectOnEnd)
                                this.gameObject.SetActive(false);
                            else
                            {
                                Destroy(this);
                            }
                        }
                        else
                        {
                            //没有完全结束
                            onInteractableChanged?.Invoke(true);
                        }
                    },startType==StartType.MessageStart);
                    return c;
            }

            throw new Exception("没有处理这种StartTrigger的逻辑：" + triggerType);
        }

        #endregion
    }
}


text:
fileFormatVersion: 2
guid: 1e5c644a44333824482867536b303b08
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 8b8d6b7b8648f444ab50eac3bb0828d6
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 1f93a3640c242c64c9793677c36ab99a
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: d3c2a8a20a7ecd645ad65bbb05f4f80d
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using ReadyGamerOne.Editor;
using ReadyGamerOne.Utility;
using UnityEditor;
using UnityEngine;

namespace DialogSystem.Scripts.Editor
{
    [CustomEditor(typeof(DialogTrigger))]
    public class DialogTriggerEditor:UnityEditor.Editor
    {
        private SerializedProperty targetDialogSystemPorp;
        private SerializedProperty dialogNameToTriggerProp;
        private SerializedProperty triggerOnlyOnce;

        private SerializedProperty triggerTypeProp;
        private SerializedProperty startTypeProp;

        private SerializedProperty sequenceRangeProp;
        private SerializedProperty disableObjProp;

        private SerializedProperty workTypeProp;
        private SerializedProperty messageToEnableThisProp;
        private SerializedProperty messageToStartProp;

        private SerializedProperty allowProgressRangeProp;
        private SerializedProperty onInteractableChangedProp;

        private DialogTrigger mb;
        private void OnEnable()
        {
            this.mb = target as DialogTrigger;
            this.triggerTypeProp = serializedObject.FindProperty("triggerType");
            this.startTypeProp = serializedObject.FindProperty("startType");
            this.targetDialogSystemPorp = serializedObject.FindProperty("targetDialogSystem");
            this.dialogNameToTriggerProp=serializedObject.FindProperty("dialogNameToTrigger");
            this.triggerOnlyOnce = serializedObject.FindProperty("triggerOnlyOnce");
            this.sequenceRangeProp = serializedObject.FindProperty("sequenceRange");
            this.disableObjProp = serializedObject.FindProperty("disableThisGameObjectOnEnd");
            this.messageToStartProp = serializedObject.FindProperty("messageToStart");
            this.messageToEnableThisProp=serializedObject.FindProperty("messageToEnableThis");
            this.workTypeProp = serializedObject.FindProperty("workType");
            this.allowProgressRangeProp = serializedObject.FindProperty("allowProgressRange");
            this.onInteractableChangedProp = serializedObject.FindProperty("onInteractableChanged");

        }
        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            EditorGUILayout.PropertyField(targetDialogSystemPorp);
            if (!targetDialogSystemPorp.objectReferenceValue)
            {
                EditorGUILayout.HelpBox("如果targetDialogSystem为空会默认使用自身的第一个DialogSystem, 如果自身没有会报错",MessageType.Info);
            }
            if (mb.UsedDialogSystem == null)
            {
                return;
            }
            EditorUtil.InitSerializedStringArray(this.dialogNameToTriggerProp.FindPropertyRelative("values"), mb.UsedDialogSystem.GetAssetNames());

            EditorGUILayout.PropertyField(this.workTypeProp);
            switch (workTypeProp.enumValueIndex)
            {
                case 1://WorkAfterMessage
                    EditorUtil.InitSerializedStringArray(messageToEnableThisProp.FindPropertyRelative("values"),mb.UsedDialogSystem.DialogInfoAssets[0].MessageType);
                    EditorGUILayout.PropertyField(this.messageToEnableThisProp);
                    break;
                case 2://WorkAtProgressRange
                    EditorGUILayout.PropertyField(this.allowProgressRangeProp);
                    break;
            }

            EditorGUILayout.PropertyField(this.startTypeProp);

            switch (startTypeProp.enumValueIndex)
            {
                case 3://MessagetToStart
                    EditorUtil.InitSerializedStringArray(messageToStartProp.FindPropertyRelative("values"),mb.UsedDialogSystem.DialogInfoAssets[0].MessageType);
                    EditorGUILayout.PropertyField(messageToStartProp);
                    break;
            }
            EditorGUILayout.PropertyField(this.triggerTypeProp);

            if (startTypeProp.enumValueIndex == 0 &&
                (triggerTypeProp.enumValueIndex == 1
                 ||startTypeProp.enumValueIndex==3
                 ||workTypeProp.enumValueIndex==1))
                EditorGUILayout.HelpBox("设置不合理", MessageType.Warning);

            switch (this.triggerTypeProp.enumValueIndex)
            {
                case 0:// Single
                EditorGUILayout.PropertyField(this.dialogNameToTriggerProp);
                    break;
                case 1://Sequence
                    EditorGUILayout.PropertyField(this.sequenceRangeProp);
                    var x = this.sequenceRangeProp.FindPropertyRelative("x").intValue;
                    var y = this.sequenceRangeProp.FindPropertyRelative("y").intValue;
                    if (x < 0 || x >= mb.UsedDialogSystem.DialogInfoAssets.Count || y < 0 ||
                        y >= mb.UsedDialogSystem.DialogInfoAssets.Count)
                        EditorGUILayout.HelpBox("设置错误，索引越界", MessageType.Error);
                    break;
                case 2:// Interact
                    break;
            }

            #region 错误检测

            var collider2D = mb.gameObject.GetComponent<Collider2D>();
            var collider3D = mb.gameObject.GetComponent<Collider>();
            var needCollider = (this.startTypeProp.enumValueIndex == 1
                                || this.startTypeProp.enumValueIndex == 2);
            var collierIsValid = (collider2D && collider2D.isTrigger)
                                 || (collider3D && collider3D.isTrigger);
            if(needCollider && !collierIsValid)
            {
                EditorGUILayout.HelpBox("使用自动触发或交互需要给此物体添加触发器！", MessageType.Error);
            }

            if (this.startTypeProp.enumValueIndex == 4 //点击触发
                && this.mb.gameObject.layer != LayerMask.NameToLayer("UI") //不是UI
                && !(collider2D || collider3D))
            {

                EditorGUILayout.HelpBox("使用点击触发器需要给此物体添加触发器或碰撞体", MessageType.Error);
            }

            #endregion

            if (startTypeProp.enumValueIndex == 0) //StartOnAwake
            {
                triggerOnlyOnce.boolValue = true;
            }else if (this.triggerTypeProp.enumValueIndex == 1) //Sequence
            {
                triggerOnlyOnce.boolValue = false;
            }else
                EditorGUILayout.PropertyField(triggerOnlyOnce);

            if (triggerOnlyOnce.boolValue)
            {
                EditorGUILayout.PropertyField(disableObjProp);
            }

            EditorGUILayout.PropertyField(onInteractableChangedProp);

            serializedObject.ApplyModifiedProperties();
        }
    }
}


text:
using UnityEditor;
using DialogSystem.ScriptObject;
using ReadyGamerOne.Utility;
using UnityEditor.SceneManagement;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace DialogSystem.Scripts.Editor
{
    [UnityEditor.CustomEditor(typeof(DialogSystem))]
    public class DialogSystemEditor:UnityEditor.Editor
    {
        private DialogSystem dialogSystem;
        private SerializedProperty dialogInfoAssetProp;

        private ReorderableList dialogUnitList;

        private void OnEnable()
        {
            this.dialogSystem = target as DialogSystem;
            this.dialogInfoAssetProp = serializedObject.FindProperty("DialogInfoAssets");

            dialogUnitList = new ReorderableList(serializedObject, dialogInfoAssetProp, true, true, true, true)
            {
                elementHeight = EditorGUIUtility.singleLineHeight
            };

            //绘制单个元素
            dialogUnitList.drawElementCallback =
                (rect, index, isActive, isFocused) =>
                {
                    var dialogUnit = dialogInfoAssetProp.GetArrayElementAtIndex(index);
                    EditorGUI.PropertyField(rect, dialogUnit);
                };

            //背景色
            dialogUnitList.drawElementBackgroundCallback = (rect, index, isActive, isFocused) =>
            {
                GUI.backgroundColor = isFocused ? Color.yellow : Color.white;
            };
            //头部
            dialogUnitList.drawHeaderCallback = (rect) =>
                EditorGUI.LabelField(rect, dialogInfoAssetProp.displayName);

        }

        public override void OnInspectorGUI()
        {

            serializedObject.Update();

            var list = EditorUtil.GetDragObjectsFromArea<AbstractDialogInfoAsset>("拖拽 SimpleDialogInfoAsset 资源到这里添加到List中去");

            foreach(var asset in list)
            {
                if (!dialogSystem.DialogInfoAssets.Contains(asset))
                    dialogSystem.DialogInfoAssets.Add(asset);
            }

            if (list.Count != 0)
            {
                EditorUtility.SetDirty(target);
                EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
            }

            dialogUnitList.DoLayoutList();
            serializedObject.ApplyModifiedProperties();

        }
    }
}


text:
using System;
using DialogSystem.ScriptObject;
using UnityEngine;

namespace DialogSystem.Model
{
    [Serializable]
    public class BoolVarChooser
    {
#pragma warning disable 649
        [SerializeField] private int selectedIndex;
#pragma warning restore 649
        public bool Value => DialogVarAsset.Instance.varInfos[selectedIndex].BoolValue;
    }
}


text:
fileFormatVersion: 2
guid: e5d511d4163db734996319402454ae89
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 8c80936db1ba7ea4895bc21295a2cbd2
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using System;
using System.Linq;
using DialogSystem.ScriptObject;
using ReadyGamerOne.EditorExtension;
using ReadyGamerOne.Utility;
#if UNITY_EDITOR

using UnityEditor;
#endif
using UnityEngine;
using UnityEngine.Assertions;

namespace DialogSystem.Model
{
    [Serializable]
#pragma warning disable 660,661
    public class ValueChooser
#pragma warning restore 660,661
    {
#pragma warning disable 649
        #region Static

#if UNITY_EDITOR
        public static int GetArgTypeFromSerializedProperty(SerializedProperty property)
        {
            var valueTypeProp = property.FindPropertyRelative("valueType");

            var argChooserProp = property.FindPropertyRelative("ArgChooser");

            SerializedProperty targetProp = null;

            switch (valueTypeProp.enumValueIndex)
            {
                case 0:// Value
                    targetProp = argChooserProp;
                    break;
                case 1://var
                    targetProp = property;
                    break;
            }

            return targetProp.FindPropertyRelative("argType").intValue;
        }

        public static string GetShowTextFromSerializedProperty(SerializedProperty property)
        {

            var argChooserProp = property.FindPropertyRelative("ArgChooser");

            switch (property.FindPropertyRelative("valueType").enumValueIndex)
            {
                case 0://value
                    return ReadyGamerOne.EditorExtension.ArgChooser.GetShowTextFromSerializedProperty(argChooserProp);
                case 1://var
                    var asset =
                        property.FindPropertyRelative("abstractAbstractDialogInfoAsset").objectReferenceValue as
                            AbstractDialogInfoAsset;
                    if (asset == null)
                        throw new Exception("asset is null");
                    var text = asset.GetValueStrings(
                        (ReadyGamerOne.EditorExtension.ArgType) property.FindPropertyRelative("argType")
                            .enumValueIndex).Keys.ToArray()[property.FindPropertyRelative("selectedIndex").intValue];
                    return text;
            }
            throw new Exception("???");
        }

        public static ArgType GetArgType(SerializedProperty property)
        {
            switch (property.FindPropertyRelative("valueType").enumValueIndex)
            {
                case 0://Value
                    return (ArgType) (property.FindPropertyRelative("ArgChooser").FindPropertyRelative("argType").enumValueIndex);
                case 1://Var
                    return (ArgType) property.FindPropertyRelative("argType").enumValueIndex;
            }
            throw new Exception("类型异常");
        }
#endif

        public static float valueTypeWidth = 0.2f;
        public static float argTypeWidth = 0.3f;

        #endregion

        #region Static

        #endregion
        public enum ValueType
        {
            Value,
            Var
        }

        public ValueType valueType;

        public AbstractDialogInfoAsset abstractAbstractDialogInfoAsset;

        [SerializeField] private ArgChooser ArgChooser;
        [SerializeField] private int selectedIndex;
        [SerializeField] private ArgType argType;

        public ArgType ArgType
        {
            get
            {
                if (valueType == ValueType.Value)
                    return ArgChooser.argType;
                return argType;
            }
        }
        public int IntValue
        {
            get
            {
                if (valueType == ValueType.Var)
                {
                    try
                    {
                        var str= abstractAbstractDialogInfoAsset.GetValueStrings(ArgType.Int).Values.ToArray()[selectedIndex];
                        return Convert.ToInt32(str);
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new Exception(abstractAbstractDialogInfoAsset.name+"   Index:"+selectedIndex);
                    }
                }
                return ArgChooser.IntArg;
            }
        }
        public Vector3 Vector3Value
        {
            get
            {
                if (valueType == ValueType.Var)
                {
                    try
                    {
                        var str= abstractAbstractDialogInfoAsset.GetValueStrings(ArgType.Vector3).Values.ToArray()[selectedIndex];
                        return ConvertUtil.String2Vector3(str);
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new Exception(abstractAbstractDialogInfoAsset.name+"   Index:"+selectedIndex);
                    }

                }
                return ArgChooser.Vector3Arg;
            }
        }
        public float FloatValue
        {
            get
            {
                if (valueType == ValueType.Var)
                {
                    try
                    {
                        var str= abstractAbstractDialogInfoAsset.GetValueStrings(ArgType.Float).Values.ToArray()[selectedIndex];
                        return Convert.ToSingle(str);
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new Exception(abstractAbstractDialogInfoAsset.name+"   Index:"+selectedIndex);
                    }

                }
                return ArgChooser.FloatArg;
            }
        }
        public bool BoolValue
        {
            get
            {
                if (valueType == ValueType.Var)
                {
                    try
                    {
                        var str= abstractAbstractDialogInfoAsset.GetValueStrings(ArgType.Bool).Values.ToArray()[selectedIndex];
                        return Convert.ToBoolean(str);
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new Exception(abstractAbstractDialogInfoAsset.name+"   Index:"+selectedIndex);
                    }

                }
                return ArgChooser.BoolArg;
            }
        }
        public string StrValue
        {
            get
            {
                if (valueType == ValueType.Var)
                {
                    try
                    {
                        var str= abstractAbstractDialogInfoAsset.GetValueStrings(ArgType.String).Values.ToArray()[selectedIndex];
                        return str;
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new Exception(abstractAbstractDialogInfoAsset.name+"   Index:"+selectedIndex);
                    }

                }
                return ArgChooser.StringArg;
            }
        }

        #region 运算符重载

        public static bool operator ==(ValueChooser a1, ValueChooser a2)
        {
            Assert.IsTrue(a1.ArgType==a2.ArgType);

            switch (a1.ArgType)
            {
                case ArgType.Bool:
                    return a1.BoolValue == a2.BoolValue;
                case ArgType.Int:
                    return a1.IntValue == a2.IntValue;
                case ArgType.String:
                    return a1.StrValue == a2.StrValue;
            }

            throw new Exception("ValueChooser 比较异常");
        }

        public static bool operator !=(ValueChooser a1, ValueChooser a2)
        {
            return !(a1 == a2);
        }

        public static bool operator >(ValueChooser a1, ValueChooser a2)
        {

            Assert.IsTrue((a1.ArgType==ArgType.Int||a1.ArgType==ArgType.Float
                           )&&(a2.ArgType==ArgType.Int||a2.ArgType==ArgType.Float
                           ));

            switch (a1.ArgType)
            {
                case ArgType.Float:
                    return a1.FloatValue > a2.FloatValue;
                case ArgType.Int:
                    return a1.IntValue > a2.IntValue;
            }

            throw new Exception("ValueChooser 比较异常");
        }

        public static bool operator <(ValueChooser a1, ValueChooser a2)
        {
            Assert.IsTrue((a1.ArgType==ArgType.Int||a1.ArgType==ArgType.Float
                          )&&(a2.ArgType==ArgType.Int||a2.ArgType==ArgType.Float
                          ));

            switch (a1.ArgType)
            {
                case ArgType.Float:
                    return a1.FloatValue < a2.FloatValue;
                case ArgType.Int:
                    return a1.IntValue < a2.IntValue;
            }

            throw new Exception("ValueChooser 比较异常");
        }

        public static bool operator >=(ValueChooser a1, ValueChooser a2)
        {
            Assert.IsTrue((a1.ArgType==ArgType.Int||a1.ArgType==ArgType.Float
                          )&&(a2.ArgType==ArgType.Int||a2.ArgType==ArgType.Float
                          ));

            switch (a1.ArgType)
            {
                case ArgType.Float:
                    return a1.FloatValue >= a2.FloatValue;
                case ArgType.Int:
                    return a1.IntValue >= a2.IntValue;
            }

            throw new Exception("ValueChooser 比较异常");
        }

        public static bool operator <=(ValueChooser a1, ValueChooser a2)
        {
            Assert.IsTrue((a1.ArgType==ArgType.Int||a1.ArgType==ArgType.Float
                          )&&(a2.ArgType==ArgType.Int||a2.ArgType==ArgType.Float
                          ));

            switch (a1.ArgType)
            {
                case ArgType.Float:
                    return a1.FloatValue <= a2.FloatValue;
                case ArgType.Int:
                    return a1.IntValue <= a2.IntValue;
            }

            throw new Exception("ValueChooser 比较异常");
        }

        #endregion

#pragma warning restore 649
    }
}


text:
fileFormatVersion: 2
guid: 2b599721c6b789144857f203e40f68d5
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using System;
using ReadyGamerOne.EditorExtension;
using ReadyGamerOne.Utility;
#if UNITY_EDITOR

using UnityEditor;
#endif
using UnityEngine;

namespace DialogSystem.Model
{
    [Serializable]
    public class VarUnitInfo
    {
        public string VarName;
        public ArgChooser ArgChooser;

        public ArgType ArgType => ArgChooser.argType;
        public bool BoolValue => ArgChooser.BoolArg;
        public int IntValue => ArgChooser.IntArg;
        public float FloatValue => ArgChooser.FloatArg;
        public string StringValue => ArgChooser.StringArg;
        public Vector3 Vector3Value => ArgChooser.Vector3Arg;

        public void SetValue(int value)
        {
            ArgChooser.IntArg = value;
        }
        public void SetValue(string value)
        {
            ArgChooser.StringArg = value;
        }
        public void SetValue(float value)
        {
            ArgChooser.FloatArg = value;
        }
        public void SetValue(bool value)
        {
            ArgChooser.BoolArg = value;
        }
        public void SetValue(Vector3 value)
        {
            ArgChooser.Vector3Arg = value;
        }

#if UNITY_EDITOR
        public void DrawWithRect(Rect rect)
        {
            var index = 0;
            this.VarName = EditorGUI.TextField(rect.GetRectAtIndex(index++), "变量名",this.VarName);
            switch (ArgChooser.argType)
            {
                case ArgType.Bool:
                    ArgChooser.BoolArg = EditorGUI.Toggle(rect.GetRectAtIndex(index++),"BoolArg", ArgChooser.BoolArg);
                    break;
                case ArgType.Float:
                    ArgChooser.FloatArg = EditorGUI.FloatField(rect.GetRectAtIndex(index++),"FloatArg", ArgChooser.FloatArg);

                    break;
                case ArgType.Int:
                    ArgChooser.IntArg = EditorGUI.IntField(rect.GetRectAtIndex(index++),"IntArg", ArgChooser.IntArg);
                    break;
                case ArgType.String:
                    ArgChooser.StringArg = EditorGUI.TextField(rect.GetRectAtIndex(index++),"StringArg", ArgChooser.StringArg);
                    break;
            }
        }
#endif

    }
}


text:
using System;
using DialogSystem.ScriptObject;
#if UNITY_EDITOR

using UnityEditor;
#endif
using UnityEngine;

namespace DialogSystem.Model
{
    [Serializable]
    public class ProgressPointChooser
    {

#pragma warning disable 649

        public static bool ShowLabel = true;

#if UNITY_EDITOR
        public static string GetShowTextFromSerializedProperty(SerializedProperty property)
        {
            var text = "设置的进度值为：";
            var valueTypeProp = property.FindPropertyRelative("valueType");
            if (valueTypeProp.enumValueIndex == 0)
                text+= property.FindPropertyRelative("value").floatValue.ToString();
            else
            {
                var info = DialogProgressAsset.Instance.DialogProgressPoints[
                    property.FindPropertyRelative("selectedIndex").intValue];
                text += info.name + $"【{info.value}】";
            }

            return text;
        }

#endif

        public ValueChooser.ValueType valueType;
        [SerializeField] private int selectedIndex;
        [SerializeField] private float value;
        public float Value
        {
            get
            {
                if (valueType == ValueChooser.ValueType.Var)
                {
                    if (DialogProgressAsset.Instance.DialogProgressPoints.Count <= selectedIndex)
                        throw new Exception("ProgressPointChooser选取的Index不当");
                    return DialogProgressAsset.Instance.DialogProgressPoints[selectedIndex].value;
                }

                return value;

            }
        }

#pragma warning restore 649
    }

}