把代码核心逻辑移入热更工程,热更工程生成编译后可以直接Copy dll 和 mdb文件到UnityAsset目录下

把代码核心逻辑移入热更工程,热更工程生成编译后可以直接Copy dll 和 mdb文件到UnityAsset目录下
This commit is contained in:
ALEXTANG
2022-05-23 13:49:07 +08:00
parent 2e7263101a
commit 572b768ce2
82 changed files with 13764 additions and 2 deletions

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="15.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -38,9 +39,24 @@
<Reference Include="UnityEngine">
<HintPath>UnityLib\UnityEngine.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>UnityLib\UnityEngine.CoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AssetBundleModule">
<HintPath>UnityLib\UnityEngine.AssetBundleModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UI">
<HintPath>UnityLib\UnityEngine.UI.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIModule">
<HintPath>UnityLib\UnityEngine.UIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PhysicsModule">
<HintPath>UnityLib\UnityEngine.PhysicsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule">
<HintPath>UnityLib\UnityEngine.InputLegacyModule.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
@@ -49,7 +65,76 @@
<ItemGroup>
<Compile Include="GameApp.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="src\**" />
<Compile Include="src\TEngineCore\ClientSaveData\ClientSaveData.cs" />
<Compile Include="src\TEngineCore\Config\ResConfigUtil.cs" />
<Compile Include="src\TEngineCore\Core\BaseLogicSys.cs" />
<Compile Include="src\TEngineCore\Core\ILogicSys.cs" />
<Compile Include="src\TEngineCore\Core\ListPool.cs" />
<Compile Include="src\TEngineCore\Core\MemPoolMgr.cs" />
<Compile Include="src\TEngineCore\Core\Singleton.cs" />
<Compile Include="src\TEngineCore\Core\TEngine.cs" />
<Compile Include="src\TEngineCore\Core\TEngineRedux.cs" />
<Compile Include="src\TEngineCore\Core\TLogger.cs" />
<Compile Include="src\TEngineCore\Core\TSingleton.cs" />
<Compile Include="src\TEngineCore\Core\UnitySingleton.cs" />
<Compile Include="src\TEngineCore\ECS\ArrayPool.cs" />
<Compile Include="src\TEngineCore\ECS\Demo\ECSDemoApp.cs" />
<Compile Include="src\TEngineCore\ECS\Demo\ECSGameSystem.cs" />
<Compile Include="src\TEngineCore\ECS\ECSActor.cs" />
<Compile Include="src\TEngineCore\ECS\ECSComponent.cs" />
<Compile Include="src\TEngineCore\ECS\ECSDebugBehaviour.cs" />
<Compile Include="src\TEngineCore\ECS\ECSEventCmpt.cs" />
<Compile Include="src\TEngineCore\ECS\ECSObject.cs" />
<Compile Include="src\TEngineCore\ECS\ECSSystem.cs" />
<Compile Include="src\TEngineCore\ECS\Entity.cs" />
<Compile Include="src\TEngineCore\ECS\HotfixComponent.cs" />
<Compile Include="src\TEngineCore\ECS\IFixedUpdate.cs" />
<Compile Include="src\TEngineCore\ECS\IUpdate.cs" />
<Compile Include="src\TEngineCore\ECS\UpdateComponent.cs" />
<Compile Include="src\TEngineCore\Event\GameEventMgr.cs" />
<Compile Include="src\TEngineCore\Event\StringId.cs" />
<Compile Include="src\TEngineCore\FileSystem\FileSystem.cs" />
<Compile Include="src\TEngineCore\FileSystem\FileWriter.cs" />
<Compile Include="src\TEngineCore\FileSystem\LogToFile.cs" />
<Compile Include="src\TEngineCore\Json\JsonHelper.cs" />
<Compile Include="src\TEngineCore\Json\LitJson\IJsonWrapper.cs" />
<Compile Include="src\TEngineCore\Json\LitJson\JsonData.cs" />
<Compile Include="src\TEngineCore\Json\LitJson\JsonException.cs" />
<Compile Include="src\TEngineCore\Json\LitJson\JsonMapper.cs" />
<Compile Include="src\TEngineCore\Json\LitJson\JsonMockWrapper.cs" />
<Compile Include="src\TEngineCore\Json\LitJson\JsonReader.cs" />
<Compile Include="src\TEngineCore\Json\LitJson\JsonWriter.cs" />
<Compile Include="src\TEngineCore\Json\LitJson\Lexer.cs" />
<Compile Include="src\TEngineCore\Json\LitJson\Netstandard15Polyfill.cs" />
<Compile Include="src\TEngineCore\Json\LitJson\ParserToken.cs" />
<Compile Include="src\TEngineCore\Json\MiniJSON\Json.cs" />
<Compile Include="src\TEngineCore\Mono\MonoController.cs" />
<Compile Include="src\TEngineCore\Mono\MonoManager.cs" />
<Compile Include="src\TEngineCore\Res\AssetBundleData.cs" />
<Compile Include="src\TEngineCore\Res\AssetConfig.cs" />
<Compile Include="src\TEngineCore\Res\AssetData.cs" />
<Compile Include="src\TEngineCore\Res\AssetTag.cs" />
<Compile Include="src\TEngineCore\Res\ResMgr.cs" />
<Compile Include="src\TEngineCore\Res\TResource.cs" />
<Compile Include="src\TEngineCore\Thread\Loom.cs" />
<Compile Include="src\TEngineCore\Thread\ThreadMgr.cs" />
<Compile Include="src\TEngineCore\UI\Extend\DragItem.cs" />
<Compile Include="src\TEngineCore\UI\Extend\EmptyGraph.cs" />
<Compile Include="src\TEngineCore\UI\Extend\TipsUI.cs" />
<Compile Include="src\TEngineCore\UI\Extend\TweenUtil.cs" />
<Compile Include="src\TEngineCore\UI\Extend\UIEventItem.cs" />
<Compile Include="src\TEngineCore\UI\Extend\UIWindowWidget.cs" />
<Compile Include="src\TEngineCore\UI\IUIController.cs" />
<Compile Include="src\TEngineCore\UI\UIBase.cs" />
<Compile Include="src\TEngineCore\UI\UIManager.cs" />
<Compile Include="src\TEngineCore\UI\UISys.cs" />
<Compile Include="src\TEngineCore\UI\UIWindow.cs" />
<Compile Include="src\TEngineCore\UI\UIWindowBase.cs" />
<Compile Include="src\TEngineCore\Unitity\DevicePerformanceUtil.cs" />
<Compile Include="src\TEngineCore\Unitity\UnityUtil.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="src\TEngineCore\3rd\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,130 @@
using System.Collections.Generic;
using TEngineCore.ListJson;
using UnityEngine;
namespace TEngineCore
{
public abstract class BaseClientData
{
private string m_configName;
public void Init(string configName)
{
m_configName = configName;
Load();
}
public void Load()
{
string fullName = GetSaveUniqPrefix() + m_configName;
var jsonString = PlayerPrefs.GetString(fullName);
if (!string.IsNullOrEmpty(jsonString))
{
JsonData json = JsonHelper.Instance.Deserialize(jsonString);
if (json != null)
{
Deserialize(json);
}
}
}
public void Save()
{
string fullName = GetSaveUniqPrefix() + m_configName;
JsonData jsonData = new JsonData();
Serialize(jsonData);
var jsonTex = JsonHelper.Instance.Serialize(jsonData);
if (!string.IsNullOrEmpty(jsonTex))
{
PlayerPrefs.SetString(fullName, jsonTex);
PlayerPrefs.Save();
}
}
protected abstract void Serialize(JsonData json);
protected abstract void Deserialize(JsonData json);
private string GetSaveUniqPrefix()
{
string hashPath = UnityUtil.GetHashCodeByString(Application.dataPath).ToString();
string uniqInstance = SystemInfo.deviceUniqueIdentifier;
string uniqKey = hashPath + uniqInstance;
return uniqKey;
}
}
public class SystemSaveData: BaseClientData
{
public int[] settingParams;
public uint test;
public float m_cameraDistance;
public SystemSaveData()
{
settingParams = new int[(int)SystemSaveType.Max];
settingParams[(int) SystemSaveType.Lod] = 0;
}
public enum SystemSaveType
{
Lod, // 同屏人数
MusicOn, // 打开音乐
SoundOn, // 打开音效
Max,
}
protected override void Serialize(JsonData json)
{
if (json == null)
{
return;
}
}
protected override void Deserialize(JsonData json)
{
if (json == null)
{
return;
}
}
}
public class ClientSaveData : TSingleton<ClientSaveData>
{
private Dictionary<string, BaseClientData> m_dictSaveData = new Dictionary<string, BaseClientData>();
public T GetSaveData<T>() where T : BaseClientData, new()
{
string typeName = typeof(T).Name;
BaseClientData ret;
if (!m_dictSaveData.TryGetValue(typeName, out ret))
{
ret = new T();
ret.Init(typeName);
m_dictSaveData.Add(typeName, ret);
}
return (T)ret;
}
public void SaveAllData()
{
var enumerator = m_dictSaveData.GetEnumerator();
while (enumerator.MoveNext())
{
enumerator.Current.Value.Save();
}
}
public SystemSaveData CurrentSystemSaveData
{
get
{
return GetSaveData<SystemSaveData>();
}
}
}
}

View File

@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace TEngineCore
{
public class ResConfigUtil
{
private static StringBuilder m_strBuilder = new StringBuilder();
private static readonly string m_split = "_";
#region
public static List<T> ReadConfigListRes<T>(string fileName)
{
string resPath = string.Format("Config/{0}.json",fileName);
TextAsset jsonStr = TResources.Load<TextAsset>(resPath);
if (jsonStr == null)
{
TLogger.LogError("读取Json配置数据失败{0}", fileName);
return null;
}
List<T> list = new List<T>();
var jsonData = JsonHelper.Instance.Deserialize<List<T>>(jsonStr.text);
list = jsonData;
return list;
}
public static Dictionary<string, T> ReadConfigRes<T>(string fileName)
{
string resPath = string.Format("Config/{0}.json", fileName);
TextAsset jsonStr = TResources.Load<TextAsset>(resPath);
if (jsonStr == null)
{
TLogger.LogError("读取Json配置数据失败{0}", fileName);
return null;
}
Dictionary<string, T> dic = new Dictionary<string, T>();
var jsonData = JsonHelper.Instance.Deserialize<Dictionary<string, T>>(jsonStr.text);
dic = jsonData;
return dic;
}
public static Dictionary<int, T> ReadConfigResIntKey<T>(string fileName)
{
string resPath = string.Format("Config/{0}.json", fileName);
TextAsset jsonStr = TResources.Load<TextAsset>(resPath);
if (jsonStr == null)
{
TLogger.LogError("读取Json配置数据失败{0}", fileName);
return null;
}
Dictionary<int, T> dic = new Dictionary<int, T>();
var jsonData = JsonHelper.Instance.Deserialize<Dictionary<int, T>>(jsonStr.text);
dic = jsonData;
return dic;
}
#endregion
public static UInt64 Make64Key(uint key1, uint key2)
{
return (((UInt64)key1) << 32) | key2;
}
public static string MakeStringKey(uint key1, uint key2, uint key3)
{
m_strBuilder.Length = 0;
m_strBuilder.Append(key1);
m_strBuilder.Append(m_split);
m_strBuilder.Append(key2);
m_strBuilder.Append(m_split);
m_strBuilder.Append(key3);
return m_strBuilder.ToString();
}
public static string MakeStringKey(string key1, uint key2)
{
m_strBuilder.Length = 0;
m_strBuilder.Append(key1);
m_strBuilder.Append(m_split);
m_strBuilder.Append(key2);
return m_strBuilder.ToString();
}
public static string MakeStringKey(string key1, string key2)
{
m_strBuilder.Length = 0;
m_strBuilder.Append(key1);
m_strBuilder.Append(m_split);
m_strBuilder.Append(key2);
return m_strBuilder.ToString();
}
}
}
/*
*
===》 example 《===
public class BufferMgr : Singleton<BufferMgr>
{
private Dictionary<string, BuffConfig> m_dictBaseConfig = new Dictionary<string, BuffConfig>();
public BufferMgr()
{
m_dictBaseConfig = ResConfigUtil.ReadConfigRes<BuffConfig>("BuffConfig");
}
public Dictionary<string, BuffConfig> GetBuffConfig()
{
return m_dictBaseConfig;
}
}
*
*/

View File

@@ -0,0 +1,74 @@
namespace TEngineCore
{
/// <summary>
/// 基础LogicSys,生命周期由TEngine实现推荐给系统实现
/// 减少多余的Mono保持系统层面只有一个Update
/// 用TEngine的主Mono来驱动LogicSys的生命周期
/// </summary>
/// <typeparam name="T"></typeparam>
public class BaseLogicSys<T> : ILogicSys where T : new()
{
private static T m_Instance;
public static bool HasInstance
{
get { return m_Instance != null; }
}
public static T Instance
{
get
{
if (null == m_Instance)
{
m_Instance = new T();
}
return m_Instance;
}
}
#region virtual fucntion
public virtual bool OnInit()
{
if (null == m_Instance)
{
m_Instance = new T();
}
return true;
}
public virtual void OnStart()
{
}
public virtual void OnUpdate()
{
}
public virtual void OnLateUpdate()
{
}
public virtual void OnDestroy()
{
}
public virtual void OnPause()
{
}
public virtual void OnResume()
{
}
public virtual void OnDrawGizmos()
{
}
public virtual void OnMapChanged()
{
}
#endregion
}
}

View File

@@ -0,0 +1,20 @@
namespace TEngineCore
{
public interface ILogicSys
{
bool OnInit();
void OnDestroy();
void OnStart();
void OnUpdate();
void OnLateUpdate();
void OnPause();
void OnResume();
}
}

View File

@@ -0,0 +1,90 @@
using System.Collections.Generic;
using UnityEngine.Events;
namespace TEngineCore
{
public static class ListPool<T>
{
private static readonly ObjectPool<List<T>> m_ListPool = new ObjectPool<List<T>>(null, Clear);
static void Clear(List<T> list)
{
list.Clear();
}
public static List<T> Get()
{
return m_ListPool.Get();
}
public static void Release(List<T> toRelease)
{
m_ListPool.Release(toRelease);
}
}
public class ObjectPool<T> where T : new()
{
private readonly Stack<T> m_Stack = new Stack<T>();
private readonly UnityAction<T> m_ActionGet;
private readonly UnityAction<T> m_ActionRelease;
public int CountAll { get; private set; }
public int CountActive
{
get
{
return CountAll - CountInActive;
}
}
public int CountInActive
{
get
{
return m_Stack.Count;
}
}
public ObjectPool()
{
}
public ObjectPool(UnityAction<T> actionGet, UnityAction<T> actionRelease)
{
m_ActionGet = actionGet;
m_ActionRelease = actionRelease;
}
public T Get()
{
T element;
if (m_Stack.Count <= 0)
{
element = new T();
CountAll++;
}
else
{
element = m_Stack.Pop();
}
if (m_ActionGet != null)
{
m_ActionGet.Invoke(element);
}
return element;
}
public void Release(T element)
{
if (m_Stack.Count > 0 && ReferenceEquals(m_Stack.Peek(), element))
{
TLogger.LogError("Internal error. Trying to destroy object that is already released to pool.");
}
m_ActionRelease?.Invoke(element);
m_Stack.Push(element);
}
}
}

View File

@@ -0,0 +1,125 @@
using System.Collections.Generic;
using System.Diagnostics;
using Debug = UnityEngine.Debug;
namespace TEngineCore
{
public interface IMemPoolObject
{
void Init();
void Destroy();
}
public interface MemPoolBase
{
string GetName();
int GetPoolItemCount();
void ClearPool();
}
public class MemPool
{
}
public class MemPoolMgr : TSingleton<MemPoolMgr>
{
List<MemPoolBase> m_listPool = new List<MemPoolBase>();
[Conditional("TEngine_DEBUG")]
public void ShowCount()
{
int totalCnt = 0;
for (int i = 0; i < m_listPool.Count; i++)
{
var pool = m_listPool[i];
totalCnt += pool.GetPoolItemCount();
TLogger.LogInfo("[pool][{0}] [{1}]", pool.GetName(), pool.GetPoolItemCount());
}
TLogger.LogInfo("-------------------------memory pool count: {0}", totalCnt);
}
public void RegMemPool(MemPoolBase pool)
{
m_listPool.Add(pool);
}
public void ClearAllPool()
{
for (int i = 0; i < m_listPool.Count; i++)
{
var pool = m_listPool[i];
pool.ClearPool();
}
}
}
public class GameMemPool<T> : TSingleton<GameMemPool<T>>, MemPoolBase where T : IMemPoolObject, new()
{
private List<T> m_objPool = new List<T>();
public static T Alloc()
{
return GameMemPool<T>.Instance.DoAlloc();
}
public static void Free(T obj)
{
GameMemPool<T>.Instance.DoFree(obj);
}
public GameMemPool()
{
MemPoolMgr.Instance.RegMemPool(this);
}
private T DoAlloc()
{
T newObj;
if (m_objPool.Count > 0)
{
var lastIndex = m_objPool.Count - 1;
newObj = m_objPool[lastIndex];
m_objPool.RemoveAt(lastIndex);
}
else
{
newObj = new T();
}
newObj.Init();
return newObj;
}
private void DoFree(T obj)
{
if (obj == null)
{
return;
}
obj.Destroy();
m_objPool.Add(obj);
}
public void ClearPool()
{
#if UNITY_EDITOR
TLogger.LogInfo("clear memory[{0}] count[{1}]", GetName(), m_objPool.Count);
#endif
m_objPool.Clear();
}
public string GetName()
{
return typeof(T).FullName;
}
public int GetPoolItemCount()
{
return m_objPool.Count;
}
}
}

View File

@@ -0,0 +1,28 @@
namespace TEngineCore
{
/// <summary>
/// 通用单例,无需释放和销毁
/// </summary>
/// <typeparam name="T"></typeparam>
public class Singleton<T> where T : new()
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
_instance = new T();
}
return _instance;
}
}
public static T Active()
{
return Instance;
}
}
}

View File

@@ -0,0 +1,149 @@
using System.Collections.Generic;
using UnityEngine;
namespace TEngineCore
{
/// <summary>
/// 游戏入口派生TEngine实现进入游戏虚函数(override StartGame)
/// </summary>
public class TEngine : UnitySingleton<TEngine>
{
public override void Awake()
{
base.Awake();
TLogger.LogInfo($"DevicePerformanceLevel 设备性能评级:{DevicePerformanceUtil.GetDevicePerformanceLevel()}");
InitLibImp();
RegisterAllSystem();
AfterAwake();
}
/// <summary>
/// 注册实现库
/// </summary>
protected virtual void InitLibImp()
{
}
/// <summary>
/// 注册系统例如BaseLogic/TEngineObject/MonoManger
/// </summary>
protected virtual void RegisterAllSystem()
{
}
protected void SetTargetFrameRate(int targetFrameRate)
{
Application.targetFrameRate = targetFrameRate;
}
//-------------------------------------------------------系统注册--------------------------------------------------------//
private List<ILogicSys> m_LogicMgrList = new List<ILogicSys>();
/// <summary>
/// 系统注册
/// </summary>
/// <param name="logicSys"></param>
/// <returns></returns>
protected bool AddLogicSys(ILogicSys logicSys)
{
if (m_LogicMgrList.Contains(logicSys))
{
TLogger.LogInfo("Repeat add logic system: " + logicSys.GetType().Name);
return false;
}
if (!logicSys.OnInit())
{
TLogger.LogInfo(" Init failed " + logicSys.GetType().Name);
return false;
}
m_LogicMgrList.Add(logicSys);
return true;
}
#region
public void Start()
{
var listLogic = m_LogicMgrList;
var logicCnt = listLogic.Count;
for (int i = 0; i < logicCnt; i++)
{
var logic = listLogic[i];
logic.OnStart();
}
TLogger.LogInfo("TEngine:StartGame");
StartGame();
}
public void Update()
{
var listLogic = m_LogicMgrList;
var logicCnt = listLogic.Count;
for (int i = 0; i < logicCnt; i++)
{
var logic = listLogic[i];
logic.OnUpdate();
}
}
public void LateUpdate()
{
var listLogic = m_LogicMgrList;
var logicCnt = listLogic.Count;
for (int i = 0; i < logicCnt; i++)
{
var logic = listLogic[i];
logic.OnLateUpdate();
}
}
public void OnPause()
{
for (int i = 0; i < m_LogicMgrList.Count; i++)
{
var logicSys = m_LogicMgrList[i];
logicSys.OnPause();
}
}
public void OnResume()
{
for (int i = 0; i < m_LogicMgrList.Count; i++)
{
var logicSys = m_LogicMgrList[i];
logicSys.OnResume();
}
}
protected override void OnDestroy()
{
for (int i = 0; i < m_LogicMgrList.Count; i++)
{
var logicSys = m_LogicMgrList[i];
logicSys.OnDestroy();
}
base.OnDestroy();
SingletonMgr.Release();
}
protected virtual void AfterAwake()
{
}
protected virtual void StartGame()
{
}
#endregion
}
}

View File

@@ -0,0 +1,880 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TEngineCore
{
#region Architecture
public interface IArchitecture
{
void RegisterSystem<T>(T system) where T : ISystem;
void RegisterModel<T>(T model) where T : IModel;
void RegisterUtility<T>(T utility) where T : IUtility;
T GetSystem<T>() where T : class, ISystem;
T GetModel<T>() where T : class, IModel;
T GetUtility<T>() where T : class, IUtility;
void SendCommand<T>() where T : ICommand, new();
void SendCommand<T>(T command) where T : ICommand;
TResult SendQuery<TResult>(IQuery<TResult> query);
void SendEvent<T>() where T : new();
void SendEvent<T>(T e);
IUnRegister RegisterEvent<T>(Action<T> onEvent);
void UnRegisterEvent<T>(Action<T> onEvent);
}
public abstract class Architecture<T> : IArchitecture where T : Architecture<T>, new()
{
private bool _Inited = false;
private List<ISystem> _Systems = new List<ISystem>();
private List<IModel> _Models = new List<IModel>();
public static Action<T> OnRegisterPatch = architecture => { };
private static T _Architecture;
public static IArchitecture Interface
{
get
{
if (_Architecture == null)
{
MakeSureArchitecture();
}
return _Architecture;
}
}
static void MakeSureArchitecture()
{
if (_Architecture == null)
{
_Architecture = new T();
_Architecture.Init();
OnRegisterPatch?.Invoke(_Architecture);
foreach (var architectureModel in _Architecture._Models)
{
architectureModel.Init();
}
_Architecture._Models.Clear();
foreach (var architectureSystem in _Architecture._Systems)
{
architectureSystem.Init();
}
_Architecture._Systems.Clear();
_Architecture._Inited = true;
}
}
protected abstract void Init();
private TEngineContainer mContainer = new TEngineContainer();
public void RegisterSystem<TSystem>(TSystem system) where TSystem : ISystem
{
system.SetArchitecture(this);
mContainer.Register<TSystem>(system);
if (!_Inited)
{
_Systems.Add(system);
}
else
{
system.Init();
}
}
public void RegisterModel<TModel>(TModel model) where TModel : IModel
{
model.SetArchitecture(this);
mContainer.Register<TModel>(model);
if (!_Inited)
{
_Models.Add(model);
}
else
{
model.Init();
}
}
public void RegisterUtility<TUtility>(TUtility utility) where TUtility : IUtility
{
mContainer.Register<TUtility>(utility);
}
public TSystem GetSystem<TSystem>() where TSystem : class, ISystem
{
return mContainer.Get<TSystem>();
}
public TModel GetModel<TModel>() where TModel : class, IModel
{
return mContainer.Get<TModel>();
}
public TUtility GetUtility<TUtility>() where TUtility : class, IUtility
{
return mContainer.Get<TUtility>();
}
public void SendCommand<TCommand>() where TCommand : ICommand, new()
{
var command = new TCommand();
command.SetArchitecture(this);
command.Execute();
}
public void SendCommand<TCommand>(TCommand command) where TCommand : ICommand
{
command.SetArchitecture(this);
command.Execute();
}
public TResult SendQuery<TResult>(IQuery<TResult> query)
{
query.SetArchitecture(this);
return query.Do();
}
private TypeEventSystem mTypeEventSystem = new TypeEventSystem();
public void SendEvent<TEvent>() where TEvent : new()
{
mTypeEventSystem.Send<TEvent>();
}
public void SendEvent<TEvent>(TEvent e)
{
mTypeEventSystem.Send<TEvent>(e);
}
public IUnRegister RegisterEvent<TEvent>(Action<TEvent> onEvent)
{
return mTypeEventSystem.Register<TEvent>(onEvent);
}
public void UnRegisterEvent<TEvent>(Action<TEvent> onEvent)
{
mTypeEventSystem.UnRegister<TEvent>(onEvent);
}
}
public interface IOnEvent<T>
{
void OnEvent(T e);
}
public static class OnGlobalEventExtension
{
public static IUnRegister RegisterEvent<T>(this IOnEvent<T> self) where T : struct
{
return TypeEventSystem.Global.Register<T>(self.OnEvent);
}
public static void UnRegisterEvent<T>(this IOnEvent<T> self) where T : struct
{
TypeEventSystem.Global.UnRegister<T>(self.OnEvent);
}
}
#endregion
#region Controller
public interface IController : IBelongToArchitecture, ICanSendCommand, ICanGetSystem, ICanGetModel,
ICanRegisterEvent, ICanSendQuery
{
}
#endregion
#region System
public interface ISystem : IBelongToArchitecture, ICanSetArchitecture, ICanGetModel, ICanGetUtility,
ICanRegisterEvent, ICanSendEvent, ICanGetSystem
{
void Init();
}
public abstract class AbstractSystem : ISystem
{
private IArchitecture _Architecture;
IArchitecture IBelongToArchitecture.GetArchitecture()
{
return _Architecture;
}
void ICanSetArchitecture.SetArchitecture(IArchitecture architecture)
{
_Architecture = architecture;
}
void ISystem.Init()
{
OnInit();
}
protected abstract void OnInit();
}
#endregion
#region Model
public interface IModel : IBelongToArchitecture, ICanSetArchitecture, ICanGetUtility, ICanSendEvent
{
void Init();
}
public abstract class AbstractModel : IModel
{
private IArchitecture _Architecturel;
IArchitecture IBelongToArchitecture.GetArchitecture()
{
return _Architecturel;
}
void ICanSetArchitecture.SetArchitecture(IArchitecture architecture)
{
_Architecturel = architecture;
}
void IModel.Init()
{
OnInit();
}
protected abstract void OnInit();
}
#endregion
#region Utility
public interface IUtility
{
}
#endregion
#region Command
public interface ICommand : IBelongToArchitecture, ICanSetArchitecture, ICanGetSystem, ICanGetModel, ICanGetUtility,
ICanSendEvent, ICanSendCommand, ICanSendQuery
{
void Execute();
}
public abstract class AbstractCommand : ICommand
{
private IArchitecture _Architecture;
IArchitecture IBelongToArchitecture.GetArchitecture()
{
return _Architecture;
}
void ICanSetArchitecture.SetArchitecture(IArchitecture architecture)
{
_Architecture = architecture;
}
void ICommand.Execute()
{
OnExecute();
}
protected abstract void OnExecute();
}
#endregion
#region Query
public interface IQuery<TResult> : IBelongToArchitecture, ICanSetArchitecture, ICanGetModel, ICanGetSystem,
ICanSendQuery
{
TResult Do();
}
public abstract class AbstractQuery<T> : IQuery<T>
{
public T Do()
{
return OnDo();
}
protected abstract T OnDo();
private IArchitecture _Architecture;
public IArchitecture GetArchitecture()
{
return _Architecture;
}
public void SetArchitecture(IArchitecture architecture)
{
_Architecture = architecture;
}
}
#endregion
#region Rule
public interface IBelongToArchitecture
{
IArchitecture GetArchitecture();
}
public interface ICanSetArchitecture
{
void SetArchitecture(IArchitecture architecture);
}
public interface ICanGetModel : IBelongToArchitecture
{
}
public static class CanGetModelExtension
{
public static T GetModel<T>(this ICanGetModel self) where T : class, IModel
{
return self.GetArchitecture().GetModel<T>();
}
}
public interface ICanGetSystem : IBelongToArchitecture
{
}
public static class CanGetSystemExtension
{
public static T GetSystem<T>(this ICanGetSystem self) where T : class, ISystem
{
return self.GetArchitecture().GetSystem<T>();
}
}
public interface ICanGetUtility : IBelongToArchitecture
{
}
public static class CanGetUtilityExtension
{
public static T GetUtility<T>(this ICanGetUtility self) where T : class, IUtility
{
return self.GetArchitecture().GetUtility<T>();
}
}
public interface ICanRegisterEvent : IBelongToArchitecture
{
}
public static class CanRegisterEventExtension
{
public static IUnRegister RegisterEvent<T>(this ICanRegisterEvent self, Action<T> onEvent)
{
return self.GetArchitecture().RegisterEvent<T>(onEvent);
}
public static void UnRegisterEvent<T>(this ICanRegisterEvent self, Action<T> onEvent)
{
self.GetArchitecture().UnRegisterEvent<T>(onEvent);
}
}
public interface ICanSendCommand : IBelongToArchitecture
{
}
public static class CanSendCommandExtension
{
public static void SendCommand<T>(this ICanSendCommand self) where T : ICommand, new()
{
self.GetArchitecture().SendCommand<T>();
}
public static void SendCommand<T>(this ICanSendCommand self, T command) where T : ICommand
{
self.GetArchitecture().SendCommand<T>(command);
}
}
public interface ICanSendEvent : IBelongToArchitecture
{
}
public static class CanSendEventExtension
{
public static void SendEvent<T>(this ICanSendEvent self) where T : new()
{
self.GetArchitecture().SendEvent<T>();
}
public static void SendEvent<T>(this ICanSendEvent self, T e)
{
self.GetArchitecture().SendEvent<T>(e);
}
}
public interface ICanSendQuery : IBelongToArchitecture
{
}
public static class CanSendQueryExtension
{
public static TResult SendQuery<TResult>(this ICanSendQuery self, IQuery<TResult> query)
{
return self.GetArchitecture().SendQuery(query);
}
}
#endregion
#region TypeEventSystem
public interface IUnRegister
{
void UnRegister();
}
public interface IUnRegisterList
{
List<IUnRegister> UnregisterList { get; }
}
public static class IUnRegisterListExtension
{
public static void AddToUnregisterList(this IUnRegister self, IUnRegisterList unRegisterList)
{
unRegisterList.UnregisterList.Add(self);
}
public static void UnRegisterAll(this IUnRegisterList self)
{
foreach (var unRegister in self.UnregisterList)
{
unRegister.UnRegister();
}
self.UnregisterList.Clear();
}
}
/// <summary>
/// 自定义可注销的类
/// </summary>
public struct CustomUnRegister : IUnRegister
{
/// <summary>
/// 委托对象
/// </summary>
private Action mOnUnRegister { get; set; }
/// <summary>
/// 带参构造函数
/// </summary>
/// <param name="onDispose"></param>
public CustomUnRegister(Action onUnRegsiter)
{
mOnUnRegister = onUnRegsiter;
}
/// <summary>
/// 资源释放
/// </summary>
public void UnRegister()
{
mOnUnRegister.Invoke();
mOnUnRegister = null;
}
}
public class UnRegisterOnDestroyTrigger : MonoBehaviour
{
private readonly HashSet<IUnRegister> mUnRegisters = new HashSet<IUnRegister>();
public void AddUnRegister(IUnRegister unRegister)
{
mUnRegisters.Add(unRegister);
}
public void RemoveUnRegister(IUnRegister unRegister)
{
mUnRegisters.Remove(unRegister);
}
private void OnDestroy()
{
foreach (var unRegister in mUnRegisters)
{
unRegister.UnRegister();
}
mUnRegisters.Clear();
}
}
public static class UnRegisterExtension
{
public static IUnRegister UnRegisterWhenGameObjectDestroyed(this IUnRegister unRegister, GameObject gameObject)
{
var trigger = gameObject.GetComponent<UnRegisterOnDestroyTrigger>();
if (!trigger)
{
trigger = gameObject.AddComponent<UnRegisterOnDestroyTrigger>();
}
trigger.AddUnRegister(unRegister);
return unRegister;
}
}
public class TypeEventSystem
{
private readonly EasyEvents mEvents = new EasyEvents();
public static readonly TypeEventSystem Global = new TypeEventSystem();
public void Send<T>() where T : new()
{
mEvents.GetEvent<EasyEvent<T>>()?.Trigger(new T());
}
public void Send<T>(T e)
{
mEvents.GetEvent<EasyEvent<T>>()?.Trigger(e);
}
public IUnRegister Register<T>(Action<T> onEvent)
{
var e = mEvents.GetOrAddEvent<EasyEvent<T>>();
return e.Register(onEvent);
}
public void UnRegister<T>(Action<T> onEvent)
{
var e = mEvents.GetEvent<EasyEvent<T>>();
if (e != null)
{
e.UnRegister(onEvent);
}
}
}
#endregion
#region TEngine
public class TEngineContainer
{
private Dictionary<Type, object> _Instances = new Dictionary<Type, object>();
public void Register<T>(T instance)
{
var key = typeof(T);
if (_Instances.ContainsKey(key))
{
_Instances[key] = instance;
}
else
{
_Instances.Add(key, instance);
}
}
public T Get<T>() where T : class
{
var key = typeof(T);
if (_Instances.TryGetValue(key, out var retInstance))
{
return retInstance as T;
}
return null;
}
}
#endregion
#region BindableProperty
public interface IBindableProperty<T> : IReadonlyBindableProperty<T>
{
new T Value { get; set; }
void SetValueWithoutEvent(T newValue);
}
public interface IReadonlyBindableProperty<T>
{
T Value { get; }
IUnRegister RegisterWithInitValue(Action<T> action);
void UnRegister(Action<T> onValueChanged);
IUnRegister Register(Action<T> onValueChanged);
}
public class BindableProperty<T> : IBindableProperty<T>
{
public BindableProperty(T defaultValue = default)
{
mValue = defaultValue;
}
protected T mValue;
public T Value
{
get => GetValue();
set
{
if (value == null && mValue == null) return;
if (value != null && value.Equals(mValue)) return;
SetValue(value);
mOnValueChanged?.Invoke(value);
}
}
protected virtual void SetValue(T newValue)
{
mValue = newValue;
}
protected virtual T GetValue()
{
return mValue;
}
public void SetValueWithoutEvent(T newValue)
{
mValue = newValue;
}
private Action<T> mOnValueChanged = (v) => { };
public IUnRegister Register(Action<T> onValueChanged)
{
mOnValueChanged += onValueChanged;
return new BindablePropertyUnRegister<T>()
{
BindableProperty = this,
OnValueChanged = onValueChanged
};
}
public IUnRegister RegisterWithInitValue(Action<T> onValueChanged)
{
onValueChanged(mValue);
return Register(onValueChanged);
}
public static implicit operator T(BindableProperty<T> property)
{
return property.Value;
}
public override string ToString()
{
return Value.ToString();
}
public void UnRegister(Action<T> onValueChanged)
{
mOnValueChanged -= onValueChanged;
}
}
public class BindablePropertyUnRegister<T> : IUnRegister
{
public BindableProperty<T> BindableProperty { get; set; }
public Action<T> OnValueChanged { get; set; }
public void UnRegister()
{
BindableProperty.UnRegister(OnValueChanged);
BindableProperty = null;
OnValueChanged = null;
}
}
#endregion
#region EasyEvent
public interface IEasyEvent
{
}
public class EasyEvent : IEasyEvent
{
private Action mOnEvent = () => { };
public IUnRegister Register(Action onEvent)
{
mOnEvent += onEvent;
return new CustomUnRegister(() => { UnRegister(onEvent); });
}
public void UnRegister(Action onEvent)
{
mOnEvent -= onEvent;
}
public void Trigger()
{
mOnEvent?.Invoke();
}
}
public class EasyEvent<T> : IEasyEvent
{
private Action<T> mOnEvent = e => { };
public IUnRegister Register(Action<T> onEvent)
{
mOnEvent += onEvent;
return new CustomUnRegister(() => { UnRegister(onEvent); });
}
public void UnRegister(Action<T> onEvent)
{
mOnEvent -= onEvent;
}
public void Trigger(T t)
{
mOnEvent?.Invoke(t);
}
}
public class EasyEvent<T, K> : IEasyEvent
{
private Action<T, K> mOnEvent = (t, k) => { };
public IUnRegister Register(Action<T, K> onEvent)
{
mOnEvent += onEvent;
return new CustomUnRegister(() => { UnRegister(onEvent); });
}
public void UnRegister(Action<T, K> onEvent)
{
mOnEvent -= onEvent;
}
public void Trigger(T t, K k)
{
mOnEvent?.Invoke(t, k);
}
}
public class EasyEvent<T, K, S> : IEasyEvent
{
private Action<T, K, S> mOnEvent = (t, k, s) => { };
public IUnRegister Register(Action<T, K, S> onEvent)
{
mOnEvent += onEvent;
return new CustomUnRegister(() => { UnRegister(onEvent); });
}
public void UnRegister(Action<T, K, S> onEvent)
{
mOnEvent -= onEvent;
}
public void Trigger(T t, K k, S s)
{
mOnEvent?.Invoke(t, k, s);
}
}
public class EasyEvents
{
private static EasyEvents mGlobalEvents = new EasyEvents();
public static T Get<T>() where T : IEasyEvent
{
return mGlobalEvents.GetEvent<T>();
}
public static void Register<T>() where T : IEasyEvent, new()
{
mGlobalEvents.AddEvent<T>();
}
private Dictionary<Type, IEasyEvent> mTypeEvents = new Dictionary<Type, IEasyEvent>();
public void AddEvent<T>() where T : IEasyEvent, new()
{
mTypeEvents.Add(typeof(T), new T());
}
public T GetEvent<T>() where T : IEasyEvent
{
IEasyEvent e;
if (mTypeEvents.TryGetValue(typeof(T), out e))
{
return (T)e;
}
return default;
}
public T GetOrAddEvent<T>() where T : IEasyEvent, new()
{
var eType = typeof(T);
if (mTypeEvents.TryGetValue(eType, out var e))
{
return (T)e;
}
var t = new T();
mTypeEvents.Add(eType, t);
return t;
}
}
#endregion
}

