text:
using System;
using System.Collections;
using System.Collections.Generic;
using ReadyGamerOne.Common;
using ReadyGamerOne.Script;
using UnityEngine;
using UnityEngine.Assertions;
using Object = UnityEngine.Object;

namespace ReadyGamerOne.MemorySystem
{
    public class AssetBundleResourceLoader:
        Singleton<AssetBundleResourceLoader>,
        IResourceLoader
    {
        #region Fields

        private Dictionary<string, Object> sourceObjectDic;
        private AssetBundleLoader assetBundleLoader;
        private IHotUpdatePath pather;
        private IOriginAssetBundleUtil originBundleConst;

        #endregion

        #region Properties

        private Dictionary<string, Object> SourceObjects
        {
            get
            {
                if (sourceObjectDic == null)
                    sourceObjectDic = new Dictionary<string, Object>();

                return sourceObjectDic;
            }
            set { sourceObjectDic = value; }
        }

        #endregion

        #region Private

        /// <summary>
        /// 从缓存中获取资源，否则采用默认方式初始化
        /// </summary>
        /// <param name="key"></param>
        /// <param name="defaultGetMethod"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private T GetSourceFromCache<T>(string key, Func<string, T> defaultGetMethod = null)
            where T : Object
        {
            if (SourceObjects.ContainsKey(key))
            {
                if (SourceObjects[key] == null)
                    throw new Exception("资源已经释放，但字典中引用亦然保留");

                var ans = SourceObjects[key] as T;
                if (ans == null)
                    Debug.LogWarning("资源引用存在，但类型转化失败，小心bug");

                return ans;
            }

            if (null == defaultGetMethod)
            {
                Debug.LogWarning("defaultGetMethod is null");
                return null;
            }

            var source = defaultGetMethod(key);
            if (source == null)
            {
                Debug.LogError("资源加载错误，错误路径：" + key);
                return null;
            }

            SourceObjects.Add(key, source);
            return source;
        }

        #endregion

        public void ShowDebugInfo()
        {
            Debug.Log("《AssetBundle加载情况》\n" + assetBundleLoader.DebugInfo());
        }

        #region IResourceLoader

        public void Init(IHotUpdatePath pather, IOriginAssetBundleUtil originConstData,IAssetConstUtil assetConstUtil)
        {
            if (null == pather)
                return;
            if (null == originConstData)
                return;
            this.originBundleConst = originConstData;
            this.pather = pather;
            assetBundleLoader = new AssetBundleLoader();
            MainLoop.Instance.StartCoroutine(assetBundleLoader.StartBundleManager(pather, originConstData));
        }

        public T GetAsset<T>(string objName, string bundleKey = null)
            where T : Object
        {
            if (null == pather)
                throw new Exception("没有初始化MemoryMgr.Pather");

            if (originBundleConst == null)
                throw new Exception("originBundleConst is null");

            return GetSourceFromCache(objName,
                key =>
                {
                    var ab = assetBundleLoader.GetBundle(bundleKey);
                    Assert.IsTrue(ab);
                    return ab.LoadAsset<T>(key);
                });
        }

        public IEnumerator GetAssetAsync<T>(string objName, string bundleKey = null, Action<T> onGetObj = null)
            where T : Object
        {
            if (null == pather)
                throw new Exception("没有初始化MemoryMgr.Pather");

            Assert.IsNotNull(onGetObj);

            if (originBundleConst.KeyToName.ContainsKey(bundleKey))
            {
                var bundleName = originBundleConst.KeyToName[bundleKey];

                //如果缓存中有，就直接使用缓存
                var temp = GetSourceFromCache<T>($"{bundleName}_{objName}");
                if (null != temp)
                {
                    onGetObj(temp);
                    yield break;
                }
            }

            //缓存没有，使用加载器加载
            yield return assetBundleLoader.GetBundleAsync(bundleKey,
                ab => GetAssetFormBundleAsync(ab, objName, onGetObj));

        }
        private IEnumerator GetAssetFormBundleAsync<T>(AssetBundle assetBundle, string _objName, Action<T> _onGetObj)
            where T : Object
        {
            var objRequest = assetBundle.LoadAssetAsync<T>(_objName);
            yield return objRequest;

            //添加到缓存
            var ans = objRequest.asset as T;
            if (null == ans)
                throw new Exception("Get Asset is null");
            SourceObjects.Add($"{assetBundle.name}_{_objName}", ans);

            var asset = (T) objRequest.asset;
            Assert.IsNotNull(asset);
            //使用物品
            _onGetObj(asset);
        }
        public void ClearCache()
        {
            SourceObjects.Clear();
        }

        #endregion
    }
}


text:
namespace ReadyGamerOne.Global
{
    /// <summary>
    /// 继承此接口，类中加上私有静态OnGUI就可以在Tools窗口中绘制控件
    /// </summary>
    public interface IEditorTools
    {
//        private static string Title = "标题";
//        private static void OnToolsGUI(string rootNs,string viewNs,string constNs,string dataNs,string autoDir,string scriptDir)
    }
}

mime_type: text/plain


text:
using System;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Object = UnityEngine.Object;

namespace ReadyGamerOne.Global
{
    public partial class GlobalVar
    {
        public static event Action<Canvas> onCreateCanvas;
        public static GameObject GCanvasObj
        {
            get
            {
                if (canvasObj == null)
                {
                    var c = Object.FindObjectOfType<Canvas>();
                    if (c)
                    {
                        canvasObj = c.gameObject;
                    }
                    else
                    {
                        var canvasObj = new GameObject("GlobalCanvas");
                        canvasObj.AddComponent<RectTransform>();
                        c = canvasObj.AddComponent<Canvas>();
                        canvasObj.AddComponent<CanvasScaler>();
                        canvasObj.AddComponent<GraphicRaycaster>();
                        c.renderMode = RenderMode.ScreenSpaceOverlay;
                        onCreateCanvas?.Invoke(c);
                        GlobalVar.canvasObj = canvasObj;

                        if (null == Object.FindObjectOfType<EventSystem>())
                        {
                            var es = new GameObject("EventSystem");
                            es.AddComponent<EventSystem>();
                            es.AddComponent<StandaloneInputModule>();
                        }
                    }

                    Assert.IsTrue(canvasObj);

                    _canvasCom = canvasObj.GetComponent<Canvas>();
                }

                return canvasObj;
            }
        }

        public static Canvas CanvasComponent => _canvasCom;

        private static GameObject canvasObj;
        private static Canvas _canvasCom;

        public static Vector3 GCanvasButton => GCanvasObj.transform.position - new Vector3(0, Screen.height, 0);

        public static Vector3 GCanvasTop => GCanvasObj.transform.position + new Vector3(0, Screen.height, 0);

        public static Vector3 GCanvasLeft => GCanvasObj.transform.position - new Vector3(Screen.width, 0, 0);

        public static Vector3 GCanvasRight => GCanvasObj.transform.position + new Vector3(Screen.width, 0, 0);
    }
}


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


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


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


text:
using UnityEngine;

namespace ReadyGamerOne.Attributes
{
    public class RequireInterfaceAttribute : PropertyAttribute
    {
        // Interface type.
        public System.Type requiredType { get; private set; }

        /// <summary>
        /// Requiring implementation of the <see cref="T:RequireInterfaceAttribute"/> interface.
        /// </summary>
        /// <param name="type">Interface type.</param>
        public RequireInterfaceAttribute(System.Type type)
        {
            this.requiredType = type;
        }
    }
}


text:
fileFormatVersion: 2
guid: daae25fb233f4659818d12242ec200b1
timeCreated: 1588131508


text:
using UnityEngine;
using UnityEditor;

namespace ReadyGamerOne.Attributes.Editor
{
    /// <summary>
    /// Drawer for the RequireInterface attribute.
    /// </summary>
    [CustomPropertyDrawer(typeof(RequireInterfaceAttribute))]
    public class RequireInterfaceDrawer : PropertyDrawer
    {
        /// <summary>
        /// Overrides GUI drawing for the attribute.
        /// </summary>
        /// <param name="position">Position.</param>
        /// <param name="property">Property.</param>
        /// <param name="label">Label.</param>
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            // Check if this is reference type property.
            if (property.propertyType == SerializedPropertyType.ObjectReference)
            {
                // Get attribute parameters.
                var requiredAttribute = this.attribute as RequireInterfaceAttribute;
                // Begin drawing property field.
                EditorGUI.BeginProperty(position, label, property);
                // Draw property field.
                property.objectReferenceValue = EditorGUI.ObjectField(position, label, property.objectReferenceValue, requiredAttribute.requiredType, true);
                // Finish drawing property field.
                EditorGUI.EndProperty();
            }
            else
            {
                // If field is not reference, show error message.
                // Save previous color and change GUI to red.
                var previousColor = GUI.color;
                GUI.color = Color.red;
                // Display label with error message.
                EditorGUI.LabelField(position, label, new GUIContent("Property is not a reference type"));
                // Revert color change.
                GUI.color = previousColor;
            }
        }
    }

}


text:
fileFormatVersion: 2
guid: 03d60547f3cd44919a7487ef458f095a
timeCreated: 1588131140


text:
namespace ReadyGamerOne.Const
{
    /// <summary>
    /// 关于版本控制的常量类
    /// </summary>
    public class VersionDefine
    {
        /// <summary>
        /// 当前客户端版本的PlayerPref键
        /// </summary>
        public static string PrefKey_LocalVersion => "NewestVersion";
    }
}


text:
fileFormatVersion: 2
guid: 433dcfc72c094985840757b1b43871b6
timeCreated: 1578976286


text:
namespace ReadyGamerOne.Const
{
    /// <summary>
    /// 保存所有继承 ITxtSerialiable接口的类的标识
    /// 初始化的时候TxtManager类需要注册这些字符串，否则无法使用
    /// </summary>
    public static partial class TxtSign
    {
        public static readonly char txtSplitChar = ',';

    }
}


text:
using System.Collections.Generic;
using ReadyGamerOne.Common;

namespace ReadyGamerOne.Const
{
    public class ConstUtil<T>:
        Singleton<ConstUtil<T>>
    {
        protected virtual Dictionary<string, string> nameToPath => null;

        public string GetPath(string resName)
        {
            if (!nameToPath.ContainsKey(resName))
                throw new System.Exception("没有这个资源名：" + resName);
            return nameToPath[resName];
        }
    }
}


