TEngine Commit 1.0.0

TEngine Commit 1.0.0
This commit is contained in:
ALEXTANG
2022-05-20 23:19:50 +08:00
parent ea8c79aa6d
commit 90ae4874a9
474 changed files with 110489 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 99bd65c4be7ea5b46a417cdbed6b9064
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 377e07ca9e18e8b408a9f2b22030fe32
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 577d9725f58264943855b8ac185531fe
folderAsset: yes
timeCreated: 1466788344
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 14f21d7a1e53a8c4e87b25526a7eb63c
folderAsset: yes
timeCreated: 1466788345
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aadad8ac54f29e44583510294ac5c312
timeCreated: 1466788355
licenseType: Store
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
fileFormatVersion: 2
guid: 6a3c684705042f345975d924f6983e36
timeCreated: 1466788352
licenseType: Store
PluginImporter:
serializedVersion: 1
iconMap: {}
executionOrder: {}
isPreloaded: 0
platformData:
Android:
enabled: 1
settings:
CPU: AnyCPU
Any:
enabled: 0
settings: {}
Editor:
enabled: 0
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
Linux:
enabled: 0
settings:
CPU: x86
Linux64:
enabled: 0
settings:
CPU: x86_64
OSXIntel:
enabled: 0
settings:
CPU: AnyCPU
OSXIntel64:
enabled: 0
settings:
CPU: AnyCPU
SamsungTV:
enabled: 1
settings:
STV_MODEL: STANDARD_13
Tizen:
enabled: 1
settings: {}
WebGL:
enabled: 1
settings: {}
Win:
enabled: 0
settings:
CPU: AnyCPU
Win64:
enabled: 0
settings:
CPU: AnyCPU
WindowsStoreApps:
enabled: 1
settings:
CPU: AnyCPU
DontProcess: False
PlaceholderPath: Assets/JsonDotNet/Assemblies/Standalone/Newtonsoft.Json.dll
SDK: AnySDK
ScriptingBackend: Il2Cpp
iOS:
enabled: 1
settings:
CompileFlags:
FrameworkDependencies:
tvOS:
enabled: 1
settings: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 01ef782d02bb1994dbe418b69432552b
folderAsset: yes
timeCreated: 1466788344
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d6807fedb8dcaf04682d2c84f0ab753f
timeCreated: 1466788355
licenseType: Store
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,75 @@
fileFormatVersion: 2
guid: 17aef65a15b471f468b5fbeb4ff0c6a1
timeCreated: 1466788349
licenseType: Store
PluginImporter:
serializedVersion: 1
iconMap: {}
executionOrder: {}
isPreloaded: 0
platformData:
Android:
enabled: 0
settings:
CPU: AnyCPU
Any:
enabled: 0
settings: {}
Editor:
enabled: 1
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
Linux:
enabled: 1
settings:
CPU: x86
Linux64:
enabled: 1
settings:
CPU: x86_64
LinuxUniversal:
enabled: 1
settings:
CPU: AnyCPU
OSXIntel:
enabled: 1
settings:
CPU: AnyCPU
OSXIntel64:
enabled: 1
settings:
CPU: AnyCPU
OSXUniversal:
enabled: 1
settings:
CPU: AnyCPU
SamsungTV:
enabled: 0
settings:
STV_MODEL: STANDARD_13
Win:
enabled: 1
settings:
CPU: AnyCPU
Win64:
enabled: 1
settings:
CPU: AnyCPU
WindowsStoreApps:
enabled: 0
settings:
CPU: AnyCPU
DontProcess: False
PlaceholderPath:
SDK: AnySDK
ScriptingBackend: Il2Cpp
iOS:
enabled: 0
settings:
CompileFlags:
FrameworkDependencies:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 1418141139a6ac443b18cb05c0643a29
folderAsset: yes
timeCreated: 1466788345
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 36f7323c55864364d8bb88c736e4bca6
timeCreated: 1466788355
licenseType: Store
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
fileFormatVersion: 2
guid: 9b6ba260dada0ea4a871a42011f8b87d
timeCreated: 1466788355
licenseType: Store
PluginImporter:
serializedVersion: 1
iconMap: {}
executionOrder: {}
isPreloaded: 0
platformData:
Android:
enabled: 0
settings:
CPU: AnyCPU
Any:
enabled: 0
settings: {}
Editor:
enabled: 0
settings:
CPU: AnyCPU
DefaultValueInitialized: true
OS: AnyOS
Linux:
enabled: 0
settings:
CPU: x86
Linux64:
enabled: 0
settings:
CPU: x86_64
OSXIntel:
enabled: 0
settings:
CPU: AnyCPU
OSXIntel64:
enabled: 0
settings:
CPU: AnyCPU
SamsungTV:
enabled: 0
settings:
STV_MODEL: STANDARD_13
Win:
enabled: 0
settings:
CPU: AnyCPU
Win64:
enabled: 0
settings:
CPU: AnyCPU
WindowsStoreApps:
enabled: 1
settings:
CPU: AnyCPU
DontProcess: False
PlaceholderPath: Assets/JsonDotNet/Assemblies/Standalone/Newtonsoft.Json.dll
SDK: AnySDK
ScriptingBackend: DotNet
iOS:
enabled: 0
settings:
CompileFlags:
FrameworkDependencies:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<linker>
<assembly fullname="System">
<type fullname="System.ComponentModel.TypeConverter" preserve="all" />
<!-- <namespace fullname="System.ComponentModel" preserve="all" /> -->
</assembly>
</linker>