View File

@@ -0,0 +1,341 @@
using System.Diagnostics;
using System.Text;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace TEngineCore
{
public static class ColorUtils
{
#region ColorStr
public const string White = "FFFFFF";
public const string Black = "000000";
public const string Red = "FF0000";
public const string Green = "00FF18";
public const string Oringe = "FF9400";
public const string Exception = "FF00BD";
#endregion
public static string ToColor(this string str, string color)
{
if (string.IsNullOrEmpty(str))
{
return str;
}
return string.Format("<color=#{0}>{1}</color>", color, str);
}
}
public class TLogger : TSingleton<TLogger>
{
protected override void Init()
{
_outputType = OutputType.EDITOR;
_logToFile = new LogToFile();
_logToFile.Init();
UnityEngine.Application.logMessageReceivedThreaded += OnLogMessageReceivedThreaded;
}
private LogToFile _logToFile;
private void OnLogMessageReceivedThreaded(string condition, string stackTrace, LogType type)
{
if (!condition.StartsWith("TLogger]"))
{
_stringBuilder.Clear();
_stringBuilder.AppendFormat("[System][{0}][{1}] {2}", type.ToString(), System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), condition);
if (type == LogType.Warning || type == LogType.Error || type == LogType.Exception)
{
_stringBuilder.AppendLine(stackTrace);
}
string strToWrite = _stringBuilder.ToString();
_logToFile.Write(strToWrite);
}
}
~TLogger()
{
}
public override void Release()
{
Application.logMessageReceivedThreaded -= OnLogMessageReceivedThreaded;
_logToFile.DeInit();
_logToFile = null;
base.Release();
}
private void ChangeOutputChannel(OutputType type)
{
if (type != _outputType)
{
_outputType = type;
}
}
public static void SetFilterLevel(LogLevel filterLevel)
{
Instance._filterLevel = filterLevel;
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_ASSERT")]
public static void LogAssert(bool condition, string logStr)
{
if (!condition)
Instance.Log(LogLevel.ASSERT, logStr);
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_ASSERT")]
public static void LogAssert(bool condition, string format, params System.Object[] args)
{
if (!condition)
{
string logStr = string.Format(format, args);
Instance.Log(LogLevel.ASSERT, logStr);
}
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_INFO")]
public static void LogInfo(string logStr)
{
Instance.Log(LogLevel.INFO, logStr);
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_INFO")]
public static void LogInfo(string format, params System.Object[] args)
{
string logStr = string.Format(format, args);
Instance.Log(LogLevel.INFO, logStr);
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_SUCCESS")]
public static void LogInfoSuccessd(string logStr)
{
Instance.Log(LogLevel.Successd, logStr);
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_SUCCESS")]
public static void LogInfoSuccessd(string format, params System.Object[] args)
{
string logStr = string.Format(format, args);
Instance.Log(LogLevel.Successd, logStr);
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_WARNING")]
public static void LogWarning(string logStr)
{
Instance.Log(LogLevel.WARNING, logStr);
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_WARNING")]
public static void LogWarning(string format, params System.Object[] args)
{
string logStr = string.Format(format, args);
Instance.Log(LogLevel.WARNING, logStr);
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_ERROR")]
public static void LogError(string logStr)
{
Instance.Log(LogLevel.ERROR, logStr);
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_ERROR")]
public static void LogError(string format, params System.Object[] args)
{
string logStr = string.Format(format, args);
Instance.Log(LogLevel.ERROR, logStr);
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_EXCEPTION")]
public static void LogException(string logStr)
{
Instance.Log(LogLevel.EXCEPTION, logStr);
}
[Conditional("UNITY_EDITOR"), Conditional("_DEVELOPMENT_BUILD_"), Conditional("ENABLE_LOG_EXCEPTION")]
public static void LogException(string format, params System.Object[] args)
{
string msg = string.Format(format, args);
Instance.Log(LogLevel.EXCEPTION, msg);
}
private StringBuilder GetFormatedString(LogLevel logLevel, string logString, bool bColor)
{
_stringBuilder.Clear();
switch (logLevel)
{
case LogLevel.Successd:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[TLogger][SUCCESSED][{0}] - <color=#{2}>{1}</color>",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString, ColorUtils.Green);
}
else
{
_stringBuilder.AppendFormat(
bColor ? "[TLogger][INFO][{0}] - <color=gray>{1}</color>" : "[TLogger][SUCCESSED][{0}] - {1}",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString);
}
break;
case LogLevel.INFO:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[TLogger][INFO][{0}] - <color=#{2}>{1}</color>" ,
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString,ColorUtils.Black);
}
else
{
_stringBuilder.AppendFormat(
bColor ? "[TLogger][INFO][{0}] - <color=gray>{1}</color>" : "[TLogger][INFO][{0}] - {1}",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString);
}
break;
case LogLevel.ASSERT:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[TLogger][ASSERT][{0}] - <color=#{2}>{1}</color>",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString,ColorUtils.Exception);
}
else
{
_stringBuilder.AppendFormat(
bColor ? "[TLogger][ASSERT][{0}] - <color=green>{1}</color>" : "[TLogger][ASSERT][{0}] - {1}",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString);
}
break;
case LogLevel.WARNING:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[TLogger][WARNING][{0}] - <color=#{2}>{1}</color>",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString, ColorUtils.Oringe);
}
else
{
_stringBuilder.AppendFormat(
bColor
? "[TLogger][WARNING][{0}] - <color=yellow>{1}</color>"
: "[TLogger][WARNING][{0}] - {1}", System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"),
logString);
}
break;
case LogLevel.ERROR:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[ERROR][WARNING][{0}] - <color=#{2}>{1}</color>",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString, ColorUtils.Red);
}
else
{
_stringBuilder.AppendFormat(
bColor ? "[TLogger][ERROR][{0}] - <color=red>{1}</color>" : "[TLogger][ERROR][{0}] - {1}",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString);
}
break;
case LogLevel.EXCEPTION:
if (UseCustomColor)
{
_stringBuilder.AppendFormat("[ERROR][EXCEPTION][{0}] - <color=#{2}>{1}</color>",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString, ColorUtils.Exception);
}
else
{
_stringBuilder.AppendFormat(
bColor
? "[TLogger][EXCEPTION][{0}] - <color=red>{1}</color>"
: "[TLogger][EXCEPTION][{0}] - {1}",
System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"), logString);
}
break;
}
return _stringBuilder;
}
private void Log(LogLevel type, string logString)
{
if (_outputType == OutputType.NONE)
{
return;
}
if (type < _filterLevel)
{
return;
}
StringBuilder infoBuilder = GetFormatedString(type, logString, UseSystemColor);
string logStr = infoBuilder.ToString();
//获取C#堆栈,Warning以上级别日志才获取堆栈
if (type == LogLevel.ERROR || type == LogLevel.WARNING || type == LogLevel.EXCEPTION)
{
StackFrame[] sf = new StackTrace().GetFrames();
for (int i = 0; i < sf.Length; i++)
{
StackFrame frame = sf[i];
string declaringTypeName = frame.GetMethod().DeclaringType.FullName;
string methodName = sf[i].GetMethod().Name;
infoBuilder.AppendFormat("[{0}::{1}\n", declaringTypeName, methodName);
}
}
if (type == LogLevel.INFO || type == LogLevel.Successd)
{
Debug.Log(logStr);
}
else if (type == LogLevel.WARNING)
{
Debug.LogWarning(logStr);
}
else if (type == LogLevel.ASSERT)
{
Debug.LogAssertion(logStr);
}
else if (type == LogLevel.ERROR)
{
Debug.LogError(logStr);
}
else if (type == LogLevel.EXCEPTION)
{
Debug.LogError(logStr);
}
}
#region Properties
public bool UseCustomColor = false;
public bool UseSystemColor = true;
public enum LogLevel
{
INFO,
Successd,
ASSERT,
WARNING,
ERROR,
EXCEPTION,
}
[System.Flags]
public enum OutputType
{
NONE = 0,
EDITOR = 0x1,
GUI = 0x2,
FILE = 0x4
}
private LogLevel _filterLevel = LogLevel.INFO;
private OutputType _outputType = OutputType.EDITOR;
private StringBuilder _stringBuilder = new StringBuilder();
#endregion
}
}

View File

@@ -0,0 +1,198 @@
using System.Collections.Generic;
using UnityEngine;
namespace TEngineCore
{
/// <summary>
/// 单例接口
/// </summary>
public interface ISingleton
{
void Active();
void Release();
}
/// <summary>
/// 单例管理器(统一化持久和释放)
/// </summary>
public static class SingletonMgr
{
private static List<ISingleton> _iSingletonList;
private static Dictionary<string, GameObject> _gameObjects;
private static GameObject _root;
public static GameObject Root
{
get
{
if (_root == null)
{
_root = GameObject.Find("TEngine");
}
return _root;
}
}
public static void Retain(ISingleton go)
{
if (_iSingletonList == null)
{
_iSingletonList = new List<ISingleton>();
}
_iSingletonList.Add(go);
}
public static void Retain(GameObject go)
{
if (_gameObjects == null)
{
_gameObjects = new Dictionary<string, GameObject>();
}
if (!_gameObjects.ContainsKey(go.name))
{
_gameObjects.Add(go.name, go);
if (Application.isPlaying)
{
UnityEngine.Object.DontDestroyOnLoad(go);
}
}
}
public static void Release(GameObject go)
{
if (_gameObjects != null && _gameObjects.ContainsKey(go.name))
{
_gameObjects.Remove(go.name);
UnityEngine.Object.Destroy(go);
}
}
public static void Release(ISingleton go)
{
if (_iSingletonList != null && _iSingletonList.Contains(go))
{
_iSingletonList.Remove(go);
}
}
public static void Release()
{
if (_gameObjects != null)
{
foreach (var item in _gameObjects)
{
UnityEngine.Object.Destroy(item.Value);
}
_gameObjects.Clear();
}
if (_iSingletonList != null)
{
for (int i = 0; i < _iSingletonList.Count; ++i)
{
_iSingletonList[i].Release();
}
_iSingletonList.Clear();
}
Resources.UnloadUnusedAssets();
}
public static GameObject GetGameObject(string name)
{
GameObject go = null;
if (_gameObjects != null)
{
_gameObjects.TryGetValue(name, out go);
}
return go;
}
internal static bool CointansKey(string name)
{
if (_gameObjects != null)
{
return _gameObjects.ContainsKey(name);
}
return false;
}
internal static ISingleton GetSingleton(string name)
{
for (int i = 0; i < _iSingletonList.Count; ++i)
{
if (_iSingletonList[i].ToString() == name)
{
return _iSingletonList[i];
}
}
return null;
}
}
/// <summary>
/// 全局单例对象(非线程安全)
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class TSingleton<T> : ISingleton where T : TSingleton<T>, new()
{
protected static T _instance = default(T);
public static T Instance
{
get
{
if (null == _instance)
{
_instance = new T();
_instance.Init();
#if UNITY_EDITOR
TLogger.LogInfo($"TSingleton Instance:{typeof(T).Name}");
#endif
SingletonMgr.Retain(_instance);
}
return _instance;
}
}
public static bool IsValid
{
get
{
return _instance != null;
}
}
protected TSingleton()
{
}
protected virtual void Init()
{
}
public virtual void Active()
{
}
public virtual void Release()
{
if (_instance != null)
{
SingletonMgr.Release(_instance);
_instance = null;
}
}
}
}

View File

@@ -0,0 +1,110 @@
using UnityEngine;
namespace TEngineCore
{
/// <summary>
/// 具备Unity完整生命周期的单例
/// </summary>
/// <typeparam name="T"></typeparam>
public class UnitySingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
System.Type thisType = typeof(T);
string instName = thisType.Name;
GameObject go = SingletonMgr.GetGameObject(instName);
if (go == null)
{
go = GameObject.Find($"/{instName}");
if (go == null)
{
go = new GameObject(instName);
go.transform.position = Vector3.zero;
}
SingletonMgr.Retain(go);
}
if (go != null)
{
_instance = go.GetComponent<T>();
if (_instance == null)
{
_instance = go.AddComponent<T>();
}
}
if (_instance == null)
{
TLogger.LogError($"Can't create UnitySingleton<{typeof(T)}>");
}
}
return _instance;
}
}
public static T Active()
{
return Instance;
}
public static bool IsValid
{
get
{
return _instance != null;
}
}
private bool CheckInstance()
{
if (this == Instance)
{
return true;
}
GameObject.Destroy(gameObject);
return false;
}
protected virtual void OnLoad()
{
}
public virtual void Awake()
{
if (CheckInstance())
{
OnLoad();
}
#if UNITY_EDITOR
TLogger.LogInfo($"UnitySingleton Instance:{typeof(T).Name}");
GameObject tEngine = SingletonMgr.Root;
if (tEngine != null)
{
this.gameObject.transform.SetParent(tEngine.transform);
}
#endif
}
protected virtual void OnDestroy()
{
Release();
}
public static void Release()
{
if (_instance != null)
{
SingletonMgr.Release(_instance.gameObject);
_instance = null;
}
}
}
}

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace TEngineCore
{
public interface IIndex
{
int Index { get; set; }
}
internal class HashSetDebugView<T> where T : IIndex
{
private readonly ArrayPool<T> m_Set;
public HashSetDebugView(ArrayPool<T> set)
{
m_Set = set ?? throw new ArgumentNullException(nameof(set));
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public T[] Items
{
get
{
return m_Set.ToArray();
}
}
}
[DebuggerTypeProxy(typeof(HashSetDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
public class ArrayPool<T> where T:IIndex
{
internal T[] m_Items = new T[256];
internal bool[] Buckets = new bool[256];
private int m_Index;
private int count;
public T this[int index]
{
get
{
return m_Items[index];
}
set
{
m_Items[index] = value;
}
}
public int Count
{
get
{
return count;
}
}
public T[] ToArray()
{
List<T> elements = new List<T>();
for (int i = 0; i < m_Items.Length; i++)
{
if (Buckets[i])
{
elements.Add(m_Items[i]);
}
}
return elements.ToArray();
}
public void Remove(T item)
{
lock (this)
{
m_Items[item.Index] = default;
Buckets[item.Index] = false;
}
}
public void Add(T item)
{
lock (this)
{
if (item.Index != -1)
{
if (!Buckets[item.Index])
{
m_Items[item.Index] = item;
Buckets[item.Index] = true;
return;
}
}
m_Items[m_Index] = item;
Buckets[m_Index] = true;
item.Index = m_Index;
m_Index++;
if (m_Index >= m_Items.Length)
{
T[] newItems = new T[m_Items.Length * 2];
bool[] newBuckets = new bool[m_Items.Length * 2];
Array.Copy(m_Items,0,newItems,0,m_Items.Length);
Array.Copy(Buckets, 0, newBuckets, 0, Buckets.Length);
m_Items = newItems;
Buckets = newBuckets;
}
count = m_Index;
}
}
}
}

View File

@@ -0,0 +1,25 @@
using TEngineCore;
using UnityEngine;
public class ECSDemoApp : MonoBehaviour
{
public ECSGameSystem EcsGameSystem = new ECSGameSystem();
public GameObject @object;
void Start()
{
var entity = EcsGameSystem.Create<Entity>();
ECSActor actor = entity.AddComponent<ECSActor>();
actor.Name = typeof(ECSActor).ToString();
actor.gameObject = Instantiate(@object);
actor.transform = actor.gameObject.GetComponent<Transform>();
entity.AddComponent<ECSComponent>();
Debug.Log(entity.ToString());
}
void Update()
{
EcsGameSystem.OnUpdate();
}
}

View File

@@ -0,0 +1,9 @@
using TEngineCore;
public class ECSGameSystem : ECSSystem
{
public void OnUpdate()
{
Update();
}
}

View File

@@ -0,0 +1,13 @@
namespace TEngineCore
{
/// <summary>
/// ECS Actor
/// </summary>
public class ECSActor : ECSComponent
{
public string Name;
public UnityEngine.GameObject gameObject;
public UnityEngine.Transform transform;
public uint ActorID;
}
}

View File

@@ -0,0 +1,14 @@
namespace TEngineCore
{
/// <summary>
/// ECS构架可以将此组件从Entity上移除这个组件并丢入对象池给其他此刻需要此组件的Entity使用
/// 因此可以节省大量的内存反复创建和释放, 这也是ECS的特性可以大量重复使用组件
/// </summary>
public class ECSComponent:ECSObject
{
#pragma warning disable IDE1006
public Entity Entity { get; set; }
#pragma warning restore IDE1006
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
namespace TEngineCore
{
public enum ECSDebugType
{
Entity,
System,
Component
}
[Serializable]
public class ECSCmptDebugKeyInfo
{
public string m_name;
public string val;
}
[Serializable]
public class ECSCmptDebugInfo
{
public string m_name;
public ECSDebugType Type = ECSDebugType.Component;
public List<ECSCmptDebugKeyInfo> m_info = new List<ECSCmptDebugKeyInfo>();
}
public class ECSDebugBehaviour : UnityEngine.MonoBehaviour
{
public List<ECSCmptDebugInfo> m_ECSInfo = new List<ECSCmptDebugInfo>();
public ECSCmptDebugInfo AddDebugCmpt(string cmptName)
{
var cmptInfo = m_ECSInfo.Find((item) => { return item.m_name == cmptName; });
if (cmptInfo == null)
{
cmptInfo = new ECSCmptDebugInfo();
cmptInfo.m_name = cmptName;
m_ECSInfo.Add(cmptInfo); ;
}
return cmptInfo;
}
public void RmvDebugCmpt(string cmptName)
{
m_ECSInfo.RemoveAll((item) => { return item.m_name == cmptName; });
}
public void SetDebugInfo(string cmptName, string key, string val)
{
var cmptInfo = AddDebugCmpt(cmptName);
var entry = cmptInfo.m_info.Find((t) => { return t.m_name == key; });
if (entry == null)
{
entry = new ECSCmptDebugKeyInfo();
entry.m_name = key;
cmptInfo.m_info.Add(entry);
}
entry.val = val;
}
public void RemoveAllDebugInfo(string cmpName)
{
var cmpInfo = m_ECSInfo.Find((item) => { return item.m_name == cmpName; });
if (cmpInfo != null)
{
cmpInfo.m_info.Clear();
}
}
}
}

View File

@@ -0,0 +1,236 @@
using System;
using System.Collections.Generic;
namespace TEngineCore
{
public class ECSEventCmpt : ECSComponent
{
private Dictionary<int, IEcsEcsEventInfo> m_eventDic = new Dictionary<int, IEcsEcsEventInfo>();
#region AddEventListener
public void AddEventListener<T>(int eventid, Action<T> action)
{
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EcsEventInfo<T>).actions += action;
}
else
{
m_eventDic.Add(eventid, new EcsEventInfo<T>(action));
}
}
public void AddEventListener<T, U>(int eventid, Action<T, U> action)
{
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EcsEventInfo<T, U>).actions += action;
}
else
{
m_eventDic.Add(eventid, new EcsEventInfo<T, U>(action));
}
}
public void AddEventListener<T, U, W>(int eventid, Action<T, U, W> action)
{
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EcsEventInfo<T, U, W>).actions += action;
}
else
{
m_eventDic.Add(eventid, new EcsEventInfo<T, U, W>(action));
}
}
public void AddEventListener(int eventid, Action action)
{
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EcsEventInfo).actions += action;
}
else
{
m_eventDic.Add(eventid, new EcsEventInfo(action));
}
}
#endregion
#region RemoveEventListener
public void RemoveEventListener<T>(int eventid, Action<T> action)
{
if (action == null)
{
return;
}
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EcsEventInfo<T>).actions -= action;
}
}
public void RemoveEventListener<T, U>(int eventid, Action<T, U> action)
{
if (action == null)
{
return;
}
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EcsEventInfo<T, U>).actions -= action;
}
}
public void RemoveEventListener<T, U, W>(int eventid, Action<T, U, W> action)
{
if (action == null)
{
return;
}
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EcsEventInfo<T, U, W>).actions -= action;
}
}
public void RemoveEventListener(int eventid, Action action)
{
if (action == null)
{
return;
}
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EcsEventInfo).actions -= action;
}
}
#endregion
#region Send
public void Send<T>(int eventid, T info)
{
if (m_eventDic.ContainsKey(eventid))
{
var EcsEventInfo = (m_eventDic[eventid] as EcsEventInfo<T>);
if (EcsEventInfo != null)
{
EcsEventInfo.actions.Invoke(info);
}
}
}
public void Send<T, U>(int eventid, T info, U info2)
{
if (m_eventDic.ContainsKey(eventid))
{
var EcsEventInfo = (m_eventDic[eventid] as EcsEventInfo<T, U>);
if (EcsEventInfo != null)
{
EcsEventInfo.actions.Invoke(info, info2);
}
}
}
public void Send<T, U, W>(int eventid, T info, U info2, W info3)
{
if (m_eventDic.ContainsKey(eventid))
{
var EcsEventInfo = (m_eventDic[eventid] as EcsEventInfo<T, U, W>);
if (EcsEventInfo != null)
{
EcsEventInfo.actions.Invoke(info, info2, info3);
}
}
}
/// <summary>
/// 事件触发 无参
/// </summary>
/// <param name="name"></param>
public void Send(int eventid)
{
if (m_eventDic.ContainsKey(eventid))
{
var EcsEventInfo = (m_eventDic[eventid] as EcsEventInfo);
if (EcsEventInfo != null)
{
EcsEventInfo.actions.Invoke();
}
}
}
#endregion
#region Clear
public void Clear()
{
m_eventDic.Clear();
}
#endregion
#region
public override void OnDestroy()
{
Clear();
}
public override void Awake()
{
Entity.Event = this;
}
#endregion
}
#region EcsEventInfo
internal interface IEcsEcsEventInfo
{
}
public class EcsEventInfo : IEcsEcsEventInfo
{
public Action actions;
public EcsEventInfo(Action action)
{
actions += action;
}
}
public class EcsEventInfo<T> : IEcsEcsEventInfo
{
public Action<T> actions;
public EcsEventInfo(Action<T> action)
{
actions += action;
}
}
public class EcsEventInfo<T, U> : IEcsEcsEventInfo
{
public Action<T, U> actions;
public EcsEventInfo(Action<T, U> action)
{
actions += action;
}
}
public class EcsEventInfo<T, U, W> : IEcsEcsEventInfo
{
public Action<T, U, W> actions;
public EcsEventInfo(Action<T, U, W> action)
{
actions += action;
}
}
#endregion
}

View File

@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
namespace TEngineCore
{
/// <summary>
/// ECS架构基类Object
/// </summary>
public class ECSObject
{
internal int HashCode;
internal ECSSystem System;
public ECSObject()
{
HashCode = GetType().GetHashCode();
}
public virtual void Awake() { }
public virtual void OnDestroy() { }
/// <summary>
/// Remove The ECSEntity or Component And Throw the ECSObject to ArrayPool When AddComponent Or Create Can Use Again
/// </summary>
/// <param name="ecsObject"></param>
/// <param name="reuse">此对象是否可以复用复用会将对象丢入System对象池中 等待再次使用如果是Entity对象并且不复用的话则把Entity所使用的组件也不复用</param>
public static void Destroy(ECSObject ecsObject, bool reuse = true)
{
if (ecsObject is ECSComponent ecsComponent)
{
ecsComponent.Entity.Components.Remove(ecsComponent);
if (ecsComponent is IUpdate update)
{
ecsComponent.Entity.Updates.Remove(update);
}
if (reuse)
{
ecsComponent.Entity.System.Push(ecsComponent);
}
ecsObject.OnDestroy();
return;
}
else if (ecsObject is Entity entity)
{
entity.System.RemoveEntity(entity);
entity.OnDestroy();
while (entity.Components.Count > 0)
{
ECSComponent ecsComponentTemp = entity.Components[0];
entity.Components.RemoveAt(0);
ecsComponentTemp.OnDestroy();
if (reuse)
{
entity.System.Push(ecsComponentTemp);
}
}
entity.Updates.Clear();
entity.CanUpdate = false;
if (reuse)
{
entity.System.Push(entity);
}
}
}
public T FindObjectOfType<T>() where T : ECSObject
{
Type type = typeof(T);
var elements = System.Entities.ToArray();
for (int i = 0; i < elements.Length; i++)
{
if (elements[i].GetType() == type)
{
return elements[i] as T;
}
for (int n = 0; n < elements[i].Components.Count; n++)
{
if (elements[i].Components[n].GetType() == type)
{
return elements[i].Components[n] as T;
}
}
}
return null;
}
public T[] FindObjectsOfType<T>() where T : ECSObject
{
Type type = typeof(T);
var items = System.Entities.ToArray();
List<T> elements = new List<T>();
for (int i = 0; i < items.Length; i++)
{
if (items[i].GetType() == type)
{
elements.Add(items[i] as T);
}
for (int n = 0; n < items[i].Components.Count; n++)
{
if (items[i].Components[n].GetType() == type)
{
elements.Add(items[i].Components[n] as T);
}
}
}
return elements.ToArray();
}
}
}

View File