text:
fileFormatVersion: 2
guid: 36d7a4c66fa64a2cb451ff1d9f751a13
timeCreated: 1578465232


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


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


text:
using ReadyGamerOne.Script;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

namespace ReadyGamerOne.Scripts
{
    public class SuperBloodBar : MonoBehaviour
    {

        #region Transition

        [Range(0,1f)] public float transitionTimeScaler=1.0f;
        public Image transitionImage;
        [SerializeField] private Color transitionColor;

        private Coroutine coroutine;

        public Color TransitionColor
        {
            set
            {
                if (transitionImage == null)
                {
                    Debug.LogError("transitionImage is null");
                    return;
                }
                transitionImage.color = value;
            }
            get
            {

                if (transitionImage == null)
                {
                    Debug.LogError("transitionImage is null");
                    return Color.black;
                }

                return transitionImage.color;

            }
        }
        private RectTransform TransitionRect
        {
            get
            {
                if (transitionImage == null)
                {
                    Debug.LogError("TransitionImage is null");
                    return null;
                }
                return transitionImage.GetComponent<RectTransform>();
            }
        }

        #endregion

        #region Fill

        public Image fillImage;
        [SerializeField] private Color fillColor;

        public Color FillColor
        {
            get
            {
                if (fillImage == null)
                {
                    Debug.LogError("FillImage is null");
                    return Color.black;
                }

                return fillImage.color;
            }
            set
            {
                if (fillImage == null)
                {

                    Debug.LogError("FillImage is null");
                    return;
                }

                fillImage.color = value;
            }
        }
        private RectTransform FillRect
        {
            get
            {
                if (fillImage == null)
                {
                    Debug.LogError("fillImage is null");
                    return null;
                }

                return fillImage.GetComponent<RectTransform>();
            }
        }

        #endregion

        #region BackGround

        public Image backGroundImage;
        [SerializeField] private Color backGroundColor;

        public Color BackGroundColor
        {
            get
            {
                if (backGroundImage == null)
                {
                    Debug.LogError("BackGroundImage is null");
                    return Color.black;
                }

                return backGroundImage.color;
            }
            set
            {
                if (backGroundImage == null)
                {
                    Debug.LogError("BackGroundImage is null");
                    return ;
                }

                backGroundImage.color = value;
            }
        }

        private Vector3[] corners=new Vector3[4];
        private float SizeDeltaX
        {
            get
            {
                if (backGroundImage == null)
                {
                    Debug.LogError("backGroundImage is null");
                    return -1;
                }
                backGroundImage.GetComponent<RectTransform>().GetLocalCorners(corners);
                return (corners[2].x - corners[1].x);
            }
        }

        #endregion

        public float maxValue = 1.0f;
        [SerializeField] private float value=1;
        private float transitionValue;
        private float timer = 0;

        /// <summary>
        /// 实际值
        /// </summary>
        public float Value
        {
            get { return value; }
            set
            {

                ValueChangeTransition(this.value, value);

                this.value = value;

                var fillRect = FillRect;
                if (fillRect == null)
                    return;
                fillRect.sizeDelta=new Vector2(
                    -(1-this.value/maxValue) *Mathf.Abs(SizeDeltaX),
                    fillRect.sizeDelta.y);

                onValueChange?.Invoke(value);
            }
        }

        public UnityEvent<float> onValueChange;

        /// <summary>
        /// 过渡值
        /// </summary>
        private float TransitionValue
        {
            get { return transitionValue; }
            set
            {
                if (this == null)
                    return ;
                transitionValue = value;

                var transitionRect = TransitionRect;
                transitionRect.sizeDelta = new Vector2(
                    -(1-this.transitionValue/maxValue) * Mathf.Abs(SizeDeltaX),
                    transitionRect.sizeDelta.y);

            }
        }

        private float speed;

        protected void Start()
        {
            TransitionValue = value;
            Value = value;
        }

        public void InitValue(float value)
        {
            this.maxValue = value;
            this.Value = value;
        }

        private void ValueChangeTransition(float oldValue, float newValue)
        {
            if(!Application.isPlaying)
                return;
//            Debug.Log("??????");
            timer = 0;
            if (coroutine != null)
                MainLoop.Instance.StopCoroutine(coroutine);
            coroutine= MainLoop.Instance.UpdateForSeconds(() =>
            {
                timer += Time.deltaTime;
                TransitionValue =
                    Mathf.SmoothDamp(TransitionValue, newValue, ref speed,
                        transitionTimeScaler*0.2f); //(oldValue, newValue, timer / transitionTime);
            }, transitionTimeScaler);
        }

    }
}


text:
fileFormatVersion: 2
guid: 059a857ed62ede048b44a36df2c78446
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
fileFormatVersion: 2
guid: 8089b8baa13f4f67a715c80f5c2cc7ea
timeCreated: 1570502684


text:
using System;
using ReadyGamerOne.Utility;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;

namespace ReadyGamerOne.Scripts.Editor
{
    [CustomEditor(typeof(SuperBloodBar))]
    public class SuperBloodBarEditor:UnityEditor.Editor
    {
        private SerializedProperty transitionTimeProp;
        private SerializedProperty transitionImageProp;
        private SerializedProperty transitionColorProp;

        private SerializedProperty fillImageProp;
        private SerializedProperty fillColorProp;

        private SerializedProperty backGroundImageProp;
        private SerializedProperty backGroundColorProp;

        private SerializedProperty maxValueProp;
        private SerializedProperty valueProp;

        private SerializedProperty onValueChangeProp;

        private SuperBloodBar bloodBar;
        private RectTransform selfRect;
        private void OnEnable()
        {
            this.bloodBar=target as SuperBloodBar;
            selfRect = bloodBar.GetComponent<RectTransform>();

            transitionTimeProp = serializedObject.FindProperty("transitionTimeScaler");
            transitionImageProp = serializedObject.FindProperty("transitionImage");
            if (transitionImageProp.objectReferenceValue == null)
                transitionImageProp.objectReferenceValue = GetComponentFromTransform<Image>(bloodBar.transform, "Transition");

            transitionColorProp = serializedObject.FindProperty("transitionColor");
            fillImageProp = serializedObject.FindProperty("fillImage");
            if (fillImageProp.objectReferenceValue == null)
                fillImageProp.objectReferenceValue = GetComponentFromTransform<Image>(bloodBar.transform, "Fill");
            fillColorProp = serializedObject.FindProperty("fillColor");
            backGroundImageProp = serializedObject.FindProperty("backGroundImage");
            if (backGroundImageProp.objectReferenceValue == null)
                backGroundImageProp.objectReferenceValue =
                    GetComponentFromTransform<Image>(bloodBar.transform, "BackGround");
            backGroundColorProp = serializedObject.FindProperty("backGroundColor");
            maxValueProp = serializedObject.FindProperty("maxValue");
            valueProp = serializedObject.FindProperty("value");
            onValueChangeProp = serializedObject.FindProperty("onValueChange");
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(fillImageProp);
            if (EditorGUI.EndChangeCheck())
            {
                var image = fillImageProp.objectReferenceValue as Image;
                var rect = image.GetComponent<RectTransform>();
                rect.name = "Fill";
                rect.SetParent(bloodBar.transform,false);
                var size = selfRect.rect.size;
                size.x *= selfRect.pivot.x-0.5f;
                size.y *= selfRect.pivot.y-0.5f;
                rect.localPosition=-size;
                rect.anchorMin=Vector2.zero;
                rect.anchorMax=Vector2.one;
                rect.pivot = new Vector2(0, 0.5f);
                rect.sizeDelta=Vector2.zero;
                fillColorProp.colorValue=Color.green;
                image.color = fillColorProp.colorValue;
            }

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(fillColorProp);
            if (EditorGUI.EndChangeCheck())
            {
                var alpha = bloodBar.FillColor.a;
                bloodBar.FillColor = fillColorProp.colorValue;
                bloodBar.fillImage.SetAlpha(alpha);
            }
            EditorGUILayout.Separator();

            EditorGUILayout.PropertyField(transitionTimeProp);

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(transitionImageProp);
            if (EditorGUI.EndChangeCheck())
            {
                var image = transitionImageProp.objectReferenceValue as Image;
                var rect = image.GetComponent<RectTransform>();
                rect.SetParent(bloodBar.transform,false);
                rect.name = "Transition";
                var size = selfRect.rect.size;
                size.x *= selfRect.pivot.x-0.5f;
                size.y *= selfRect.pivot.y-0.5f;
                rect.localPosition=-size;
                rect.anchorMin=Vector2.zero;
                rect.anchorMax=Vector2.one;
                rect.pivot = new Vector2(0, 0.5f);
                rect.sizeDelta=Vector2.zero;
                transitionColorProp.colorValue=Color.yellow;
                image.color = transitionColorProp.colorValue;
            }

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(transitionColorProp);
            if (EditorGUI.EndChangeCheck())
            {
                var alpha = bloodBar.TransitionColor.a;
                bloodBar.TransitionColor = transitionColorProp.colorValue;
                bloodBar.transitionImage.SetAlpha(alpha);

            }
            EditorGUILayout.Separator();

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(backGroundImageProp);
            if (EditorGUI.EndChangeCheck())
            {
                var image = backGroundImageProp.objectReferenceValue as Image;
                var rect = image.GetComponent<RectTransform>();
                rect.name = "BackGround";
                rect.SetParent(bloodBar.transform,false);

                var size = selfRect.rect.size;
                size.x *= selfRect.pivot.x-0.5f;
                size.y *= selfRect.pivot.y-0.5f;
                rect.localPosition=-size;

                rect.anchorMin=Vector2.zero;
                rect.anchorMax=Vector2.one;
                rect.sizeDelta=Vector2.zero;
                backGroundColorProp.colorValue = Color.gray;
                image.color = backGroundColorProp.colorValue;
            }

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(backGroundColorProp);
            if (EditorGUI.EndChangeCheck())
            {
                var alpha = bloodBar.BackGroundColor.a;
                bloodBar.BackGroundColor = backGroundColorProp.colorValue;
                bloodBar.BackGroundColor.SetAlpha(alpha);
            }
            EditorGUILayout.Separator();

            EditorGUILayout.PropertyField(maxValueProp);
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.Slider(valueProp, 0, maxValueProp.floatValue);
            if (EditorGUI.EndChangeCheck())
            {
                bloodBar.Value = valueProp.floatValue;
            }

            serializedObject.ApplyModifiedProperties();
        }