View File

@@ -0,0 +1,6 @@
fileFormatVersion: 2
guid: 06314f49bdda26043963578d60a0a7ee
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 83007d75ac9798343a7c69bae15e6ce3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: fa22137905c778947a383e10c3a9e800
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 1
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2f6ee4c168f3e364ab85faf457f75038
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,130 @@
using System.Collections.Generic;
using LitJson;
using UnityEngine;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: 19999af1b542c4040bea4b45f95d1807
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4ba7cabbe2806af4689ed667c89bb7ab
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: 47732fcfbdbefb94e9922877e93e81ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e7a14c1ddd696e74abc1460f63bf580c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,74 @@
namespace TEngine
{
/// <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,11 @@
fileFormatVersion: 2
guid: 13e1df50dc89375458f8e0e646cf3e0b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 076f0bb54d9835e45907ce6ea3147e72
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
using System.Collections.Generic;
using UnityEngine.Events;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: ce3d838c8607a1442acaee8b2ff1b7af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,125 @@
using System.Collections.Generic;
using System.Diagnostics;
using Debug = UnityEngine.Debug;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: 538182f774d67f0449e479ce28993300
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
namespace TEngine
{
/// <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,11 @@
fileFormatVersion: 2
guid: 80e398d58b294df4596e470547c69b01
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,149 @@
using System.Collections.Generic;
using UnityEngine;
namespace TEngine
{
/// <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,11 @@
fileFormatVersion: 2
guid: eab97947b9db71a47b27c473727f40bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,880 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TEngine
{
#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,11 @@
fileFormatVersion: 2
guid: d6ac57b69a5ba014c86bb71d54e8c24d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,341 @@
using System.Diagnostics;
using System.Text;
using UnityEngine;
using Debug = UnityEngine.Debug;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: 3db72e0120ff79a4cb83a29cbbc3df04
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,198 @@
using System.Collections.Generic;
using UnityEngine;
namespace TEngine
{
/// <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,11 @@
fileFormatVersion: 2
guid: 9f616a84727082041946279b89d4a1fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,110 @@
using UnityEngine;
namespace TEngine
{
/// <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,11 @@
fileFormatVersion: 2
guid: 3ff6e26c492126a4c84b39b2ce7a8423
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d941eb2d2cbae294bb5d2788bb724e80
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: 1abd052a77e45b44ebcde5803fb36afd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 385b1863dab169f4fa291611477e106c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
using TEngine;
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,11 @@
fileFormatVersion: 2
guid: fb5cf3287e9bf3949820b50049e4bd8c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d9d458a85873d744ab382e86008b89a0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
namespace TEngine
{
/// <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,11 @@
fileFormatVersion: 2
guid: 34a977c48d3bdb144b7c923a702164b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
namespace TEngine
{
/// <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,11 @@
fileFormatVersion: 2
guid: e93d874e10ffedf488c413fd5bbc012f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: 2dc3e456c545c0c419624e068b9249dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,236 @@
using System;
using System.Collections.Generic;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: af343da6b3090a24b92fc12aaa638411
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
namespace TEngine
{
/// <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,11 @@
fileFormatVersion: 2
guid: 003794832e9179348a633bdafe92ff3c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,233 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TEngine
{
/// <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,11 @@
fileFormatVersion: 2
guid: d2bd4af51a518164c8da0dff296b2bb1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,273 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: 9f5bc14d7a4aee34695c39d02ae1c71f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: c0ac8b7fabe2bae499a568608191eb57
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7fb8a7b6d364a024e8a49a0a731de201
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e7918afae3870234391c6e6f521e9ca7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02463b27b6971f0408bb517c32c66553
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bbe3f3f803983744f83757c6180a1c22
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,392 @@
using System;
using System.Collections.Generic;
using TEngine;
namespace TEngine
{
#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,11 @@
fileFormatVersion: 2
guid: c42c5b68ecfcd7849bc964b670a1217e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,37 @@
using System.Collections.Generic;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: aa2415431c50eaf468e5c8cc468ac47f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4d49eaeb5e19e9945add3faaf9921f10
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,130 @@
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: d47370f2bbc4b354d9d8b6cd95c9f3bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,96 @@
using System;
using System.IO;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: 3e93fa62068e31849833f7077a8179d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace TEngine
{
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,11 @@
fileFormatVersion: 2
guid: e1223cf4c8c7f0746968878b1e16f356
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bcb4b9a81c7ec9e4485ffdd16ea3b198
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0957d93b8c01bb74a8b6c8a6b15dede9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,234 @@
using System;
using System.Collections;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace Huatuo.Editor
{
enum EFILE_NAME
{
NONE,
HUATUO,
IL2CPP,
HUATUO_MAIN,
}
internal class HTEditorCache
{
private string libil2cppTagPrefix;
private string huatuoTagPrefix;
private int m_nDownloadTotal;
private int m_counter;
private int m_nSuccessCount;
private int m_nFailedCount;
private static HTEditorCache instance = null;
public static HTEditorCache Instance
{
get
{
if (instance == null)
{
instance = new HTEditorCache();
}
return instance;
}
}
private static string CacheDirName = ".huatuo_cache";
public string CacheBasePath;
HTEditorCache()
{
libil2cppTagPrefix = HTEditorConfig.libil2cppTagPrefixGithub;
huatuoTagPrefix = HTEditorConfig.huatuoTagPrefixGithub;
}
public void SetDownloadCount(int count)
{
m_nDownloadTotal = count;
m_counter = 0;
m_nSuccessCount = 0;
m_nFailedCount = 0;
}
public bool DownloadDone()
{
return m_nDownloadTotal == m_nFailedCount + m_nSuccessCount;
}
public bool DownloadSuccess()
{
return m_nDownloadTotal == m_nSuccessCount;
}
public void SetCacheDirectory(string path)
{
var tmp = "";
if (path == null || path.Length == 0)
{
tmp = Path.Combine(Path.GetFullPath("Library"), CacheDirName);
}
else
{
tmp = path;
}
try
{
Directory.CreateDirectory(tmp);
CacheBasePath = tmp;
HTEditorInstaller.Instance.SaveCacheDir();
}
catch (UnauthorizedAccessException ex)
{
Debug.LogError("缓存设置失败请不要使用C盘路径做缓存");
}
}
public string GetDownUrlWithTagHuatuo(string tag)
{
return $"{huatuoTagPrefix}/{tag}.zip";
}
public string GetDownUrlWithTagIl2cpp(string tag)
{
return $"{libil2cppTagPrefix}/{tag}.zip";
}
public string GetZipName(EFILE_NAME nameType, string tag)
{
var zipFileName = "";
switch (nameType)
{
case EFILE_NAME.HUATUO:
zipFileName = $"huatuo-{tag}";
break;
case EFILE_NAME.IL2CPP:
zipFileName = $"il2cpp_huatuo-{tag}";
break;
default:
throw new Exception($"no support file type{nameof(nameType)}");
}
return zipFileName;
}
public static string GetHuatuoZipInnerFolder(EFILE_NAME nameType, string tag)
{
switch (nameType)
{
case EFILE_NAME.HUATUO_MAIN:
return $"/huatuo-main/huatuo";
case EFILE_NAME.HUATUO:
return $"/huatuo-{tag}/huatuo";
}
return "error param";
}
public string GetZipPath(EFILE_NAME nameType, string tag)
{
var zipFileName = "";
switch (nameType)
{
case EFILE_NAME.HUATUO_MAIN:
zipFileName = $"huatuo-{tag}";
break;
case EFILE_NAME.HUATUO:
zipFileName = $"huatuo-{tag}";
break;
case EFILE_NAME.IL2CPP:
zipFileName = $"il2cpp_huatuo-{tag}";
break;
default:
throw new Exception($"no support file type{nameof(nameType)}");
}
return Path.Combine(CacheBasePath, $"{zipFileName}.zip");
}
public IEnumerator GetCache(EFILE_NAME nameType, string tag, string hashCode)
{
m_counter++;
var downloadUrl = "";
var zipFileName = "";
switch (nameType)
{
case EFILE_NAME.HUATUO_MAIN:
zipFileName = $"huatuo-{tag}";
downloadUrl = $"{HTEditorConfig.huatuoPrefixGithub}/main.zip";
break;
case EFILE_NAME.HUATUO:
zipFileName = $"huatuo-{tag}";
downloadUrl = $"{huatuoTagPrefix}/{tag}.zip";
break;
case EFILE_NAME.IL2CPP:
zipFileName = $"il2cpp_huatuo-{tag}";
downloadUrl = $"{libil2cppTagPrefix}/{tag}.zip";
break;
default:
throw new Exception($"no support file type{nameof(nameType)}");
}
var downloadErr = false;
var zipPath = Path.Combine(CacheBasePath, $"{zipFileName}.zip");
if (File.Exists(zipPath))
{
// TODO 校验文件MD5
Debug.Log($"Download {zipFileName}, use cache file: {zipPath}");
yield return null;
}
else
{
var curRetryCnt = 0;
var maxRetryCnt = 0;
var itor = HTEditorUtility.DownloadFile(downloadUrl, zipPath,
(curCnt, maxCnt) =>
{
curRetryCnt = curCnt;
maxRetryCnt = maxCnt;
},
p =>
{
var msg = $"下载中{(curRetryCnt > 0 ? $"[{curRetryCnt}/{maxRetryCnt}]" : "...")}";
EditorUtility.DisplayProgressBar(msg, $"{m_counter}/{m_nDownloadTotal}", p);
},
ret =>
{
EditorUtility.ClearProgressBar();
if (!string.IsNullOrEmpty(ret))
{
downloadErr = true;
EditorUtility.DisplayDialog("错误", $"下载{zipFileName}出错.\n{ret}", "ok");
}
});
while (itor.MoveNext())
{
yield return itor.Current;
}
if (!File.Exists(zipPath))
{
EditorUtility.DisplayDialog("错误", $"下载的文件{zipPath}不存在", "ok");
downloadErr = false;
}
//else if (MD5.ComputeFileMD5(zipPath).ToLower() != hashCode)
//{
// EditorUtility.DisplayDialog("错误", $"下载的文件{zipPath} hash不匹配请重新下载", "ok");
// downloadErr = false;
//}
}
if (downloadErr)
{
m_nFailedCount++;
}
else
{
m_nSuccessCount++;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e4c3edb7dda7a5d43b76ce5a048e80d2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,50 @@
using System;
using System.IO;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace Huatuo.Editor
{
/// <summary>
/// 这个类存放各种常量信息
/// </summary>
public static class HTEditorConfig
{
public static string UnityFullVersion = "";
public static string UnityVersionDigits = "";
//public static readonly string libil2cppPrefixGitee = "https://gitee.com/juvenior/il2cpp_huatuo/repository/archive";
//public static readonly string libil2cppPrefixGithub = "https://github.com/pirunxi/il2cpp_huatuo/archive/refs/heads";
//public static readonly string huatuoPrefixGitee = "https://gitee.com/focus-creative-games/huatuo/repository/archive";
public static readonly string huatuoPrefixGithub = "https://github.com/focus-creative-games/huatuo/archive/refs/heads/";
public static readonly string libil2cppTagPrefixGithub = "https://github.com/pirunxi/il2cpp_huatuo/archive/refs/tags";
public static readonly string huatuoTagPrefixGithub = "https://github.com/focus-creative-games/huatuo/archive/refs/tags";
public static readonly string urlVersionConfig = "https://focus-creative-games.github.io/huatuo_upm/Doc/version.json";
public static readonly string urlHuatuoCommits = "https://api.github.com/repos/focus-creative-games/huatuo/commits";
public static readonly string urlHuatuoTags = "https://api.github.com/repos/focus-creative-games/huatuo/tags";
private static readonly string WebSiteBase = "https://github.com/focus-creative-games/huatuo";
public static readonly string WebSite = WebSiteBase;
public static readonly string Document = WebSiteBase;
public static readonly string Changelog = WebSiteBase;
public static readonly string SupportedVersion = WebSiteBase + "/wiki/support_versions";
private static readonly string EditorBasePath = EditorApplication.applicationContentsPath;
public static readonly string HuatuoIL2CPPPath = EditorBasePath + "/il2cpp/libil2cpp";
public static readonly string HuatuoIL2CPPBackPath = EditorBasePath + "/il2cpp/libil2cpp_huatuo";
public static readonly string Il2cppPath = Path.Combine(EditorBasePath, "il2cpp");
public static readonly string Libil2cppPath = Path.Combine(Il2cppPath, "libil2cpp");
public static readonly string Libil2cppOritinalPath = Path.Combine(Il2cppPath, "libil2cpp_original_unity");
public static readonly string HuatuoPath = Path.Combine(HuatuoIL2CPPPath, "huatuo");
public static string DownloadCache = "";
public static string HuatuoVersionPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, ".huatuo");
public static void Init()
{
UnityFullVersion = InternalEditorUtility.GetFullUnityVersion();
UnityVersionDigits = InternalEditorUtility.GetUnityVersionDigits();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e4741bd22971475083f91e74c5434f77
timeCreated: 1652082272

View File

@@ -0,0 +1,405 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
namespace Huatuo.Editor
{
internal class HTEditorInstaller
{
private static HTEditorInstaller instance = null;
public static HTEditorInstaller Instance
{
get
{
if (instance == null)
{
instance = new HTEditorInstaller();
}
return instance;
}
}
HTEditorInstaller()
{
}
public void Init()
{
if (File.Exists(HTEditorConfig.HuatuoVersionPath))
{
var data = File.ReadAllText(HTEditorConfig.HuatuoVersionPath, Encoding.UTF8);
m_HuatuoVersion = JsonUtility.FromJson<HuatuoVersion>(data);
}
else
{
m_HuatuoVersion = default;
}
HTEditorCache.Instance.SetCacheDirectory(m_HuatuoVersion.CacheDir);
}
public void DoUninstall()
{
// backup libil2cpp
if (Directory.Exists(HTEditorConfig.Libil2cppOritinalPath))
{
if (Directory.Exists(HTEditorConfig.Libil2cppPath))
{
Directory.Delete(HTEditorConfig.Libil2cppPath, true);
}
Directory.Move(HTEditorConfig.Libil2cppOritinalPath, HTEditorConfig.Libil2cppPath);
}
m_InstallVersion.huatuoTag = "";
m_InstallVersion.il2cppTag = "";
SaveVersionLog();
// 不存在原始备份目录
// TODO 这里考虑下是否帮用户下载libil2cpp
}
public static void Enable(Action<string> callback)
{
var mv1 = HTEditorUtility.Mv(HTEditorConfig.Libil2cppPath, HTEditorConfig.Libil2cppOritinalPath);
if (!string.IsNullOrEmpty(mv1))
{
Debug.LogError(mv1);
callback?.Invoke(mv1);
return;
}
mv1 = HTEditorUtility.Mv(HTEditorConfig.HuatuoIL2CPPBackPath, HTEditorConfig.HuatuoIL2CPPPath);
if (!string.IsNullOrEmpty(mv1))
{
Debug.LogError(mv1);
callback?.Invoke(mv1);
return;
}
callback?.Invoke(null);
}
public static void Disable(Action<string> callback)
{
var mv1 = HTEditorUtility.Mv(HTEditorConfig.HuatuoIL2CPPPath, HTEditorConfig.HuatuoIL2CPPBackPath);
if (!string.IsNullOrEmpty(mv1))
{
Debug.LogError(mv1);
callback?.Invoke(mv1);
return;
}
mv1 = HTEditorUtility.Mv(HTEditorConfig.Libil2cppOritinalPath, HTEditorConfig.Libil2cppPath);
if (!string.IsNullOrEmpty(mv1))
{
Debug.LogError(mv1);
callback?.Invoke(mv1);
return;
}
callback?.Invoke(null);
}
public static void Uninstall(Action<string> callback)
{
Disable(ret =>
{
if (!string.IsNullOrEmpty(ret))
{
callback?.Invoke(ret);
return;
}
if (Directory.Exists(HTEditorConfig.HuatuoIL2CPPBackPath))
{
Directory.Delete(HTEditorConfig.HuatuoIL2CPPBackPath, true);
}
callback?.Invoke(null);
});
}
public InstallVersion m_InstallVersion; // 当前安装临时使用的版本数据
public HuatuoVersion m_HuatuoVersion; // 已安装的版本信息
private bool m_bDoBackup;
private string m_sBackupFileName;
private IEnumerator Extract(Action<bool> callback)
{
var il2cppZip = HTEditorCache.Instance.GetZipPath(EFILE_NAME.IL2CPP, m_InstallVersion.il2cppTag);
var huatuozip = HTEditorCache.Instance.GetZipPath(m_InstallVersion.huatuoType, m_InstallVersion.huatuoTag);
var il2cppCachePath = Path.GetDirectoryName(il2cppZip) + $"/il2cpp_huatuo-{m_InstallVersion.il2cppTag}";
var huatuoCachePath = Path.GetDirectoryName(huatuozip) + $"/huatuo-{m_InstallVersion.huatuoTag}";
var cnt = 0;
var haserr = false;
var itor = HTEditorUtility.UnzipAsync(il2cppZip, il2cppCachePath, b => { cnt = b; },
p => { EditorUtility.DisplayProgressBar("解压中...", $"il2cpp:{p}/{cnt}", (float) p / cnt); }, null,
() => { haserr = true; });
while (itor.MoveNext())
{
yield return itor.Current;
}
EditorUtility.ClearProgressBar();
if (haserr)
{
callback?.Invoke(true);
yield break;
}
cnt = 0;
itor = HTEditorUtility.UnzipAsync(huatuozip, huatuoCachePath, b => { cnt = b; },
p => { EditorUtility.DisplayProgressBar("解压中...", $"huatuo:{p}/{cnt}", (float) p / cnt); }, null,
() => { haserr = true; });
while (itor.MoveNext())
{
yield return itor.Current;
}
EditorUtility.ClearProgressBar();
if (haserr)
{
callback?.Invoke(true);
yield break;
}
var il2cppDirName = il2cppCachePath + $"/il2cpp_huatuo-{m_InstallVersion.il2cppTag}/libil2cpp";
var huatuoDirName = huatuoCachePath + HTEditorCache.GetHuatuoZipInnerFolder(m_InstallVersion.huatuoType, m_InstallVersion.huatuoTag);
if (!Directory.Exists(il2cppDirName))
{
Debug.LogError($"{il2cppDirName} not exists!!!");
callback?.Invoke(true);
yield break;
}
if (!Directory.Exists(huatuoDirName))
{
Debug.LogError($"{huatuoDirName} not exists!!!");
callback?.Invoke(true);
yield break;
}
try
{
if (Directory.Exists(HTEditorConfig.Libil2cppPath))
{
Directory.Delete(HTEditorConfig.Libil2cppPath, true);
}
HTEditorUtility.CopyFilesRecursively(il2cppDirName, HTEditorConfig.HuatuoIL2CPPPath);
HTEditorUtility.CopyFilesRecursively(huatuoDirName, HTEditorConfig.HuatuoPath);
}
catch (Exception ex)
{
Debug.LogException(ex);
haserr = true;
}
callback?.Invoke(haserr);
}
public IEnumerator Install(InstallVersion installVersion, Action<bool> callback)
{
this.m_InstallVersion = installVersion;
Debug.Log("备份il2cpp目录");
var task = Task.Run(BackupLibil2cpp);
while (!task.IsCompleted)
{
yield return null;
}
var hasErr = false;
var itor = Extract(r => { hasErr = r; });
while (itor.MoveNext())
{
yield return itor.Current;
}
if (hasErr)
{
RevertInstall();
callback?.Invoke(false);
yield break;
}
task = Task.Run(SaveVersionLog);
while (!task.IsCompleted)
{
yield return null;
}
task = Task.Run(DelBackupLibil2cpp);
while (!task.IsCompleted)
{
yield return null;
}
callback?.Invoke(true);
}
public void RevertInstall()
{
m_InstallVersion.huatuoTag = m_HuatuoVersion.HuatuoTag;
m_InstallVersion.il2cppTag = m_HuatuoVersion.Il2cppTag;
if (!m_bDoBackup)
{
return;
}
string installPathBak = Path.Combine(HTEditorConfig.Il2cppPath, m_sBackupFileName);
// backup libil2cpp
if (Directory.Exists(installPathBak))
{
Directory.Delete(HTEditorConfig.Libil2cppPath, true);
Directory.Move(installPathBak, HTEditorConfig.Libil2cppPath);
}
}
public void DelBackupLibil2cpp()
{
if (!m_bDoBackup)
{
return;
}
string installPathBak = Path.Combine(HTEditorConfig.Il2cppPath, m_sBackupFileName);
// backup libil2cpp
if (Directory.Exists(installPathBak))
{
Directory.Delete(installPathBak, true);
}
}
public void BackupLibil2cpp()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
m_sBackupFileName = $"libil2cpp_{ts.TotalSeconds}";
string installPathBak = Path.Combine(HTEditorConfig.Il2cppPath, m_sBackupFileName);
string original = Path.Combine(HTEditorConfig.Il2cppPath, "libil2cpp_original_unity");
if (!Directory.Exists(HTEditorConfig.Libil2cppPath))
{
return;
}
// backup libil2cpp original
if (!Directory.Exists(original))
{
Directory.Move(HTEditorConfig.Libil2cppPath, original);
}
if (Directory.Exists(HTEditorConfig.Libil2cppPath))
{
m_bDoBackup = true;
Directory.Move(HTEditorConfig.Libil2cppPath, installPathBak);
}
}
public void SaveVersionLog()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
// TODO 记录libil2cpp 和 huatuo 版本信息
m_HuatuoVersion.HuatuoTag = m_InstallVersion.huatuoTag;
m_HuatuoVersion.Il2cppTag = m_InstallVersion.il2cppTag;
//m_HuatuoVersion.Il2cppUrl = HTEditorCache.Instance.GetDownUrlWithTagIl2cpp(m_InstallVersion.il2cppTag);
//m_HuatuoVersion.HuatuoUrl = HTEditorCache.Instance.GetDownUrlWithTagHuatuo(m_InstallVersion.huatuoTag);
m_HuatuoVersion.InstallTime = DateTime.Now.ToString();
m_HuatuoVersion.Timestamp = Convert.ToInt64(ts.TotalMilliseconds);
Debug.Log($"Save huatuo install version, path: {HTEditorConfig.HuatuoVersionPath}");
File.WriteAllText(HTEditorConfig.HuatuoVersionPath, JsonUtility.ToJson(m_HuatuoVersion, true),
Encoding.UTF8);
}
public void SaveCacheDir()
{
m_HuatuoVersion.CacheDir = HTEditorCache.Instance.CacheBasePath;
File.WriteAllText(HTEditorConfig.HuatuoVersionPath, JsonUtility.ToJson(m_HuatuoVersion, true),
Encoding.UTF8);
}
/*
public static HuatuoRemoteConfig GetVersionData()
{
var data = File.ReadAllText(HTEditorConfig.HuatuoVersionPath, Encoding.UTF8);
return JsonUtility.FromJson<HuatuoRemoteConfig>(data);
}
public static bool Extract(string zipPath, string extractDir, string installPath)
{
var result = ExtractZip(zipPath, extractDir, installPath);
return result.Count > 0;
}
public static List<string> ExtractZip(string zipFilePath, string relativePath, string destPath)
{
var result = new List<string>();
relativePath = relativePath.Replace(@"\", @"/");
using (FileStream zipToOpen = new FileStream(zipFilePath, FileMode.Open))
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Read))
{
var entry = archive.Entries.FirstOrDefault(x => x.FullName.ToUpper() == relativePath.ToUpper());
if (entry == null)
entry = archive.Entries.FirstOrDefault(x =>
x.FullName.ToUpper() == (relativePath + "/").ToUpper());
if (!string.IsNullOrWhiteSpace(entry.Name))
{
var path = Path.Combine(destPath, entry.Name);
using (var file = new FileStream(path, FileMode.Create, FileAccess.Write))
{
entry.Open().CopyTo(file);
file.Close();
}
result.Add(path);
}
else
{
var items = archive.Entries.Where(x => x.FullName.StartsWith(entry.FullName)).ToList();
foreach (var item in items.Where(x => string.IsNullOrWhiteSpace(x.Name)).OrderBy(x => x.Length))
{
var path = Path.Combine(destPath, item.FullName.Substring(entry.FullName.Length));
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
}
foreach (var item in items.Where(x => !string.IsNullOrWhiteSpace(x.Name))
.OrderBy(x => x.Length))
{
var path = new FileInfo(Path.Combine(destPath,
item.FullName.Substring(entry.FullName.Length))).Directory.FullName;
path = Path.Combine(path, item.Name);
using (var file = new FileStream(path, FileMode.Create, FileAccess.Write))
{
item.Open().CopyTo(file);
file.Close();
}
result.Add(path);
}
}
}
}
return result;
}*/
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b59a820a925dfaa4cad33934824d7a5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More