@@ -0,0 +1,233 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TEngineCore
{
/// <summary>
/// ECS系统 管理Entity、ECSComponent复用对象池
/// </summary>
[Serializable]
public class ECSSystem : IDisposable
{
private static ECSSystem instance = new ECSSystem();
public static ECSSystem Instance => instance;
private readonly Dictionary<int,Stack<ECSObject>> m_ObjectPool = new Dictionary<int, Stack<ECSObject>>();
internal readonly ArrayPool<Entity> Entities = new ArrayPool<Entity>();
private bool m_IsDispose = false;
public void AddEntity(Entity entity)
{
entity.System = this;
entity.Awake();
Entities.Add(entity);
}
public void RemoveEntity(Entity entity)
{
Entities.Remove(entity);
}
/// <summary>
/// Get Object From ECSSystem
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T Get<T>() where T : ECSObject, new()
{
int type = typeof(T).GetHashCode();
if (m_ObjectPool.TryGetValue(type,out Stack<ECSObject> stack))
{
if (stack.Count > 0)
{
return (T) stack.Pop();
}
goto Instantiate;
}
stack = new Stack<ECSObject>();
m_ObjectPool.Add(type,stack);
Instantiate: T ecsObject = new T();
return ecsObject;
}
/// <summary>
/// Push Object To ECSSystem
/// </summary>
public void Push(ECSObject ecsObject)
{
int type = ecsObject.HashCode;
if (m_ObjectPool.TryGetValue(type,out Stack<ECSObject> stack))
{
stack.Push(ecsObject);
return;
}
stack = new Stack<ECSObject>();
m_ObjectPool.Add(type,stack);
stack.Push(ecsObject);
}
public T Create<T>() where T : Entity, new()
{
T entity = Get<T>();
AddEntity(entity);
return entity;
}
public T Create<T>(T entity) where T : Entity, new()
{
AddEntity(entity);
return entity;
}
/// <summary>
/// 更新ECS系统
/// </summary>
/// <param name="worker">线程池是否并行</param>
public void Update(bool worker = false)
{
Run(worker);
}
/// <summary>
/// 更新ECS物理系统
/// </summary>
/// <param name="worker">线程池是否并行</param>
public void FixedUpdate(bool worker = false)
{
RunFixed(worker);
}
/// <summary>
/// 运行ECS系统
/// </summary>
/// <param name="worker">线程池是否并行</param>
public void Run(bool worker = false)
{
int count = Entities.Count;
if (!worker)
{
for (int i = 0; i < count; i++)
{
if (!Entities.Buckets[i])
{
continue;
}
if (!Entities[i].CanUpdate)
{
continue;
}
Entities[i].Execute();
}
}
else
{
Parallel.For(0, count, i =>
{
if (!Entities.Buckets[i])
{
return;
}
if (!Entities[i].CanUpdate)
{
return;
}
Entities[i].Execute();
});
}
}
public void RunFixed(bool worker = false)
{
int count = Entities.Count;
if (!worker)
{
for (int i = 0; i < count; i++)
{
if (!Entities.Buckets[i])
{
continue;
}
if (!Entities[i].CanFixedUpdate)
{
continue;
}
Entities[i].FixedUpdate();
}
}
else
{
Parallel.For(0, count, i =>
{
if (!Entities.Buckets[i])
{
return;
}
if (!Entities[i].CanFixedUpdate)
{
return;
}
Entities[i].FixedUpdate();
});
}
}
public void Dispose()
{
if (m_IsDispose)
{
return;
}
m_IsDispose = true;
}
public T FindObjectOfType<T>() where T : ECSObject
{
Type type = typeof(T);
var elements = Entities.ToArray();
for (int i = 0; i < elements.Length; i++)
{
if (elements[i].GetType() == type)
{
return elements[i] as T;
}
for (int j = 0; j < elements[i].Components.Count; j++)
{
if (elements[i].Components[j].GetType() == type)
{
return elements[i].Components[j] as T;
}
}
}
return null;
}
public T[] FindObjectsOfType<T>() where T : ECSObject
{
Type type = typeof(T);
var entities = Entities.ToArray();
List<T> elements = new List<T>();
for (int i = 0; i < entities.Length; i++)
{
if (entities[i].GetType() == type)
{
elements.Add(entities[i] as T);
}
for (int n = 0; n < entities[i].Components.Count; n++)
{
if (entities[i].Components[n].GetType() == type)
{
elements.Add(entities[i].Components[n] as T);
}
}
}
return elements.ToArray();
}
}
}

View File

@@ -0,0 +1,273 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TEngineCore
{
public class Entity : ECSObject, IIndex
{
[SerializeField]
internal List<ECSComponent> Components = new List<ECSComponent>();
internal List<IUpdate> Updates = new List<IUpdate>();
internal List<IFixedUpdate> FixedUpdates = new List<IFixedUpdate>();
internal bool InActive;
internal bool CanUpdate;
internal bool CanFixedUpdate;
public int Index { get; set; } = -1;
public ECSEventCmpt Event { get; set; }
public Entity()
{
InActive = true;
System = ECSSystem.Instance;
}
~Entity()
{
InActive = false;
}
internal void Execute()
{
for (int i = 0; i < Updates.Count; i++)
{
Updates[i].Update();
}
}
internal void FixedUpdate()
{
for (int i = 0; i < FixedUpdates.Count; i++)
{
FixedUpdates[i].FixedUpdate();
}
}
public void RmvComponent<T>() where T : ECSComponent, new()
{
for (int i = 0; i < Components.Count; i++)
{
if (Components[i] is T component)
{
if (component is IUpdate update)
{
Updates.Remove(update);
}
else if (component is IFixedUpdate fixedUpdate)
{
FixedUpdates.Remove(fixedUpdate);
}
System.Push(component);
CanUpdate = Updates.Count > 0;
CanFixedUpdate = FixedUpdates.Count > 0;
}
}
#if UNITY_EDITOR
CheckDebugInfo();
#endif
}
public void RmvComponent(Type componentType)
{
for (int i = 0; i < Components.Count; i++)
{
if (Components[i].GetType() == componentType)
{
if (componentType is IUpdate update)
{
Updates.Remove(update);
CanUpdate = Updates.Count > 0;
}
else if (componentType is IFixedUpdate fixedUpdate)
{
FixedUpdates.Remove(fixedUpdate);
CanFixedUpdate = FixedUpdates.Count > 0;
}
//if (componentType is ECSComponent component)
//{
// System.Push(component);
//}
}
}
#if UNITY_EDITOR
CheckDebugInfo();
#endif
}
public T AddComponent<T>() where T : ECSComponent, new()
{
#if UNITY_EDITOR
CheckDebugInfo();
#endif
T component = System.Get<T>();
component.Entity = this;
component.System = System;
Components.Add(component);
component.Awake();
if (component is IUpdate update)
{
Updates.Add(update);
}
else if (component is IFixedUpdate fixedUpdate)
{
FixedUpdates.Add(fixedUpdate);
}
CanUpdate = Updates.Count > 0;
CanFixedUpdate = FixedUpdates.Count > 0;
return component;
}
public ECSComponent AddComponent(ECSComponent component)
{
#if UNITY_EDITOR
CheckDebugInfo();
#endif
component.Entity = this;
component.System = System;
Components.Add(component);
component.Awake();
if (component is IUpdate update)
{
Updates.Add(update);
}
else if (component is IFixedUpdate fixedUpdate)
{
FixedUpdates.Add(fixedUpdate);
}
CanUpdate = Updates.Count > 0;
CanFixedUpdate = FixedUpdates.Count > 0;
return component;
}
public T GetComponent<T>() where T : ECSComponent
{
for (int i = 0; i < Components.Count; i++)
{
if (Components[i] is T type)
{
return type;
}
}
return null;
}
public ECSComponent GetComponent(Type componentType)
{
for (int i = 0; i < Components.Count; i++)
{
if (Components[i].GetType() == componentType)
{
return Components[i];
}
}
return null;
}
public T[] GetComponents<T>() where T : ECSComponent
{
List<T> elements = new List<T>();
for (int i = 0; i < Components.Count; i++)
{
if (Components[i] is T type)
{
elements.Add(type);
}
}
return elements.ToArray();
}
public List<T> GetComponentsList<T>() where T : ECSComponent
{
List<T> elements = new List<T>();
for (int i = 0; i < Components.Count; i++)
{
if (Components[i] is T type)
{
elements.Add(type);
}
}
return elements;
}
public ECSComponent[] GetComponents(Type comType)
{
List<ECSComponent> elements = new List<ECSComponent>();
for (int i = 0; i < Components.Count; i++)
{
{
if (Components[i].GetType() == comType)
{
elements.Add(Components[i]);
}
}
}
return elements.ToArray();
}
public override string ToString()
{
string str = "[";
for (int i = 0; i < Components.Count; i++)
{
str += Components[i].GetType().Name + ",";
}
str = str.TrimEnd(',');
str += "]";
return $"{GetType().Name} Components: {str}";
}
public void CheckDebugInfo(GameObject gameObject)
{
#if UNITY_EDITOR
if (gameObject == null)
{
return;
}
var debugBehaviour = UnityUtil.AddMonoBehaviour<ECSDebugBehaviour>(gameObject);
debugBehaviour.m_ECSInfo.Clear();
for (int i = 0; i < this.Components.Count; i++)
{
var component = this.Components[i];
var cmptName = component.GetType().Name;
debugBehaviour.SetDebugInfo(cmptName, "", "");
}
#endif
}
public void CheckDebugInfo()
{
#if UNITY_EDITOR
//var actorEntity = this as Entity;
//if (actorEntity == null)
//{
// return;
//}
//if (actorEntity.gameObject == null)
//{
// return;
//}
//var debugBehaviour = UnityUtil.AddMonoBehaviour<ECSDebugBehaviour>(actorEntity.gameObject);
//debugBehaviour.m_ECSInfo.Clear();
//for (int i = 0; i < this.Components.Count; i++)
//{
// var component = this.Components[i];
// var cmptName = component.GetType().Name;
// debugBehaviour.SetDebugInfo(cmptName, "", "");
//}
#endif
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TEngineCore
{
public class HotfixComponent : ECSComponent,IUpdate
{
public object[] Values;
public Action OnAwake, OnUpdate, OnDestroyExt;
public override void Awake()
{
OnAwake?.Invoke();
}
void IUpdate.Update()
{
OnUpdate?.Invoke();
}
public override void OnDestroy()
{
OnDestroyExt?.Invoke();
OnAwake = null;
OnUpdate = null;
OnDestroyExt = null;
}
}
}

View File

@@ -0,0 +1,10 @@
namespace TEngineCore
{
/// <summary>
/// ECS组件更新接口减少组件for循环开销
/// </summary>
public interface IFixedUpdate
{
void FixedUpdate();
}
}

View File

@@ -0,0 +1,10 @@
namespace TEngineCore
{
/// <summary>
/// ECS组件更新接口减少组件for循环开销
/// </summary>
public interface IUpdate
{
void Update();
}
}

View File

@@ -0,0 +1,13 @@
namespace TEngineCore
{
/// <summary>
/// 热更层由此组件进行更新ILRuntime不支持多继承, 接口继承)
/// </summary>
public class UpdateComponent :ECSComponent, IUpdate
{
public virtual void Update()
{
}
}
}

View File

@@ -0,0 +1,392 @@
using System;
using System.Collections.Generic;
using TEngineCore;
namespace TEngineCore
{
#region EventInfo
internal interface IEventInfo
{
}
public class EventInfo : IEventInfo
{
public Action actions;
public EventInfo(Action action)
{
actions += action;
}
}
public class EventInfo<T> : IEventInfo
{
public Action<T> actions;
public EventInfo(Action<T> action)
{
actions += action;
}
}
public class EventInfo<T, U> : IEventInfo
{
public Action<T, U> actions;
public EventInfo(Action<T, U> action)
{
actions += action;
}
}
public class EventInfo<T, U, W> : IEventInfo
{
public Action<T, U, W> actions;
public EventInfo(Action<T, U, W> action)
{
actions += action;
}
}
#endregion
/// <summary>
/// 总观察者 - 总事件中心系统
/// </summary>
public class GameEventMgr : TSingleton<GameEventMgr>
{
/// <summary>
/// Dictionary<int, IEventInfo> Key->Int.32 Value->EventInfo,调用频率高建议使用int事件减少字典内String的哈希碰撞
/// </summary>
private Dictionary<int, IEventInfo> m_eventDic = new Dictionary<int, IEventInfo>();
/// <summary>
/// Dictionary<string, IEventInfo> Key->string Value->EventInfo,调用频率不高的时候可以使用
/// </summary>
private Dictionary<string, IEventInfo> m_eventStrDic = new Dictionary<string, IEventInfo>();
#region AddEventListener
public void AddEventListener<T>(int eventid, Action<T> action)
{
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EventInfo<T>).actions += action;
}
else
{
m_eventDic.Add(eventid, new EventInfo<T>(action));
}
}
public void AddEventListener<T, U>(int eventid, Action<T, U> action)
{
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EventInfo<T, U>).actions += action;
}
else
{
m_eventDic.Add(eventid, new EventInfo<T, U>(action));
}
}
public void AddEventListener<T, U, W>(int eventid, Action<T, U, W> action)
{
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EventInfo<T, U, W>).actions += action;
}
else
{
m_eventDic.Add(eventid, new EventInfo<T, U, W>(action));
}
}
public void AddEventListener(int eventid, Action action)
{
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EventInfo).actions += action;
}
else
{
m_eventDic.Add(eventid, new EventInfo(action));
}
}
#endregion
#region RemoveEventListener
public void RemoveEventListener<T>(int eventid, Action<T> action)
{
if (action == null)
{
return;
}
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EventInfo<T>).actions -= action;
}
}
public void RemoveEventListener<T, U>(int eventid, Action<T, U> action)
{
if (action == null)
{
return;
}
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EventInfo<T, U>).actions -= action;
}
}
public void RemoveEventListener<T, U, W>(int eventid, Action<T, U, W> action)
{
if (action == null)
{
return;
}
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EventInfo<T, U, W>).actions -= action;
}
}
public void RemoveEventListener(int eventid, Action action)
{
if (action == null)
{
return;
}
if (m_eventDic.ContainsKey(eventid))
{
(m_eventDic[eventid] as EventInfo).actions -= action;
}
}
#endregion
#region Send
public void Send<T>(int eventid, T info)
{
if (m_eventDic.ContainsKey(eventid))
{
var eventInfo = (m_eventDic[eventid] as EventInfo<T>);
if (eventInfo != null)
{
eventInfo.actions.Invoke(info);
}
}
}
public void Send<T, U>(int eventid, T info, U info2)
{
if (m_eventDic.ContainsKey(eventid))
{
var eventInfo = (m_eventDic[eventid] as EventInfo<T, U>);
if (eventInfo != null)
{
eventInfo.actions.Invoke(info, info2);
}
}
}
public void Send<T, U, W>(int eventid, T info, U info2, W info3)
{
if (m_eventDic.ContainsKey(eventid))
{
var eventInfo = (m_eventDic[eventid] as EventInfo<T, U, W>);
if (eventInfo != null)
{
eventInfo.actions.Invoke(info, info2, info3);
}
}
}
/// <summary>
/// 事件触发 无参
/// </summary>
/// <param name="name"></param>
public void Send(int eventid)
{
if (m_eventDic.ContainsKey(eventid))
{
var eventInfo = (m_eventDic[eventid] as EventInfo);
if (eventInfo != null)
{
eventInfo.actions.Invoke();
}
}
}
#endregion
#region StringEvent
#region AddEventListener
public void AddEventListener<T>(string eventid, Action<T> action)
{
if (m_eventStrDic.ContainsKey(eventid))
{
(m_eventStrDic[eventid] as EventInfo<T>).actions += action;
}
else
{
m_eventStrDic.Add(eventid, new EventInfo<T>(action));
}
}
public void AddEventListener<T, U>(string eventid, Action<T, U> action)
{
if (m_eventStrDic.ContainsKey(eventid))
{
(m_eventStrDic[eventid] as EventInfo<T, U>).actions += action;
}
else
{
m_eventStrDic.Add(eventid, new EventInfo<T, U>(action));
}
}
public void AddEventListener<T, U, W>(string eventid, Action<T, U, W> action)
{
if (m_eventStrDic.ContainsKey(eventid))
{
(m_eventStrDic[eventid] as EventInfo<T, U, W>).actions += action;
}
else
{
m_eventStrDic.Add(eventid, new EventInfo<T, U, W>(action));
}
}
public void AddEventListener(string eventid, Action action)
{
if (m_eventStrDic.ContainsKey(eventid))
{
(m_eventStrDic[eventid] as EventInfo).actions += action;
}
else
{
m_eventStrDic.Add(eventid, new EventInfo(action));
}
}
#endregion
#region RemoveEventListener
public void RemoveEventListener<T>(string eventid, Action<T> action)
{
if (action == null)
{
return;
}
if (m_eventStrDic.ContainsKey(eventid))
{
(m_eventStrDic[eventid] as EventInfo<T>).actions -= action;
}
}
public void RemoveEventListener<T, U>(string eventid, Action<T, U> action)
{
if (action == null)
{
return;
}
if (m_eventStrDic.ContainsKey(eventid))
{
(m_eventStrDic[eventid] as EventInfo<T, U>).actions -= action;
}
}
public void RemoveEventListener<T, U, W>(string eventid, Action<T, U, W> action)
{
if (action == null)
{
return;
}
if (m_eventStrDic.ContainsKey(eventid))
{
(m_eventStrDic[eventid] as EventInfo<T, U, W>).actions -= action;
}
}
public void RemoveEventListener(string eventid, Action action)
{
if (action == null)
{
return;
}
if (m_eventStrDic.ContainsKey(eventid))
{
(m_eventStrDic[eventid] as EventInfo).actions -= action;
}
}
#endregion
#region Send
public void Send<T>(string eventid, T info)
{
if (m_eventStrDic.ContainsKey(eventid))
{
var eventInfo = (m_eventStrDic[eventid] as EventInfo<T>);
if (eventInfo != null)
{
eventInfo.actions.Invoke(info);
}
}
}
public void Send<T, U>(string eventid, T info, U info2)
{
if (m_eventStrDic.ContainsKey(eventid))
{
var eventInfo = (m_eventStrDic[eventid] as EventInfo<T, U>);
if (eventInfo != null)
{
eventInfo.actions.Invoke(info, info2);
}
}
}
public void Send<T, U, W>(string eventid, T info, U info2, W info3)
{
if (m_eventStrDic.ContainsKey(eventid))
{
var eventInfo = (m_eventStrDic[eventid] as EventInfo<T, U, W>);
if (eventInfo != null)
{
eventInfo.actions.Invoke(info, info2, info3);
}
}
}
public void Send(string eventid)
{
if (m_eventStrDic.ContainsKey(eventid))
{
var eventInfo = (m_eventStrDic[eventid] as EventInfo);
if (eventInfo != null)
{
eventInfo.actions.Invoke();
}
}
}
#endregion
#endregion
#region Clear
public void Clear()
{
m_eventDic.Clear();
m_eventStrDic.Clear();
}
#endregion
}
}

View File

@@ -0,0 +1,37 @@
using System.Collections.Generic;
namespace TEngineCore
{
public class StringId
{
private static Dictionary<string, int> m_eventTypeHashMap = new Dictionary<string, int>();
private static Dictionary<int, string> m_eventHashToStringMap = new Dictionary<int, string>();
private static int m_currentId = 0;
public static int StringToHash(string val)
{
int hashId;
if (m_eventTypeHashMap.TryGetValue(val, out hashId))
{
return hashId;
}
hashId = ++m_currentId;
m_eventTypeHashMap[val] = hashId;
m_eventHashToStringMap[hashId] = val;
return hashId;
}
public static string HashToString(int hash)
{
string value;
if (m_eventHashToStringMap.TryGetValue(hash, out value))
{
return value;
}
return string.Empty;
}
}
}

View File