        private T GetComponentFromTransform<T>(Transform from, string path)
        where T:MonoBehaviour
        {
            if (from == null)
                throw new Exception("当前物品为空");
            var obj = from.Find(path);
            if (obj == null)
                return null;

            return obj.GetComponent<T>();
        }
    }
}


text:
fileFormatVersion: 2
guid: 1ec27d6a01d84e32a634aaac83a212c1
timeCreated: 1576046429


text:
fileFormatVersion: 2
guid: 82eb940f41d7442fa2a401e91f92e185
timeCreated: 1576501097


text:
fileFormatVersion: 2
guid: d09e5b7b193a42699865d90cfd46bde5
timeCreated: 1579181420


text:
fileFormatVersion: 2
guid: 77b7d763c0ba4c5d8200c31f6caad036
timeCreated: 1576119761


text:
fileFormatVersion: 2
guid: f5aca46b802949ed8925671093e0522c
timeCreated: 1588125401


text:
fileFormatVersion: 2
guid: f21f882c174048d7add2aa9a1b90954b
timeCreated: 1576120417


text:
using ReadyGamerOne.Common;

namespace ReadyGamerOne.Rougelike.Item
{
    public interface IItemInfo : IHasStringId
    {
        string ItemName { get; }
        string UiText { get; }
        int Count { get; }
        string SpriteName { get; }
        string ItemPrefabName { get; }
        string Statement { get; }
        int MaxSlotCount { get; }
    }

    public abstract class AbstractItemInfo:
        IItemInfo
    {
        public abstract string ID { get; }

        /// <summary>
        /// 物品名，需要符合变量命名规则，同时和Sprite资源名一致
        /// </summary>
        public abstract string ItemName { get; }

        /// <summary>
        /// 显示给玩家看的名字，一般是中文
        /// </summary>
        public abstract string UiText { get; }

        /// <summary>
        /// 当前拥有的物品数量
        /// </summary>
        public abstract int Count { get; set; }

        /// <summary>
        /// 图片资源加载路径
        /// </summary>
        public abstract string SpriteName { get; }

        /// <summary>
        /// 物品预制体加载路径
        /// </summary>
        public virtual string ItemPrefabName => null;

        /// <summary>
        /// 物品描述
        /// </summary>
        public virtual string Statement => "没有物品描述";

        /// <summary>
        /// 一个格子最多放置多少该物品
        /// </summary>
        public virtual int MaxSlotCount => 999;
    }
}


text:
using System;
using ReadyGamerOne.Data;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace ReadyGamerOne.Rougelike.Item
{
    public abstract class Slot<T,DataType> :
        MonoBehaviour,
        IPointerEnterHandler,
        IPointerExitHandler,
        IPointerClickHandler
    where T:Slot<T,DataType>
    where DataType :CsvMgr
    {
        public DataType ItemData;
        public Image icon;
        public Text countText;
        public event Action<T> onPointerEnter;
        public event Action<T> onPointerExit;
        public event Action<T> onPointerClick;

        private Action<string> onDelete;

        public int Count => int.Parse(countText.text);

        public void Init(string itemId, int count = 1,Action<string> ondelete=null)
        {
            this.onDelete = ondelete;

            ItemData = CsvMgr.GetData<DataType>(itemId);

            countText.text = count.ToString();

            UseItemData();
        }

        protected abstract void UseItemData();

        public void Add(int count)
        {
            countText.text = (Count + count).ToString();
        }

        public int Remove(int amount)
        {
            var count = Count;
            if (count <= amount)
            {
                onDelete?.Invoke(ItemData.ID);
                Destroy(gameObject);
                return count;
            }

            countText.text = (Count - amount).ToString();

            return amount;
        }

        public void OnPointerEnter(PointerEventData eventData)
        {
            onPointerEnter?.Invoke(this as T);
        }

        public void OnPointerExit(PointerEventData eventData)
        {
            onPointerExit?.Invoke(this as T);
        }

        public void OnPointerClick(PointerEventData eventData)
        {
            onPointerClick?.Invoke(this as T);
        }
    }
}


text:
using System.Collections.Generic;

namespace ReadyGamerOne.Rougelike.Item
{
    /// <summary>
    /// 具有获取道具功能的角色需要实现此接口
    /// </summary>
    /// <typeparam name="ItemType"></typeparam>
    public interface IItemablePerson<ItemType>
        where ItemType:IItemInfo
    {
        /// <summary>
        /// 添加物品
        /// </summary>
        /// <param name="itemId">添加物品的Id</param>
        /// <param name="count">添加物品个数</param>
        /// <returns>当前这个物品的信息</returns>
        ItemType AddItem(string itemId,int count=1);
        /// <summary>
        /// 移除物品
        /// </summary>
        /// <param name="itemId">移除物品个数</param>
        /// <param name="count">移除物品个数</param>
        /// <returns>当前这个物品的信息</returns>
        ItemType RemoveItem(string itemId,int count=1);
        /// <summary>
        /// 获取物品信息
        /// </summary>
        /// <returns></returns>
        Dictionary<string,ItemType> GetItems();
        /// <summary>
        /// 获取物品数量
        /// </summary>
        /// <param name="itemId"></param>
        /// <returns></returns>
        int GetItemCount(string itemId);
    }
}


text:
fileFormatVersion: 2
guid: fa10eea2e8a8451db6e93881dbf24ecc
timeCreated: 1576119931


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


text:
using System;
using UnityEngine;

namespace ReadyGamerOne.Rougelike.Mover
{
    public interface IMover2D
    {
        /// <summary>
        /// 设置和获取位置
        /// </summary>
        Vector3 Position { get; set; }

        /// <summary>
        /// 获取和设置速度
        /// </summary>
        Vector2 Velocity { get; set; }

        /// <summary>
        /// 重力实际值
        /// </summary>
        float Gravity { get; set; }

        /// <summary>
        /// 重力缩放值
        /// </summary>
        float GravityScale { get; set; }

        /// <summary>
        /// 会和什么层发生碰撞碰撞
        /// </summary>
        LayerMask ColliderLayers { get; set; }

        /// <summary>
        /// 会和那些层触发Trigger但不碰撞
        /// </summary>
        LayerMask TriggerLayers { get; set; }

        /// <summary>
        /// 上方是否有碰撞
        /// </summary>
        bool CollidedUp { get; }
        /// <summary>
        /// 下方是否有碰撞
        /// </summary>
        bool CollidedDown { get; }
        /// <summary>
        /// 左方是否有碰撞
        /// </summary>
        bool CollidedLeft { get; }
        /// <summary>
        /// 右方是否有碰撞
        /// </summary>
        bool CollidedRight { get; }

        event Action<RaycastHit2D> eventOnColliderEnter;
        event Action<RaycastHit2D> eventOnColliderStay;
        event Action<RaycastHit2D> eventOnColliderExit;
        event Action<GameObject> eventOnTriggerEnter;
        event Action<GameObject> eventOnTriggerStay;
        event Action<GameObject> eventOnTriggerExit;
    }
}


text:
fileFormatVersion: 2
guid: ca70adc1569847139fb37cedd9a18b5f
timeCreated: 1588125427


text:
namespace ReadyGamerOne.Rougelike.Agent
{
    public interface IAgent
    {

    }
}


text:
fileFormatVersion: 2
guid: d103361cf20541dfbb9ac99b0595e19e
timeCreated: 1576501160


text:
using ReadyGamerOne.Common;
using ReadyGamerOne.MemorySystem;
using UnityEngine;
using UnityEngine.Assertions;

namespace ReadyGamerOne.Rougelike
{
    public abstract class AbstractEffect<T>:
        IPoolable,
        IResourcableObject
    where T:AbstractEffect<T>,new()
    {
        #region Fields

        private GameObject _gameObject;

        #endregion

        #region IResourcableObject

        #region IUnityGameObject

        public GameObject gameObject => _gameObject;
        public Transform transform => _gameObject?.transform;

        public Vector3 position
        {
            get
            {
                Assert.IsNotNull(transform);
                return transform.position;
            }
            set
            {
                Assert.IsNotNull(transform);
                transform.position = value;
            }
        }
        public Vector3 localPosition
        {
            get
            {
                Assert.IsNotNull(transform);
                return transform.localPosition;
            }
            set
            {
                Assert.IsNotNull(transform);
                transform.localPosition = value;
            }
        }
        #endregion

        public abstract string ResKey { get; }
        public virtual void OnInstanciateObject()
        {
            Assert.IsNull(_gameObject);
            _gameObject = ResourceMgr.InstantiateGameObject(ResKey);
        }

        public virtual void Destroy()
        {
            if(_gameObject)
                Object.Destroy(_gameObject);
        }

        public virtual void EnableObject()
        {
            if(!_gameObject)
                this.OnInstanciateObject();
            Assert.IsTrue(_gameObject);
            gameObject?.SetActive(true);
        }

        public virtual void DisableObject()
        {
            gameObject?.SetActive(false);
        }

        #endregion

        #region IPoolable<AbstractEffect>

        public virtual void OnRecycleToPool()
        {
            DisableObject();
        }

        public virtual void OnGetFromPool()
        {
            EnableObject();
        }

        #endregion

        protected AbstractEffect()
        {
            this.OnInstanciateObject();
        }

    }
}


text:
fileFormatVersion: 2
guid: 1a301b12dc114e8cacdc1dda76ab9fee
timeCreated: 1579181455


text:
using System.IO;
using ReadyGamerOne.Global;
using ReadyGamerOne.Utility;
using UnityEditor;
using UnityEngine;
using FileUtil = ReadyGamerOne.Utility.FileUtil;

namespace ReadyGamerOne.Rougelike.Person
{
    public class PersonTool
#if UNITY_EDITOR
        :IEditorTools
#endif
    {
#if UNITY_EDITOR
#pragma warning disable 414
        static string Title = "角色系统";
#pragma warning restore 414
        private static string sourDir;
        private static string generateDir;
        private static bool createControllers = true;

        static void OnToolsGUI(string rootNs, string viewNs, string constNs, string dataNs, string autoDir,
            string scriptDir)
        {
               EditorGUILayout.Space();

               EditorGUILayout.HelpBox("使用本工具需要满足以下条件：\n" +
                                       "1、源预制体目录在Resources下\n" +
                                       "2、需要单独分类的角色放在Type前缀目录下\n" +
                                       "3、需要有和分类名对应的Data类型",MessageType.Info);

               EditorGUILayout.Space();

               EditorGUILayout.LabelField("角色预制体目录", sourDir);
               if (GUILayout.Button("编辑角色预制体路径"))
               {
                   sourDir = EditorUtility.OpenFolderPanel("选择预制体目录", Application.dataPath, "");
               }

               EditorGUILayout.Space();

               EditorGUILayout.LabelField("角色类命名空间",rootNs+".Model.Person");
               createControllers = EditorGUILayout.Toggle("是否生成对应控制器", createControllers);

               EditorGUILayout.Space();

               if (GUILayout.Button("开始生成", GUILayout.Height(3 * EditorGUIUtility.singleLineHeight)))
               {
                   if (string.IsNullOrEmpty(sourDir))
                   {
                       Debug.LogError("预制体目录不能为空");
                       return;
                   }
                   if (!sourDir.Contains("Resources"))
                   {
                       Debug.LogError("预制体目录需要在Resources下");
                       return;
                   }

                   StartGenerate( rootNs, createControllers);
               }

        }

        private static string rootNs;

        private static void StartGenerate(string rootNs, bool createControllers)
        {
            PersonTool.rootNs = rootNs;

            FileUtil.SearchDirectory(
                sourDir,
                OnOperateFile,
                true,
                OnOperateFolder);

            AssetDatabase.Refresh();
            Debug.Log("生成完毕");
        }

        private static bool OnOperateFolder(DirectoryInfo dirInfo)
        {

//            if (dirInfo.FullName!=sourDir && dirInfo.Name.StartsWith("Type") == false)
//                return false;

            var curName = dirInfo.Name;
            var parName = dirInfo.Parent.Name;

            var parControllerName = "";
            var controllerName = "";
            if ( curName == FileUtil.GetDirName(sourDir))
            {
                parName = "PoolDataPerson";
                curName = "Person";
                controllerName = rootNs + curName + "Controller";
                parControllerName = "AbstractPersonController";
            }
            else if(parName == FileUtil.GetDirName(sourDir))
            {
                parName = rootNs + "Person";
                curName = curName.GetAfterSubstring("Type");

                controllerName = rootNs + curName + "Controller";
                parControllerName = parName + "Controller";
            }
            else
            {
                parName = rootNs + parName.GetAfterSubstring("Type");
                curName = curName.GetAfterSubstring("Type");

                controllerName = rootNs + curName + "Controller";
                parControllerName = parName + "Controller";
            }

            var genDir = Application.dataPath + "/" + rootNs + "/Model/Person" + dirInfo.GetSpecialPath("Type")+"/"+rootNs+curName;

            CreateAbstractPersonType(genDir,dirInfo,curName,parName);
            CreateAbstractControllerType(genDir, curName, controllerName, parControllerName);
            return true;
        }

        private static void OnOperateFile(FileInfo fileInfo)
        {
            if(fileInfo.Name.EndsWith(".meta"))
                return;
            var fileName = Path.GetFileNameWithoutExtension(fileInfo.FullName);
            var genPath = Application.dataPath + "/" + rootNs + "/Model/Person" +
                          fileInfo.Directory.GetSpecialPath("Type") + "/" + fileName;
            var parentName = rootNs + fileInfo.Directory.Name.GetAfterSubstring("Type");

            CreatePersonType(genPath, fileName, parentName);
            CreateControllerType(genPath, fileName + "Controller", parentName + "Controller");
//
//            Debug.Log(genPath+"\n" +
//                      parentName+"\n" +
//                      fileInfo.Name);
        }

        private static void CreateControllerType(string gendir, string className, string parentName)
        {
            FileUtil.CreateFolder(gendir);

            var fullpath = gendir + "/" + className + ".cs";
            if (File.Exists(fullpath))
                return;

            var stream = File.CreateText(fullpath);

            stream.Write("namespace "+rootNs+".Model.Person\n" +
                         "{\n" +
                         "\tpublic class "+className+" :\n" +
                         "\t\t"+parentName+"\n" +
                         "\t{\n" +
                         "\t\tpublic override void SetMoveable(bool state)\n" +
                         "\t\t{\n" +
                         "\t\t\tthrow new System.NotImplementedException();\n" +
                         "\t\t}\n" +
                         "\t}\n" +
                         "}\n");

            stream.Dispose();
            stream.Close();
        }

        private static void CreatePersonType(string gendir, string className, string parentName)
        {
            FileUtil.CreateFolder(gendir);

            var fullpath = gendir + "/" + className + ".cs";
            if (File.Exists(fullpath))
                return;

            var stream = File.CreateText(fullpath);

            stream.Write("using ReadyGamerOne.Data;\n" +
                         "using ReadyGamerOne.Rougelike.Person;\n" +
                         "using " + rootNs + ".Const;\n" +
                         "namespace " + rootNs + ".Model.Person\n" +
                         "{\n");
            if(createControllers)
                stream.Write("\t[UsePersonController(typeof("+className+"Controller))]\n");
            stream.Write("\tpublic partial class "+className+" :\n" +
                         "\t\t"+parentName+"<"+className+">\n" +
                         "\t{\n" +
                         "\t\tpublic override string ResKey => PersonName."+className+";\n" +
                         "\t\tpublic override void LoadData(CsvMgr data)\n" +
                         "\t\t{\n" +
                         "\t\t\t//    如果父类没有此方法，删掉就行\n"+
                         "\t\t\tbase.LoadData(data);\n"+
                         "\t\t\t//    在这里需要使用数据对类内变量进行初始化赋值(比如_hp,_maxhp,_attack，这三项自动生成在基类中了)\n" +
                         "\t\t\t//    这个函数人物每次激活时都会调用\n" +
                         "\t\t}\n" +
                         "\t}\n" +
                         "}\n");

            stream.Dispose();
            stream.Close();
        }

        private static void CreateAbstractControllerType(string gendir,string curName, string controllerName, string parControllerName)
        {
            FileUtil.CreateClassFile(
                controllerName,
                rootNs + ".Model.Person",
                gendir,
                parControllerName,
                curName+"角色控制类，在角色类加UsePersonController属性的话会自动添加上去，使用InitController初始化",
                usingStatements:"using ReadyGamerOne.Rougelike.Person;\n",
                isAbstract:true);
        }

        private static void CreateAbstractPersonType(string gendir, DirectoryInfo dirInfo, string curName,string parName)
        {
            var className = rootNs + curName;

            var isRootPerson = new DirectoryInfo(dirInfo.FullName).FullName == new DirectoryInfo(sourDir).FullName;

            FileUtil.CreateFolder(gendir);

            var fileFullPath = gendir + "/" + className + ".cs";
            if (File.Exists(fileFullPath))
                return;

            var stream = File.CreateText(fileFullPath);

            stream.Write("using ReadyGamerOne.Rougelike.Person;\n");

            if (dirInfo.HasValuableFiles())
                stream.Write("using System;\n" +
                             "using "+rootNs+".Data;\n");

            stream.Write("using UnityEngine;\n\n" +
                         "namespace " + rootNs + ".Model.Person\n" +
                         "{\n" +
                         "\tpublic interface I" + className);

            if(!isRootPerson)
                stream.Write(" : \n" +
                             "\t\tI"+parName);
            stream.Write("\n" +
                         "\t{\n" +
                         "\t}\n\n" +
                         "\tpublic abstract class " + className + "<T>:\n" +
                         "\t\t" + parName + "<T>,\n" +
                         "\t\tI" + className + "\n" +
                         "\t\twhere T : " + className + "<T>,new()\n" +
                         "\t{\n");

            if(isRootPerson)
                stream.Write("\t\t#region Fields\n\n" +
                             "\t\tprotected int _hp;\n" +
                             "\t\tprotected int _maxHp;\n" +
                             "\t\tprotected int _attack;\n\n" +
                             "\t\t#endregion\n\n" +
                             "\t\t#region ITakeDamageablePerson<T>\n\n" +
                             "\t\tpublic override int Hp => _hp;\n" +
                             "\t\tpublic override int MaxHp => _maxHp;\n" +
                             "\t\tpublic virtual void OnTakeDamage(AbstractPerson takeDamageFrom, int Damage)\n" +
                             "\t\t{\n" +
                             "\t\t\tDebug.Log($\"{CharacterName}收到来自{takeDamageFrom.CharacterName}的{Damage}伤害\");\n\n" +
                             "\t\t\t_hp -= Damage;\n" +
                             "\t\t\tif(_hp<0)\n" +
                             "\t\t\t\tKill();\n" +
                             "\t\t}\n\n" +
                             "\t\t public void OnCauseDamage(AbstractPerson causeDamageTo, int Damage)\n" +
                             "\t\t{\n" +
                             "\t\t\tDebug.Log($\"{CharacterName}对{causeDamageTo.CharacterName}造成{Damage}伤害\");\n" +
                             "\t\t}\n\n" +
                             "\t\t#endregion\n");

            if (dirInfo.HasValuableFiles())
                stream.Write("\t\tpublic override Type DataType => typeof(" + curName + "Data);\n");

            stream.Write("\t}\n" +
                         "}\n");
            stream.Dispose();
            stream.Close();
        }
#endif
    }
}


text:
fileFormatVersion: 2
guid: f0552a7de340481b90592cea1e4dfb5b
timeCreated: 1576569002


text:
fileFormatVersion: 2
guid: e418c8945a7449709287f22aa51b6180
timeCreated: 1576043563


text:
namespace ReadyGamerOne.Rougelike.Person
{
    public class BasicDamage
    {
        public float OriginAttack { get; protected set; }
        public float Damage { get; protected set; }
        public float ScaleSkillDamageScale { get; protected set; }

        protected BasicDamage()
        {
        }