@@ -0,0 +1,130 @@
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace TEngineCore
{
public static class FileSystem
{
public const string ArtResourcePath = "Assets/ArtResources";
public const string GameResourcePath = AssetConfig.AssetRootPath;
internal static Dictionary<string, string> _fileFixList = new Dictionary<string, string>();
private static string _persistentDataPath = null;
private static string _resRootPath = null;
private static string _resRootStreamAssetPath = null;
public const string BuildPath = "Build";
public const string AssetBundleBuildPath = BuildPath + "/AssetBundles";
private const string AssetBundleTargetPath = "{0}/AssetBundles";
/// <summary>
/// 资源更新读取根目录
/// </summary>
/// <returns></returns>
public static string ResourceRoot
{
get
{
if (string.IsNullOrEmpty(_resRootPath))
{
_resRootPath = Path.Combine(PersistentDataPath, "TEngine");
}
if (!Directory.Exists(_resRootPath))
{
Directory.CreateDirectory(_resRootPath);
}
return _resRootPath.FixPath();
}
}
/// <summary>
/// 持久化数据存储路径
/// </summary>
public static string PersistentDataPath
{
get
{
if (string.IsNullOrEmpty(_persistentDataPath))
{
#if UNITY_EDITOR_WIN
_persistentDataPath = Application.dataPath + "/../TEnginePersistentDataPath";
if (!Directory.Exists(_persistentDataPath))
{
Directory.CreateDirectory(_persistentDataPath);
}
#else
_persistentDataPath = Application.persistentDataPath;
#endif
}
return _persistentDataPath.FixPath();
}
}
/// <summary>
/// 资源更新读取StreamAsset根目录
/// </summary>
/// <returns></returns>
public static string ResourceRootInStreamAsset
{
get
{
if (string.IsNullOrEmpty(_resRootStreamAssetPath))
{
_resRootStreamAssetPath = Path.Combine(Application.streamingAssetsPath, "TEngine");
}
return _resRootStreamAssetPath.FixPath();
}
}
public static string GetAssetBundlePathInVersion(string bundlename)
{
//默认用外部目录
string path = FilePath($"{ResourceRoot}/AssetBundles/{bundlename}");
if (!File.Exists(path))
{
path = $"{ResourceRootInStreamAsset}/AssetBundles/{bundlename}";
}
return path;
}
public static string StreamAssetBundlePath
{
get { return string.Format(AssetBundleTargetPath, ResourceRootInStreamAsset); }
}
internal static string FilePath(string path)
{
path = path.FixPath();
#if UNITY_EDITOR_WIN
path = path.Replace("Assets/../", "");
#endif
if (_fileFixList.ContainsKey(path))
{
return _fileFixList[path];
}
else
{
return path;
}
}
public static string FixPath(this string str)
{
str = str.Replace("\\", "/");
return str;
}
public static Stream OpenRead(string filePath)
{
#if UNITY_ANDROID && !UNITY_EDITOR
byte[] bytes = ReadAllBytesFromOutOrInnerFolder(filePath);
if (bytes != null)
return new MemoryStream(bytes);
else
return null;
#else
return File.OpenRead(filePath);
#endif
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.IO;
namespace TEngineCore
{
public class FileWriter
{
private FileStream _fStream;
private StreamWriter _writer;
public bool OpenFile(string path)
{
try
{
_fStream = File.Open(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
_writer = new StreamWriter(_fStream);
return true;
}
catch (Exception e)
{
TLogger.LogException(e.ToString());
return false;
}
}
public void Shutdown()
{
try
{
if (_writer != null)
{
_writer.Close();
}
_writer = null;
if (_fStream != null)
{
_fStream.Close();
}
_fStream = null;
}
catch (Exception e)
{
TLogger.LogException(e.ToString());
_writer = null;
_fStream = null;
}
}
public void Write(string msg)
{
if (_writer == null)
{
return;
}
if (string.IsNullOrWhiteSpace(msg))
{
return;
}
try
{
_writer.WriteLine(msg);
}
catch (Exception e)
{
Shutdown();
}
Flush();
}
public void Flush()
{
if (_writer == null)
{
return;
}
try
{
if (_writer.BaseStream != null)
{
_writer.Flush();
}
}
catch (Exception e)
{
Shutdown();
TLogger.LogException( e.ToString());
}
}
}
}

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace TEngineCore
{
public class LogToFile
{
private FileWriter _fileWriter = new FileWriter();
private static readonly string mLogRootPath = Path.Combine(FileSystem.PersistentDataPath, "Log").FixPath();
private static int MaxLogDays = 3;
private static string _currentLogName = string.Empty;
private string GetLogPath(DateTime dt)
{
string dataDir = dt.ToString("yyyy_MM_dd");
string logPath = Path.Combine(mLogRootPath, dataDir);
return logPath.FixPath();
}
public void DeInit()
{
if (_fileWriter == null)
{
return;
}
_fileWriter.Flush();
_fileWriter.Shutdown();
}
public void Init()
{
DateTime currentTime = DateTime.Now;
RemoveOldLogs(currentTime);
string logDir = GetLogPath(currentTime);
string logFileName = string.Format("Log_{0}.log", currentTime.ToString("yyyy_MM_dd-HH_mm_ss"));
_currentLogName = logFileName;
string fullPath = Path.Combine(logDir, logFileName).FixPath();
try
{
if (!Directory.Exists(logDir))
{
Directory.CreateDirectory(logDir);
}
if (File.Exists(fullPath))
{
File.Delete(fullPath);
}
_fileWriter.OpenFile(fullPath);
}
catch (Exception e)
{
TLogger.LogException( e.ToString());
}
}
public void Write(string msg)
{
if (_fileWriter == null)
{
return;
}
_fileWriter.Write(msg);
}
private void RemoveOldLogs(DateTime now)
{
HashSet<string> foldersToKeep = new HashSet<string>();
for (int i = 0; i < MaxLogDays; i++)
{
DateTime current = now.AddDays(-i);
string folder = GetLogPath(current);
foldersToKeep.Add(folder);
}
if (Directory.Exists(mLogRootPath))
{
try
{
string[] allLogDir = Directory.GetDirectories(mLogRootPath);
foreach (string dir in allLogDir)
{
string fixedDir = dir.FixPath();
if (!foldersToKeep.Contains(fixedDir))
{
try
{
Directory.Delete(fixedDir, true);
}
catch (Exception e)
{
TLogger.LogException(e.ToString());
}
}
}
}
catch (Exception e)
{
TLogger.LogException(e.ToString());
}
}
}
}
}

View File

@@ -0,0 +1,30 @@
using UnityEngine;
using TEngineCore;
using TEngineCore.ListJson;
public class JsonHelper : Singleton<JsonHelper>
{
public JsonHelper()
{
}
public T Deserialize<T>(string json)
{
return JsonMapper.ToObject<T>(json);
}
public JsonData Deserialize(string json)
{
return JsonMapper.ToObject(json);
}
public string Serialize(JsonData jsonData)
{
return JsonMapper.ToJson(jsonData);
}
public string Serialize(Object jsonData)
{
return JsonMapper.ToJson(jsonData);
}
}

View File

@@ -0,0 +1,60 @@
#region Header
/**
* IJsonWrapper.cs
* Interface that represents a type capable of handling all kinds of JSON
* data. This is mainly used when mapping objects through JsonMapper, and
* it's implemented by JsonData.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System.Collections;
using System.Collections.Specialized;
namespace TEngineCore.ListJson
{
public enum JsonType
{
None,
Object,
Array,
String,
Int,
Long,
Double,
Boolean
}
public interface IJsonWrapper : IList, IOrderedDictionary
{
bool IsArray { get; }
bool IsBoolean { get; }
bool IsDouble { get; }
bool IsInt { get; }
bool IsLong { get; }
bool IsObject { get; }
bool IsString { get; }
bool GetBoolean ();
double GetDouble ();
int GetInt ();
JsonType GetJsonType ();
long GetLong ();
string GetString ();
void SetBoolean (bool val);
void SetDouble (double val);
void SetInt (int val);
void SetJsonType (JsonType type);
void SetLong (long val);
void SetString (string val);
string ToJson ();
void ToJson (JsonWriter writer);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
#region Header
/**
* JsonException.cs
* Base class throwed by LitJSON when a parsing error occurs.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
namespace TEngineCore.ListJson
{
public class JsonException :
#if NETSTANDARD1_5
Exception
#else
ApplicationException
#endif
{
public JsonException () : base ()
{
}
internal JsonException (ParserToken token) :
base (String.Format (
"Invalid token '{0}' in input string", token))
{
}
internal JsonException (ParserToken token,
Exception inner_exception) :
base (String.Format (
"Invalid token '{0}' in input string", token),
inner_exception)
{
}
internal JsonException (int c) :
base (String.Format (
"Invalid character '{0}' in input string", (char) c))
{
}
internal JsonException (int c, Exception inner_exception) :
base (String.Format (
"Invalid character '{0}' in input string", (char) c),
inner_exception)
{
}
public JsonException (string message) : base (message)
{
}
public JsonException (string message, Exception inner_exception) :
base (message, inner_exception)
{
}
}
}

View File

@@ -0,0 +1,987 @@
#region Header
/**
* JsonMapper.cs
* JSON to .Net object and object to JSON conversions.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
namespace TEngineCore.ListJson
{
internal struct PropertyMetadata
{
public MemberInfo Info;
public bool IsField;
public Type Type;
}
internal struct ArrayMetadata
{
private Type element_type;
private bool is_array;
private bool is_list;
public Type ElementType {
get {
if (element_type == null)
return typeof (JsonData);
return element_type;
}
set { element_type = value; }
}
public bool IsArray {
get { return is_array; }
set { is_array = value; }
}
public bool IsList {
get { return is_list; }
set { is_list = value; }
}
}
internal struct ObjectMetadata
{
private Type element_type;
private bool is_dictionary;
private IDictionary<string, PropertyMetadata> properties;
public Type ElementType {
get {
if (element_type == null)
return typeof (JsonData);
return element_type;
}
set { element_type = value; }
}
public bool IsDictionary {
get { return is_dictionary; }
set { is_dictionary = value; }
}
public IDictionary<string, PropertyMetadata> Properties {
get { return properties; }
set { properties = value; }
}
}
internal delegate void ExporterFunc (object obj, JsonWriter writer);
public delegate void ExporterFunc<T> (T obj, JsonWriter writer);
internal delegate object ImporterFunc (object input);
public delegate TValue ImporterFunc<TJson, TValue> (TJson input);
public delegate IJsonWrapper WrapperFactory ();
public class JsonMapper
{
#region Fields
private static readonly int max_nesting_depth;
private static readonly IFormatProvider datetime_format;
private static readonly IDictionary<Type, ExporterFunc> base_exporters_table;
private static readonly IDictionary<Type, ExporterFunc> custom_exporters_table;
private static readonly IDictionary<Type,
IDictionary<Type, ImporterFunc>> base_importers_table;
private static readonly IDictionary<Type,
IDictionary<Type, ImporterFunc>> custom_importers_table;
private static readonly IDictionary<Type, ArrayMetadata> array_metadata;
private static readonly object array_metadata_lock = new Object ();
private static readonly IDictionary<Type,
IDictionary<Type, MethodInfo>> conv_ops;
private static readonly object conv_ops_lock = new Object ();
private static readonly IDictionary<Type, ObjectMetadata> object_metadata;
private static readonly object object_metadata_lock = new Object ();
private static readonly IDictionary<Type,
IList<PropertyMetadata>> type_properties;
private static readonly object type_properties_lock = new Object ();
private static readonly JsonWriter static_writer;
private static readonly object static_writer_lock = new Object ();
#endregion
#region Constructors
static JsonMapper ()
{
max_nesting_depth = 100;
array_metadata = new Dictionary<Type, ArrayMetadata> ();
conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>> ();
object_metadata = new Dictionary<Type, ObjectMetadata> ();
type_properties = new Dictionary<Type,
IList<PropertyMetadata>> ();
static_writer = new JsonWriter ();
datetime_format = DateTimeFormatInfo.InvariantInfo;
base_exporters_table = new Dictionary<Type, ExporterFunc> ();
custom_exporters_table = new Dictionary<Type, ExporterFunc> ();
base_importers_table = new Dictionary<Type,
IDictionary<Type, ImporterFunc>> ();
custom_importers_table = new Dictionary<Type,
IDictionary<Type, ImporterFunc>> ();
RegisterBaseExporters ();
RegisterBaseImporters ();
}
#endregion
#region Private Methods
private static void AddArrayMetadata (Type type)
{
if (array_metadata.ContainsKey (type))
return;
ArrayMetadata data = new ArrayMetadata ();
data.IsArray = type.IsArray;
if (type.GetInterface ("System.Collections.IList") != null)
data.IsList = true;
foreach (PropertyInfo p_info in type.GetProperties ()) {
if (p_info.Name != "Item")
continue;
ParameterInfo[] parameters = p_info.GetIndexParameters ();
if (parameters.Length != 1)
continue;
if (parameters[0].ParameterType == typeof (int))
data.ElementType = p_info.PropertyType;
}
lock (array_metadata_lock) {
try {
array_metadata.Add (type, data);
} catch (ArgumentException) {
return;
}
}
}
private static void AddObjectMetadata (Type type)
{
if (object_metadata.ContainsKey (type))
return;
ObjectMetadata data = new ObjectMetadata ();
if (type.GetInterface ("System.Collections.IDictionary") != null)
data.IsDictionary = true;
data.Properties = new Dictionary<string, PropertyMetadata> ();
foreach (PropertyInfo p_info in type.GetProperties ()) {
if (p_info.Name == "Item") {
ParameterInfo[] parameters = p_info.GetIndexParameters ();
if (parameters.Length != 1)
continue;
if (parameters[0].ParameterType == typeof (string))
data.ElementType = p_info.PropertyType;
continue;
}
PropertyMetadata p_data = new PropertyMetadata ();
p_data.Info = p_info;
p_data.Type = p_info.PropertyType;
data.Properties.Add (p_info.Name, p_data);
}
foreach (FieldInfo f_info in type.GetFields ()) {
PropertyMetadata p_data = new PropertyMetadata ();
p_data.Info = f_info;
p_data.IsField = true;
p_data.Type = f_info.FieldType;
data.Properties.Add (f_info.Name, p_data);
}
lock (object_metadata_lock) {
try {
object_metadata.Add (type, data);
} catch (ArgumentException) {
return;
}
}
}
private static void AddTypeProperties (Type type)
{
if (type_properties.ContainsKey (type))
return;
IList<PropertyMetadata> props = new List<PropertyMetadata> ();
foreach (PropertyInfo p_info in type.GetProperties ()) {
if (p_info.Name == "Item")
continue;
PropertyMetadata p_data = new PropertyMetadata ();
p_data.Info = p_info;
p_data.IsField = false;
props.Add (p_data);
}
foreach (FieldInfo f_info in type.GetFields ()) {
PropertyMetadata p_data = new PropertyMetadata ();
p_data.Info = f_info;
p_data.IsField = true;
props.Add (p_data);
}
lock (type_properties_lock) {
try {
type_properties.Add (type, props);
} catch (ArgumentException) {
return;
}
}
}
private static MethodInfo GetConvOp (Type t1, Type t2)
{
lock (conv_ops_lock) {
if (! conv_ops.ContainsKey (t1))
conv_ops.Add (t1, new Dictionary<Type, MethodInfo> ());
}
if (conv_ops[t1].ContainsKey (t2))
return conv_ops[t1][t2];
MethodInfo op = t1.GetMethod (
"op_Implicit", new Type[] { t2 });
lock (conv_ops_lock) {
try {
conv_ops[t1].Add (t2, op);
} catch (ArgumentException) {
return conv_ops[t1][t2];
}
}
return op;
}
private static object ReadValue (Type inst_type, JsonReader reader)
{
reader.Read ();
if (reader.Token == JsonToken.ArrayEnd)
return null;
Type underlying_type = Nullable.GetUnderlyingType(inst_type);
Type value_type = underlying_type ?? inst_type;
if (reader.Token == JsonToken.Null) {
#if NETSTANDARD1_5
if (inst_type.IsClass() || underlying_type != null) {
return null;
}
#else
if (inst_type.IsClass || underlying_type != null) {
return null;
}
#endif
throw new JsonException (String.Format (
"Can't assign null to an instance of type {0}",
inst_type));
}
if (reader.Token == JsonToken.Double ||
reader.Token == JsonToken.Int ||
reader.Token == JsonToken.Long ||
reader.Token == JsonToken.String ||
reader.Token == JsonToken.Boolean) {
Type json_type = reader.Value.GetType ();
if (value_type.IsAssignableFrom (json_type))
return reader.Value;
// If there's a custom importer that fits, use it
if (custom_importers_table.ContainsKey (json_type) &&
custom_importers_table[json_type].ContainsKey (
value_type)) {
ImporterFunc importer =
custom_importers_table[json_type][value_type];
return importer (reader.Value);
}
// Maybe there's a base importer that works
if (base_importers_table.ContainsKey (json_type) &&
base_importers_table[json_type].ContainsKey (
value_type)) {
ImporterFunc importer =
base_importers_table[json_type][value_type];
return importer (reader.Value);
}
// Maybe it's an enum
#if NETSTANDARD1_5
if (value_type.IsEnum())
return Enum.ToObject (value_type, reader.Value);
#else
if (value_type.IsEnum)
return Enum.ToObject (value_type, reader.Value);
#endif
// Try using an implicit conversion operator
MethodInfo conv_op = GetConvOp (value_type, json_type);
if (conv_op != null)
return conv_op.Invoke (null,
new object[] { reader.Value });
// No luck
throw new JsonException (String.Format (
"Can't assign value '{0}' (type {1}) to type {2}",
reader.Value, json_type, inst_type));
}
object instance = null;
if (reader.Token == JsonToken.ArrayStart) {
AddArrayMetadata (inst_type);
ArrayMetadata t_data = array_metadata[inst_type];
if (! t_data.IsArray && ! t_data.IsList)
throw new JsonException (String.Format (
"Type {0} can't act as an array",
inst_type));
IList list;
Type elem_type;
if (! t_data.IsArray) {
list = (IList) Activator.CreateInstance (inst_type);
elem_type = t_data.ElementType;
} else {
list = new ArrayList ();
elem_type = inst_type.GetElementType ();
}
list.Clear();
while (true) {
object item = ReadValue (elem_type, reader);
if (item == null && reader.Token == JsonToken.ArrayEnd)
break;
list.Add (item);
}
if (t_data.IsArray) {
int n = list.Count;
instance = Array.CreateInstance (elem_type, n);
for (int i = 0; i < n; i++)
((Array) instance).SetValue (list[i], i);
} else
instance = list;
} else if (reader.Token == JsonToken.ObjectStart) {
AddObjectMetadata (value_type);
ObjectMetadata t_data = object_metadata[value_type];
instance = Activator.CreateInstance (value_type);
while (true) {
reader.Read ();
if (reader.Token == JsonToken.ObjectEnd)
break;
string property = (string) reader.Value;
if (t_data.Properties.ContainsKey (property)) {
PropertyMetadata prop_data =
t_data.Properties[property];
if (prop_data.IsField) {
((FieldInfo) prop_data.Info).SetValue (
instance, ReadValue (prop_data.Type, reader));
} else {
PropertyInfo p_info =
(PropertyInfo) prop_data.Info;
if (p_info.CanWrite)
p_info.SetValue (
instance,
ReadValue (prop_data.Type, reader),
null);
else
ReadValue (prop_data.Type, reader);
}
} else {
if (! t_data.IsDictionary) {
if (! reader.SkipNonMembers) {
throw new JsonException (String.Format (
"The type {0} doesn't have the " +
"property '{1}'",
inst_type, property));
} else {
ReadSkip (reader);
continue;
}
}
((IDictionary) instance).Add (
property, ReadValue (
t_data.ElementType, reader));
}
}
}
return instance;
}
private static IJsonWrapper ReadValue (WrapperFactory factory,
JsonReader reader)
{
reader.Read ();
if (reader.Token == JsonToken.ArrayEnd ||
reader.Token == JsonToken.Null)
return null;
IJsonWrapper instance = factory ();
if (reader.Token == JsonToken.String) {
instance.SetString ((string) reader.Value);
return instance;
}
if (reader.Token == JsonToken.Double) {
instance.SetDouble ((double) reader.Value);
return instance;
}
if (reader.Token == JsonToken.Int) {
instance.SetInt ((int) reader.Value);
return instance;
}
if (reader.Token == JsonToken.Long) {
instance.SetLong ((long) reader.Value);
return instance;
}
if (reader.Token == JsonToken.Boolean) {
instance.SetBoolean ((bool) reader.Value);
return instance;
}
if (reader.Token == JsonToken.ArrayStart) {
instance.SetJsonType (JsonType.Array);
while (true) {
IJsonWrapper item = ReadValue (factory, reader);
if (item == null && reader.Token == JsonToken.ArrayEnd)
break;
((IList) instance).Add (item);
}
}
else if (reader.Token == JsonToken.ObjectStart) {
instance.SetJsonType (JsonType.Object);
while (true) {
reader.Read ();
if (reader.Token == JsonToken.ObjectEnd)
break;
string property = (string) reader.Value;
((IDictionary) instance)[property] = ReadValue (
factory, reader);
}
}
return instance;
}
private static void ReadSkip (JsonReader reader)
{
ToWrapper (
delegate { return new JsonMockWrapper (); }, reader);
}
private static void RegisterBaseExporters ()
{
base_exporters_table[typeof (byte)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToInt32 ((byte) obj));
};
base_exporters_table[typeof (char)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToString ((char) obj));
};
base_exporters_table[typeof (DateTime)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToString ((DateTime) obj,
datetime_format));
};
base_exporters_table[typeof (decimal)] =
delegate (object obj, JsonWriter writer) {
writer.Write ((decimal) obj);
};
base_exporters_table[typeof (sbyte)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToInt32 ((sbyte) obj));
};
base_exporters_table[typeof (short)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToInt32 ((short) obj));
};
base_exporters_table[typeof (ushort)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToInt32 ((ushort) obj));
};
base_exporters_table[typeof (uint)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToUInt64 ((uint) obj));
};
base_exporters_table[typeof (ulong)] =
delegate (object obj, JsonWriter writer) {
writer.Write ((ulong) obj);
};
base_exporters_table[typeof(DateTimeOffset)] =
delegate (object obj, JsonWriter writer) {
writer.Write(((DateTimeOffset)obj).ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", datetime_format));
};
}
private static void RegisterBaseImporters ()
{
ImporterFunc importer;
importer = delegate (object input) {
return Convert.ToByte ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (byte), importer);
importer = delegate (object input) {
return Convert.ToUInt64 ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (ulong), importer);
importer = delegate (object input) {
return Convert.ToInt64((int)input);
};
RegisterImporter(base_importers_table, typeof(int),
typeof(long), importer);
importer = delegate (object input) {
return Convert.ToSByte ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (sbyte), importer);
importer = delegate (object input) {
return Convert.ToInt16 ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (short), importer);
importer = delegate (object input) {
return Convert.ToUInt16 ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (ushort), importer);
importer = delegate (object input) {
return Convert.ToUInt32 ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (uint), importer);
importer = delegate (object input) {
return Convert.ToSingle ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (float), importer);
importer = delegate (object input) {
return Convert.ToDouble ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (double), importer);
importer = delegate (object input) {
return Convert.ToDecimal ((double) input);
};
RegisterImporter (base_importers_table, typeof (double),
typeof (decimal), importer);
importer = delegate (object input) {
return Convert.ToSingle((double)input);
};
RegisterImporter(base_importers_table, typeof(double),
typeof(float), importer);
importer = delegate (object input) {
return Convert.ToUInt32 ((long) input);
};
RegisterImporter (base_importers_table, typeof (long),
typeof (uint), importer);
importer = delegate (object input) {
return Convert.ToChar ((string) input);
};
RegisterImporter (base_importers_table, typeof (string),
typeof (char), importer);
importer = delegate (object input) {
return Convert.ToDateTime ((string) input, datetime_format);
};
RegisterImporter (base_importers_table, typeof (string),
typeof (DateTime), importer);
importer = delegate (object input) {
return DateTimeOffset.Parse((string)input, datetime_format);
};
RegisterImporter(base_importers_table, typeof(string),
typeof(DateTimeOffset), importer);
}
private static void RegisterImporter (
IDictionary<Type, IDictionary<Type, ImporterFunc>> table,
Type json_type, Type value_type, ImporterFunc importer)
{
if (! table.ContainsKey (json_type))
table.Add (json_type, new Dictionary<Type, ImporterFunc> ());
table[json_type][value_type] = importer;
}
private static void WriteValue (object obj, JsonWriter writer,
bool writer_is_private,
int depth)
{
if (depth > max_nesting_depth)
throw new JsonException (
String.Format ("Max allowed object depth reached while " +
"trying to export from type {0}",
obj.GetType ()));
if (obj == null) {
writer.Write (null);
return;
}
if (obj is IJsonWrapper) {
if (writer_is_private)
writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ());
else
((IJsonWrapper) obj).ToJson (writer);
return;
}
if (obj is String) {
writer.Write ((string) obj);
return;
}
if (obj is Double) {
writer.Write ((double) obj);
return;
}
if (obj is Single)
{
writer.Write((float)obj);
return;
}
if (obj is Int32) {
writer.Write ((int) obj);
return;
}
if (obj is Boolean) {
writer.Write ((bool) obj);
return;
}
if (obj is Int64) {
writer.Write ((long) obj);
return;
}
if (obj is Array) {
writer.WriteArrayStart ();
foreach (object elem in (Array) obj)
WriteValue (elem, writer, writer_is_private, depth + 1);
writer.WriteArrayEnd ();
return;
}
if (obj is IList) {
writer.WriteArrayStart ();
foreach (object elem in (IList) obj)
WriteValue (elem, writer, writer_is_private, depth + 1);
writer.WriteArrayEnd ();
return;
}
if (obj is IDictionary dictionary) {
writer.WriteObjectStart ();
foreach (DictionaryEntry entry in dictionary) {
var propertyName = entry.Key is string key ?
key
: Convert.ToString(entry.Key, CultureInfo.InvariantCulture);
writer.WritePropertyName (propertyName);
WriteValue (entry.Value, writer, writer_is_private,
depth + 1);
}
writer.WriteObjectEnd ();
return;
}
Type obj_type = obj.GetType ();
// See if there's a custom exporter for the object
if (custom_exporters_table.ContainsKey (obj_type)) {
ExporterFunc exporter = custom_exporters_table[obj_type];
exporter (obj, writer);
return;
}
// If not, maybe there's a base exporter
if (base_exporters_table.ContainsKey (obj_type)) {
ExporterFunc exporter = base_exporters_table[obj_type];
exporter (obj, writer);
return;
}
// Last option, let's see if it's an enum
if (obj is Enum) {
Type e_type = Enum.GetUnderlyingType (obj_type);
if (e_type == typeof (long))
writer.Write ((long) obj);
else if (e_type == typeof (uint))
writer.Write ((uint) obj);
else if (e_type == typeof (ulong))
writer.Write ((ulong) obj);
else if (e_type == typeof(ushort))
writer.Write ((ushort)obj);
else if (e_type == typeof(short))
writer.Write ((short)obj);
else if (e_type == typeof(byte))
writer.Write ((byte)obj);
else if (e_type == typeof(sbyte))
writer.Write ((sbyte)obj);
else
writer.Write ((int) obj);
return;
}
// Okay, so it looks like the input should be exported as an
// object
AddTypeProperties (obj_type);
IList<PropertyMetadata> props = type_properties[obj_type];
writer.WriteObjectStart ();
foreach (PropertyMetadata p_data in props) {
if (p_data.IsField) {
writer.WritePropertyName (p_data.Info.Name);
WriteValue (((FieldInfo) p_data.Info).GetValue (obj),
writer, writer_is_private, depth + 1);
}
else {
PropertyInfo p_info = (PropertyInfo) p_data.Info;
if (p_info.CanRead) {
writer.WritePropertyName (p_data.Info.Name);
WriteValue (p_info.GetValue (obj, null),
writer, writer_is_private, depth + 1);
}
}
}
writer.WriteObjectEnd ();
}
#endregion
public static string ToJson (object obj)
{
lock (static_writer_lock) {
static_writer.Reset ();
WriteValue (obj, static_writer, true, 0);
return static_writer.ToString ();
}
}
public static void ToJson (object obj, JsonWriter writer)
{
WriteValue (obj, writer, false, 0);
}
public static JsonData ToObject (JsonReader reader)
{
return (JsonData) ToWrapper (
delegate { return new JsonData (); }, reader);
}
public static JsonData ToObject (TextReader reader)
{
JsonReader json_reader = new JsonReader (reader);
return (JsonData) ToWrapper (
delegate { return new JsonData (); }, json_reader);
}
public static JsonData ToObject (string json)
{
return (JsonData) ToWrapper (
delegate { return new JsonData (); }, json);
}
public static T ToObject<T> (JsonReader reader)
{
return (T) ReadValue (typeof (T), reader);
}
public static T ToObject<T> (TextReader reader)
{
JsonReader json_reader = new JsonReader (reader);
return (T) ReadValue (typeof (T), json_reader);
}
public static T ToObject<T> (string json)
{
JsonReader reader = new JsonReader (json);
return (T) ReadValue (typeof (T), reader);
}
public static object ToObject(string json, Type ConvertType )
{
JsonReader reader = new JsonReader(json);
return ReadValue(ConvertType, reader);
}
public static IJsonWrapper ToWrapper (WrapperFactory factory,
JsonReader reader)
{
return ReadValue (factory, reader);
}
public static IJsonWrapper ToWrapper (WrapperFactory factory,
string json)
{
JsonReader reader = new JsonReader (json);
return ReadValue (factory, reader);
}
public static void RegisterExporter<T> (ExporterFunc<T> exporter)
{
ExporterFunc exporter_wrapper =
delegate (object obj, JsonWriter writer) {
exporter ((T) obj, writer);
};
custom_exporters_table[typeof (T)] = exporter_wrapper;
}
public static void RegisterImporter<TJson, TValue> (
ImporterFunc<TJson, TValue> importer)
{
ImporterFunc importer_wrapper =
delegate (object input) {
return importer ((TJson) input);
};
RegisterImporter (custom_importers_table, typeof (TJson),
typeof (TValue), importer_wrapper);
}
public static void UnregisterExporters ()
{
custom_exporters_table.Clear ();
}
public static void UnregisterImporters ()
{
custom_importers_table.Clear ();
}
}
}

View File

@@ -0,0 +1,105 @@
#region Header
/**
* JsonMockWrapper.cs
* Mock object implementing IJsonWrapper, to facilitate actions like
* skipping data more efficiently.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections;
using System.Collections.Specialized;
namespace TEngineCore.ListJson
{
public class JsonMockWrapper : IJsonWrapper
{
public bool IsArray { get { return false; } }
public bool IsBoolean { get { return false; } }
public bool IsDouble { get { return false; } }
public bool IsInt { get { return false; } }
public bool IsLong { get { return false; } }
public bool IsObject { get { return false; } }
public bool IsString { get { return false; } }
public bool GetBoolean () { return false; }
public double GetDouble () { return 0.0; }
public int GetInt () { return 0; }
public JsonType GetJsonType () { return JsonType.None; }
public long GetLong () { return 0L; }
public string GetString () { return ""; }
public void SetBoolean (bool val) {}
public void SetDouble (double val) {}
public void SetInt (int val) {}
public void SetJsonType (JsonType type) {}
public void SetLong (long val) {}
public void SetString (string val) {}
public string ToJson () { return ""; }
public void ToJson (JsonWriter writer) {}
bool IList.IsFixedSize { get { return true; } }
bool IList.IsReadOnly { get { return true; } }
object IList.this[int index] {
get { return null; }
set {}
}
int IList.Add (object value) { return 0; }
void IList.Clear () {}
bool IList.Contains (object value) { return false; }
int IList.IndexOf (object value) { return -1; }
void IList.Insert (int i, object v) {}
void IList.Remove (object value) {}
void IList.RemoveAt (int index) {}
int ICollection.Count { get { return 0; } }
bool ICollection.IsSynchronized { get { return false; } }
object ICollection.SyncRoot { get { return null; } }
void ICollection.CopyTo (Array array, int index) {}
IEnumerator IEnumerable.GetEnumerator () { return null; }
bool IDictionary.IsFixedSize { get { return true; } }
bool IDictionary.IsReadOnly { get { return true; } }
ICollection IDictionary.Keys { get { return null; } }
ICollection IDictionary.Values { get { return null; } }
object IDictionary.this[object key] {
get { return null; }
set {}
}
void IDictionary.Add (object k, object v) {}
void IDictionary.Clear () {}
bool IDictionary.Contains (object key) { return false; }
void IDictionary.Remove (object key) {}
IDictionaryEnumerator IDictionary.GetEnumerator () { return null; }
object IOrderedDictionary.this[int idx] {
get { return null; }
set {}
}
IDictionaryEnumerator IOrderedDictionary.GetEnumerator () {
return null;
}
void IOrderedDictionary.Insert (int i, object k, object v) {}
void IOrderedDictionary.RemoveAt (int i) {}
}
}

View File

@@ -0,0 +1,478 @@
#region Header
/**
* JsonReader.cs
* Stream-like access to JSON text.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
namespace TEngineCore.ListJson
{
public enum JsonToken
{
None,
ObjectStart,
PropertyName,
ObjectEnd,
ArrayStart,
ArrayEnd,
Int,
Long,
Double,
String,
Boolean,
Null
}
public class JsonReader
{
#region Fields
private static readonly IDictionary<int, IDictionary<int, int[]>> parse_table;
private Stack<int> automaton_stack;
private int current_input;
private int current_symbol;
private bool end_of_json;
private bool end_of_input;
private Lexer lexer;
private bool parser_in_string;
private bool parser_return;
private bool read_started;
private TextReader reader;
private bool reader_is_owned;
private bool skip_non_members;
private object token_value;
private JsonToken token;
#endregion
#region Public Properties
public bool AllowComments {
get { return lexer.AllowComments; }
set { lexer.AllowComments = value; }
}
public bool AllowSingleQuotedStrings {
get { return lexer.AllowSingleQuotedStrings; }
set { lexer.AllowSingleQuotedStrings = value; }
}
public bool SkipNonMembers {
get { return skip_non_members; }
set { skip_non_members = value; }
}
public bool EndOfInput {
get { return end_of_input; }
}
public bool EndOfJson {
get { return end_of_json; }
}
public JsonToken Token {
get { return token; }
}
public object Value {
get { return token_value; }
}
#endregion
#region Constructors
static JsonReader ()
{
parse_table = PopulateParseTable ();
}
public JsonReader (string json_text) :
this (new StringReader (json_text), true)
{
}
public JsonReader (TextReader reader) :
this (reader, false)
{
}
private JsonReader (TextReader reader, bool owned)
{
if (reader == null)
throw new ArgumentNullException ("reader");
parser_in_string = false;
parser_return = false;
read_started = false;
automaton_stack = new Stack<int> ();
automaton_stack.Push ((int) ParserToken.End);
automaton_stack.Push ((int) ParserToken.Text);
lexer = new Lexer (reader);
end_of_input = false;
end_of_json = false;
skip_non_members = true;
this.reader = reader;
reader_is_owned = owned;
}
#endregion
#region Static Methods
private static IDictionary<int, IDictionary<int, int[]>> PopulateParseTable ()
{
// See section A.2. of the manual for details
IDictionary<int, IDictionary<int, int[]>> parse_table = new Dictionary<int, IDictionary<int, int[]>> ();
TableAddRow (parse_table, ParserToken.Array);
TableAddCol (parse_table, ParserToken.Array, '[',
'[',
(int) ParserToken.ArrayPrime);
TableAddRow (parse_table, ParserToken.ArrayPrime);
TableAddCol (parse_table, ParserToken.ArrayPrime, '"',
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, '[',
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, ']',
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, '{',
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.Number,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.True,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.False,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.Null,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddRow (parse_table, ParserToken.Object);
TableAddCol (parse_table, ParserToken.Object, '{',
'{',
(int) ParserToken.ObjectPrime);
TableAddRow (parse_table, ParserToken.ObjectPrime);
TableAddCol (parse_table, ParserToken.ObjectPrime, '"',
(int) ParserToken.Pair,
(int) ParserToken.PairRest,
'}');
TableAddCol (parse_table, ParserToken.ObjectPrime, '}',
'}');
TableAddRow (parse_table, ParserToken.Pair);
TableAddCol (parse_table, ParserToken.Pair, '"',
(int) ParserToken.String,
':',
(int) ParserToken.Value);
TableAddRow (parse_table, ParserToken.PairRest);
TableAddCol (parse_table, ParserToken.PairRest, ',',
',',
(int) ParserToken.Pair,
(int) ParserToken.PairRest);
TableAddCol (parse_table, ParserToken.PairRest, '}',
(int) ParserToken.Epsilon);
TableAddRow (parse_table, ParserToken.String);
TableAddCol (parse_table, ParserToken.String, '"',
'"',
(int) ParserToken.CharSeq,
'"');
TableAddRow (parse_table, ParserToken.Text);
TableAddCol (parse_table, ParserToken.Text, '[',
(int) ParserToken.Array);
TableAddCol (parse_table, ParserToken.Text, '{',
(int) ParserToken.Object);
TableAddRow (parse_table, ParserToken.Value);
TableAddCol (parse_table, ParserToken.Value, '"',
(int) ParserToken.String);
TableAddCol (parse_table, ParserToken.Value, '[',
(int) ParserToken.Array);
TableAddCol (parse_table, ParserToken.Value, '{',
(int) ParserToken.Object);
TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.Number,
(int) ParserToken.Number);
TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.True,
(int) ParserToken.True);
TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.False,
(int) ParserToken.False);
TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.Null,
(int) ParserToken.Null);
TableAddRow (parse_table, ParserToken.ValueRest);
TableAddCol (parse_table, ParserToken.ValueRest, ',',
',',
(int) ParserToken.Value,
(int) ParserToken.ValueRest);
TableAddCol (parse_table, ParserToken.ValueRest, ']',
(int) ParserToken.Epsilon);
return parse_table;
}
private static void TableAddCol (IDictionary<int, IDictionary<int, int[]>> parse_table, ParserToken row, int col,
params int[] symbols)
{
parse_table[(int) row].Add (col, symbols);
}
private static void TableAddRow (IDictionary<int, IDictionary<int, int[]>> parse_table, ParserToken rule)
{
parse_table.Add ((int) rule, new Dictionary<int, int[]> ());
}
#endregion
#region Private Methods
private void ProcessNumber (string number)
{
if (number.IndexOf ('.') != -1 ||
number.IndexOf ('e') != -1 ||
number.IndexOf ('E') != -1) {
double n_double;
if (double.TryParse (number, NumberStyles.Any, CultureInfo.InvariantCulture, out n_double)) {
token = JsonToken.Double;
token_value = n_double;
return;
}
}
int n_int32;
if (int.TryParse (number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int32)) {
token = JsonToken.Int;
token_value = n_int32;
return;
}
long n_int64;
if (long.TryParse (number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int64)) {
token = JsonToken.Long;
token_value = n_int64;
return;
}
ulong n_uint64;
if (ulong.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_uint64))
{
token = JsonToken.Long;
token_value = n_uint64;
return;
}
// Shouldn't happen, but just in case, return something
token = JsonToken.Int;
token_value = 0;
}
private void ProcessSymbol ()
{
if (current_symbol == '[') {
token = JsonToken.ArrayStart;
parser_return = true;
} else if (current_symbol == ']') {
token = JsonToken.ArrayEnd;
parser_return = true;
} else if (current_symbol == '{') {
token = JsonToken.ObjectStart;
parser_return = true;
} else if (current_symbol == '}') {
token = JsonToken.ObjectEnd;
parser_return = true;
} else if (current_symbol == '"') {
if (parser_in_string) {
parser_in_string = false;
parser_return = true;
} else {
if (token == JsonToken.None)
token = JsonToken.String;
parser_in_string = true;
}
} else if (current_symbol == (int) ParserToken.CharSeq) {
token_value = lexer.StringValue;
} else if (current_symbol == (int) ParserToken.False) {
token = JsonToken.Boolean;
token_value = false;
parser_return = true;
} else if (current_symbol == (int) ParserToken.Null) {
token = JsonToken.Null;
parser_return = true;
} else if (current_symbol == (int) ParserToken.Number) {
ProcessNumber (lexer.StringValue);
parser_return = true;
} else if (current_symbol == (int) ParserToken.Pair) {
token = JsonToken.PropertyName;
} else if (current_symbol == (int) ParserToken.True) {
token = JsonToken.Boolean;
token_value = true;
parser_return = true;
}
}
private bool ReadToken ()
{
if (end_of_input)
return false;
lexer.NextToken ();
if (lexer.EndOfInput) {
Close ();
return false;
}
current_input = lexer.Token;
return true;
}
#endregion
public void Close ()
{
if (end_of_input)
return;
end_of_input = true;
end_of_json = true;
if (reader_is_owned)
{
using(reader){}
}
reader = null;
}
public bool Read ()
{
if (end_of_input)
return false;
if (end_of_json) {
end_of_json = false;
automaton_stack.Clear ();
automaton_stack.Push ((int) ParserToken.End);
automaton_stack.Push ((int) ParserToken.Text);
}
parser_in_string = false;
parser_return = false;
token = JsonToken.None;
token_value = null;
if (! read_started) {
read_started = true;
if (! ReadToken ())
return false;
}
int[] entry_symbols;
while (true) {
if (parser_return) {
if (automaton_stack.Peek () == (int) ParserToken.End)
end_of_json = true;
return true;
}
current_symbol = automaton_stack.Pop ();
ProcessSymbol ();
if (current_symbol == current_input) {
if (! ReadToken ()) {
if (automaton_stack.Peek () != (int) ParserToken.End)
throw new JsonException (
"Input doesn't evaluate to proper JSON text");
if (parser_return)
return true;
return false;
}
continue;
}
try {
entry_symbols =
parse_table[current_symbol][current_input];
} catch (KeyNotFoundException e) {
throw new JsonException ((ParserToken) current_input, e);
}
if (entry_symbols[0] == (int) ParserToken.Epsilon)
continue;
for (int i = entry_symbols.Length - 1; i >= 0; i--)
automaton_stack.Push (entry_symbols[i]);
}
}
}
}

View File

@@ -0,0 +1,486 @@
#region Header
/**
* JsonWriter.cs
* Stream-like facility to output JSON text.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
namespace TEngineCore.ListJson
{
internal enum Condition
{
InArray,
InObject,
NotAProperty,
Property,
Value
}
internal class WriterContext
{
public int Count;
public bool InArray;
public bool InObject;
public bool ExpectingValue;
public int Padding;
}
public class JsonWriter
{
#region Fields
private static readonly NumberFormatInfo number_format;
private WriterContext context;
private Stack<WriterContext> ctx_stack;
private bool has_reached_end;
private char[] hex_seq;
private int indentation;
private int indent_value;
private StringBuilder inst_string_builder;
private bool pretty_print;
private bool validate;
private bool lower_case_properties;
private TextWriter writer;
#endregion
#region Properties
public int IndentValue {
get { return indent_value; }
set {
indentation = (indentation / indent_value) * value;
indent_value = value;
}
}
public bool PrettyPrint {
get { return pretty_print; }
set { pretty_print = value; }
}
public TextWriter TextWriter {
get { return writer; }
}
public bool Validate {
get { return validate; }
set { validate = value; }
}
public bool LowerCaseProperties {
get { return lower_case_properties; }
set { lower_case_properties = value; }
}
#endregion
#region Constructors
static JsonWriter ()
{
number_format = NumberFormatInfo.InvariantInfo;
}
public JsonWriter ()
{
inst_string_builder = new StringBuilder ();
writer = new StringWriter (inst_string_builder);
Init ();
}
public JsonWriter (StringBuilder sb) :
this (new StringWriter (sb))
{
}
public JsonWriter (TextWriter writer)
{
if (writer == null)
throw new ArgumentNullException ("writer");
this.writer = writer;
Init ();
}
#endregion
#region Private Methods
private void DoValidation (Condition cond)
{
if (! context.ExpectingValue)
context.Count++;
if (! validate)
return;
if (has_reached_end)
throw new JsonException (
"A complete JSON symbol has already been written");
switch (cond) {
case Condition.InArray:
if (! context.InArray)
throw new JsonException (
"Can't close an array here");
break;
case Condition.InObject:
if (! context.InObject || context.ExpectingValue)
throw new JsonException (
"Can't close an object here");
break;
case Condition.NotAProperty:
if (context.InObject && ! context.ExpectingValue)
throw new JsonException (
"Expected a property");
break;
case Condition.Property:
if (! context.InObject || context.ExpectingValue)
throw new JsonException (
"Can't add a property here");
break;
case Condition.Value:
if (! context.InArray &&
(! context.InObject || ! context.ExpectingValue))
throw new JsonException (
"Can't add a value here");
break;
}
}
private void Init ()
{
has_reached_end = false;
hex_seq = new char[4];
indentation = 0;
indent_value = 4;
pretty_print = false;
validate = true;
lower_case_properties = false;
ctx_stack = new Stack<WriterContext> ();
context = new WriterContext ();
ctx_stack.Push (context);
}
private static void IntToHex (int n, char[] hex)
{
int num;
for (int i = 0; i < 4; i++) {
num = n % 16;
if (num < 10)
hex[3 - i] = (char) ('0' + num);
else
hex[3 - i] = (char) ('A' + (num - 10));
n >>= 4;
}
}
private void Indent ()
{
if (pretty_print)
indentation += indent_value;
}
private void Put (string str)
{
if (pretty_print && ! context.ExpectingValue)
for (int i = 0; i < indentation; i++)
writer.Write (' ');
writer.Write (str);
}
private void PutNewline ()
{
PutNewline (true);
}
private void PutNewline (bool add_comma)
{
if (add_comma && ! context.ExpectingValue &&
context.Count > 1)
writer.Write (',');
if (pretty_print && ! context.ExpectingValue)
writer.Write (Environment.NewLine);
}
private void PutString (string str)
{
Put (String.Empty);
writer.Write ('"');
int n = str.Length;
for (int i = 0; i < n; i++) {
switch (str[i]) {
case '\n':
writer.Write ("\\n");
continue;
case '\r':
writer.Write ("\\r");
continue;
case '\t':
writer.Write ("\\t");
continue;
case '"':
case '\\':
writer.Write ('\\');
writer.Write (str[i]);
continue;
case '\f':
writer.Write ("\\f");
continue;
case '\b':
writer.Write ("\\b");
continue;
}
if ((int) str[i] >= 32 && (int) str[i] <= 126) {
writer.Write (str[i]);
continue;
}
// Default, turn into a \uXXXX sequence
IntToHex ((int) str[i], hex_seq);
writer.Write ("\\u");
writer.Write (hex_seq);
}
writer.Write ('"');
}
private void Unindent ()
{
if (pretty_print)
indentation -= indent_value;
}
#endregion
public override string ToString ()
{
if (inst_string_builder == null)
return String.Empty;
return inst_string_builder.ToString ();
}
public void Reset ()
{
has_reached_end = false;
ctx_stack.Clear ();
context = new WriterContext ();
ctx_stack.Push (context);
if (inst_string_builder != null)
inst_string_builder.Remove (0, inst_string_builder.Length);
}
public void Write (bool boolean)
{
DoValidation (Condition.Value);
PutNewline ();
Put (boolean ? "true" : "false");
context.ExpectingValue = false;
}
public void Write (decimal number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void Write (double number)
{
DoValidation (Condition.Value);
PutNewline ();
string str = Convert.ToString (number, number_format);
Put (str);
if (str.IndexOf ('.') == -1 &&
str.IndexOf ('E') == -1)
writer.Write (".0");
context.ExpectingValue = false;
}
public void Write(float number)
{
DoValidation(Condition.Value);
PutNewline();
string str = Convert.ToString(number, number_format);
Put(str);
context.ExpectingValue = false;
}
public void Write (int number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void Write (long number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void Write (string str)
{
DoValidation (Condition.Value);
PutNewline ();
if (str == null)
Put ("null");
else
PutString (str);
context.ExpectingValue = false;
}
[CLSCompliant(false)]
#pragma warning disable CS3021 // <20><><EFBFBD>ڳ<EFBFBD><DAB3><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB> CLSCompliant <20><><EFBFBD>ԣ<EFBFBD><D4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>Ա<EFBFBD><D4B1><EFBFBD><EFBFBD>Ҫ CLSCompliant <20><><EFBFBD><EFBFBD>
public void Write (ulong number)
#pragma warning restore CS3021 // <20><><EFBFBD>ڳ<EFBFBD><DAB3><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB> CLSCompliant <20><><EFBFBD>ԣ<EFBFBD><D4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>Ա<EFBFBD><D4B1><EFBFBD><EFBFBD>Ҫ CLSCompliant <20><><EFBFBD><EFBFBD>
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void WriteArrayEnd ()
{
DoValidation (Condition.InArray);
PutNewline (false);
ctx_stack.Pop ();
if (ctx_stack.Count == 1)
has_reached_end = true;
else {
context = ctx_stack.Peek ();
context.ExpectingValue = false;
}
Unindent ();
Put ("]");
}
public void WriteArrayStart ()
{
DoValidation (Condition.NotAProperty);
PutNewline ();
Put ("[");
context = new WriterContext ();
context.InArray = true;
ctx_stack.Push (context);
Indent ();
}
public void WriteObjectEnd ()
{
DoValidation (Condition.InObject);
PutNewline (false);
ctx_stack.Pop ();
if (ctx_stack.Count == 1)
has_reached_end = true;
else {
context = ctx_stack.Peek ();
context.ExpectingValue = false;
}
Unindent ();
Put ("}");
}
public void WriteObjectStart ()
{
DoValidation (Condition.NotAProperty);
PutNewline ();
Put ("{");
context = new WriterContext ();
context.InObject = true;
ctx_stack.Push (context);
Indent ();
}
public void WritePropertyName (string property_name)
{
DoValidation (Condition.Property);
PutNewline ();
string propertyName = (property_name == null || !lower_case_properties)
? property_name
: property_name.ToLowerInvariant();
PutString (propertyName);
if (pretty_print) {
if (propertyName.Length > context.Padding)
context.Padding = propertyName.Length;
for (int i = context.Padding - propertyName.Length;
i >= 0; i--)
writer.Write (' ');
writer.Write (": ");
} else
writer.Write (':');
context.ExpectingValue = true;
}
}
}

View File

@@ -0,0 +1,912 @@
#region Header
/**
* Lexer.cs
* JSON lexer implementation based on a finite state machine.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace TEngineCore.ListJson
{
internal class FsmContext
{
public bool Return;
public int NextState;
public Lexer L;
public int StateStack;
}
internal class Lexer
{
#region Fields
private delegate bool StateHandler (FsmContext ctx);
private static readonly int[] fsm_return_table;
private static readonly StateHandler[] fsm_handler_table;
private bool allow_comments;
private bool allow_single_quoted_strings;
private bool end_of_input;
private FsmContext fsm_context;
private int input_buffer;
private int input_char;
private TextReader reader;
private int state;
private StringBuilder string_buffer;
private string string_value;
private int token;
private int unichar;
#endregion
#region Properties
public bool AllowComments {
get { return allow_comments; }
set { allow_comments = value; }
}
public bool AllowSingleQuotedStrings {
get { return allow_single_quoted_strings; }
set { allow_single_quoted_strings = value; }
}
public bool EndOfInput {
get { return end_of_input; }
}
public int Token {
get { return token; }
}
public string StringValue {
get { return string_value; }
}
#endregion
#region Constructors
static Lexer ()
{
PopulateFsmTables (out fsm_handler_table, out fsm_return_table);
}
public Lexer (TextReader reader)
{
allow_comments = true;
allow_single_quoted_strings = true;
input_buffer = 0;
string_buffer = new StringBuilder (128);
state = 1;
end_of_input = false;
this.reader = reader;
fsm_context = new FsmContext ();
fsm_context.L = this;
}
#endregion
#region Static Methods
private static int HexValue (int digit)
{
switch (digit) {
case 'a':
case 'A':
return 10;
case 'b':
case 'B':
return 11;
case 'c':
case 'C':
return 12;
case 'd':
case 'D':
return 13;
case 'e':
case 'E':
return 14;
case 'f':
case 'F':
return 15;
default:
return digit - '0';
}
}
private static void PopulateFsmTables (out StateHandler[] fsm_handler_table, out int[] fsm_return_table)
{
// See section A.1. of the manual for details of the finite
// state machine.
fsm_handler_table = new StateHandler[28] {
State1,
State2,
State3,
State4,
State5,
State6,
State7,
State8,
State9,
State10,
State11,
State12,
State13,
State14,
State15,
State16,
State17,
State18,
State19,
State20,
State21,
State22,
State23,
State24,
State25,
State26,
State27,
State28
};
fsm_return_table = new int[28] {
(int) ParserToken.Char,
0,
(int) ParserToken.Number,
(int) ParserToken.Number,
0,
(int) ParserToken.Number,
0,
(int) ParserToken.Number,
0,
0,
(int) ParserToken.True,
0,
0,
0,
(int) ParserToken.False,
0,
0,
(int) ParserToken.Null,
(int) ParserToken.CharSeq,
(int) ParserToken.Char,
0,
0,
(int) ParserToken.CharSeq,
(int) ParserToken.Char,
0,
0,
0,
0
};
}
private static char ProcessEscChar (int esc_char)
{
switch (esc_char) {
case '"':
case '\'':
case '\\':
case '/':
return Convert.ToChar (esc_char);
case 'n':
return '\n';
case 't':
return '\t';
case 'r':
return '\r';
case 'b':
return '\b';
case 'f':
return '\f';
default:
// Unreachable
return '?';
}
}
private static bool State1 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
continue;
if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 3;
return true;
}
switch (ctx.L.input_char) {
case '"':
ctx.NextState = 19;
ctx.Return = true;
return true;
case ',':
case ':':
case '[':
case ']':
case '{':
case '}':
ctx.NextState = 1;
ctx.Return = true;
return true;
case '-':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 2;
return true;
case '0':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 4;
return true;
case 'f':
ctx.NextState = 12;
return true;
case 'n':
ctx.NextState = 16;
return true;
case 't':
ctx.NextState = 9;
return true;
case '\'':
if (! ctx.L.allow_single_quoted_strings)
return false;
ctx.L.input_char = '"';
ctx.NextState = 23;
ctx.Return = true;
return true;
case '/':
if (! ctx.L.allow_comments)
return false;
ctx.NextState = 25;
return true;
default:
return false;
}
}
return true;
}
private static bool State2 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char >= '1' && ctx.L.input_char<= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 3;
return true;
}
switch (ctx.L.input_char) {
case '0':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 4;
return true;
default:
return false;
}
}
private static bool State3 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
case '.':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 5;
return true;
case 'e':
case 'E':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 7;
return true;
default:
return false;
}
}
return true;
}
private static bool State4 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
case '.':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 5;
return true;
case 'e':
case 'E':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 7;
return true;
default:
return false;
}
}
private static bool State5 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 6;
return true;
}
return false;
}
private static bool State6 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
case 'e':
case 'E':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 7;
return true;
default:
return false;
}
}
return true;
}
private static bool State7 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 8;
return true;
}
switch (ctx.L.input_char) {
case '+':
case '-':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 8;
return true;
default:
return false;
}
}
private static bool State8 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char<= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
return true;
}
private static bool State9 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'r':
ctx.NextState = 10;
return true;
default:
return false;
}
}
private static bool State10 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'u':
ctx.NextState = 11;
return true;
default:
return false;
}
}
private static bool State11 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'e':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State12 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'a':
ctx.NextState = 13;
return true;
default:
return false;
}
}
private static bool State13 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'l':
ctx.NextState = 14;
return true;
default:
return false;
}
}
private static bool State14 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 's':
ctx.NextState = 15;
return true;
default:
return false;
}
}
private static bool State15 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'e':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State16 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'u':
ctx.NextState = 17;
return true;
default:
return false;
}
}
private static bool State17 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'l':
ctx.NextState = 18;
return true;
default:
return false;
}
}
private static bool State18 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'l':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State19 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
switch (ctx.L.input_char) {
case '"':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 20;
return true;
case '\\':
ctx.StateStack = 19;
ctx.NextState = 21;
return true;
default:
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
}
return true;
}
private static bool State20 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case '"':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State21 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'u':
ctx.NextState = 22;
return true;
case '"':
case '\'':
case '/':
case '\\':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
ctx.L.string_buffer.Append (
ProcessEscChar (ctx.L.input_char));
ctx.NextState = ctx.StateStack;
return true;
default:
return false;
}
}
private static bool State22 (FsmContext ctx)
{
int counter = 0;
int mult = 4096;
ctx.L.unichar = 0;
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9' ||
ctx.L.input_char >= 'A' && ctx.L.input_char <= 'F' ||
ctx.L.input_char >= 'a' && ctx.L.input_char <= 'f') {
ctx.L.unichar += HexValue (ctx.L.input_char) * mult;
counter++;
mult /= 16;
if (counter == 4) {
ctx.L.string_buffer.Append (
Convert.ToChar (ctx.L.unichar));
ctx.NextState = ctx.StateStack;
return true;
}
continue;
}
return false;
}
return true;
}
private static bool State23 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
switch (ctx.L.input_char) {
case '\'':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 24;
return true;
case '\\':
ctx.StateStack = 23;
ctx.NextState = 21;
return true;
default:
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
}
return true;
}
private static bool State24 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case '\'':
ctx.L.input_char = '"';
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State25 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case '*':
ctx.NextState = 27;
return true;
case '/':
ctx.NextState = 26;
return true;
default:
return false;
}
}
private static bool State26 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == '\n') {
ctx.NextState = 1;
return true;
}
}
return true;
}
private static bool State27 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == '*') {
ctx.NextState = 28;
return true;
}
}
return true;
}
private static bool State28 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == '*')
continue;
if (ctx.L.input_char == '/') {
ctx.NextState = 1;
return true;
}
ctx.NextState = 27;
return true;
}
return true;
}
#endregion
private bool GetChar ()
{
if ((input_char = NextChar ()) != -1)
return true;
end_of_input = true;
return false;
}
private int NextChar ()
{
if (input_buffer != 0) {
int tmp = input_buffer;
input_buffer = 0;
return tmp;
}
return reader.Read ();
}
public bool NextToken ()
{
StateHandler handler;
fsm_context.Return = false;
while (true) {
handler = fsm_handler_table[state - 1];
if (! handler (fsm_context))
throw new JsonException (input_char);
if (end_of_input)
return false;
if (fsm_context.Return) {
string_value = string_buffer.ToString ();
string_buffer.Remove (0, string_buffer.Length);
token = fsm_return_table[state - 1];
if (token == (int) ParserToken.Char)
token = input_char;
state = fsm_context.NextState;
return true;
}
state = fsm_context.NextState;
}
}
private void UngetChar ()
{
input_buffer = input_char;
}
}
}

View File

@@ -0,0 +1,24 @@
#if NETSTANDARD1_5
using System;
using System.Reflection;
namespace TEngineCore.ListJson
{
internal static class Netstandard15Polyfill
{
internal static Type GetInterface(this Type type, string name)
{
return type.GetTypeInfo().GetInterface(name);
}
internal static bool IsClass(this Type type)
{
return type.GetTypeInfo().IsClass;
}
internal static bool IsEnum(this Type type)
{
return type.GetTypeInfo().IsEnum;
}
}
}
#endif

View File

@@ -0,0 +1,44 @@
#region Header
/**
* ParserToken.cs
* Internal representation of the tokens used by the lexer and the parser.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
namespace TEngineCore.ListJson
{
internal enum ParserToken
{
// Lexer tokens (see section A.1.1. of the manual)
None = System.Char.MaxValue + 1,
Number,
True,
False,
Null,
CharSeq,
// Single char
Char,
// Parser Rules (see section A.2.1 of the manual)
Text,
Object,
ObjectPrime,
Pair,
PairRest,
Array,
ArrayPrime,
Value,
ValueRest,
String,
// End of input
End,
// The empty rule
Epsilon
}
}

View File

@@ -0,0 +1,441 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace MiniJSON
{
public static class Json
{
public static object Deserialize(string json)
{
if (json == null)
return (object)null;
return Json.Parser.Parse(json);
}
public static string Serialize(object obj)
{
return Json.Serializer.Serialize(obj);
}
private sealed class Parser : IDisposable
{
private const string WORD_BREAK = "{}[],:\"";
private StringReader json;
public static bool IsWordBreak(char c)
{
return char.IsWhiteSpace(c) || "{}[],:\"".IndexOf(c) != -1;
}
private Parser(string jsonString)
{
this.json = new StringReader(jsonString);
}
public static object Parse(string jsonString)
{
using (Json.Parser parser = new Json.Parser(jsonString))
return parser.ParseValue();
}
public void Dispose()
{
this.json.Dispose();
this.json = (StringReader)null;
}
private Dictionary<string, object> ParseObject()
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
this.json.Read();
while (true)
{
Json.Parser.TOKEN nextToken;
do
{
nextToken = this.NextToken;
if (nextToken != Json.Parser.TOKEN.NONE)
{
if (nextToken == Json.Parser.TOKEN.CURLY_CLOSE)
goto label_4;
}
else
goto label_3;
}
while (nextToken == Json.Parser.TOKEN.COMMA);
string index = this.ParseString();
if (index != null && this.NextToken == Json.Parser.TOKEN.COLON)
{
this.json.Read();
dictionary[index] = this.ParseValue();
}
else
goto label_6;
}
label_3:
return (Dictionary<string, object>)null;
label_4:
return dictionary;
label_6:
return (Dictionary<string, object>)null;
}
private List<object> ParseArray()
{
List<object> objectList = new List<object>();
this.json.Read();
bool flag = true;
while (flag)
{
Json.Parser.TOKEN nextToken = this.NextToken;
switch (nextToken)
{
case Json.Parser.TOKEN.NONE:
return (List<object>)null;
case Json.Parser.TOKEN.SQUARED_CLOSE:
flag = false;
break;
case Json.Parser.TOKEN.COMMA:
continue;
default:
object byToken = this.ParseByToken(nextToken);
objectList.Add(byToken);
break;
}
}
return objectList;
}
private object ParseValue()
{
return this.ParseByToken(this.NextToken);
}
private object ParseByToken(Json.Parser.TOKEN token)
{
switch (token)
{
case Json.Parser.TOKEN.CURLY_OPEN:
return (object)this.ParseObject();
case Json.Parser.TOKEN.SQUARED_OPEN:
return (object)this.ParseArray();
case Json.Parser.TOKEN.STRING:
return (object)this.ParseString();
case Json.Parser.TOKEN.NUMBER:
return this.ParseNumber();
case Json.Parser.TOKEN.TRUE:
return (object)true;
case Json.Parser.TOKEN.FALSE:
return (object)false;
case Json.Parser.TOKEN.NULL:
return (object)null;
default:
return (object)null;
}
}
private string ParseString()
{
StringBuilder stringBuilder = new StringBuilder();
this.json.Read();
bool flag = true;
while (flag)
{
if (this.json.Peek() == -1)
break;
char nextChar1 = this.NextChar;
switch (nextChar1)
{
case '"':
flag = false;
break;
case '\\':
if (this.json.Peek() == -1)
{
flag = false;
break;
}
char nextChar2 = this.NextChar;
switch (nextChar2)
{
case '"':
case '/':
case '\\':
stringBuilder.Append(nextChar2);
break;
case 'b':
stringBuilder.Append('\b');
break;
case 'f':
stringBuilder.Append('\f');
break;
case 'n':
stringBuilder.Append('\n');
break;
case 'r':
stringBuilder.Append('\r');
break;
case 't':
stringBuilder.Append('\t');
break;
case 'u':
char[] chArray = new char[4];
for (int index = 0; index < 4; ++index)
chArray[index] = this.NextChar;
stringBuilder.Append((char)Convert.ToInt32(new string(chArray), 16));
break;
}
break;
default:
stringBuilder.Append(nextChar1);
break;
}
}
return stringBuilder.ToString();
}
private object ParseNumber()
{
string nextWord = this.NextWord;
if (nextWord.IndexOf('.') == -1)
{
long result;
long.TryParse(nextWord, out result);
return (object)result;
}
double result1;
double.TryParse(nextWord, out result1);
return (object)result1;
}
private void EatWhitespace()
{
while (char.IsWhiteSpace(this.PeekChar))
{
this.json.Read();
if (this.json.Peek() == -1)
break;
}
}
private char PeekChar
{
get
{
return Convert.ToChar(this.json.Peek());
}
}
private char NextChar
{
get
{
return Convert.ToChar(this.json.Read());
}
}
private string NextWord
{
get
{
StringBuilder stringBuilder = new StringBuilder();
while (!Json.Parser.IsWordBreak(this.PeekChar))
{
stringBuilder.Append(this.NextChar);
if (this.json.Peek() == -1)
break;
}
return stringBuilder.ToString();
}
}
private Json.Parser.TOKEN NextToken
{
get
{
this.EatWhitespace();
if (this.json.Peek() == -1)
return Json.Parser.TOKEN.NONE;
switch (this.PeekChar)
{
case '"':
return Json.Parser.TOKEN.STRING;
case ',':
this.json.Read();
return Json.Parser.TOKEN.COMMA;
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return Json.Parser.TOKEN.NUMBER;
case ':':
return Json.Parser.TOKEN.COLON;
case '[':
return Json.Parser.TOKEN.SQUARED_OPEN;
case ']':
this.json.Read();
return Json.Parser.TOKEN.SQUARED_CLOSE;
case '{':
return Json.Parser.TOKEN.CURLY_OPEN;
case '}':
this.json.Read();
return Json.Parser.TOKEN.CURLY_CLOSE;
default:
string nextWord = this.NextWord;
if (nextWord == "false")
return Json.Parser.TOKEN.FALSE;
if (nextWord == "true")
return Json.Parser.TOKEN.TRUE;
return nextWord == "null" ? Json.Parser.TOKEN.NULL : Json.Parser.TOKEN.NONE;
}
}
}
private enum TOKEN
{
NONE,
CURLY_OPEN,
CURLY_CLOSE,
SQUARED_OPEN,
SQUARED_CLOSE,
COLON,
COMMA,
STRING,
NUMBER,
TRUE,
FALSE,
NULL,
}
}
private sealed class Serializer
{
private StringBuilder builder;
private Serializer()
{
this.builder = new StringBuilder();
}
public static string Serialize(object obj)
{
Json.Serializer serializer = new Json.Serializer();
serializer.SerializeValue(obj);
return serializer.builder.ToString();
}
private void SerializeValue(object value)
{
if (value == null)
this.builder.Append("null");
else if (value is string str)
this.SerializeString(str);
else if (value is bool)
this.builder.Append((bool)value ? "true" : "false");
else if (value is IList anArray)
this.SerializeArray(anArray);
else if (value is IDictionary dictionary)
this.SerializeObject(dictionary);
else if (value is char)
this.SerializeString(new string((char)value, 1));
else
this.SerializeOther(value);
}
private void SerializeObject(IDictionary obj)
{
bool flag = true;
this.builder.Append('{');
foreach (object key in (IEnumerable)obj.Keys)
{
if (!flag)
this.builder.Append(',');
this.SerializeString(key.ToString());
this.builder.Append(':');
this.SerializeValue(obj[key]);
flag = false;
}
this.builder.Append('}');
}
private void SerializeArray(IList anArray)
{
this.builder.Append('[');
bool flag = true;
foreach (object an in (IEnumerable)anArray)
{
if (!flag)
this.builder.Append(',');
this.SerializeValue(an);
flag = false;
}
this.builder.Append(']');
}
private void SerializeString(string str)
{
this.builder.Append('"');
foreach (char ch in str.ToCharArray())
{
switch (ch)
{
case '\b':
this.builder.Append("\\b");
break;
case '\t':
this.builder.Append("\\t");
break;
case '\n':
this.builder.Append("\\n");
break;
case '\f':
this.builder.Append("\\f");
break;
case '\r':
this.builder.Append("\\r");
break;
case '"':
this.builder.Append("\\\"");
break;
case '\\':
this.builder.Append("\\\\");
break;
default:
int int32 = Convert.ToInt32(ch);
if (int32 >= 32 && int32 <= 126)
{
this.builder.Append(ch);
break;
}
this.builder.Append("\\u");
this.builder.Append(int32.ToString("x4"));
break;
}
}
this.builder.Append('"');
}
private void SerializeOther(object value)
{
if (value is float)
this.builder.Append(((float)value).ToString("R"));
else if (value is int || value is uint || (value is long || value is sbyte) || (value is byte || value is short || value is ushort) || value is ulong)
this.builder.Append(value);
else if (value is double || value is Decimal)
this.builder.Append(Convert.ToDouble(value).ToString("R"));
else
this.SerializeString(value.ToString());
}
}
}
}

View File

@@ -0,0 +1,64 @@
using UnityEngine;
using UnityEngine.Events;
namespace TEngineCore
{
/// <summary>
/// Mono管理者
/// </summary>
public class MonoController : MonoBehaviour
{
private event UnityAction updateEvent;
private event UnityAction fixedUpdateEvent;
void Update()
{
if (updateEvent != null)
{
updateEvent();
}
}
void FixedUpdate()
{
if (fixedUpdateEvent != null)
{
fixedUpdateEvent();
}
}
public void AddFixedUpdateListener(UnityAction fun)
{
fixedUpdateEvent += fun;
}
public void RemoveFixedUpdateListener(UnityAction fun)
{
fixedUpdateEvent -= fun;
}
/// <summary>
/// 为给外部提供的 添加帧更新事件
/// </summary>
/// <param name="fun"></param>
public void AddUpdateListener(UnityAction fun)
{
updateEvent += fun;
}
/// <summary>
/// 移除帧更新事件
/// </summary>
/// <param name="fun"></param>
public void RemoveUpdateListener(UnityAction fun)
{
updateEvent -= fun;
}
public void Release()
{
updateEvent = null;
fixedUpdateEvent = null;
}
}
}

View File

@@ -0,0 +1,144 @@
using System.Collections;
using System.ComponentModel;
using TEngineCore;
using UnityEngine;
using UnityEngine.Events;
namespace TEngineCore
{
public class MonoManager : TSingleton<MonoManager>
{
private MonoController controller;
public override void Release()
{
StopAllCoroutine();
controller.Release();
controller = null;
base.Release();
}
public MonoManager()
{
GameObject obj = new GameObject("MonoManager");
controller = obj.AddComponent<MonoController>();
#if UNITY_EDITOR
GameObject tEngine = SingletonMgr.Root;
if (tEngine != null)
{
obj.transform.SetParent(tEngine.transform);
}
#endif
}
~MonoManager()
{
StopAllCoroutine();
controller.Release();
controller = null;
}
#region UnityUpdate/FixedUpdate
/// <summary>
/// 为给外部提供的 添加帧更新事件
/// </summary>
/// <param name="fun"></param>
public void AddUpdateListener(UnityAction fun)
{
controller.AddUpdateListener(fun);
}
/// <summary>
/// 为给外部提供的 添加物理帧更新事件
/// </summary>
/// <param name="fun"></param>
public void AddFixedUpdateListener(UnityAction fun)
{
controller.AddFixedUpdateListener(fun);
}
/// <summary>
/// 移除帧更新事件
/// </summary>
/// <param name="fun"></param>
public void RemoveUpdateListener(UnityAction fun)
{
controller.RemoveUpdateListener(fun);
}
#endregion
#region Coroutine
public Coroutine StartCoroutine(string methodName)
{
if (controller == null)
{
return null;
}
return controller.StartCoroutine(methodName);
}
public Coroutine StartCoroutine(IEnumerator routine)
{
if (controller == null)
{
return null;
}
return controller.StartCoroutine(routine);
}
public Coroutine StartCoroutine(string methodName, [DefaultValue("null")] object value)
{
if (controller == null)
{
return null;
}
return controller.StartCoroutine(methodName, value);
}
public void StopCoroutine(string methodName)
{
if (controller == null)
{
return;
}
controller.StopCoroutine(methodName);
}
public void StopCoroutine(IEnumerator routine)
{
if (controller == null)
{
return;
}
controller.StopCoroutine(routine);
}
public void StopCoroutine(Coroutine routine)
{
if (controller == null)
{
return;
}
controller.StopCoroutine(routine);
}
public void StopAllCoroutine()
{
if (controller != null)
{
controller.StopAllCoroutines();
}
}
#endregion
#region GC
public void GC()
{
System.GC.Collect();
}
#endregion
}
}

View File

@@ -0,0 +1,408 @@
using UnityEngine;
using System.Collections.Generic;
namespace TEngineCore
{
public class AssetBundleData
{
public AssetBundle Bundle;
public AssetBundleData[] Dependencies;
private AssetData[] _assets = null;
private Dictionary<string, int> _path2Index = null;
internal static ulong Offset;
string _name;
float _unloadTimer;
int _refCount;
int _depCount;
bool _isInvokeLoad;
bool _bLoaded;
public int RefCount => _refCount;
public int DepCount => _depCount;
class AsyncLoadRequest
{
public AssetBundleCreateRequest Request;
public int DependedRefCount;
}
AsyncLoadRequest _asyncLoadRequest;
private event System.Action<AssetBundleData> _onAsyncLoadComplete;
public string Name
{
get
{
return _name;
}
}
/// <summary>
/// 是否能被卸载
/// </summary>
public bool Unloadable
{
get
{
return Bundle != null && _refCount <= 0 && _depCount <= 0;
}
}
/// <summary>
/// 是否正在加载
/// </summary>
public bool IsAsyncLoading => _asyncLoadRequest != null;
public bool IsLoadComplete => _bLoaded;
public event System.Action<AssetBundleData> OnAsyncLoadComplete
{
add
{
_onAsyncLoadComplete += value;
}
remove
{
_onAsyncLoadComplete -= value;
}
}
public AssetBundleData(string name)
{
Bundle = null;
_name = name;
_unloadTimer = 0f;
_refCount = 0;
_depCount = 0;
_asyncLoadRequest = null;
_isInvokeLoad = false;
_bLoaded = false;
}
public void InitAssets(string[] assets)
{
if (assets.Length > 0)
{
_assets = new AssetData[assets.Length];
_path2Index = new Dictionary<string, int>();
for (int i = 0; i < assets.Length; ++i)
{
_path2Index.Add(assets[i], i);
_assets[i] = null;
}
}
}
public AssetData GetAsset(string assetPath)
{
if (_assets != null)
{
if (_path2Index.ContainsKey(assetPath))
return _assets[_path2Index[assetPath]];
else
{
TLogger.LogError($"Try to get asset data '{assetPath}' which not in the bundle '{_name}'");
}
}
else
{
TLogger.LogError($"Try to get asset data in the bundle '{_name}' which not include any asset");
}
return null;
}
public void SetAsset(string assetPath, AssetData assetData)
{
if (_assets != null)
{
if (_path2Index.ContainsKey(assetPath))
_assets[_path2Index[assetPath]] = assetData;
else
TLogger.LogError($"Try to set asset data '{assetPath}' which not in the bundle '{_name}'");
}
else
TLogger.LogError($"Try to set asset data in the bundle '{_name}' which not include any asset");
}
/// <summary>
/// 同步加载AssetBundle接口
/// </summary>
/// <param name="bDepended">该AssetBundle是否被其他AssetBundle依赖</param>
public void Load(bool bDepended = false)
{
if (Bundle == null)
{
// 置标志,用于循环依赖检测
_isInvokeLoad = true;
for (int i = 0; i < Dependencies.Length; ++i)
{
if (!Dependencies[i]._isInvokeLoad)
{
Dependencies[i].Load(true);
}
else
{
TLogger.LogWarning($"Dependency cycle detected for '{Dependencies[i]._name}'");
}
}
Bundle = AssetBundle.LoadFromFile(FileSystem.GetAssetBundlePathInVersion(_name), 0, Offset);
_isInvokeLoad = false;
}
if (Bundle != null)
{
if (bDepended)
{
AddDepRef();
}
}
else
{
TLogger.LogError($"Can not load AssetBundle '{_name}'!");
}
}
/// <summary>
/// 异步加载AssetBundle接口
/// </summary>
/// <param name="onComplete">加载回调</param>
/// <param name="bDepended">该AssetBundle是否被其他AssetBundle依赖</param>
public void LoadAsync(System.Action<AssetBundleData> onComplete, bool bDepended = false)
{
_onAsyncLoadComplete -= onComplete;
_onAsyncLoadComplete += onComplete;
if (Bundle == null)
{
if (_asyncLoadRequest == null)
{
_isInvokeLoad = true;
for (int i = 0; i < Dependencies.Length; ++i)
{
if (!Dependencies[i]._isInvokeLoad)
Dependencies[i].LoadAsync(OnDependenciesAsyncLoadComplete, true);
else
TLogger.LogWarning($"Dependency cycle detected for '{Dependencies[i]._name}'");
}
_asyncLoadRequest = new AsyncLoadRequest
{
Request = AssetBundle.LoadFromFileAsync(FileSystem.GetAssetBundlePathInVersion(_name), 0, Offset)
,
DependedRefCount = bDepended ? 1 : 0
};
_asyncLoadRequest.Request.completed += OnAssetBundleLoadComplete;
_isInvokeLoad = false;
}
else
{
if (bDepended)
{
++_asyncLoadRequest.DependedRefCount;
}
}
}
else
{
if (bDepended)
{
AddDepRef();
}
OnDependenciesAsyncLoadComplete(this);
}
}
/// <summary>
/// 卸载AssetBundle及其中包含的Asset
/// </summary>
/// <param name="bForce">强制卸载</param>
public void Unload(bool bForce = false)
{
// 当仅作为依赖时_assets为空
if (_assets != null)
{
for (int i = 0; i < _assets.Length; ++i)
{
if (_assets[i] != null)
{
_assets[i].Unload();
_assets[i] = null;
}
}
}
if (Bundle != null)
{
Bundle.Unload(true);
Bundle = null;
TLogger.LogInfo($"Unload Bundle {_name}");
}
_onAsyncLoadComplete = null;
_asyncLoadRequest = null;
_isInvokeLoad = false;
_bLoaded = false;
if (!bForce)
{
for (int i = 0; i < Dependencies.Length; ++i)
{
Dependencies[i].DecDepRef();
}
}
}
//不卸载bundle相关的资源防止出错
public void UnloadBundleFalse()
{
if (_assets != null)
{
for (int i = 0; i < _assets.Length; ++i)
{
if (_assets[i] != null)
{
_assets[i].Unload();
_assets[i] = null;
}
}
}
if (Bundle != null)
{
Bundle.Unload(false);
Bundle = null;
TLogger.LogInfo($"Unload Bundle {_name}");
}
_onAsyncLoadComplete = null;
_asyncLoadRequest = null;
_isInvokeLoad = false;
_bLoaded = false;
}
/// <summary>
/// 增加依赖计数
/// </summary>
/// <param name="count">引用计数增量</param>
/// <remark>异步加载未完成时,存在另外的加载请求,此时加载请求里记录依赖次数</remark>
public void AddDepRef(int count = 1)
{
_depCount += count;
}
/// <summary>
/// 减依赖计数
/// </summary>
public void DecDepRef()
{
--_depCount;
if (_depCount == 0)
{
_unloadTimer = 0f;
}
else if (_depCount < 0)
{
_depCount = 0;
TLogger.LogWarning($"{_name} _depCount < 0");
}
}
/// <summary>
/// 增加引用计数
/// </summary>
public void AddRef()
{
++_refCount;
//TLogger.LogInfo($"Add AssetBundle {_name} refCount = {_refCount}");
}
/// <summary>
/// 减引用计数
/// </summary>
public void DecRef(bool bNoDelay)
{
--_refCount;
//TLogger.LogInfo($"Dec AssetBundle {_name} refCount = {_refCount}");
if (_refCount == 0)
{
_unloadTimer = bNoDelay ? System.Single.MaxValue : 0f;
}
else if (_refCount < 0)
{
_refCount = 0;
TLogger.LogWarning($"{_name} _refCount < 0");
}
}
/// <summary>
/// 卸载时间更新
/// </summary>
/// <param name="delta">游戏时间帧间隔</param>
/// <returns>从引用计数为0开始到现在的时长</returns>
public float Update(float delta)
{
if (Unloadable)
{
_unloadTimer += delta;
}
return _unloadTimer;
}
void OnAssetBundleLoadComplete(AsyncOperation asyncOperation)
{
if (asyncOperation.isDone)
{
if (_asyncLoadRequest != null && _asyncLoadRequest.Request == asyncOperation)
{
AssetBundleCreateRequest assetBundleCreateRequest = asyncOperation as AssetBundleCreateRequest;
if (assetBundleCreateRequest != null)
{
Bundle = assetBundleCreateRequest.assetBundle;
if (Bundle != null)
{
AddDepRef(_asyncLoadRequest.DependedRefCount);
OnDependenciesAsyncLoadComplete(this);
}
else
{
TLogger.LogError($"Can not load AssetBundle '{_name}' asynchronously!");
}
}
_asyncLoadRequest = null;
}
else
{
TLogger.LogError("Return a mismatch asyncOperation for AssetBundleCreateRequest");
}
}
else
{
TLogger.LogError("Return a not done AsyncOperation for AssetBundleCreateRequest");
}
}
void OnDependenciesAsyncLoadComplete(AssetBundleData depBundle)
{
bool bDepAllLoaded = true;
for (int i = 0; i < Dependencies.Length; ++i)
{
if (Dependencies[i].Bundle == null)
{
bDepAllLoaded = false;
break;
}
}
if (Bundle != null && bDepAllLoaded && _onAsyncLoadComplete != null)
{
_onAsyncLoadComplete(this);
_bLoaded = true;
}
}
}
}

View File

@@ -0,0 +1,356 @@
using System.IO;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
namespace TEngineCore
{
/// <summary>
/// 资源配置器 负责资源路径 AssetBundle映射管理AssetBundle、Asset数据
/// </summary>
public class AssetConfig
{
public const string AssetRootPath = "Assets/TResources";
public const string AssetBundleMeta = "AssetBundleMeta.bin";
private float _assetUnloadDelay = 10f;
private int _maxUnloadNumPerFrame = 5;
public float AssetUnloadDelay
{
set => _assetUnloadDelay = value;
get { return _assetUnloadDelay; }
}
public int MaxUnloadNumPerFrame
{
set => _maxUnloadNumPerFrame = value;
get { return _maxUnloadNumPerFrame; }
}
readonly Dictionary<string, AssetBundleData> _bundleDatas = new Dictionary<string, AssetBundleData>();
readonly Dictionary<string, string> _assetPath2BundleDatas = new Dictionary<string, string>();
/// <summary>
/// 加载资源依赖数据产生AssetBundle依赖拓扑
/// </summary>
public void Load()
{
#if ASSETBUNDLE_ENABLE
Stream stream = FileSystem.OpenRead(FileSystem.GetAssetBundlePathInVersion(AssetBundleMeta));
BinaryReader reader = new BinaryReader(stream);
uint resVersion = reader.ReadUInt32();
int count = reader.ReadInt32();
ulong offset = reader.ReadUInt32();
AssetBundleData.Offset = offset;
string bundleName;
AssetBundleData assetBundleData;
AssetBundleData depAssetBundleData;
int assetCount;
int depCount;
string[] assetPaths;
for (int i = 0; i < count; ++i)
{
bundleName = reader.ReadString();
assetCount = reader.ReadInt32();
assetPaths = new string[assetCount];
for (int ii = 0; ii < assetCount; ++ii)
{
assetPaths[ii] = reader.ReadString();
_assetPath2BundleDatas.Add(assetPaths[ii], bundleName);
}
depCount = reader.ReadInt32();
if (!_bundleDatas.TryGetValue(bundleName, out assetBundleData))
{
assetBundleData = new AssetBundleData(bundleName);
_bundleDatas.Add(assetBundleData.Name, assetBundleData);
assetBundleData.Dependencies = new AssetBundleData[depCount];
}
else
{
if (assetBundleData.Dependencies == null)
assetBundleData.Dependencies = new AssetBundleData[depCount];
}
assetBundleData.InitAssets(assetPaths);
for (int ii = 0; ii < depCount; ++ii)
{
bundleName = reader.ReadString();
if (!_bundleDatas.TryGetValue(bundleName, out depAssetBundleData))
{
depAssetBundleData = new AssetBundleData(bundleName);
_bundleDatas.Add(bundleName, depAssetBundleData);
}
assetBundleData.Dependencies[ii] = depAssetBundleData;
}
}
stream.Close();
#endif
}
/// <summary>
/// 卸载AssetBundle数据
/// </summary>
public void Unload()
{
#if ASSETBUNDLE_ENABLE
foreach(var bundleData in _bundleDatas)
bundleData.Value.Unload(true);
_bundleDatas.Clear();
_assetPath2BundleDatas.Clear();
#endif
}
public void UnloadFalse()
{
#if ASSETBUNDLE_ENABLE
foreach(var bundleData in _bundleDatas)
bundleData.Value.UnloadBundleFalse();
_bundleDatas.Clear();
_assetPath2BundleDatas.Clear();
#endif
}
public void TryReload()
{
if (_bundleDatas.Count > 0)
{
UnloadFalse();
Load();
}
}
/// <summary>
/// 延迟卸载更新
/// </summary>
/// <param name="delta">游戏帧间隔</param>
public void Update(float delta)
{
#if ASSETBUNDLE_ENABLE
var iter = _bundleDatas.GetEnumerator();
AssetBundleData bundleData;
int count = 0;
while (iter.MoveNext())
{
bundleData = iter.Current.Value;
if (bundleData.Unloadable)
{
if (bundleData.Update(delta) >= AssetUnloadDelay && count < MaxUnloadNumPerFrame)
{
bundleData.Unload();
++count;
}
}
}
iter.Dispose();
#endif
}
/// <summary>
/// 立即卸载没有引用的AssetBundle
/// </summary>
public void UnloadUnusedAssetBundle()
{
var iter = _bundleDatas.GetEnumerator();
AssetBundleData bundleData;
while (iter.MoveNext())
{
bundleData = iter.Current.Value;
if (bundleData.Unloadable)
bundleData.Unload();
}
iter.Dispose();
}
/// <summary>
/// 同步获取Asset
/// </summary>
/// <param name="path">是否加载子Asset针对Sprite图集</param>
/// <param name="withSubAssets">是否加载子Asset针对Sprite图集</param>
/// <returns>Asset数据</returns>
public AssetData GetAssetAtPath(string path, bool withSubAssets = false)
{
AssetData assetData = null;
#if ASSETBUNDLE_ENABLE
AssetBundleData bundleData = FindAssetBundle(path);
if (bundleData != null)
{
assetData = bundleData.GetAsset(path);
if(assetData == null)
{
assetData = new AssetData(path, bundleData);
assetData.LoadAsset(withSubAssets);
bundleData.SetAsset(path, assetData);
}
}
#elif UNITY_EDITOR
if (withSubAssets)
{
UnityEngine.Object[] subAssets = UnityEditor.AssetDatabase.LoadAllAssetsAtPath($"{AssetRootPath}/{path}");
if (subAssets != null && subAssets.Length > 0)
{
assetData = new AssetData(path);
assetData.ProcessSubAssets(subAssets);
}
else
{
TLogger.LogError($"Can not load the asset '{path}'");
}
}
else
{
UnityEngine.Object obj = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>($"{AssetRootPath}/{path}");
if (obj != null)
{
assetData = new AssetData(path, null, obj);
}
else
{
TLogger.LogError($"Can not load the asset '{path}'");
}
}
#endif
return assetData;
}
public AssetData GetPackageAssetAtPath(string path, bool withSubAssets = false)
{
AssetData assetData = null;
#if ASSETBUNDLE_ENABLE
AssetBundleData bundleData = FindAssetBundle(path);
if (bundleData != null)
{
assetData = bundleData.GetAsset(path);
if(assetData == null)
{
assetData = new AssetData(path, bundleData);
assetData.SetAsPackageAsset(path);
assetData.LoadAsset(withSubAssets);
bundleData.SetAsset(path, assetData);
}
}
#elif UNITY_EDITOR
if (withSubAssets)
{
UnityEngine.Object[] subAssets = UnityEditor.AssetDatabase.LoadAllAssetsAtPath(path);
if (subAssets != null && subAssets.Length > 0)
{
assetData = new AssetData(path);
assetData.SetAsPackageAsset(path);
assetData.ProcessSubAssets(subAssets);
}
else
{
TLogger.LogError($"Can not load the asset '{path}'");
}
}
else
{
UnityEngine.Object obj = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);
if (obj != null)
{
assetData = new AssetData(path, null, obj);
assetData.SetAsPackageAsset(path);
}
else
{
TLogger.LogError($"Can not load the asset '{path}'");
}
}
#endif
return assetData;
}
/// <summary>
/// 资源是否存在
/// </summary>
/// <param name="path">通过右键菜单Get Asset Path获取的路径</param>
/// <returns>true存在false不存在</returns>
public bool Exists(string path)
{
#if ASSETBUNDLE_ENABLE
return _assetPath2BundleDatas.ContainsKey(path);
#elif UNITY_EDITOR
return File.Exists($"{AssetRootPath}/{path}");
#else
return false;
#endif
}
/// <summary>
/// 异步获取Asset
/// </summary>
/// <param name="path">通过右键菜单Get Asset Path获取的路径</param>
/// <param name="withSubAssets">是否加载子Asset针对Sprite图集</param>
/// <param name="onComplete">加载回调</param>
/// <returns>Asset数据</returns>
public void GetAssetAtPathAsync(string path, bool withSubAssets, System.Action<AssetData> onComplete)
{
#if ASSETBUNDLE_ENABLE
AssetData assetData = null;
AssetBundleData bundleData = FindAssetBundle(path);
if (bundleData != null)
{
assetData = bundleData.GetAsset(path);
if (assetData != null)
{
assetData.LoadAsync(onComplete, withSubAssets);
}
else
{
assetData = new AssetData(path, bundleData);
bundleData.SetAsset(path, assetData);
assetData.LoadAsync(onComplete, withSubAssets);
}
}
else
onComplete(null);
#endif
}
/// <summary>
/// 获取场景Asset
/// </summary>
/// <param name="sceneName">场景名</param>
/// <returns>Asset数据</returns>
public AssetData GetSceneAsset(string sceneName, LoadSceneMode mode)
{
AssetData assetData = null;
#if ASSETBUNDLE_ENABLE
AssetBundleData bundleData = FindAssetBundle(sceneName);
if (bundleData != null)
{
assetData = new AssetData(sceneName, bundleData);
assetData.LoadScene(mode);
}
else
{
TLogger.LogError($"Can not load scene asset '{sceneName}'");
}
#else
assetData = new AssetData(sceneName);
assetData.LoadScene(mode);
#endif
return assetData;
}
AssetBundleData FindAssetBundle(string path)
{
string bundleName;
AssetBundleData assetBundleData = null;
if (_assetPath2BundleDatas.TryGetValue(path, out bundleName))
{
if (!_bundleDatas.TryGetValue(bundleName, out assetBundleData))
TLogger.LogError($"Can not get AssetBundleData with AssetBundle '{bundleName}'!");
}
else
TLogger.LogError($"Can not find '{path}' in any AssetBundle!");
return assetBundleData;
}
}
}

View File

@@ -0,0 +1,358 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.U2D;
namespace TEngineCore
{
/// <summary>
/// 封装的AssetBundle
/// </summary>
public class AssetData
{
private AssetBundleData _refBundle;
private Object _assetObject;
private Dictionary<string, UnityEngine.Object> _subAssetObjects;
private string _kPath;
private string _fPath;
private string _name;
private int _refCount;
private bool _useSubAsset;
private AsyncOperation _asyncLoadRequest;
private event System.Action<AssetData> _onAsyncLoadComplete;
public UnityEngine.Object AssetObject => _assetObject;
public UnityEngine.Object this[string key]
{
get
{
UnityEngine.Object assetObject = null;
if (_subAssetObjects != null)
{
if (!_subAssetObjects.TryGetValue(key, out assetObject))
{
if (_assetObject != null && _assetObject is SpriteAtlas atlas)
{
assetObject = atlas.GetSprite(key);
if (assetObject != null)
{
_subAssetObjects.Add(key, assetObject);
}
else
{
TLogger.LogError($"Can not get sub asset({key}) from {_fPath}");
}
}
}
}
return assetObject;
}
}
public string Path => _kPath;
public string FullPath => _fPath;
/// <summary>
/// Asset名
/// </summary>
public string Name => _name;
/// <summary>
/// 异步操作对象
/// </summary>
public AsyncOperation AsyncOp
{
get
{
return _asyncLoadRequest;
}
}
public event System.Action<AssetData> OnAsyncLoadComplete
{
add
{
_onAsyncLoadComplete += value;
}
remove
{
_onAsyncLoadComplete -= value;
}
}
public AssetData(string path = "", AssetBundleData refBundle = null, UnityEngine.Object assetObject = null)
{
_kPath = path;
if (!string.IsNullOrEmpty(_kPath))
{
int ei = _kPath.LastIndexOf('/');
_name = ei >= 0 ? _kPath.Substring(ei + 1) : _kPath;
_fPath = $"{AssetConfig.AssetRootPath}/{_kPath}";
}
else
{
_fPath = System.String.Empty;
}
_assetObject = assetObject;
_refBundle = refBundle;
if (refBundle != null)
{
_refBundle.AddRef();
}
}
internal void SetAsPackageAsset(string path)
{
_fPath = path;
}
/// <summary>
/// 增引用计数
/// </summary>
public void AddRef()
{
++_refCount;
#if UNITY_EDITOR
//TLogger.LogInfo($"Add AssetData {_fPath} _refCount = {_refCount}");
#endif
}
/// <summary>
/// 减引用计数当引用计数为0时减其AssetBundle的引用计数
/// </summary>
public void DecRef(bool bNoDelay = false)
{
--_refCount;
#if UNITY_EDITOR
//TLogger.LogInfo($"Dec AssetData {_fPath} _refCount = {_refCount}");
#endif
if (_refCount <= 0)
{
if (_refBundle != null)
{
_refBundle.DecRef(bNoDelay);
_refBundle.SetAsset(_kPath, null);
Unload();
}
}
}
/// <summary>
/// 同步加载Asset
/// </summary>
/// <param name="withSubAssets">是否加载子Asset针对Sprite图集</param>
public void LoadAsset(bool withSubAssets = false)
{
_useSubAsset = withSubAssets;
if (_refBundle.Bundle == null)
_refBundle.Load();
if (_refBundle.Bundle != null)
{
if (_useSubAsset)
{
UnityEngine.Object[] subAssets = _refBundle.Bundle.LoadAssetWithSubAssets(_fPath);
if (subAssets != null && subAssets.Length > 0)
{
ProcessSubAssets(subAssets);
}
else
{
TLogger.LogError($"Can not load the asset '{_fPath}'");
}
}
else
{
UnityEngine.Object assetObject = _refBundle.Bundle.LoadAsset(_fPath);
if (assetObject != null)
{
_assetObject = assetObject;
}
else
{
TLogger.LogError($"Can not load the asset '{_fPath}'");
}
}
}
}
/// <summary>
/// 异步加载Asset
/// </summary>
/// <param name="onComplete">加载回调</param>
/// <param name="withSubAssets">是否加载子Asset针对Sprite图集</param>
public void LoadAsync(System.Action<AssetData> onComplete, bool withSubAssets = false)
{
_onAsyncLoadComplete -= onComplete;
_onAsyncLoadComplete += onComplete;
_useSubAsset = withSubAssets;
if (!_refBundle.IsLoadComplete)
{
_refBundle.LoadAsync(OnAssetBundleDataLoadComplete);
}
else
{
OnAssetBundleDataLoadComplete(_refBundle);
}
}
void OnAssetBundleDataLoadComplete(AssetBundleData bundleData)
{
if (_refBundle == bundleData)
{
_refBundle.OnAsyncLoadComplete -= OnAssetBundleDataLoadComplete;
if (_useSubAsset)
{
if (_subAssetObjects == null)
{
if (_asyncLoadRequest == null)
{
_asyncLoadRequest = bundleData.Bundle.LoadAssetWithSubAssetsAsync(_fPath);
_asyncLoadRequest.completed += OnAssetLoadComplete;
}
}
else
{
_onAsyncLoadComplete(this);
}
}
else
{
if (_assetObject == null)
{
if (_asyncLoadRequest == null)
{
_asyncLoadRequest = bundleData.Bundle.LoadAssetAsync(_fPath);
_asyncLoadRequest.completed += OnAssetLoadComplete;
}
}
else
{
_onAsyncLoadComplete(this);
}
}
}
else
TLogger.LogError("Return a mismatch AssetBundleData for OnAssetBundleDataLoadComplete");
}
void OnAssetLoadComplete(AsyncOperation asyncOperation)
{
if (asyncOperation.isDone)
{
if (_asyncLoadRequest != null && _asyncLoadRequest == asyncOperation)
{
AssetBundleRequest assetBundleRequest = asyncOperation as AssetBundleRequest;
if (assetBundleRequest != null)
{
if (_useSubAsset)
{
if (assetBundleRequest.allAssets != null && assetBundleRequest.allAssets.Length > 0)
{
ProcessSubAssets(assetBundleRequest.allAssets);
}
else
{
TLogger.LogError($"Can not load the asset '{_fPath}'");
}
}
else
{
_assetObject = assetBundleRequest.asset;
if (_assetObject == null)
{
TLogger.LogError($"Can not load the asset '{_fPath}'");
}
}
}
_asyncLoadRequest = null;
_onAsyncLoadComplete(this);
}
else
{
TLogger.LogError("Return a mismatch asyncOperation for AssetBundleCreateRequest");
}
}
else
{
TLogger.LogError("Return a not done AsyncOperation for AssetBundleCreateRequest");
}
}
internal void ProcessSubAssets(UnityEngine.Object[] subAssets)
{
_subAssetObjects = new Dictionary<string, UnityEngine.Object>();
if (subAssets[0] is SpriteAtlas) // SpriteAtlas
{
_assetObject = subAssets[0];
// load all 懒加载//TODO
SpriteAtlas spriteAtlas = subAssets[0] as SpriteAtlas;
Sprite[] sprites = new Sprite[spriteAtlas.spriteCount];
int count = spriteAtlas.GetSprites(sprites);
for (int i = 0; i < count; ++i)
{
string name = sprites[i].name;
int ci = name.LastIndexOf("(Clone)", System.StringComparison.Ordinal);
if (ci >= 0)
name = name.Substring(0, ci);
_subAssetObjects.Add(name, sprites[i]);
}
}
else
{
for (int i = 0; i < subAssets.Length; ++i)
{
if (subAssets[i].GetType() != typeof(UnityEngine.Texture2D))
{
_subAssetObjects.Add(subAssets[i].name, subAssets[i]);
}
}
}
}
/// <summary>
/// 加载场景
/// </summary>
/// <remarks>先加载场景AssetBundle才能使用SceneManager中的加载接口</remarks>
public void LoadScene(LoadSceneMode mode)
{
if (_refBundle != null && _refBundle.Bundle == null)
_refBundle.Load();
_asyncLoadRequest = SceneManager.LoadSceneAsync(_name, mode);
if (_asyncLoadRequest != null)
_asyncLoadRequest.allowSceneActivation = false;
}
/// <summary>
/// 卸载Asset
/// </summary>
/// <param name="bForce">是否强制卸载</param>
public void Unload(bool bForce = false)
{
if (bForce || _refCount <= 0)
{
_assetObject = null;
_subAssetObjects?.Clear();
_refBundle = null;
_onAsyncLoadComplete = null;
_asyncLoadRequest = null;
}
else
{
TLogger.LogWarning($"Try to unload refcount > 0 asset({_fPath})!");
}
}
}
}

View File

@@ -0,0 +1,49 @@
using UnityEngine;
namespace TEngineCore
{
/// <summary>
/// GameObject与AssetData的绑定对象用于管理对AssetData的引用计数
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("")]
public sealed class AssetTag : MonoBehaviour
{
AssetData _assetData;
[SerializeField, HideInInspector] private string _path;
/// <summary>
/// 对应的资源路径
/// </summary>
public string Path => _path;
/// <summary>
/// 缓存池中的归还时间戳
/// </summary>
public float PoolReturnTimestamp { get; set; }
private int _instanceID = 0;
private void Awake()
{
// 处理Cloned GameObject上引用计数不正确的问题
if (_path != null && (_instanceID == -1 || _instanceID != gameObject.GetInstanceID()))
Bind(ResMgr.Instance.GetAsset(_path, false));
}
/// <summary>
/// GameObject绑定AssetData
/// </summary>
/// <param name="assetData">Asset数据</param>
public void Bind(AssetData assetData)
{
_assetData = assetData;
_assetData.AddRef();
_path = _assetData.Path;
_instanceID = gameObject.GetInstanceID();
}
private void OnDestroy()
{
_assetData.DecRef();
}
}
}

View File

@@ -0,0 +1,259 @@
using System.Collections.Generic;
using UnityEngine;
namespace TEngineCore
{
internal class ResMgr : TSingleton<ResMgr>
{
AssetConfig _assetConfig = new AssetConfig();
private Dictionary<ScriptableObject, AssetData> _scriptableObjects = new Dictionary<ScriptableObject, AssetData>();
public ResMgr()
{
_assetConfig.Load();
}
~ResMgr()
{
_assetConfig.Unload();
}
public void AssetUnloadDelay(float value)
{
_assetConfig.AssetUnloadDelay = value;
}
public void MaxUnloadNumPerFrame(int value)
{
_assetConfig.MaxUnloadNumPerFrame = value;
}
/// <summary>
/// 卸载无用资源
/// </summary>
public void UnloadUnusedAssetBundle()
{
_assetConfig.UnloadUnusedAssetBundle();
}
#region
/// <summary>
/// 从文件获取字符串
/// </summary>
/// <param name="path">Asset下路径</param>
/// <returns></returns>
public string GetStringFromAsset(string path)
{
if (string.IsNullOrEmpty(path))
return null;
string result = null;
AssetData assetData = _assetConfig.GetAssetAtPath(path);
if (assetData != null)
{
assetData.AddRef();
TextAsset textAsset = assetData.AssetObject as TextAsset;
result = textAsset.text;
assetData.DecRef();
}
return result;
}
public T GetScriptableObject<T>(string path) where T : ScriptableObject
{
T result = null;
if (!string.IsNullOrEmpty(path))
{
AssetData assetData = _assetConfig.GetAssetAtPath(path);
if (assetData != null)
{
assetData.AddRef();
result = assetData.AssetObject as T;
if (result != null && !_scriptableObjects.ContainsKey(result))
_scriptableObjects.Add(result, assetData);
}
}
return result;
}
public T Load<T>(string path) where T:UnityEngine.Object
{
if (string.IsNullOrEmpty(path))
return null;
T result = null;
AssetData assetData = _assetConfig.GetAssetAtPath(path);
if (assetData != null)
{
result = assetData.AssetObject as T;
if (result is GameObject)
{
var go = Object.Instantiate(assetData.AssetObject) as GameObject;
BindAssetData(go, assetData);
}
else
{
assetData.AddRef();
}
}
return result;
}
public GameObject Load(string path)
{
return GetGameObject(path);
}
public GameObject GetGameObject(string path)
{
if (string.IsNullOrEmpty(path))
return null;
GameObject go = null;
AssetData assetData = _assetConfig.GetAssetAtPath(path);
if (assetData != null)
{
go = Object.Instantiate(assetData.AssetObject) as GameObject;
BindAssetData(go, assetData);
}
return go;
}
public AssetData GetAsset(string path, bool withSubAssets)
{
if (string.IsNullOrEmpty(path))
{
return null;
}
return _assetConfig.GetAssetAtPath(path, withSubAssets);
}
public byte[] GetBytesFromAsset(string path)
{
if (string.IsNullOrEmpty(path))
return null;
byte[] result = null;
AssetData assetData = _assetConfig.GetAssetAtPath(path);
if (assetData != null)
{
assetData.AddRef();
TextAsset textAsset = assetData.AssetObject as TextAsset;
result = textAsset.bytes;
assetData.DecRef();
}
return result;
}
public void DestroyScriptableObject(ScriptableObject scriptableObject)
{
if (_scriptableObjects.TryGetValue(scriptableObject, out var assetData))
{
assetData.DecRef();
_scriptableObjects.Remove(scriptableObject);
}
}
#endregion
#region
public void GetGameObjectAsync(string path, System.Action<GameObject> onComplete)
{
if (string.IsNullOrEmpty(path))
onComplete(null);
#if ASSETBUNDLE_ENABLE
void CallBack(AssetData assetData)
{
GameObject go = null;
if (assetData != null)
{
go = Object.Instantiate(assetData.AssetObject) as GameObject;
BindAssetData(go, assetData);
assetData.OnAsyncLoadComplete -= CallBack;
}
onComplete(go);
}
_assetConfig.GetAssetAtPathAsync(path, false, CallBack);
#else
onComplete(GetGameObject(path));
#endif
}
public void GetAssetAtPathAsync(string path, bool withSubAssets, System.Action<AssetData> onComplete)
{
if (string.IsNullOrEmpty(path))
{
onComplete(null);
}
#if ASSETBUNDLE_ENABLE
void CallBack(AssetData assetData)
{
if (assetData != null)
{
if (assetData.AssetObject is GameObject)
{
GameObject go = Object.Instantiate(assetData.AssetObject) as GameObject;
BindAssetData(go, assetData);
}
else
{
assetData.AddRef();
}
assetData.OnAsyncLoadComplete -= CallBack;
onComplete(assetData);
}
_assetConfig.GetAssetAtPathAsync(path, withSubAssets, CallBack);
}
#else
onComplete(GetAsset(path,withSubAssets));
#endif
}
#endregion
public bool Exists(string path)
{
return _assetConfig.Exists(path);
}
public void Release(GameObject go)
{
if (go == null) return;
Object.Destroy(go);
}
private void BindAssetData(GameObject go, AssetData assetData)
{
bool isActive = go.activeSelf;
GameObject prefab = (GameObject)assetData.AssetObject;
if (!go.activeSelf && prefab.activeSelf)
{
go.SetActive(true);
}
else if (!prefab.activeSelf)
{
TLogger.LogWarning($"Try to get gameObject by an inactive Prefab ({assetData.Path})!");
}
go.AddComponent<AssetTag>().Bind(assetData);
if (isActive != go.activeSelf)
{
go.SetActive(isActive);
}
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
using UnityEngine;
namespace TEngineCore
{
public static class TResources
{
#region
public static GameObject Load(string path)
{
return ResMgr.Instance.Load(path);
}
public static GameObject Load(string path, Transform parent)
{
var obj = Load(path);
if (obj != null && parent != null)
{
obj.transform.SetParent(parent);
}
return obj;
}
public static T Load<T>(string path) where T : UnityEngine.Object
{
return ResMgr.Instance.Load<T>(path);
}
#endregion
#region
public static void LoadAsync(string path, Action<GameObject> callBack)
{
ResMgr.Instance.GetGameObjectAsync(path, callBack);
}
public static void LoadAsync(string path, Action<AssetData> callBack, bool withSubAsset = false)
{
ResMgr.Instance.GetAssetAtPathAsync(path, withSubAsset, callBack);
}
#endregion
}
}

View File

@@ -0,0 +1,193 @@
using UnityEngine;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Linq;
/*******************************************************************************
* 开启一个Loom进程
Loom.RunAsync(() =>
{
aucThread = new Thread(ReceiveMsg);
aucThread.Start();
}
进程调用主线程方法
MainPack pack = (MainPack)MainPack.Descriptor.Parser.ParseFrom(buffer, 0, len);
Loom.QueueOnMainThread((param) =>
{
UdpHandleResponse(pack);
}, null);
*******************************************************************************/
namespace TEngineCore
{
// <summary>
// 从子线程调用Unity的方法
// </summary>
public class Loom : MonoBehaviour
{
public Dictionary<string, CancellationTokenSource> TokenSourcesDictionary = new Dictionary<string, CancellationTokenSource>();
public static int MaxThreads = 8;
private static int _numThreads;
private static Loom _current;
public static Loom Current
{
get
{
Initialize();
return _current;
}
}
public void Awake()
{
_current = this;
initialized = true;
}
protected void OnDestroy()
{
}
private static bool initialized;
public static void Initialize()
{
if (!initialized)
{
if (!Application.isPlaying)
{
return;
}
initialized = true;
var obj = new GameObject("Loom");
_current = obj.AddComponent<Loom>();
GameObject tEngine = SingletonMgr.Root;
if (tEngine != null)
{
obj.transform.SetParent(tEngine.transform);
}
}
}
public struct NoDelayedQueueItem
{
public Action<object> action;
public object param;
}
private List<NoDelayedQueueItem> _actions = new List<NoDelayedQueueItem>();
public struct DelayedQueueItem
{
public float time;
public Action<object> action;
public object param;
}
private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();
List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>();
public static void QueueOnMainThread(Action<object> taction, object tparam)
{
QueueOnMainThread(taction, tparam, 0f);
}
public static void QueueOnMainThread(Action<object> taction, object tparam, float time)
{
if (time != 0f)
{
lock (Current._delayed)
{
Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = taction, param = tparam });
}
}
else
{
lock (Current._actions)
{
Current._actions.Add(new NoDelayedQueueItem { action = taction, param = tparam });
}
}
}
public static Thread RunAsync(string actionName,Action action)
{
Initialize();
while (_numThreads >= MaxThreads)
{
Thread.Sleep(100);
}
Interlocked.Increment(ref _numThreads);
ThreadPool.QueueUserWorkItem(RunAction, action);
return null;
}
private static void RunAction(object action)
{
try
{
((Action)action)();
}
catch
{
}
finally
{
Interlocked.Decrement(ref _numThreads);
}
}
void OnDisable()
{
if (_current == this)
{
_current = null;
}
}
List<NoDelayedQueueItem> _currentActions = new List<NoDelayedQueueItem>();
void Update()
{
if (_actions.Count > 0)
{
lock (_actions)
{
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
}
for (int i = 0; i < _currentActions.Count; i++)
{
_currentActions[i].action(_currentActions[i].param);
}
}
if (_delayed.Count > 0)
{
lock (_delayed)
{
_currentDelayed.Clear();
_currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time));
for (int i = 0; i < _currentDelayed.Count; i++)
{
_delayed.Remove(_currentDelayed[i]);
}
}
for (int i = 0; i < _currentDelayed.Count; i++)
{
_currentDelayed[i].action(_currentDelayed[i].param);
}
}
}
}
}