        public BasicDamage(IPerson person, float skillDamageScale, IPerson another)
        {
            this.ScaleSkillDamageScale = skillDamageScale;
            this.OriginAttack = person.Attack;
            Damage = person.Attack * skillDamageScale;
        }
    }
}


text:
fileFormatVersion: 2
guid: 5643659d5565453982b67fdd7fbdfe37
timeCreated: 1589364011


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


text:
fileFormatVersion: 2
guid: 3d776c3ab9484c2ca6bc8cce34da7d26
timeCreated: 1576734270


text:
using System;

namespace ReadyGamerOne.Rougelike.Person
{
    public interface IInteractablePerson
    {
        bool IfInteract { get; }
        Action<AbstractPerson> OnInteract { get; set; }
    }
}


text:
fileFormatVersion: 2
guid: 2e9005fe8c314f4999f8a5fd745e6d5f
timeCreated: 1576066939


text:
fileFormatVersion: 2
guid: a1d44106ac3f401aaac385841b21c03c
timeCreated: 1576411118


text:
fileFormatVersion: 2
guid: c9caf1d14c6c4630bbe3ca0decbdd7df
timeCreated: 1576066980


text:
using System;

namespace ReadyGamerOne.Rougelike.Person
{
    /// <summary>
    /// 可以制造和承受伤害
    /// </summary>
    /// <typeparam name="PersonType"></typeparam>
    public interface ITakeDamageablePerson<PersonType,DamageType>
        where PersonType:AbstractPerson
    {
        /// <summary>
        /// 触发事件会对damage进行四舍五入
        /// </summary>
        event Action<AbstractPerson, int> onCauseDamage;
        event Action<AbstractPerson, int> onTakeDamage;

        DamageType CalculateDamage(float skillDamageScale, PersonType receiver);

        /// <summary>
        /// 承受这么多伤害
        /// </summary>
        /// <param name="takeDamageFrom">谁打我的</param>
        /// <param name="damage">外界带来的伤害</param>
        /// <returns>实际造成的伤害</returns>
        float OnTakeDamage(PersonType takeDamageFrom,DamageType damage);
        float OnCauseDamage(PersonType causeDamageTo,DamageType damage);

    }
}


text:
namespace ReadyGamerOne.Rougelike.Person
{
    public interface IRankablePerson
    {
        int Exp { get; }
        int MaxExp { get; }
        string Rank { get; }
        bool TryLevelUp(int extraExp);
    }
}


text:
fileFormatVersion: 2
guid: 22044ffabc3544d0b9b9b1c662ec2651
timeCreated: 1575994989


text:
fileFormatVersion: 2
guid: a9c8aa0dc301487895f46742377e7e01
timeCreated: 1575995550


text:
fileFormatVersion: 2
guid: f9c3a20c7cc14a918902ed1df30a1eaf
timeCreated: 1575995226


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


text:
using System;
using ReadyGamerOne.Common;
using UnityEngine;

namespace ReadyGamerOne.Rougelike.Person
{
    public interface IPoolPerson :
        IPerson,
        IPoolable
    {
        void Release();
        event Action<IPoolPerson> onAfterGet;
        event Action<IPoolPerson> onBeforeRealse;
    }

    /// <summary>
    /// 自带对象池维护的Person
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class PoolPerson<T> :
        AbstractPerson,
        IPoolPerson
        where T : PoolPerson<T>, new()
    {
        #region Static

        /// <summary>
        /// 对象池，这是整个泛型定义存在的意义!
        /// 泛型对象池可以做到为所有可能的子类各自维护一个对象池
        /// </summary>
        private static ObjPool<T> _objPool= new ObjPool<T>(
            () => new T(),
            obj => obj.OnRecycleToPool(),
            obj => obj.OnGetFromPool());

        public static T GetInstance(Vector3? pos, Transform parent = null)
        {
            var person = _objPool.GetObj();
            if (parent)
                parent.gameObject.transform.SetParent(parent);
            if(pos!=null)
                person.gameObject.transform.position = pos.Value;
            return person;
        }

        #endregion

        /// <summary>
        /// 重写死亡操作，对象池控制的话就不会销毁，而是回收
        /// </summary>
        public override void LogicKill()
        {
            Release();
        }

        /// <summary>
        /// 重写快速终结操作
        /// </summary>
        public override void Destroy()
        {
            Release();
        }

        public override bool IsAlive
        {
            get
            {
                if (gameObject == null)
                    return false;

                return gameObject.activeSelf && Hp > 0;
            }
        }

        #region 对象池操作，只有在角色出生和死亡时调用

        public virtual void OnRecycleToPool()
        {
            onBeforeRealse?.Invoke(this);
            DisableObject();
        }

        public virtual void OnGetFromPool()
        {
            EnableObject();
            onAfterGet?.Invoke(this);
        }

        public void Release()
        {
            TickOnKillEventAndClearEvent();
            _objPool.ReleaseObj(this as T);
        }

        public event Action<IPoolPerson> onAfterGet;
        public event Action<IPoolPerson> onBeforeRealse;

        #endregion

        #region 禁止子类重载EnableObject和DisableObject，使用OnGetFromPool和OnRecycleToPool代替

        public sealed override void EnableObject()
        {
            base.EnableObject();
        }

        public sealed override void DisableObject()
        {
            base.DisableObject();
        }

        #endregion

    }
}


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


text:
fileFormatVersion: 2
guid: c91bd89f59744690bd8b13dffeed9495
timeCreated: 1575995161


text:
using System;
using UnityEngine;

namespace ReadyGamerOne.Rougelike.Person
{
    public static class AttackPersonExtension
    {

        /// <summary>
        /// 尝试攻击另一单位
        /// </summary>
        /// <param name="self">自身角色</param>
        /// <param name="other">攻击目标</param>
        /// <param name="damageScale">攻击缩放，比如技能可能造成200%伤害</param>
        /// <returns>返回是否进行了有效攻击</returns>
        /// <exception cref="Exception">self为空</exception>
        public static bool TryAttack(this AbstractPerson self, AbstractPerson other, float? damageScale=null)
        {
            var ds = damageScale ?? 1.0f;

            var selfAtk = self as ITakeDamageablePerson<AbstractPerson,BasicDamage>;
            var otherAtk = other as ITakeDamageablePerson<AbstractPerson,BasicDamage>;

            if(null==self)
                throw new Exception("自身角色为空？");

            if (null == other)
                return false;

            if (!self.IsAlive || !other.IsAlive)
                return false;

            if (null == selfAtk || null == otherAtk)
                return false;

            var damage = self.CalculateDamage(ds, other);

            selfAtk.OnCauseDamage(other,damage);

            return true;
        }

        /// <summary>
        /// 尝试攻击另一单位，需要IFightablePerson<T>接口
        /// </summary>
        /// <param name="self"></param>
        /// <param name="other"></param>
        /// <param name="damageScale"></param>
        /// <returns>有效攻击返回True，否则返回False</returns>
        public static bool TryAttack(this IPerson self, IPerson other, float? damageScale=null)
        {
            if (self == null || other == null)
                return false;

            return self.gameObject.TryAttack(other.gameObject,damageScale);
        }

        /// <summary>
        /// 尝试用一个GameObject对另一单位造成伤害
        /// </summary>
        /// <param name="self"></param>
        /// <param name="other"></param>
        /// <param name="damageScale"></param>
        /// <returns></returns>
        public static bool TryAttack(this GameObject self, GameObject other, float? damageScale=null)
        {
            if (self == null || other == null)
                return false;

            var selfPerson = self.GetPersonInfo();
            var otherPerson = other.GetPersonInfo();

            return selfPerson.TryAttack(otherPerson,damageScale);
        }
    }
}


text:
using UnityEngine;

namespace ReadyGamerOne.Rougelike.Person
{
    /// <summary>
    /// 拓展GameObject快速获取角色信息的引用
    /// </summary>
    public static class GameObjectExtension
    {
        public static T GetPersonInfo<T>(this GameObject obj)
            where T : AbstractPerson
        {
            if (obj == null)
                return null;
            var id = obj.GetComponent<AbstractPerson.PersonIdentity>();
            if (id == null)
                return null;
            return id.abstractPerson as T;
        }

        public static AbstractPerson GetPersonInfo(this GameObject obj)
        {
            var id = obj.GetComponent<AbstractPerson.PersonIdentity>();
            if (id)
                return id.abstractPerson;

            if (!obj.transform.parent)
                return null;

            return obj.GetComponentInParent<AbstractPerson.PersonIdentity>()?.abstractPerson;
        }
    }
}


text:
fileFormatVersion: 2
guid: 1a995cd464314046b0014c97760b2925
timeCreated: 1576720135


text:
using System;
using ReadyGamerOne.Common;
using ReadyGamerOne.MemorySystem;
using ReadyGamerOne.Utility;
using UnityEngine;
using UnityEngine.Assertions;
using Object = UnityEngine.Object;

namespace ReadyGamerOne.Rougelike.Person
{
    /// <summary>
    /// 人物信息接口
    /// </summary>
    public interface IPerson :
        ITakeDamageablePerson<AbstractPerson,BasicDamage>,
        IResourcableObject
    {
        /// <summary>
        /// 角色名
        /// </summary>
        string CharacterName { get; set; }

        AbstractPersonController Controller { get; }

        #region 战斗必须

        /// <summary>
        /// 角色是否活着
        /// </summary>
        bool IsAlive { get; }

        /// <summary>
        /// 当前生命值
        /// </summary>
        int Hp { get; }

        /// <summary>
        /// 最大生命值
        /// </summary>
        int MaxHp { get; }

        /// <summary>
        /// 基础攻击力
        /// </summary>
        int Attack { get; }

        /// <summary>
        /// 杀死当前角色
        /// </summary>
        void LogicKill();

        #endregion

        #region Events
        event Action onUpdate;

        #endregion

    }