View File

@@ -0,0 +1,27 @@
namespace TEngineCore
{
public class ThreadMgr : UnitySingleton<ThreadMgr>
{
protected override void OnLoad()
{
base.OnLoad();
StartThread();
}
protected override void OnDestroy()
{
base.OnDestroy();
ShutDownThread();
}
private void StartThread()
{
}
private void ShutDownThread()
{
}
}
}

View File

@@ -0,0 +1,119 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace TEngineCore
{
public enum UIDragType
{
Draging,
Drop
}
public class DragItem : UIEventItem<DragItem>
{
private UIDragType m_DragState = UIDragType.Drop;
private Vector3 m_ItemOldPos;
private Vector3 m_ItemCachePos;
private bool m_CanDrag = false;
/// <summary>
/// 是否可以拖拽
/// </summary>
public bool CanDrag
{
get
{
return m_CanDrag;
}
set
{
m_CanDrag = value;
if (m_CanDrag)
{
BindDrag();
}
}
}
protected override void OnCreate()
{
base.OnCreate();
BindDrag();
}
private void BindDrag()
{
if (m_CanDrag)
{
BindBeginDragEvent(delegate (DragItem item, PointerEventData data)
{
if (!m_CanDrag)
{
return;
}
StartDragItem(UIDragType.Draging);
});
BindEndDragEvent(delegate (DragItem item, PointerEventData data)
{
if (!m_CanDrag)
{
return;
}
EndDrag();
});
}
}
protected override void OnUpdate()
{
if (!m_CanDrag)
{
return;
}
UpdateDragPos();
}
private void StartDragItem(UIDragType type)
{
if (type != UIDragType.Drop)
{
m_ItemOldPos = transform.position;
Vector3 pos;
UISys.Mgr.GetMouseDownUiPos(out pos);
m_ItemCachePos = pos;
UpdateDragPos();
m_DragState = type;
}
}
private void EndDrag()
{
m_DragState = UIDragType.Drop;
transform.position = m_ItemOldPos;
#if UNITY_EDITOR
//Debug.LogError("m_ItemCachePos.y - m_ItemOldPos.y " + (m_ItemCachePos.y - m_ItemOldPos.y));
#endif
if (m_ItemCachePos.y - m_ItemOldPos.y > 3)
{
}
}
private void UpdateDragPos()
{
if (m_DragState == UIDragType.Drop)
{
return;
}
Vector3 pos;
UISys.Mgr.GetMouseDownUiPos(out pos);
transform.position += (pos - m_ItemCachePos);
m_ItemCachePos = pos;
}
}
}

View File

@@ -0,0 +1,18 @@
using UnityEngine.UI;
public class EmptyGraph : Graphic
{
public bool m_debug = false;
protected override void OnPopulateMesh(VertexHelper vbo)
{
vbo.Clear();
#if UNITY_EDITOR
if (m_debug)
{
base.OnPopulateMesh(vbo);
}
#endif
}
}

View File

@@ -0,0 +1,253 @@
using System.Collections;
using System.Collections.Generic;
using TEngineCore;
using UnityEngine;
using UnityEngine.UI;
namespace TEngineCore
{
public class MsgUI : UIWindow
{
protected override void RegisterEvent()
{
base.RegisterEvent();
GameEventMgr.Instance.AddEventListener<string>(TipsEvent.Log, TipsUI.Instance.Show);
}
}
public class TipsEvent
{
public static int Log = StringId.StringToHash("TipsEvent.Log");
}
public class TipsUI : MonoBehaviour
{
//单例
public static TipsUI Instance;
private void Awake()
{
Instance = this;
}
//Prefab
public GameObject Prefab;
public GameObject Mask;
//对象池
public List<GameObject> AvailablePool;
public List<GameObject> UsedPool;
//自定义内容
[SerializeField] private float Speed;
//定时器
private float timer1;
private float timer2;
void Start()
{
AvailablePool = new List<GameObject>();
UsedPool = new List<GameObject>();
for (int i = 0; i < 5; i++)
{
AvailablePool.Add(Instantiate(Prefab, Mask.transform));
AvailablePool[i].SetActive(false);
}
//GameEventMgr.Instance.AddEventListener<string>(TipsEvent.Log, Show);
}
void Update()
{
//如果一定时间内没有新消息,则挨个消失
timer1 += Time.deltaTime;
if (timer1 >= 2)
{
timer2 += Time.deltaTime;
if (timer2 > 1)
{
timer2 = 0;
if (UsedPool.Count > 0)
{
Text Tname = UsedPool[0].transform.Find("Name").GetComponent<Text>();
Text Tmessage = UsedPool[0].transform.Find("Message").GetComponent<Text>();
Image BG = UsedPool[0].GetComponent<Image>();
StartCoroutine(AlphaDown(Tname));
StartCoroutine(AlphaDown(Tmessage));
StartCoroutine(ImageAlphaDown(BG));
}
}
}
}
public void Show(string message)
{
GameObject go;
//使用对象池
if (AvailablePool.Count > 0)
{
go = AvailablePool[0];
AvailablePool.Remove(go);
UsedPool.Add(go);
}
else
{
go = UsedPool[0];
UsedPool.Remove(go);
UsedPool.Add(go);
}
//进行一些初始化设定
go.transform.localPosition = new Vector3(0, -75, 0);
go.SetActive(true);
go.GetComponent<Image>().color = new Color(0, 0, 0, 150f / 255f);
timer1 = timer2 = 0;
Text Tname = go.transform.Find("Name").GetComponent<Text>();
Text Tmessage = go.transform.Find("Message").GetComponent<Text>();
Tname.text = " " + "SYSTEM";
Tmessage.text = " " + message;
float TnameWidth = Tname.preferredWidth;
float TmessageWidth = Tmessage.preferredWidth;
float goSizey = go.transform.GetComponent<RectTransform>().sizeDelta.y;
go.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(TnameWidth + TmessageWidth, goSizey);
Tname.rectTransform.sizeDelta = new Vector2(TnameWidth, Tname.rectTransform.sizeDelta.y);
Tname.rectTransform.anchoredPosition = new Vector2(TnameWidth / 2, Tname.rectTransform.anchoredPosition.y);
Tmessage.rectTransform.sizeDelta = new Vector2(TmessageWidth, Tmessage.rectTransform.sizeDelta.y);
Tmessage.rectTransform.anchoredPosition = new Vector2(-TmessageWidth / 2, Tmessage.rectTransform.anchoredPosition.y);
StartCoroutine(AlphaUP(Tname));
StartCoroutine(AlphaUP(Tmessage));
foreach (GameObject go1 in UsedPool)
{
StartCoroutine(MoveUP(go1));
}
if (UsedPool.Count >= 4)
{
Text Tname2 = UsedPool[UsedPool.Count - 4].transform.Find("Name").GetComponent<Text>();
Text Tmessage2 = UsedPool[UsedPool.Count - 4].transform.Find("Message").GetComponent<Text>();
Image BG = UsedPool[UsedPool.Count - 4].GetComponent<Image>();
StartCoroutine(AlphaDown(Tname2));
StartCoroutine(AlphaDown(Tmessage2));
StartCoroutine(ImageAlphaDown(BG));
}
}
public void Show(string name, string message)
{
GameObject go;
//使用对象池
if (AvailablePool.Count > 0)
{
go = AvailablePool[0];
AvailablePool.Remove(go);
UsedPool.Add(go);
}
else
{
go = UsedPool[0];
UsedPool.Remove(go);
UsedPool.Add(go);
}
//进行一些初始化设定
go.transform.localPosition = new Vector3(0, -75, 0);
go.SetActive(true);
go.GetComponent<Image>().color = new Color(0, 0, 0, 150f / 255f);
timer1 = timer2 = 0;
Text Tname = go.transform.Find("Name").GetComponent<Text>();
Text Tmessage = go.transform.Find("Message").GetComponent<Text>();
Tname.text = " " + name;
Tmessage.text = " " + message;
float TnameWidth = Tname.preferredWidth;
float TmessageWidth = Tmessage.preferredWidth;
float goSizey = go.transform.GetComponent<RectTransform>().sizeDelta.y;
go.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(TnameWidth + TmessageWidth, goSizey);
Tname.rectTransform.sizeDelta = new Vector2(TnameWidth, Tname.rectTransform.sizeDelta.y);
Tname.rectTransform.anchoredPosition = new Vector2(TnameWidth / 2, Tname.rectTransform.anchoredPosition.y);
Tmessage.rectTransform.sizeDelta = new Vector2(TmessageWidth, Tmessage.rectTransform.sizeDelta.y);
Tmessage.rectTransform.anchoredPosition = new Vector2(-TmessageWidth / 2, Tmessage.rectTransform.anchoredPosition.y);
StartCoroutine(AlphaUP(Tname));
StartCoroutine(AlphaUP(Tmessage));
foreach (GameObject go1 in UsedPool)
{
StartCoroutine(MoveUP(go1));
}
if (UsedPool.Count >= 4)
{
Text Tname2 = UsedPool[UsedPool.Count - 4].transform.Find("Name").GetComponent<Text>();
Text Tmessage2 = UsedPool[UsedPool.Count - 4].transform.Find("Message").GetComponent<Text>();
Image BG = UsedPool[UsedPool.Count - 4].GetComponent<Image>();
StartCoroutine(AlphaDown(Tname2));
StartCoroutine(AlphaDown(Tmessage2));
StartCoroutine(ImageAlphaDown(BG));
}
}
//文字透明度提高
public IEnumerator AlphaUP(Text text)
{
text.color += new Color(0, 0, 0, -1);
while (true)
{
yield return new WaitForSeconds(0.01f);
text.color += new Color(0, 0, 0, 0.08f);
if (text.color.a >= 1)
{
yield break;
}
}
}
//向上移动
public IEnumerator MoveUP(GameObject go)
{
float i = 0;
while (true)
{
yield return new WaitForSeconds(0.01f);
if (i + Speed >= 35)
{
go.transform.localPosition += new Vector3(0, 35 - i, 0);
yield break;
}
else
{
go.transform.localPosition += new Vector3(0, Speed, 0);
i += Speed;
}
}
}
//文字透明度下降
public IEnumerator AlphaDown(Text text)
{
while (true)
{
yield return new WaitForSeconds(0.01f);
text.color -= new Color(0, 0, 0, 0.08f);
if (text.color.a <= 0)
{
yield break;
}
}
}
//背景透明度下降
public IEnumerator ImageAlphaDown(Image image)
{
while (true)
{
yield return new WaitForSeconds(0.01f);
image.color -= new Color(0, 0, 0, 0.08f);
if (image.color.a <= 0)
{
image.gameObject.SetActive(false);
UsedPool.Remove(image.gameObject);
AvailablePool.Add(image.gameObject);
yield break;
}
}
}
//三个按钮的测试函数
public void test()
{
Show("[没关系丶是爱情啊(安娜)]", "该睡觉咯。");
}
public void test2()
{
Show("[没关系丶是爱情啊(安娜)]", "妈妈永远是对的。");
}
public void test3()
{
Show("[没关系丶是爱情啊(安娜)]", "天降正义。");
}
}
}