    /// <summary>
    /// 必须有一个统一的基类来做统一处理
    /// </summary>
    public abstract class AbstractPerson:
        IPerson
    {
        #region Static

        public static event Action<AbstractPerson> OnPersonEnable;
        public static event Action<AbstractPerson> OnPersonDisable;

        #endregion

        #region 内部类，用于方便GameObject拿到PersonSystem引用

        public class PersonIdentity : MonoBehaviour
        {
            public AbstractPerson abstractPerson;

            public event Action onUpdate;

            private void Update()
            {
                onUpdate?.Invoke();
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// 构造函数里完成实例化，添加Identity组件，并设置不激活
        /// </summary>
        protected AbstractPerson()
        {
            this.OnInstanciateObject();
        }

        #endregion

        #region Fields

        public event Action onUpdate;
        public event Action<AbstractPerson> onBeforeKill;

        protected void TickOnKillEventAndClearEvent()
        {
//            Debug.Log("Tick onkill");
            onBeforeKill?.Invoke(this);

            onUpdate = null;
            onTakeDamage = null;
            onCauseDamage = null;
            onBeforeKill = null;
        }

        protected GameObject _gameObject;

        private AbstractPersonController _controller;

        #endregion

        #region ITakeDamageablePerson<T>

        public event Action<AbstractPerson, int> onCauseDamage;
        public event Action<AbstractPerson, int> onTakeDamage;

        public virtual BasicDamage CalculateDamage(float skillDamageScale, AbstractPerson receiver)
        {
            return new BasicDamage(this, skillDamageScale, receiver);
        }

        public virtual float OnTakeDamage(AbstractPerson takeDamageFrom, BasicDamage damage)
        {

            var finalDamage = Mathf.RoundToInt(damage.Damage);
            onTakeDamage?.Invoke(takeDamageFrom, finalDamage);
            Hp -= finalDamage;
//            Debug.Log($"{CharacterName}收到来自{takeDamageFrom.CharacterName}的{finalDamage}伤害,当前血量：{Hp}");

            var realDamage = 0f;
            if (Hp <= 0)
            {
                realDamage = Hp;
//                Debug.Log(CharacterName+"该死！");
                Hp = 0;
                LogicKill();
            }
            else
            {
                realDamage = finalDamage;
            }

            return realDamage;
        }

        public virtual float OnCauseDamage(AbstractPerson causeDamageTo, BasicDamage damage)
        {
            var realDamage = causeDamageTo.OnTakeDamage(this, damage);
            if(realDamage>0)
                onCauseDamage?.Invoke(causeDamageTo, Mathf.RoundToInt(realDamage));
            return realDamage;
//            Debug.Log($"{CharacterName}对{causeDamageTo.CharacterName}造成{realDamage}伤害");
        }

        #endregion

        #region IPerson

        /// <summary>
        /// 角色名字
        /// </summary>
        public virtual string CharacterName
        {
            get
            {
                if (!_gameObject)
                    return "物体被销毁";
                return _gameObject.name;
            }
            set
            {
                if (_gameObject)
                    _gameObject.name = value;
            }
        }

        public AbstractPersonController Controller => _controller;

        #region IResourcableObject

        #region IUnityGameObject

        /// <summary>
        /// 本类对应GameObject的索引
        /// </summary>
        public virtual GameObject gameObject => _gameObject;

        /// <summary>
        /// 获取物体Transform
        /// </summary>
        public virtual Transform transform => gameObject.transform;

        /// <summary>
        /// 获取和设置物体坐标
        /// </summary>
        public virtual Vector3 position
        {
            get
            {
                Assert.IsNotNull(transform);
                return transform.position;
            }
            set
            {
                Assert.IsNotNull(transform);
                transform.position = value;
            }
        }

        public Vector3 localPosition
        {
            get
            {
                Assert.IsNotNull(transform);
                return transform.localPosition;
            }
            set
            {
                Assert.IsNotNull(transform);
                transform.localPosition = value;
            }
        }

        #endregion

        /// <summary>
        /// 资预制体路径
        /// </summary>
        public abstract string ResKey { get; }

        /// <summary>
        /// 实例化角色预制体时创建
        /// </summary>
        public virtual void OnInstanciateObject()
        {
            _gameObject = ResourceMgr.InstantiateGameObject(ResKey);

            gameObject.name = GetType().Name;

            //自动添加PersonIdentity

            var id = gameObject.GetOrAddComponent<PersonIdentity>();
            id.abstractPerson = this;
            id.onUpdate += Update;
            gameObject.SetActive(false);

            //反射添加人物控制脚本
            var controllerTypeAttribute = GetType().GetAttribute<UsePersonControllerAttribute>();
            if (controllerTypeAttribute != null)
            {
                _controller = (AbstractPersonController)gameObject.GetOrAddComponent(controllerTypeAttribute.controllerType);

//                Debug.Log(controllerTypeAttribute.controllerType);

                _controller.InitController(this);

                _controller.eventOnDestory += Destroy;
            }

//            Debug.Log(CharacterName + " Init");

            Assert.IsTrue(_controller);
        }

        /// <summary>
        /// 真正直接销毁物体，用于场景切换等硬性要求
        /// </summary>
        public virtual void Destroy()
        {
            Object.Destroy(gameObject);
        }

        /// <summary>
        /// 启动角色
        /// </summary>
        public virtual void EnableObject()
        {
            if(gameObject==null)
                OnInstanciateObject();
            OnPersonEnable?.Invoke(this);
            gameObject.SetActive(true);
            onBeforeKill = null;
        }

        /// <summary>
        /// 关闭角色
        /// </summary>
        public virtual void DisableObject()
        {
            OnPersonDisable?.Invoke(this);
            if (gameObject)
            {
//                Debug.Log("隐藏：" + CharacterName);
                gameObject.SetActive(false);
            }
        }

        #endregion

        #region 战斗必须

        public virtual int Hp { get; protected set; }
        public virtual int MaxHp { get; protected set; }
        public abstract int Attack { get; }

        /// <summary>
        /// 是否活着
        /// </summary>
        public virtual bool IsAlive => gameObject != null && Hp > 0;

        /// <summary>
        /// 调用此函数逻辑上杀死角色，可能还会有动画特效的调用，此函数调用后IsAlive为false
        /// </summary>
        public virtual void LogicKill()
        {
            //处理消息
            TickOnKillEventAndClearEvent();
            //这里就直接销毁物体
            Destroy();
        }

        #endregion

        #endregion

        #region Functions

        /// <summary>
        /// 更新函数，角色活着并且激活的时候每帧调用
        /// </summary>
        protected virtual void Update()
        {
            this.onUpdate?.Invoke();
        }

        #endregion
    }
}


text:
using System;
using ReadyGamerOne.Data;

namespace ReadyGamerOne.Rougelike.Person
{
    public interface IPoolDataPerson :
        IPoolPerson,
        IUseCsvData
    {
    }

    /// <summary>
    /// 自带从CSV读取数据的人物，继承此类的Person类需要具有UseCsvData特性
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class PoolDataPerson<T> :
        PoolPerson<T>,
        IPoolDataPerson
        where T : PoolPerson<T>, new()
    {

        #region Fields

        private CsvMgr _personData;

        #endregion

        #region IUseCsvData

        public CsvMgr CsvData => _personData;

        public abstract Type DataType { get; }

        /// <summary>
        /// 加载数据，在这个函数中，应该完成对当前角色各项数据的赋值
        /// </summary>
        /// <param name="data"></param>
        public virtual void LoadData(CsvMgr data)
        {
            this._personData = data;
        }

        #endregion

        /// <summary>
        /// 从对象池获取时加载数据资源
        /// </summary>
        public override void OnGetFromPool()
        {
            LoadData(CsvMgr.GetData(GetType().Name,DataType));
            base.OnGetFromPool();
        }
    }
}


text:
fileFormatVersion: 2
guid: e59beeec102c4b7b8646c9b20be38ee5
timeCreated: 1575995568


text:
using System;

namespace ReadyGamerOne.Rougelike.Person
{
    /// <summary>
    /// 特性类，标记Person类使用哪个类数据
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public class UseCsvDataAttribute : System.Attribute
    {
        public Type dataType;

        public UseCsvDataAttribute(Type type)
        {
            dataType = type;
        }
    }
}


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


text:
fileFormatVersion: 2
guid: 0e9093e3630c4357a5b01a9b3055aa5a
timeCreated: 1576044521


text:
using System;

namespace ReadyGamerOne.Rougelike.Person
{
    [AttributeUsage(AttributeTargets.Class)]
    public class UsePersonControllerAttribute:System.Attribute
    {
        public Type controllerType;

        public UsePersonControllerAttribute(Type controllerType)
        {
            this.controllerType = controllerType;
        }
    }
}


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


text:
using System;
using UnityEngine;

namespace ReadyGamerOne.Rougelike.Person
{
    public abstract class AbstractPersonController:MonoBehaviour
    {
        public AbstractPerson selfPerson;
        public virtual Vector3 Velocity3D => Vector3.zero;
        public virtual Vector2 Velocity2D => Vector2.zero;

        public event Action eventOnDestory;

        /// <summary>
        /// 设置当前角色是否可以移动
        /// </summary>
        /// <param name="state"></param>
        public abstract void SetMoveable(bool state);

        public virtual void InitController(AbstractPerson self)
        {
            this.selfPerson = self;
        }

        /// <summary>
        /// 此函数如果使用不能调用base.ToDie
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        public virtual void ToDie()
        {
            throw new NotImplementedException();
        }

        protected virtual void Update()
        {
        }

        private void OnDestroy()
        {
            eventOnDestory?.Invoke();
        }
    }
}


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


text:
using ReadyGamerOne.Utility;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;

namespace ReadyGamerOne.ScriptableObjects
{
    public class AnimationCurveAsset:ScriptableObject
    {
#if UNITY_EDITOR
        [MenuItem("ReadyGamerOne/Create/AnimationCurveAsset")]
        public static void CreateAsset()
        {
            EditorUtil.CreateAsset<AnimationCurveAsset>("AnimationCurveAsset");
        }
#endif

        public AnimationCurve curve;
    }
}


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


text:
using System.Collections.Generic;
using ReadyGamerOne.Common;
using UnityEngine;

namespace ReadyGamerOne.ScriptableObjects
{
    [ScriptableSingletonInfo("GlobalConstStrings")]
    public class PrefUtil: Common.ScriptableSingleton<PrefUtil>
    {

        public List<string> constStrings = new List<string>();

        [SerializeField]
        public List<PrefItem> prefItems = new List<PrefItem>();

        public void SetString(string key,string value)
        {
            if (-1 == Find(key))
                prefItems.Add(new PrefItem
                {
                    key=key
                });

            prefItems[Find(key)].value = value;
        }

        public string GetString(string key,string defaultValue)
        {
            if (-1 == Find(key))
                return defaultValue;

            return prefItems[Find(key)].value;
        }

        public int Find(string key)
        {
            var index = 0;
            foreach(var pf in prefItems)
            {
                if (pf.key == key)
                    return index;
                index++;
            }
            return -1;
        }

    }
}


text:
using System;

namespace ReadyGamerOne.ScriptableObjects
{
    [Serializable]
    public class PrefItem
    {
        public string key;
        public string value;
    }
}


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


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


text:
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;

#endif

namespace ReadyGamerOne.ScriptableObjects
{
    [Serializable]
    public class ConstStringChooser
    {
#if UNITY_EDITOR

        public static string GetShowText(SerializedProperty property)
        {
            var prop = property.FindPropertyRelative("selectedIndex");
            return PrefUtil.Instance.constStrings[prop.intValue];
        }
#endif

        [SerializeField] private int selectedIndex;
        public string StringValue => PrefUtil.Instance.constStrings[selectedIndex];
        public void SetIndex(int index)
        {
            selectedIndex = index;
        }

    }
}


text:
fileFormatVersion: 2
guid: 61b374162a7434f4cb127038402071f4
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

namespace ReadyGamerOne.ScriptableObjects.Editor
{
    [CustomEditor(typeof(PrefUtil))]
    public class PrefUtilEditor:UnityEditor.Editor
    {
        private Vector2 pos;
        [MenuItem("ReadyGamerOne/Show/ConstStrings")]
        public static void CreateAsset()
        {
            Selection.activeInstanceID = PrefUtil.Instance.GetInstanceID();
        }

        private ReorderableList varList;
        private PrefUtil asset;
        private void OnEnable()
        {
            asset=target as PrefUtil;

            var varListProp = serializedObject.FindProperty("constStrings");
            this.varList = new ReorderableList(serializedObject, varListProp, false, true, true, true);
            //绘制单个元素
            varList.drawElementCallback =
                (rect, index, isActive, isFocused) =>
                {
                    EditorGUI.PropertyField(rect, varListProp.GetArrayElementAtIndex(index));
                };

        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            pos = EditorGUILayout.BeginScrollView(pos);
            varList.DoLayoutList();
            EditorGUILayout.EndScrollView();

            foreach (var VARIABLE in asset.constStrings)
            {
                if (string.IsNullOrEmpty(VARIABLE))
                {
                    EditorGUILayout.HelpBox("字符串不得为空！！！",MessageType.Error);
                }
            }

            if(GUILayout.Button("Clear PrefUtil"))
                asset.prefItems.Clear();
            foreach(var kv in asset.prefItems)
            {
                GUILayout.BeginHorizontal();
                GUILayout.Label(kv.key);
                GUILayout.FlexibleSpace();
                GUILayout.Label(kv.value);
                GUILayout.EndHorizontal();
            }

            serializedObject.ApplyModifiedProperties();
        }
    }
}


text:
fileFormatVersion: 2
guid: 0766a63ab7e640649c60e5b1e8309f51
timeCreated: 1569070623


text:
using UnityEditor;
using UnityEngine;

namespace ReadyGamerOne.ScriptableObjects.Editor
{
    [CustomPropertyDrawer(typeof(ConstStringChooser))]
    public class ConstStringChooserDrawer:PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            var indexProp = property.FindPropertyRelative("selectedIndex");
            indexProp.intValue = EditorGUI.Popup(position, property.displayName, indexProp.intValue,
                PrefUtil.Instance.constStrings.ToArray());
        }
    }
}


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


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


text:
fileFormatVersion: 2
guid: 84d71cf42c15f1c40ad761fe21f4f88d
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:


text:
using System;
using UnityEditor;
using UnityEngine;

namespace ReadyGamerOne.EditorExtension
{
    [Serializable]
    public class ArgChooser
    {
        #region Static

        public static bool typeChangAble = true;
        public static float argTypeWidth = 0.4f;
#if UNITY_EDITOR
        public static string GetShowTextFromSerializedProperty(SerializedProperty property)
        {
            var text = "";

            var argTypeProp = property.FindPropertyRelative("argType");

            switch (argTypeProp.enumValueIndex)
            {
                case 0://int
                    text = property.FindPropertyRelative("IntArg").intValue.ToString();
                    break;
                case 1://float
                    text = property.FindPropertyRelative("FloatArg").floatValue.ToString();
                    break;
                case 2://string
                    text = property.FindPropertyRelative("StringArg").stringValue;
                    break;
                case 3://bool
                    text = property.FindPropertyRelative("BoolArg").boolValue.ToString();
                    break;
                case 4://Vector3
                    text = property.FindPropertyRelative("Vector3Arg").vector3Value.ToString();
                    break;
            }

            return text;
        }
#endif

        public string GetValueString()
        {
            switch (argType)
            {
                case ArgType.Bool:
                    return BoolArg.ToString();
                case ArgType.Int:
                    return IntArg.ToString();
                case ArgType.Float:
                    return FloatArg.ToString();
                case ArgType.String:
                    return StringArg;
                case ArgType.Vector3:
                    return Vector3Arg.ToString();
            }

            return "???";
        }

        #endregion

        public ArgType argType;

        public bool BoolArg;
        public int IntArg;
        public float FloatArg;
        public string StringArg;
        public Vector3 Vector3Arg;

        public void SetValue(ArgChooser arg)
        {
            this.BoolArg = arg.BoolArg;
            this.IntArg = arg.IntArg;
            this.FloatArg = arg.FloatArg;
            this.StringArg = arg.StringArg;
            this.Vector3Arg = arg.Vector3Arg;
        }

    }
}


text:
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace ReadyGamerOne.EditorExtension
{
    [Serializable]
    public class StringChooser
    {
#if UNITY_EDITOR
        public static string GetShowTextFromSerializedProperty(SerializedProperty property)
        {
            return  property.FindPropertyRelative("values").GetArrayElementAtIndex(property.FindPropertyRelative("selectedIndex").intValue).stringValue;

        }
#endif

        //private static Type typeToShow;
        [SerializeField] protected string[] values;
        [SerializeField] protected int selectedIndex;
        public string StringValue => values[selectedIndex];

        public StringChooser(Type type)
        {
            var fieldInfos = type.GetFields(BindingFlags.Public | BindingFlags.Static);
            if (this.values == null)
                this.values = new string[fieldInfos.Length];
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = fieldInfos[i].GetValue(null) as string;
            }
        }
        public StringChooser(IList<string> strs)
        {
            if(values==null)
                values = new string[strs.Count];
            for (int i = 0; i < values.Length; i++)
            {
                values[i] = strs[i];
            }

        }
    }
}


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


text:
using System;
using UnityEngine;

namespace ReadyGamerOne.EditorExtension
{
    [Serializable]
    public class AnimationNameChooser
    {
#pragma warning disable 649
        public const float LabelWidth=0.4f;
        public const float ObjectFieldWidth = 0.2f;

        [SerializeField] private RuntimeAnimatorController rac;
        [SerializeField] private int selectedIndex;
        [SerializeField] private string stringValue;

        public string StringValue
        {
            get
            {
                if (rac == null)
                    throw new Exception("动画状态机为空");
                return stringValue;
            }
        }
#pragma warning restore 649
    }
}


text:
using System;
using UnityEngine;

namespace ReadyGamerOne.EditorExtension
{
    [Serializable]
    public class ResourcesPathChooser
    {
        [SerializeField] private int selectedIndex;
        public string Path;

        public string Name
        {
            get
            {
                var currentName = Path;
                if (currentName.Contains("/"))
                {
                    var select = currentName.LastIndexOf('/') + 1;
                    currentName = currentName.Substring(select, currentName.Length-select);
                    return currentName;
                }
                else
                    return Path;
            }
        }
    }
}


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


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


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


text:
using System;
using UnityEngine;

namespace ReadyGamerOne.EditorExtension
{
    [Serializable]
    public class TransformPathChooser
    {
        public const float LabelWidth = 0.4f;
        public const float ObjectFidldWidth = 0.2f;

        [SerializeField] private GameObject go;
        [SerializeField] private int selectedIndex;
#pragma warning disable 649
        [SerializeField] private string path;
#pragma warning restore 649

        public string Path => path;

        public string Name
        {
            get
            {
                var currentName = Path;
                if (currentName.Contains("/"))
                {
                    var select = currentName.LastIndexOf('/') + 1;
                    currentName = currentName.Substring(select, currentName.Length-select);
                    return currentName;
                }
                else
                    return Path;
            }
        }
    }
}


text:
namespace ReadyGamerOne.EditorExtension
{
    public enum ArgType
    {
        Int=0,
        Float=1,
        String=2,
        Bool=3,
        Vector3=4
    }

}


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


text:
namespace ReadyGamerOne.EditorExtension
{
    using UnityEngine;

    #if UNITY_EDITOR
    using UnityEditor;
    #endif

    // Author: JohannesMP (2018-08-12)
    //
    // A wrapper that provides the means to safely serialize Scene Asset References.
    //
    // Internally we serialize an Object to the SceneAsset which only exists at editor time.
    // Any time the object is serialized, we store the path provided by this Asset (assuming it was valid).
    //
    // This means that, come build time, the string path of the scene asset is always already stored, which if
    // the scene was added to the build settings means it can be loaded.
    //
    // It is up to the user to ensure the scene exists in the build settings so it is loadable at runtime.
    // To help with this, a custom PropertyDrawer displays the scene build settings state.
    //
    // Known issues:
    //     -   When reverting back to a prefab which has the asset stored as null, Unity will show the property
    //         as modified despite having just reverted. This only happens the fist time, and reverting again
    //         fixes it. Under the hood the state is still always valid, and serialized correctly regardless.

    /// <summary>
    /// A wrapper that provides the means to safely serialize Scene Asset References.
    /// </summary>
    [System.Serializable]
    public class SceneField : ISerializationCallbackReceiver
    {
    #if UNITY_EDITOR
        // What we use in editor to select the scene
        [SerializeField] private Object sceneAsset = null;
        bool IsValidSceneAsset
        {
            get
            {
                if (sceneAsset == null)
                    return false;
                return sceneAsset.GetType().Equals(typeof(SceneAsset));
            }
        }
    #endif