View File

@@ -0,0 +1,112 @@
using TEngineCore;
using UnityEngine;
namespace TEngineCore
{
public enum TweenType
{
Position,
Rotation,
Scale,
Alpha,
}
public class TweenUtil : MonoBehaviour
{
public bool isLocal;
public TweenType type;
public Vector3 from;
public Vector3 to;
public AnimationCurve curve = AnimationCurve.Linear(0, 0, 1, 1);
public float duration = 1f;
public bool isLoop;
public bool isPingPong;
private float timer = 0f;
private CanvasGroup canvasGroup;
void Awake()
{
canvasGroup = gameObject.GetComponent<CanvasGroup>();
}
void Update()
{
if (duration > 0)
{
timer += Time.deltaTime;
float curveValue;
if (isLoop)
{
float remainTime = timer % duration;
int loopCount = (int)(timer / duration);
float evaluateTime = remainTime / duration;
if (isPingPong)
{
evaluateTime = loopCount % 2 == 0 ? evaluateTime : 1 - evaluateTime;
}
curveValue = curve.Evaluate(evaluateTime);
}
else
{
curveValue = curve.Evaluate(timer);
}
var lerpValue = Vector3.Lerp(from, to, curveValue);
//if (lerpValue == lastValue)
//{
// return;
//}
//lastValue = lerpValue;
switch (type)
{
case TweenType.Position:
if (isLocal)
{
transform.localPosition = lerpValue;
}
else
{
transform.position = lerpValue;
}
break;
case TweenType.Rotation:
if (isLocal)
{
transform.localEulerAngles = lerpValue;
}
else
{
transform.eulerAngles = lerpValue;
}
break;
case TweenType.Scale:
if (isLocal)
{
transform.localScale = lerpValue;
}
else
{
var value1 = VectorWiseDivision(transform.lossyScale, transform.localScale);
var value2 = VectorWiseDivision(lerpValue, value1);
transform.localScale = value2;
}
break;
case TweenType.Alpha:
if (canvasGroup != null)
{
canvasGroup.alpha = lerpValue.x;
}
else
{
TLogger.LogError("Change Alpha need Component: [CanvasGroup]");
}
break;
}
}
}
Vector3 VectorWiseDivision(Vector3 a, Vector3 b)
{
return new Vector3(a.x / b.x, a.y / b.y, a.z / b.z);
}
}
}

View File

@@ -0,0 +1,200 @@
using System;
using TEngineCore;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace TEngineCore
{
public class UIEventItem<T> : UIWindowWidget where T : UIEventItem<T>
{
protected Button m_buttonClick;
private object[] m_eventParam;
public object EventParam1
{
get
{
return m_eventParam != null && m_eventParam.Length > 0 ? m_eventParam[0] : null;
}
}
public object EventParam2
{
get
{
return m_eventParam != null && m_eventParam.Length > 1 ? m_eventParam[1] : null;
}
}
public object EventParam3
{
get { return m_eventParam != null && m_eventParam.Length > 2 ? m_eventParam[2] : null; }
}
public object this[int index]
{
get { return m_eventParam != null && index < m_eventParam.Length ? m_eventParam[index] : null; }
}
private Action<T> m_clickAction;
private Action<T, bool, PointerEventData> m_pressAction;
private Action<T, PointerEventData> m_beginDragAction;
private Action<T, PointerEventData> m_dragAction;
private Action<T, PointerEventData> m_endDragAction;
public void BindClickEvent(Action<T> clickAction, params object[] arg)
{
if (m_clickAction != null)
{
m_clickAction = clickAction;
}
else
{
m_clickAction = clickAction;
m_buttonClick = UnityUtil.AddMonoBehaviour<Button>(gameObject);
m_buttonClick.transition = Selectable.Transition.None;
m_buttonClick.onClick.AddListener(OnButtonClick);
}
SetEventParam(arg);
}
private void OnButtonClick()
{
if (m_clickAction != null)
{
//AudioSys.GameMgr.PlayUISoundEffect(UiSoundType.UI_SOUND_CLICK);
m_clickAction(this as T);
}
}
public void BindBeginDragEvent(Action<T, PointerEventData> dragAction, params object[] arg)
{
if (m_beginDragAction != null)
{
m_beginDragAction = dragAction;
}
else
{
m_beginDragAction = dragAction;
var trigger = UnityUtil.AddMonoBehaviour<EventTrigger>(gameObject);
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.BeginDrag;
entry.callback = new EventTrigger.TriggerEvent();
entry.callback.AddListener(OnTriggerBeginDrag);
trigger.triggers.Add(entry);
}
SetEventParam(arg);
}
private void OnTriggerBeginDrag(BaseEventData data)
{
var pointerEventData = (PointerEventData)data;
if (m_beginDragAction != null)
{
m_beginDragAction(this as T, pointerEventData);
}
}
public void BindDragEvent(Action<T, PointerEventData> dragAction, params object[] arg)
{
if (m_dragAction != null)
{
m_dragAction = dragAction;
}
else
{
m_dragAction = dragAction;
var trigger = UnityUtil.AddMonoBehaviour<EventTrigger>(gameObject);
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.Drag;
entry.callback = new EventTrigger.TriggerEvent();
entry.callback.AddListener(OnTriggerDrag);
trigger.triggers.Add(entry);
}
SetEventParam(arg);
}
private void OnTriggerDrag(BaseEventData data)
{
var pointerEventData = (PointerEventData)data;
if (m_dragAction != null)
{
m_dragAction(this as T, pointerEventData);
}
}
public void BindEndDragEvent(Action<T, PointerEventData> dragendAction, params object[] arg)
{
if (m_endDragAction != null)
{
m_endDragAction = dragendAction;
}
else
{
m_endDragAction = dragendAction;
var trigger = UnityUtil.AddMonoBehaviour<EventTrigger>(gameObject);
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.EndDrag;
entry.callback = new EventTrigger.TriggerEvent();
entry.callback.AddListener(OnTriggerEndDrag);
trigger.triggers.Add(entry);
}
SetEventParam(arg);
}
private void OnTriggerEndDrag(BaseEventData data)
{
if (m_endDragAction != null)
{
m_endDragAction(this as T, (PointerEventData)data);
}
}
public void BindPressEvent(Action<T, bool, PointerEventData> pressAction, params object[] arg)
{
if (m_pressAction != null)
{
m_pressAction = pressAction;
}
else
{
m_pressAction = pressAction;
var trigger = UnityUtil.AddMonoBehaviour<EventTrigger>(gameObject);
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerDown;
entry.callback = new EventTrigger.TriggerEvent();
entry.callback.AddListener(OnTriggerPointerDown);
trigger.triggers.Add(entry);
entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerUp;
entry.callback = new EventTrigger.TriggerEvent();
entry.callback.AddListener(OnTriggerPointerUp);
trigger.triggers.Add(entry);
}
SetEventParam(arg);
}
private void OnTriggerPointerUp(BaseEventData data)
{
if (m_pressAction != null)
{
m_pressAction(this as T, false, data as PointerEventData);
}
}
private void OnTriggerPointerDown(BaseEventData data)
{
if (m_pressAction != null)
{
m_pressAction(this as T, true, data as PointerEventData);
}
}
public void SetEventParam(params object[] arg)
{
m_eventParam = arg;
}
}
}

View File

@@ -0,0 +1,178 @@
using TEngineCore;
using UnityEngine;
namespace TEngineCore
{
/// <summary>
/// 用来封装各个界面里子模块用
/// </summary>
public class UIWindowWidget : UIWindowBase
{
public int SortingOrder
{
get
{
if (m_canvas != null)
{
return m_canvas.sortingOrder;
}
return 0;
}
set
{
if (m_canvas != null)
{
int oldOrder = m_canvas.sortingOrder;
if (oldOrder != value)
{
var listCanvas = gameObject.GetComponentsInChildren<Canvas>(true);
for (int i = 0; i < listCanvas.Length; i++)
{
var childCanvas = listCanvas[i];
childCanvas.sortingOrder = value + (childCanvas.sortingOrder - oldOrder);
}
m_canvas.sortingOrder = value;
_OnSortingOrderChg();
}
}
}
}
/// <summary>
/// 所属的窗口
/// </summary>
public UIWindow OwnerWindow
{
get
{
var parent = m_parent;
while (parent != null)
{
if (parent.BaseType == UIWindowBaseType.Window)
{
return parent as UIWindow;
}
parent = parent.Parent;
}
return null;
}
}
public override UIWindowBaseType BaseType
{
get { return UIWindowBaseType.Widget; }
}
/// <summary> 根据类型创建 </summary>
public bool CreateByType<T>(UIWindowBase parent, Transform parentTrans = null) where T : UIWindowWidget
{
string resPath = string.Format("UI/{0}.prefab", typeof(T).Name);
return CreateByPath(resPath, parent, parentTrans);
}
/// <summary> 根据资源名创建 </summary>
public bool CreateByPath(string resPath, UIWindowBase parent, Transform parentTrans = null, bool visible = true)
{
GameObject goInst = TResources.Load(resPath, parentTrans);
if (goInst == null)
{
return false;
}
if (!Create(parent, goInst, visible))
{
return false;
}
goInst.transform.localScale = Vector3.one;
goInst.transform.localPosition = Vector3.zero;
return true;
}
/**
* 根据prefab或者模版来创建新的 widget
*/
public bool CreateByPrefab(UIWindowBase parent, GameObject goPrefab, Transform parentTrans, bool visible = true)
{
if (parentTrans == null)
{
parentTrans = parent.transform;
}
var widgetRoot = GameObject.Instantiate(goPrefab, parentTrans);
return CreateImp(parent, widgetRoot, true, visible);
}
/**
* 创建窗口内嵌的界面
*/
public bool Create(UIWindowBase parent, GameObject widgetRoot, bool visible = true)
{
return CreateImp(parent, widgetRoot, false, visible);
}
#region
private bool CreateImp(UIWindowBase parent, GameObject widgetRoot, bool bindGo, bool visible = true)
{
if (!CreateBase(widgetRoot, bindGo))
{
return false;
}
RestChildCanvas(parent);
m_parent = parent;
if (m_parent != null)
{
m_parent.AddChild(this);
}
if (m_canvas != null)
{
m_canvas.overrideSorting = true;
}
ScriptGenerator();
BindMemberProperty();
RegisterEvent();
OnCreate();
if (visible)
{
Show(true);
}
else
{
widgetRoot.SetActive(false);
}
return true;
}
private void RestChildCanvas(UIWindowBase parent)
{
if (gameObject == null)
{
return;
}
if (parent == null || parent.gameObject == null)
{
return;
}
Canvas parentCanvas = parent.gameObject.GetComponentInParent<Canvas>();
if (parentCanvas == null)
{
return;
}
var listCanvas = gameObject.GetComponentsInChildren<Canvas>(true);
for (var index = 0; index < listCanvas.Length; index++)
{
var childCanvas = listCanvas[index];
childCanvas.sortingOrder = parentCanvas.sortingOrder + childCanvas.sortingOrder % UIWindow.MaxCanvasSortingOrder;
}
}
#endregion
}
}

View File

@@ -0,0 +1,7 @@
namespace TEngineCore
{
interface IUIController
{
void ResigterUIEvent();
}
}

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using TEngineCore;
using UnityEngine;
namespace TEngineCore
{
public class UIBase
{
protected GameObject m_go;
protected RectTransform m_transform;
protected string m_name;
protected bool m_destroyed = true;
private GameEventMgr m_eventMgr;
protected GameEventMgr EventMgr
{
get
{
if (m_eventMgr == null)
{
m_eventMgr = GameEventMgr.Instance;
}
return m_eventMgr;
}
}
public bool IsDestroyed
{
get { return m_destroyed; }
}
public bool IsCreated
{
get { return !IsDestroyed; }
}
public RectTransform transform
{
get { return m_transform; }
}
public GameObject gameObject
{
get { return m_go; }
}
public string name
{
get
{
if (string.IsNullOrEmpty(m_name))
{
m_name = GetType().Name;
}
return m_name;
}
}
#region Event
private Dictionary<int, Delegate> m_eventTable = new Dictionary<int, Delegate>();
protected void ClearAllRegisterEvent()
{
var element = m_eventTable.GetEnumerator();
while (element.MoveNext())
{
var m_event = element.Current.Value;
//GameEventMgr.Instance.RemoveEventListener(element.Current.Key, m_event);
}
m_eventTable.Clear();
}
protected void AddUIEvent(int eventType, Action handler)
{
m_eventTable.Add(eventType, handler);
EventMgr.AddEventListener(eventType, handler);
}
protected void AddUIEvent<T>(int eventType, Action<T> handler)
{
m_eventTable.Add(eventType, handler);
EventMgr.AddEventListener(eventType, handler);
}
protected void AddUIEvent<T, U>(int eventType, Action<T, U> handler)
{
m_eventTable.Add(eventType, handler);
EventMgr.AddEventListener(eventType, handler);
}
protected void AddUIEvent<T, U, V>(int eventType, Action<T, U, V> handler)
{
m_eventTable.Add(eventType, handler);
EventMgr.AddEventListener(eventType, handler);
}
#endregion
}
}

View File

@@ -0,0 +1,546 @@
using System.Collections.Generic;
using TEngineCore;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace TEngineCore
{
public enum WindowStackIndex
{
StackNormal = 0,
StackTop = 1,
StackMax
};
public class UIWindowStack
{
public WindowStackIndex m_stackIndex;
public int m_baseOrder = 0;
public List<uint> m_windowList = new List<uint>();
public Transform m_parentTrans;
public int FindIndex(uint windowId)
{
for (int i = 0; i < m_windowList.Count; i++)
{
if (m_windowList[i] == windowId)
{
return i;
}
}
return -1;
}
}
public sealed partial class UIManager : TSingleton<UIManager>
{
private Transform m_canvasTrans;
public Canvas m_canvas;
private Dictionary<uint, UIWindow> m_allWindow = new Dictionary<uint, UIWindow>();
/// <summary>
/// 不同显示顺序的的窗口列表
/// </summary>
private UIWindowStack[] m_listWindowStack = new UIWindowStack[(int)WindowStackIndex.StackMax];
/// <summary>
/// 类型到实例的索引
/// </summary>
private static Dictionary<string, UIWindow> m_typeToInst = new Dictionary<string, UIWindow>();
/// <summary>
/// 类型和资源的绑定关系
/// </summary>
private Dictionary<string, string> m_uiType2PrefabPath = new Dictionary<string, string>();
private GameObject m_uiManagerGo;
private Transform m_uiManagerTransform;
private Camera m_uiCamera;
public Camera Camera => m_uiCamera;
public UIManager()
{
m_uiManagerGo = TResources.Load("UI/UIRoot.prefab");
Object.DontDestroyOnLoad(m_uiManagerGo);
m_uiManagerTransform = m_uiManagerGo.transform;
m_uiCamera = UnityUtil.FindChildComponent<Camera>(m_uiManagerTransform, "Camera");
Canvas canvas = m_uiManagerGo.GetComponentInChildren<Canvas>();
if (canvas != null)
{
m_canvas = canvas;
m_canvasTrans = canvas.transform;
}
var windowRoot = m_canvasTrans;
int baseOrder = 1000;
for (int i = 0; i < (int)WindowStackIndex.StackMax; i++)
{
m_listWindowStack[i] = new UIWindowStack();
m_listWindowStack[i].m_stackIndex = (WindowStackIndex)i;
m_listWindowStack[i].m_baseOrder = baseOrder;
m_listWindowStack[i].m_parentTrans = windowRoot;
baseOrder += 1000;
}
CalcCameraRect();
}
void CalcCameraRect()
{
CanvasScaler canvasScale = m_canvas.GetComponent<CanvasScaler>();
if (canvasScale != null)
{
canvasScale.referenceResolution = new Vector2(UISys.DesginWidth, UISys.DesginHeight);
float sceneScale = Screen.width / (float)Screen.height;
float designScale = canvasScale.referenceResolution.x / canvasScale.referenceResolution.y;
canvasScale.matchWidthOrHeight = sceneScale > designScale ? 1 : 0;
}
}
public void Update()
{
var allList = GetAllWindowList();
for (int i = 0; i < allList.Count; i++)
{
UIWindow window = allList[i];
if (!window.IsDestroyed)
{
window.Update();
}
}
}
private List<UIWindow> m_tmpWindowList = new List<UIWindow>();
private bool m_tmpWindowListDirty = true;
private List<UIWindow> GetAllWindowList()
{
if (m_tmpWindowListDirty)
{
m_tmpWindowList.Clear();
var itr = m_allWindow.GetEnumerator();
while (itr.MoveNext())
{
var kv = itr.Current;
m_tmpWindowList.Add(kv.Value);
}
m_tmpWindowListDirty = false;
}
return m_tmpWindowList;
}
#region Methods
public T ShowWindow<T>(bool isAsync = false) where T : UIWindow, new()
{
string typeName = GetWindowTypeName<T>();
T window = GetUIWindowByType(typeName) as T;
if (window == null)
{
window = new T();
if (!CreateWindowByType(window, typeName, isAsync))
{
return null;
}
}
ShowWindow(window, -1);
return window;
}
public string GetWindowTypeName<T>()
{
string typeName = typeof(T).Name;
return typeName;
}
public string GetWindowTypeName(UIWindow window)
{
string typeName = window.GetType().Name;
return typeName;
}
public void CloseWindow<T>() where T : UIWindow
{
string typeName = GetWindowTypeName<T>();
CloseWindow(typeName);
}
public T GetWindow<T>() where T : UIWindow
{
string typeName = GetWindowTypeName<T>();
UIWindow window = GetUIWindowByType(typeName);
if (window != null)
{
return window as T;
}
return null;
}
public UIWindow GetUIWindowByType(string typeName)
{
UIWindow window;
if (m_typeToInst.TryGetValue(typeName, out window))
{
return window;
}
return null;
}
#endregion
private bool CreateWindowByType(UIWindow window, string typeName,bool async = false)
{
//先判断是否有缓存
GameObject uiGo = null;
string resPath = string.Format("{0}.prefab", GetUIResourcePath(typeName));
if (string.IsNullOrEmpty(resPath))
{
Debug.LogErrorFormat("CreateWindowByType failed, typeName:{0}, cant find respath", typeName);
return false;
}
UIWindowStack windowStack = GetUIWindowStack(window);
if (async)
{
TResources.LoadAsync(resPath, (obj) =>
{
if (obj == null)
{
Debug.LogErrorFormat("CreateWindowByType failed, typeName:{0}, load prefab failed: {1}", typeName, resPath);
}
if (obj != null && windowStack.m_parentTrans != null)
{
obj.transform.SetParent(windowStack.m_parentTrans);
}
obj.name = typeName;
window.AllocWindowId();
var rectTrans_ = obj.transform as RectTransform;
if (window.NeedCenterUI())
{
rectTrans_.SetMax(); //localPosition = new Vector3(0, 0, 0);
}
rectTrans_.localRotation = Quaternion.identity;
rectTrans_.localScale = Vector3.one;
if (!window.Create(this, obj))
{
Debug.LogErrorFormat("window create failed, typeName:{0}", typeName);
if (obj != null)
{
Object.Destroy(obj);
obj = null;
}
}
m_typeToInst[typeName] = window;
m_allWindow[window.WindowId] = window;
m_tmpWindowListDirty = true;
});
return true;
}
uiGo = TResources.Load(resPath, windowStack.m_parentTrans);
if (uiGo == null)
{
Debug.LogErrorFormat("CreateWindowByType failed, typeName:{0}, load prefab failed: {1}", typeName, resPath);
//UISys.Mgr.ShowTipMsg(TextDefine.DOWNLOAD_TIP_UI);
//GameEvent.Get<IHomePageUI>().ShowDownloadUI();
return false;
}
uiGo.name = typeName;
window.AllocWindowId();
RectTransform rectTrans = uiGo.transform as RectTransform;
if (window.NeedCenterUI())
{
rectTrans.SetMax(); //localPosition = new Vector3(0, 0, 0);
}
rectTrans.localRotation = Quaternion.identity;
rectTrans.localScale = Vector3.one;
if (!window.Create(this, uiGo))
{
Debug.LogErrorFormat("window create failed, typeName:{0}", typeName);
if (uiGo != null)
{
Object.Destroy(uiGo);
uiGo = null;
}
return false;
}
m_typeToInst[typeName] = window;
m_allWindow[window.WindowId] = window;
m_tmpWindowListDirty = true;
return true;
}
#region MyRegion
private string GetUIResourcePath(string typeName)
{
string resPath;
if (m_uiType2PrefabPath.TryGetValue(typeName, out resPath))
{
return resPath;
}
string path = string.Format("UI/{0}", typeName);
m_uiType2PrefabPath.Add(typeName, path);
return path;
}
private void ShowWindow(UIWindow window, int showIndex)
{
UIWindowStack windowStack = GetUIWindowStack(window);
List<uint> windowList = windowStack.m_windowList;
int resortIndex = -1;
int findIndex = windowList.IndexOf(window.WindowId);
if (findIndex >= 0)
{
windowList.RemoveAt(findIndex);
resortIndex = findIndex;
}
windowList.Add(window.WindowId);
ResortStackUI(windowStack, resortIndex);
ShowTopUI(windowStack);
}
private void ResortStackUI(UIWindowStack stack, int startIdx)
{
if (stack.m_windowList.Count > 0)
{
startIdx = startIdx < 0 ? (stack.m_windowList.Count - 1) : startIdx;
for (int i = startIdx; i < stack.m_windowList.Count; i++)
{
uint windowId = stack.m_windowList[i];
UIWindow window = FindWindow(windowId);
if (window != null)
{
int order;
if (window.IsFixedSortingOrder)
{
order = stack.m_baseOrder + window.FixedAdditionalOrder;
}
else
{
order = stack.m_baseOrder + i * UIWindow.MaxCanvasSortingOrder;
}
window.SortingOrder = order;
}
}
}
}
private void ShowTopUI(UIWindowStack stack)
{
if (stack.m_windowList.Count > 0)
{
bool hasTop = false;
for (int i = stack.m_windowList.Count - 1; i >= 0; i--)
{
uint windowId = stack.m_windowList[i];
UIWindow window = FindWindow(windowId);
if (window != null)
{
if (!hasTop)
{
hasTop = window.IsFullScreen;
window.Show(true);
}
else
{
window.Show(false);
}
}
}
}
OnWindowVisibleChanged();
}
private void OnWindowVisibleChanged()
{
bool isFullScreenMaskscene = false;
for (int i = 0; i < m_listWindowStack.Length && !isFullScreenMaskscene; i++)
{
var stack = m_listWindowStack[i];
if (stack == null)
{
continue;
}
var listWindow = stack.m_windowList;
for (int k = 0; k < listWindow.Count; k++)
{
var winId = listWindow[k];
var win = FindWindow(winId);
if (win == null || !win.Visible)
{
continue;
}
if (win.IsFullScreenMaskScene)
{
isFullScreenMaskscene = true;
break;
}
}
}
//SceneSys.Instance.CameraMgr.SetSceneCameraEnableByUI(true);
}
public UIWindow FindWindow(uint windowId)
{
UIWindow window;
if (m_allWindow.TryGetValue(windowId, out window))
{
return window;
}
return null;
}
public void CloseWindow(string typeName)
{
UIWindow window = GetUIWindowByType(typeName);
if (window != null)
{
CloseWindow(window);
}
}
public void CloseWindow(UIWindow window)
{
if (window.IsDestroyed)
{
return;
}
//刷新窗口order保证新创建的窗口不会出现重叠
UIWindowStack windowStack = GetUIWindowStack(window);
int findIndex = windowStack.FindIndex(window.WindowId);
//window.Destroy();
DestroyWindowObject(window);
ResortStackUI(windowStack, findIndex);
ShowTopUI(windowStack);
}
private void DestroyWindowObject(UIWindow window)
{
string typeName = window.GetType().Name;
UIWindow typeWindow = null;
if (m_typeToInst.TryGetValue(typeName, out typeWindow) && typeWindow == window)
{
m_typeToInst.Remove(typeName);
}
uint windowId = window.WindowId;
m_allWindow.Remove(windowId);
UIWindowStack windowStack = GetUIWindowStack(window);
windowStack.m_windowList.Remove(windowId);
window.Destroy();
m_tmpWindowListDirty = true;
}
private int GetIndexByWindowType(UIWindowType windowType)
{
if (windowType == UIWindowType.WindowTop)
{
return (int)WindowStackIndex.StackTop;
}
return (int)WindowStackIndex.StackNormal;
}
public UIWindowStack GetUIWindowStack(UIWindow window)
{
int index = GetIndexByWindowType(window.GetWindowType());
return m_listWindowStack[index];
}
public UIWindow GetWindowById(uint windowId)
{
return FindWindow(windowId);
}
public UIWindowStack GetUIWindowStack(UIWindowType windowType)
{
int index = GetIndexByWindowType(windowType);
return m_listWindowStack[index];
}
#endregion
#region
/// <summary>
/// 给控件添加自定义事件监听
/// </summary>
/// <param name="control">控件对象</param>
/// <param name="type">事件类型</param>
/// <param name="callback">事件的响应函数</param>
public static void AddCustomEventListener(UIBehaviour control, EventTriggerType type, UnityAction<BaseEventData> callback)
{
EventTrigger trigger = control.GetComponent<EventTrigger>();
if (trigger == null)
{
trigger = control.gameObject.AddComponent<EventTrigger>();
}
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = type;
entry.callback.AddListener(callback);
trigger.triggers.Add(entry);
}
public bool GetMouseDownUiPos(out Vector3 screenPos)
{
bool hadMouseDown = false;
Vector3 mousePos = Vector3.zero;
#if UNITY_STANDALONE_WIN || UNITY_EDITOR
mousePos = Input.mousePosition;
hadMouseDown = Input.GetMouseButton(0);
#else
if (Input.touchCount > 0)
{
mousePos = Input.GetTouch(0).position;
hadMouseDown = true;
}
else
{
hadMouseDown = false;
}
#endif
Vector2 pos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(m_canvasTrans as RectTransform, Input.mousePosition,
m_uiCamera, out pos);
screenPos = m_canvasTrans.TransformPoint(pos);
return hadMouseDown;
}
#endregion
}
}