        // This should only ever be set during serialization/deserialization!
        [SerializeField]
        private string scenePath = string.Empty;

        // Use this when you want to actually have the scene path
        public string ScenePath
        {
            get
            {
    #if UNITY_EDITOR
                // In editor we always use the asset's path
                return GetScenePathFromAsset();
    #else
                // At runtime we rely on the stored path value which we assume was serialized correctly at build time.
                // See OnBeforeSerialize and OnAfterDeserialize
                return scenePath;
    #endif
            }
            set
            {
                scenePath = value;
    #if UNITY_EDITOR
                sceneAsset = GetSceneAssetFromPath();
    #endif
            }
        }

        public static implicit operator string(SceneField sceneField)
        {
            return sceneField.ScenePath;
        }

        // Called to prepare this data for serialization. Stubbed out when not in editor.
        public void OnBeforeSerialize()
        {
    #if UNITY_EDITOR
            HandleBeforeSerialize();
    #endif
        }

        // Called to set up data for deserialization. Stubbed out when not in editor.
        public void OnAfterDeserialize()
        {
    #if UNITY_EDITOR
            // We sadly cannot touch assetdatabase during serialization, so defer by a bit.
            EditorApplication.update += HandleAfterDeserialize;
    #endif
        }

    #if UNITY_EDITOR
        private SceneAsset GetSceneAssetFromPath()
        {
            if (string.IsNullOrEmpty(scenePath))
                return null;
            return AssetDatabase.LoadAssetAtPath<SceneAsset>(scenePath);
        }

        private string GetScenePathFromAsset()
        {
            if (sceneAsset == null)
                return string.Empty;
            return AssetDatabase.GetAssetPath(sceneAsset);
        }

        private void HandleBeforeSerialize()
        {
            // Asset is invalid but have Path to try and recover from
            if (IsValidSceneAsset == false && string.IsNullOrEmpty(scenePath) == false)
            {
                sceneAsset = GetSceneAssetFromPath();
                if (sceneAsset == null)
                    scenePath = string.Empty;

                UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
            }
            // Asset takes precendence and overwrites Path
            else
            {
                scenePath = GetScenePathFromAsset();
            }
        }

        private void HandleAfterDeserialize()
        {
            EditorApplication.update -= HandleAfterDeserialize;
            // Asset is valid, don't do anything - Path will always be set based on it when it matters
            if (IsValidSceneAsset)
                return;

            // Asset is invalid but have path to try and recover from
            if (string.IsNullOrEmpty(scenePath) == false)
            {
                sceneAsset = GetSceneAssetFromPath();
                // No asset found, path was invalid. Make sure we don't carry over the old invalid path
                if (sceneAsset == null)
                    scenePath = string.Empty;

                if (Application.isPlaying == false)
                    UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty();
            }
        }
    #endif
    }

}


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


text:
using System;
using ReadyGamerOne.Common;
using UnityEngine;

namespace ReadyGamerOne.EditorExtension
{
//#pragma warning disable CS0649
    [Serializable]
    public class MessageTrigger
    {
#pragma warning disable 649
        public bool tickMessage;

        public int argCount;

        [SerializeField] private ArgChooser arg1;
        [SerializeField] private ArgChooser arg2;

        public StringChooser messageToTick;

        public void TickMessage()
        {
            switch (argCount)
            {
                case 0:
                    CEventCenter.BroadMessage(messageToTick.StringValue);
                    break;
                case 1:
                    switch (arg1.argType)
                    {
                        case ArgType.Float:
                            CEventCenter.BroadMessage(messageToTick.StringValue,arg1.FloatArg);
                            break;
                        case ArgType.Int:
                            CEventCenter.BroadMessage(messageToTick.StringValue,arg1.IntArg);
                            break;
                        case ArgType.String:
                            CEventCenter.BroadMessage(messageToTick.StringValue,arg1.StringArg);
                            break;
                        case ArgType.Bool:
                            CEventCenter.BroadMessage(messageToTick.StringValue,arg1.BoolArg);
                            break;
                    }
                    break;
                case 2:
                    switch (arg1.argType)
                    {
                        case ArgType.Float:
                            switch (arg2.argType)
                            {
                                case ArgType.Float:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.FloatArg, arg2.FloatArg);
                                    break;
                                case ArgType.Int:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.FloatArg,arg2.IntArg);
                                    break;
                                case ArgType.String:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.FloatArg,arg2.StringArg);
                                    break;
                                case ArgType.Bool:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.FloatArg,arg2.BoolArg);
                                    break;
                            }
                            break;
                        case ArgType.Int:
                            switch (arg2.argType)
                            {
                                case ArgType.Float:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.IntArg, arg2.FloatArg);
                                    break;
                                case ArgType.Int:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.IntArg,arg2.IntArg);
                                    break;
                                case ArgType.String:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.IntArg,arg2.StringArg);
                                    break;
                                case ArgType.Bool:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.IntArg,arg2.BoolArg);
                                    break;
                            }
                            break;
                        case ArgType.String:
                            switch (arg2.argType)
                            {
                                case ArgType.Float:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.StringArg, arg2.FloatArg);
                                    break;
                                case ArgType.Int:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.StringArg,arg2.IntArg);
                                    break;
                                case ArgType.String:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.StringArg,arg2.StringArg);
                                    break;
                                case ArgType.Bool:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.StringArg,arg2.BoolArg);
                                    break;
                            }
                            break;
                        case ArgType.Bool :
                            switch (arg2.argType)
                            {
                                case ArgType.Float:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.BoolArg, arg2.FloatArg);
                                    break;
                                case ArgType.Int:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.BoolArg,arg2.IntArg);
                                    break;
                                case ArgType.String:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.BoolArg,arg2.StringArg);
                                    break;
                                case ArgType.Bool:
                                    CEventCenter.BroadMessage(messageToTick.StringValue,arg1.BoolArg,arg2.BoolArg);
                                    break;
                            }
                            break;
                    }
                    break;
            }
        }
#pragma warning restore 649
    }

}


text:
fileFormatVersion: 2
guid: 74902ded22a547a2b02b3fc7d0b8646a
timeCreated: 1564062853


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


text:
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Assertions;

namespace ReadyGamerOne.EditorExtension
{
    [CustomPropertyDrawer(typeof(StringChooser))]
    public class StringChooseDrawer : PropertyDrawer
    {
        private List<string> values;

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            var index = property.FindPropertyRelative("selectedIndex").intValue;
            if (values == null)
            {
                values = new List<string>();
                var vs = property.FindPropertyRelative("values");
                Assert.IsTrue( vs!=null&&vs.isArray);
                string ans = "";
   //             Debug.Log(property.displayName+" "+"size: "+vs.arraySize);
                for (int i = 0; i < vs.arraySize; i++)
                {
                    values.Add(vs.GetArrayElementAtIndex(i).stringValue);
                    ans += values[i]+" ";
                }
//                Debug.Log("执行！！"+property.displayName+" "+ans);
            }

            //base.OnGUI(position, property, label);
            EditorGUI.BeginChangeCheck();
            //得到描述在列表中的下标

            index = EditorGUI.Popup(position, property.displayName, index, values.ToArray());
            if (EditorGUI.EndChangeCheck())
            {
                property.FindPropertyRelative("selectedIndex").intValue = index;

                //根据下标从id列表中找出技能id进行赋值

                //Debug.Log(property.FindPropertyRelative("selectedValue").stringValue);

            }
        }
    }
}


text:
fileFormatVersion: 2
guid: a46487439ab0425a8e6e5628e6cba766
timeCreated: 1569321760


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

namespace ReadyGamerOne.EditorExtension
{
    [CustomPropertyDrawer(typeof(ArgChooser))]
    public class ArgChooserDrawer:PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            var argType = property.FindPropertyRelative("argType");

            if (ArgChooser.typeChangAble)
            {
                argType.enumValueIndex = EditorGUI.Popup(position.GetLeft(ArgChooser.argTypeWidth), argType.enumValueIndex, argType.enumNames);

                var argValueWidth = 1 - ArgChooser.argTypeWidth;
                switch (argType.enumValueIndex)
                {
                    case 0:    // Int
                        var intArgProp = property.FindPropertyRelative("IntArg");
                        intArgProp.intValue = EditorGUI.IntField(position.GetRight(argValueWidth), intArgProp.intValue);
                        break;
                    case 1:    // Float
                        var floatArgProp = property.FindPropertyRelative("FloatArg");
                        floatArgProp.floatValue =
                            EditorGUI.FloatField(position.GetRight(argValueWidth), floatArgProp.floatValue);
                        break;
                    case 2:    // String
                        var strArgProp = property.FindPropertyRelative("StringArg");
                        strArgProp.stringValue = EditorGUI.TextField(position.GetRight(argValueWidth), strArgProp.stringValue);
                        break;
                    case 3:    // bool
                        var boolArgProp = property.FindPropertyRelative("BoolArg");
                        boolArgProp.boolValue = EditorGUI.Toggle(position.GetRight(argValueWidth), boolArgProp.boolValue);
                        break;
                    case 4://Vector3
                        var vec3Prop = property.FindPropertyRelative("Vector3Arg");
                        vec3Prop.vector3Value =
                            EditorGUI.Vector3Field(position.GetRight(argValueWidth), "", vec3Prop.vector3Value);
                        break;
                }
            }
            else
            {
                switch (argType.enumValueIndex)
                {
                    case 0:    // Int
                        EditorGUI.PropertyField(position, property.FindPropertyRelative("IntArg"));
                        break;
                    case 1:    // Float
                        EditorGUI.PropertyField(position, property.FindPropertyRelative("FloatArg"));
                        break;
                    case 2:    // String
                        EditorGUI.PropertyField(position, property.FindPropertyRelative("StringArg"));
                        break;
                    case 3:
                        EditorGUI.PropertyField(position, property.FindPropertyRelative("BoolArg"));
                        break;
                    case 4:
                        EditorGUI.PropertyField(position, property.FindPropertyRelative("Vector3Arg"));
                        break;
                }
            }

        }
    }
}