View File

@@ -0,0 +1,166 @@
using System.Collections.Generic;
using TEngineCore;
using UnityEngine;
namespace TEngineCore
{
public class UISys : BaseLogicSys<UISys>
{
public static int DesginWidth
{
get
{
return 750;
}
}
public static int DesginHeight
{
get
{
return 1624;
}
}
public static int ScreenWidth;
public static int ScreenHeight;
public bool IsLandScape { private set; get; }
private List<IUIController> m_listController = new List<IUIController>();
public static UIManager Mgr
{
get { return UIManager.Instance; }
}
public override void OnUpdate()
{
UIManager.Instance.Update();
}
public override bool OnInit()
{
base.OnInit();
ScreenWidth = Screen.width;
ScreenHeight = Screen.height;
IsLandScape = ScreenWidth > ScreenHeight;
RegistAllController();
return true;
}
private void RegistAllController()
{
//AddController<LoadingUIController>();
}
private void AddController<T>() where T : IUIController, new()
{
for (int i = 0; i < m_listController.Count; i++)
{
var type = m_listController[i].GetType();
if (type == typeof(T))
{
Debug.LogError(string.Format("repeat controller type: {0}", typeof(T).Name));
return;
}
}
var controller = new T();
m_listController.Add(controller);
controller.ResigterUIEvent();
}
public static void ShowTipMsg(string str)
{
}
}
public static class CanvasUtils
{
public static void SetMax(this RectTransform rectTransform)
{
if (rectTransform == null)
{
return;
}
rectTransform.localPosition = new Vector3(0, 0, 0);
rectTransform.localRotation = Quaternion.identity;
rectTransform.localScale = Vector3.one;
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, 0, 0);
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, 0);
rectTransform.anchorMin = Vector2.zero;
rectTransform.anchorMax = Vector2.one;
}
/// <summary>
/// 调整 RectTransform 组件中的 Left、Bottom 属性
/// </summary>
/// <param name="rt">引用目标 RectTransform 对象</param>
/// <param name="left">Left值</param>
/// <param name="bottom">Bottom值</param>
public static void LeftBottom(RectTransform rectTransform, float left, float bottom)
{
Vector2 size = rectTransform.rect.size;
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, left, size.x);
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, bottom, size.y);
}
/// <summary>
/// 调整 RectTransform 组件中的 Left、Top 属性
/// </summary>
/// <param name="rt"></param>
/// <param name="left">Left值</param>
/// <param name="top">Top值</param>
public static void LeftTop(RectTransform rectTransform, float left, float top)
{
Vector2 size = rectTransform.rect.size;
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, left, size.x);
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, top, size.y);
}
/// <summary>
/// 调整 RectTransform 组件中的 Right、Bottom 属性
/// </summary>
/// <param name="rt"></param>
/// <param name="right">Right值</param>
/// <param name="bottom">Bottom值</param>
public static void RightBottom(RectTransform rectTransform, float right, float bottom)
{
Vector2 size = rectTransform.rect.size;
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, right, size.x);
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, bottom, size.y);
}
/// <summary>
/// 调整 RectTransform 组件中的 Right、Top 属性
/// </summary>
/// <param name="rt"></param>
/// <param name="right">Right值</param>
/// <param name="top">Top值</param>
public static void RightTop(RectTransform rectTransform, float right, float top)
{
Vector2 size = rectTransform.rect.size;
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, right, size.x);
rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, top, size.y);
}
public static void SetCenter(this RectTransform rectTransform, float x = 0, float y = 0)
{
rectTransform.localPosition = new Vector3(0, 0, 0);
rectTransform.localRotation = Quaternion.identity;
rectTransform.localScale = Vector3.one;
Vector2 size = rectTransform.rect.size;
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x);
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y);
rectTransform.localPosition = new Vector2(x, y);
}
}
}

View File

@@ -0,0 +1,280 @@
using TEngineCore;
using UnityEngine;
using UnityEngine.UI;
namespace TEngineCore
{
public enum UIWindowType
{
/// <summary> 普通窗口 </summary>
WindowNormal,
/// <summary> 置顶窗口 </summary>
WindowTop,
/// <summary> 模态窗口 </summary>
WindowModel
}
public class UIWindow : UIWindowBase
{
#region
private bool m_isClosed = false;
private bool m_isCreating = false;
private Image m_modalImage;
private float m_modalAlpha = 0.86f;
/// <summary>
/// 是否固定SortingOrder
/// </summary>
public virtual bool IsFixedSortingOrder
{
get { return false; }
}
public virtual bool NeedCenterUI()
{
return true;
}
/// <summary>
/// 窗口Id
/// </summary>
private uint m_windowId = 0;
/// <summary>
/// 窗口Id
/// </summary>
public uint WindowId
{
get { return m_windowId; }
}
private static uint m_nextWindowId = 0;
public virtual bool IsFullScreen
{
get { return false; }
}
public virtual bool IsFullScreenMaskScene
{
get { return false; }
}
/// <summary>
/// 一个界面中最大sortOrder值
/// </summary>
public const int MaxCanvasSortingOrder = 50;
/// <summary>
/// SortingOrder = stack.m_baseOrder + FixedAdditionalOrder
/// </summary>
public virtual int FixedAdditionalOrder
{
get { return UIWindow.MaxCanvasSortingOrder; }
}
public int SortingOrder
{
get
{
if (m_canvas != null)
{
return m_canvas.sortingOrder;
}
return 0;
}
set
{
if (m_canvas != null)
{
int oldOrder = m_canvas.sortingOrder;
if (oldOrder != value)
{
var listCanvas = gameObject.GetComponentsInChildren<Canvas>(true);
for (int i = 0; i < listCanvas.Length; i++)
{
var childCanvas = listCanvas[i];
childCanvas.sortingOrder = value + (childCanvas.sortingOrder - oldOrder);
}
m_canvas.sortingOrder = value;
_OnSortingOrderChg();
}
}
}
}
#endregion
public void AllocWindowId()
{
if (m_nextWindowId == 0)
{
m_nextWindowId++;
}
m_windowId = m_nextWindowId++;
}
#region virtual function
public virtual UIWindowType GetWindowType()
{
return UIWindowType.WindowNormal;
}
#endregion
#region Call From UIManager
public bool Create(UIManager uiMgr, GameObject uiGo)
{
if (IsCreated)
{
return true;
}
m_isClosed = false;
if (!CreateBase(uiGo, true))
{
return false;
}
if (m_canvas == null)
{
Debug.LogErrorFormat("{0} have not a canvas!!", this.ToString());
Destroy();
return false;
}
m_ownUIManager = uiMgr;
m_firstVisible = false;
if (m_canvas != null)
{
m_canvas.overrideSorting = true;
}
ScriptGenerator();
BindMemberProperty();
RegisterEvent();
m_isCreating = true;
OnCreate();
m_isCreating = false;
if (m_isClosed)
{
Destroy();
return false;
}
SetModalState(GetModalType());
return true;
}
public virtual ModalType GetModalType()
{
if (IsFullScreen || GetWindowType() == UIWindowType.WindowTop)
{
return ModalType.TransparentType;
}
return ModalType.NormalType;
}
private void SetModalState(ModalType type)
{
var canClose = false;
switch (type)
{
case ModalType.NormalType:
{
m_modalAlpha = 0f;
break;
}
case ModalType.NormalHaveClose:
{
canClose = true;
break;
}
case ModalType.TransparentType:
{
m_modalAlpha = 0.01f;
break;
}
case ModalType.TransparentHaveClose:
{
m_modalAlpha = 0.01f;
canClose = true;
break;
}
default:
{
m_modalAlpha = 0f;
break;
}
}
if (m_modalAlpha > 0)
{
string path = "UI/ModalSprite.prefab";
GameObject modal = TResources.Load(path);
modal.transform.SetParent(transform);
modal.transform.SetAsFirstSibling();
modal.transform.localScale = Vector3.one;
modal.transform.localPosition = Vector3.zero;
if (canClose)
{
var button = UnityUtil.AddMonoBehaviour<Button>(modal);
button.onClick.AddListener(Close);
}
m_modalImage = UnityUtil.AddMonoBehaviour<Image>(modal);
m_modalImage.color = new Color(0, 0, 0, m_modalAlpha);
}
}
public virtual void Close()
{
if (m_isCreating)
{
m_isClosed = true;
return;
}
var mgr = UIMgr;
if (mgr != null)
{
mgr.CloseWindow(this);
}
}
#endregion
}
public enum ModalType
{
/// <summary> 普通模态 </summary>
NormalType,
/// <summary> 透明模态 </summary>
TransparentType,
/// <summary> 普通状态且有关闭功能 </summary>
NormalHaveClose,
/// <summary> 透明状态且有关闭功能 </summary>
TransparentHaveClose,
/// <summary> 非模态 </summary>
NoneType,
}
public enum UIWindowBaseType
{
None,
Window,
Widget,
}
}

View File

@@ -0,0 +1,445 @@
using System.Collections;
using System.Collections.Generic;
using TEngineCore;
using UnityEngine;
namespace TEngineCore
{
public class UIWindowBase : UIBase
{
/// <summary>
/// 所属的window
/// </summary>
protected UIWindowBase m_parent = null;
protected Canvas m_canvas;
private List<UIWindowBase> m_listChild = null;
private List<UIWindowBase> m_listUpdateChild = null;
private bool m_updateListValid = false;
/// <summary>
/// 是否首次显示过了
/// </summary>
protected bool m_firstVisible = false;
/// <summary>
/// 当前是否显示出来了
/// </summary>
private bool m_visible = false;
public bool Visible
{
get { return m_visible; }
}
public UIWindowBase Parent
{
get { return m_parent; }
}
protected UIManager m_ownUIManager = null;
protected UIManager UIMgr
{
get
{
if (m_ownUIManager == null && m_parent != null)
{
return m_parent.UIMgr;
}
return m_ownUIManager;
}
}
public virtual UIWindowBaseType BaseType
{
get { return UIWindowBaseType.None; }
}
#region
/**
* 创建对象
*
* bindGO 是否把GameObject和Window绑定在一起
*/
protected bool CreateBase(GameObject go, bool bindGo)
{
///has created
if (!m_destroyed)
{
Debug.LogErrorFormat("UIBase has created: {0}", go.name);
return false;
}
if (go == null)
{
return false;
}
m_destroyed = false;
m_go = go;
m_transform = go.GetComponent<RectTransform>();
m_canvas = gameObject.GetComponent<Canvas>();
var canvas = gameObject.GetComponentsInChildren<Canvas>(true);
for (var i = 0; i < canvas.Length; i++)
{
var canva = canvas[i];
canva.additionalShaderChannels = AdditionalCanvasShaderChannels.TexCoord1;
}
if (m_transform == null)
{
Debug.LogErrorFormat("{0} ui base element need to be RectTransform", go.name);
}
return true;
}
protected void DestroyAllChild()
{
//销毁子对象
if (m_listChild != null)
{
for (int i = 0; i < m_listChild.Count; i++)
{
var child = m_listChild[i];
child.Destroy();
}
m_listChild.Clear();
}
}
public void Destroy()
{
if (IsDestroyed)
{
return;
}
m_destroyed = true;
OnDestroy();
DestroyAllChild();
if (m_parent != null)
{
m_parent.RmvChild(this);
m_parent = null;
}
if (m_go != null)
{
Object.Destroy(m_go);
m_go = null;
}
m_transform = null;
}
#endregion
#region
/// <summary> 脚本生成的代码 </summary>
protected virtual void ScriptGenerator()
{
}
/// <summary>
/// 绑定代码和prefab之间元素的关系
/// </summary>
protected virtual void BindMemberProperty()
{
}
protected virtual void RegisterEvent()
{
}
private bool m_hasOverrideUpdate = true;
protected virtual void OnUpdate()
{
m_hasOverrideUpdate = false;
}
/// <summary>
/// 界面创建出来的时候调用,被覆盖不可见不会重复触发
/// </summary>
protected virtual void OnCreate()
{
}
protected virtual void OnDestroy()
{
}
/// <summary>
/// 创建出来首次visible
/// 用来播放一些显示动画之类的
/// </summary>
protected virtual void OnFirstVisible()
{
}
/// <summary>
/// 当显示出来的时候调用
/// 包括首次初始化后显示和上面的界面消失后重新恢复显示
/// </summary>
protected virtual void OnVisible()
{
}
/// <summary>
/// 界面不可见的时候调用
/// 当被上层全屏界面覆盖后,也会触发一次隐藏
/// </summary>
protected virtual void OnHidden()
{
}
protected void _OnSortingOrderChg()
{
if (m_listChild != null)
{
for (int i = 0; i < m_listChild.Count; i++)
{
if (m_listChild[i].m_visible)
{
m_listChild[i]._OnSortingOrderChg();
}
}
}
OnSortingOrderChg();
}
protected virtual void OnSortingOrderChg()
{
}
#endregion
public void AddChild(UIWindowBase child)
{
if (m_listChild == null)
{
m_listChild = new List<UIWindowBase>();
}
m_listChild.Add(child);
MarkListChanged();
}
public void RmvChild(UIWindowBase child)
{
//如果已经销毁了或者销毁过程中,那么不掉用删除
if (m_destroyed)
{
return;
}
if (m_listChild != null)
{
if (m_listChild.Remove(child))
{
MarkListChanged();
}
}
}
/// <summary>
/// 重新整理update和lateupdate的调用缓存
/// </summary>
private void MarkListChanged()
{
m_updateListValid = false;
if (m_parent != null)
{
m_parent.MarkListChanged();
}
}
#region
protected Coroutine StartCoroutine(IEnumerator routine)
{
return MonoManager.Instance.StartCoroutine(routine);
}
protected void StopCoroutine(Coroutine cort)
{
MonoManager.Instance.StopCoroutine(cort);
}
#endregion
#region
public Transform FindChild(string path)
{
return UnityUtil.FindChild(transform, path);
}
public Transform FindChild(Transform _transform, string path)
{
return UnityUtil.FindChild(_transform, path);
}
public T FindChildComponent<T>(string path) where T : Component
{
return UnityUtil.FindChildComponent<T>(transform, path);
}
public T FindChildComponent<T>(Transform _transform, string path) where T : Component
{
return UnityUtil.FindChildComponent<T>(_transform, path);
}
public void Show(bool visible)
{
// 加个保护
if (m_destroyed || gameObject == null)
{
return;
}
if (m_visible != visible)
{
m_visible = visible;
if (visible)
{
gameObject.SetActive(true);
_OnVisible();
}
else
{
_OnHidden();
if (gameObject == null)
{
Debug.LogErrorFormat("ui bug, hiden destory gameobject: {0}", name);
}
else
{
gameObject.SetActive(false);
}
}
MarkListChanged();
}
}
protected void _OnVisible()
{
if (m_listChild != null)
{
for (int i = 0; i < m_listChild.Count; i++)
{
var child = m_listChild[i];
if (child.gameObject.activeInHierarchy)
{
child._OnVisible();
}
}
}
if (!m_firstVisible)
{
m_firstVisible = true;
OnFirstVisible();
}
OnVisible();
}
protected void _OnHidden()
{
if (m_listChild != null)
{
for (int i = 0; i < m_listChild.Count; i++)
{
var child = m_listChild[i];
if (child.gameObject.activeInHierarchy)
{
child._OnHidden();
}
}
}
OnHidden();
}
/// <summary>
/// 返回是否有必要下一帧继续执行
/// </summary>
/// <returns></returns>
public bool Update()
{
if (!m_visible || m_destroyed)
{
return false;
}
List<UIWindowBase> listNextUpdateChild = null;
if (m_listChild != null && m_listChild.Count > 0)
{
listNextUpdateChild = m_listUpdateChild;
var updateListValid = m_updateListValid;
List<UIWindowBase> listChild = null;
if (!updateListValid)
{
if (listNextUpdateChild == null)
{
listNextUpdateChild = new List<UIWindowBase>();
m_listUpdateChild = listNextUpdateChild;
}
else
{
listNextUpdateChild.Clear();
}
listChild = m_listChild;
}
else
{
listChild = listNextUpdateChild;
}
for (int i = 0; i < listChild.Count; i++)
{
var window = listChild[i];
var needValid = window.Update();
if (!updateListValid && needValid)
{
listNextUpdateChild.Add(window);
}
}
if (!updateListValid)
{
m_updateListValid = true;
}
}
bool needUpdate = false;
if (listNextUpdateChild == null || listNextUpdateChild.Count <= 0)
{
m_hasOverrideUpdate = true;
OnUpdate();
needUpdate = m_hasOverrideUpdate;
}
else
{
OnUpdate();
needUpdate = true;
}
return needUpdate;
}
#endregion
}
}

View File

@@ -0,0 +1,175 @@
using UnityEngine;
namespace TEngineCore
{
/// <summary>
/// 硬件设备性能适配工具
/// </summary>
public static class DevicePerformanceUtil
{
/// <summary>
/// 获取设备性能评级
/// </summary>
/// <returns>性能评级</returns>
public static DevicePerformanceLevel GetDevicePerformanceLevel()
{
if (SystemInfo.graphicsDeviceVendorID == 32902)
{
//集显
return DevicePerformanceLevel.Low;
}
else //NVIDIA 系列显卡N卡和AMD系列显卡
{
//根据目前硬件配置三个平台设置了不一样的评判标准(仅个人意见)
//CPU核心数
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
if (SystemInfo.processorCount <= 2)
#elif UNITY_STANDALONE_OSX || UNITY_IPHONE
if (SystemInfo.processorCount < 2)
#elif UNITY_ANDROID
if (SystemInfo.processorCount <= 4)
#else
if(SystemInfo.processorCount <= 2)
#endif
{
//CPU核心数<=2判定为低端
return DevicePerformanceLevel.Low;
}
else
{
//显存
int graphicsMemorySize = SystemInfo.graphicsMemorySize;
//内存
int systemMemorySize = SystemInfo.systemMemorySize;
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
if (graphicsMemorySize >= 4000 && systemMemorySize >= 8000)
return DevicePerformanceLevel.High;
else if (graphicsMemorySize >= 2000 && systemMemorySize >= 4000)
return DevicePerformanceLevel.Mid;
else
return DevicePerformanceLevel.Low;
#elif UNITY_STANDALONE_OSX || UNITY_IPHONE
if (graphicsMemorySize >= 4000 && systemMemorySize >= 8000)
return DevicePerformanceLevel.High;
else if (graphicsMemorySize >= 2000 && systemMemorySize >= 4000)
return DevicePerformanceLevel.Mid;
else
return DevicePerformanceLevel.Low;
#elif UNITY_ANDROID
if (graphicsMemorySize >= 6000 && systemMemorySize >= 8000)
return DevicePerformanceLevel.High;
else if (graphicsMemorySize >= 2000 && systemMemorySize >= 4000)
return DevicePerformanceLevel.Mid;
else
return DevicePerformanceLevel.Low;
#else
return DevicePerformanceLevel.Low;
#endif
}
}
}
/// <summary>
/// 根据手机性能修改项目设置
/// </summary>
/// <param name="lowQuality">QualitySettings中对应Low的等级</param>
/// <param name="midQuality">QualitySettings中对应Mid的等级</param>
/// <param name="highQuality">QualitySettings中对应High的等级</param>
public static void ModifySettingsBasedOnPerformance(int lowQuality, int midQuality, int highQuality)
{
DevicePerformanceLevel level = GetDevicePerformanceLevel();
switch (level)
{
case DevicePerformanceLevel.Low:
QualitySettings.SetQualityLevel(lowQuality, true);
break;
case DevicePerformanceLevel.Mid:
QualitySettings.SetQualityLevel(midQuality, true);
break;
case DevicePerformanceLevel.High:
QualitySettings.SetQualityLevel(highQuality, true);
break;
}
}
/// <summary>
/// 根据机型配置自动设置质量
/// </summary>
public static void ModifySettingsBasedOnPerformance()
{
DevicePerformanceLevel level = GetDevicePerformanceLevel();
switch (level)
{
case DevicePerformanceLevel.Low:
SetQualitySettings(QualityLevel.Low);
break;
case DevicePerformanceLevel.Mid:
SetQualitySettings(QualityLevel.Mid);
break;
case DevicePerformanceLevel.High:
SetQualitySettings(QualityLevel.High);
break;
}
}
/// <summary>
/// 根据自身需要调整各级别需要修改的设置,可根据需求修改低中高三种方案某一项具体设置
/// </summary>
/// <param name="qualityLevel">质量等级</param>
public static void SetQualitySettings(QualityLevel qualityLevel)
{
switch (qualityLevel)
{
case QualityLevel.Low:
//前向渲染使用的像素灯的最大数量建议最少为1
QualitySettings.pixelLightCount = 2;
//你可以设置使用最大分辨率的纹理或者部分纹理(低分辨率纹理的处理开销低)。选项有 0_完整分辨率1_1/2分辨率2_1/4分辨率3_1/8分辨率
QualitySettings.masterTextureLimit = 1;
//设置抗锯齿级别。选项有​​ 0_不开启抗锯齿2_2倍4_4倍和8_8倍采样。
QualitySettings.antiAliasing = 0;
//是否使用粒子软融合
QualitySettings.softParticles = false;
//启用实时反射探针,此设置需要用的时候再打开
QualitySettings.realtimeReflectionProbes = false;
//如果启用,公告牌将面向摄像机位置而不是摄像机方向。似乎与地形系统有关,此处没啥必要打开
QualitySettings.billboardsFaceCameraPosition = false;
//设置软硬阴影是否打开
QualitySettings.shadows = ShadowQuality.Disable;
//设置垂直同步方案VSyncs数值需要在每帧之间传递使用0为不等待垂直同步。值必须是01或2。
QualitySettings.vSyncCount = 0;
break;
case QualityLevel.Mid:
QualitySettings.pixelLightCount = 4;
QualitySettings.antiAliasing = 2;
QualitySettings.softParticles = false;
QualitySettings.realtimeReflectionProbes = true;
QualitySettings.billboardsFaceCameraPosition = true;
QualitySettings.shadows = ShadowQuality.HardOnly;
QualitySettings.vSyncCount = 2;
break;
case QualityLevel.High:
QualitySettings.pixelLightCount = 4;
QualitySettings.antiAliasing = 8;
QualitySettings.softParticles = true;
QualitySettings.realtimeReflectionProbes = true;
QualitySettings.billboardsFaceCameraPosition = true;
QualitySettings.shadows = ShadowQuality.All;
QualitySettings.vSyncCount = 2;
break;
}
}
}
public enum DevicePerformanceLevel
{
Low,
Mid,
High
}
public enum QualityLevel
{
Low,
Mid,
High
}
}

View File

@@ -0,0 +1,298 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngineInternal;
using Object = UnityEngine.Object;
namespace TEngineCore
{
/// <summary>
/// 封装Unity相关的一些通用接口
/// </summary>
public class UnityUtil
{
[TypeInferenceRule(TypeInferenceRules.TypeReferencedByFirstArgument)]
public static Component AddMonoBehaviour(Type type, GameObject go)
{
var comp = go.GetComponent(type);
if (comp == null)
{
comp = go.AddComponent(type);
}
return comp;
}
public static T AddMonoBehaviour<T>(Component comp) where T : Component
{
var ret = comp.GetComponent<T>();
if (ret == null)
{
ret = comp.gameObject.AddComponent<T>();
}
return ret;
}
public static T AddMonoBehaviour<T>(GameObject go) where T : Component
{
var comp = go.GetComponent<T>();
if (comp == null)
{
comp = go.AddComponent<T>();
}
return comp;
}
[TypeInferenceRule(TypeInferenceRules.TypeReferencedByFirstArgument)]
public static void RmvMonoBehaviour(Type type, GameObject go)
{
var comp = go.GetComponent(type);
if (comp != null)
{
UnityEngine.Object.Destroy(comp);
}
}
public static void RmvMonoBehaviour<T>(GameObject go) where T : Component
{
var comp = go.GetComponent<T>();
if (comp != null)
{
UnityEngine.Object.Destroy(comp);
}
}
public static Transform FindChild(Transform transform, string path)
{
var findTrans = transform.Find(path);
if (findTrans != null)
{
return findTrans;
}
return null;
}
public static Transform FindChildByName(Transform transform, string name)
{
if (transform == null)
{
return null;
}
for (int i = 0; i < transform.childCount; i++)
{
var childTrans = transform.GetChild(i);
if (childTrans.name == name)
{
return childTrans;
}
var find = FindChildByName(childTrans, name);
if (find != null)
{
return find;
}
}
return null;
}
[TypeInferenceRule(TypeInferenceRules.TypeReferencedByFirstArgument)]
public static Component FindChildComponent(Type type, Transform transform, string path)
{
var findTrans = transform.Find(path);
if (findTrans != null)
{
return findTrans.gameObject.GetComponent(type);
}
return null;
}
public static T FindChildComponent<T>(Transform transform, string path) where T : Component
{
var findTrans = transform.Find(path);
if (findTrans != null)
{
return findTrans.gameObject.GetComponent<T>();
}
return null;
}
public static void SetLayer(GameObject go, int layer)
{
if (go == null)
{
return;
}
SetLayer(go.transform, layer);
}
public static void SetLayer(Transform trans, int layer)
{
if (trans == null)
{
return;
}
trans.gameObject.layer = layer;
for (int i = 0, imax = trans.childCount; i < imax; ++i)
{
Transform child = trans.GetChild(i);
SetLayer(child, layer);
}
}
public static int RandomRangeInt(int min, int max)
{
return UnityEngine.Random.Range(min, max);
}
public static float RandomRangeFloat(float min, float max)
{
return UnityEngine.Random.Range(min, max);
}
public static Vector2 RandomInsideCircle(float radius)
{
return UnityEngine.Random.insideUnitCircle * radius;
}
[TypeInferenceRule(TypeInferenceRules.TypeReferencedByFirstArgument)]
public static Array CreateUnityArray(Type type, int length)
{
return Array.CreateInstance(type, length);
}
public static T[] CreateUnityArray<T>(int length)
{
return new T[length];
}
public static GameObject Instantiate(GameObject go)
{
if (go != null)
{
return UnityEngine.GameObject.Instantiate(go);
}
return null;
}
public static int GetHashCodeByString(string str)
{
return str.GetHashCode();
}
public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask)
{
return Physics.Raycast(ray, out hitInfo, maxDistance, layerMask);
}
public static List<string> GetRegexMatchGroups(string pattern, string input)
{
List<string> list = new List<string>();
var regexLink = new Regex(pattern);
var links = regexLink.Match(input);
for (var i = 0; i < links.Groups.Count; ++i)
{
list.Add(links.Groups[i].Value);
}
return list;
}
public static void SetMaterialVector3(Material mat, int nameId, Vector3 val)
{
mat.SetVector(nameId, val);
}
public static void GetVectorData(Vector3 val, out float x, out float y, out float z)
{
x = val.x;
y = val.y;
z = val.z;
}
public static void GetVector2Data(Vector2 val, out float x, out float y)
{
x = val.x;
y = val.y;
}
public static bool GetTouchByFingerId(int fingerId, out Touch findTouch)
{
var finded = false;
var touchCnt = Input.touchCount;
findTouch = new Touch();
for (int i = 0; i < touchCnt; i++)
{
var touch = Input.GetTouch(i);
if (touch.fingerId == fingerId)
{
findTouch = touch;
finded = true;
break;
}
}
return finded;
}
public static bool SetAnimatorController(GameObject go, string resPath)
{
//RuntimeAnimatorController rac = (RuntimeAnimatorController)ResourcesManager.Instance.Load<UnityEngine.Object>(resPath);
//if (rac == null)
//{
// Debug.Log("GetAnimator failed path: " + resPath);
// return false;
//}
//var ani = go.GetComponentInChildren<Animator>(true);
//if (ani != null)
//{
// ani.runtimeAnimatorController = rac;
// return true;
//}
return false;
}
public static void SetGameObjectActive(GameObject go, bool active)
{
if (go != null && go.activeSelf != active)
{
go.SetActive(active);
}
}
public static T[] GetComponentsInChildren<T>(GameObject go) where T : UIBehaviour
{
if (go != null)
{
return go.GetComponentsInChildren<T>();
}
return null;
}
public static T GetComponent<T>(GameObject go)
{
if (go != null)
{
return go.GetComponent<T>();
}
return default(T);
}
}
}