diff --git a/Unity/Assets/Scripts/TH1_Data/MapData.cs b/Unity/Assets/Scripts/TH1_Data/MapData.cs index 3a0595058..5825c527b 100644 --- a/Unity/Assets/Scripts/TH1_Data/MapData.cs +++ b/Unity/Assets/Scripts/TH1_Data/MapData.cs @@ -16,6 +16,7 @@ using Logic; using Logic.Action; using Logic.AI; using Logic.CrashSight; +using Logic.Pool; using Logic.Skill; using MemoryPack; using TH1_Core.Events; @@ -434,7 +435,7 @@ namespace RuntimeData // 通过玩家 ID 查找首都城市 cityData public bool GetCapitalCityDataByPlayerId(uint pid, out CityData cityData) { - var cityList = new List(); + using var pooledCityList = THCollectionPool.GetListHandle(out var cityList); GetCityDataListByPlayerId(pid, cityList); foreach (var city in cityList) { @@ -467,7 +468,7 @@ namespace RuntimeData CollectManager.Instance.PlayerGameEndCollect(this, oldPlayerData, newPlayerData); //step #2 所有unit都销毁 - var unitDataList = new List(); + using var pooledUnitDataList = THCollectionPool.GetListHandle(out var unitDataList); GetUnitDataListByCityId(cid,unitDataList); foreach (var unitData in unitDataList) unitData.Renderer(this)?.Die(); @@ -502,7 +503,7 @@ namespace RuntimeData } } //开始将所有cid的小兵都转移到oldPlayerCapitalCityData下去 - var tmpUnitDataList = new List(); + using var pooledTmpUnitDataList = THCollectionPool.GetListHandle(out var tmpUnitDataList); GetUnitDataListByCityId(cid, tmpUnitDataList); foreach(var tmpUnitData in tmpUnitDataList) SetUnitIdToCityId(tmpUnitData.Id,oldPlayerCapitalCityData.Id); @@ -1588,9 +1589,7 @@ namespace RuntimeData gameRecord.Score = PlayerMap.SelfPlayerData.PlayerScore; DateTime now = DateTime.Now; gameRecord.Time = now.ToString("yyyy.MM.dd HH:mm"); - var cityList = new List(); - GetCityDataListByPlayerId(PlayerMap.SelfPlayerId, cityList); - gameRecord.CityCount = (uint)cityList.Count; + gameRecord.CityCount = (uint)GetCityCount(PlayerMap.SelfPlayerId); gameRecord.MapWidth = MapConfig.Width; gameRecord.MapHeight = MapConfig.Height; gameRecord.PlayerCount = MapConfig.PlayerCount; diff --git a/Unity/Assets/Scripts/TH1_Data/PlayerData.cs b/Unity/Assets/Scripts/TH1_Data/PlayerData.cs index a073e0cb1..17e444d8e 100644 --- a/Unity/Assets/Scripts/TH1_Data/PlayerData.cs +++ b/Unity/Assets/Scripts/TH1_Data/PlayerData.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using Logic.Action; using Logic.AI; using Logic.Audio; +using Logic.Pool; using MemoryPack; using NUnit.Framework; using TH1_Core.Events; @@ -1023,7 +1024,7 @@ namespace RuntimeData public void Surrender(MapData map) { IsSurrender = true; - var selfUnits = new HashSet(); + using var pooledSelfUnits = THCollectionPool.GetHashSetHandle(out var selfUnits); map.GetUnitDataListByPlayerId(Id, selfUnits); // 先播放Fog特效并销毁渲染层,再清除数据层 foreach (var unit in selfUnits) @@ -1569,7 +1570,7 @@ namespace RuntimeData _tmpGridListBuf ??= new List(); _tmpGridListBuf.Clear(); map.GridMap.GetAroundGridData(1, 1, cityGrid, _tmpGridListBuf); - var randomList = new List(); + using var pooledRandomList = THCollectionPool.GetListHandle(out var randomList); foreach (var grid in _tmpGridListBuf) { if (grid == cityGrid) continue; diff --git a/Unity/Assets/Scripts/TH1_Logic/AI/AIActionBase.cs b/Unity/Assets/Scripts/TH1_Logic/AI/AIActionBase.cs index d282be19f..0abedbb9f 100644 --- a/Unity/Assets/Scripts/TH1_Logic/AI/AIActionBase.cs +++ b/Unity/Assets/Scripts/TH1_Logic/AI/AIActionBase.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using Logic.Action; using Logic.CrashSight; +using Logic.Pool; using MemoryPack; using OPS.Obfuscator.Attribute; using RuntimeData; @@ -2434,7 +2435,7 @@ namespace Logic.AI public void CheckIsActionInPlayerSight() { IsInSight = true; - var checkGridList = new List(); + using var pooledCheckGridList = THCollectionPool.GetListHandle(out var checkGridList); if (Param.MapData.GridMap.GetGridDataByGid(Param.GridId, out var targetGrid)) checkGridList.Add(targetGrid); if (Param.MapData.GetGridDataByUnitId(Param.UnitId, out var unitGrid) ) checkGridList.Add(unitGrid); if (Param.MapData.GetGridDataByUnitId(Param.TargetUnitId, out var targetUnit)) checkGridList.Add(targetUnit); diff --git a/Unity/Assets/Scripts/TH1_Logic/AI/AIActionGenerator.cs b/Unity/Assets/Scripts/TH1_Logic/AI/AIActionGenerator.cs index 29e7a6900..c60e16cc9 100644 --- a/Unity/Assets/Scripts/TH1_Logic/AI/AIActionGenerator.cs +++ b/Unity/Assets/Scripts/TH1_Logic/AI/AIActionGenerator.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using Logic.Action; using Logic.CrashSight; +using Logic.Pool; using RuntimeData; using TH1_Logic.Action; using TH1_Logic.Core; @@ -279,9 +280,9 @@ namespace Logic.AI var data = new AICalculatorData(); data.Map = map; data.Player = selfPlayer; - var selfUnits = new HashSet(); + using var pooledSelfUnits = THCollectionPool.GetHashSetHandle(out var selfUnits); map.GetUnitDataListByPlayerId(selfPlayer.Id, selfUnits); - var selfCities = new HashSet(); + using var pooledSelfCities = THCollectionPool.GetHashSetHandle(out var selfCities); map.GetCityDataListByPlayerId(selfPlayer.Id, selfCities); data.TargetParam.MapData = map; @@ -343,9 +344,9 @@ namespace Logic.AI var data = new AICalculatorData(); data.Map = map; data.Player = selfPlayer; - var selfUnits = new HashSet(); + using var pooledSelfUnits = THCollectionPool.GetHashSetHandle(out var selfUnits); map.GetUnitDataListByPlayerId(selfPlayer.Id, selfUnits); - var selfCities = new HashSet(); + using var pooledSelfCities = THCollectionPool.GetHashSetHandle(out var selfCities); map.GetCityDataListByPlayerId(selfPlayer.Id, selfCities); data.TargetParam.MapData = map; @@ -731,4 +732,4 @@ namespace Logic.AI } } } -} \ No newline at end of file +} diff --git a/Unity/Assets/Scripts/TH1_Logic/AI/AIActionScoreCalculator.cs b/Unity/Assets/Scripts/TH1_Logic/AI/AIActionScoreCalculator.cs index 7a6e0c3cc..bd67191df 100644 --- a/Unity/Assets/Scripts/TH1_Logic/AI/AIActionScoreCalculator.cs +++ b/Unity/Assets/Scripts/TH1_Logic/AI/AIActionScoreCalculator.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Diagnostics; using Logic.Action; using Logic.CrashSight; +using Logic.Pool; using TH1_Logic.Core; using UnityEngine; using Debug = UnityEngine.Debug; @@ -764,7 +765,7 @@ namespace Logic.AI { //TODO Check PlayerData Right if (aiAction.Param.GridData.VisibleUnit(aiAction.Param.MapData,aiAction.Param.PlayerData, out _)) return false; - var selfCity = new HashSet(); + using var pooledSelfCity = THCollectionPool.GetHashSetHandle(out var selfCity); aiAction.Param.MapData.GetCityDataListByPlayerId(aiAction.Param.PlayerData.Id, selfCity); if (!selfCity.Contains(city)) return true; } diff --git a/Unity/Assets/Scripts/TH1_Logic/AITrain/TrainingState.cs b/Unity/Assets/Scripts/TH1_Logic/AITrain/TrainingState.cs index a5fec5f1b..3f88425c4 100644 --- a/Unity/Assets/Scripts/TH1_Logic/AITrain/TrainingState.cs +++ b/Unity/Assets/Scripts/TH1_Logic/AITrain/TrainingState.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using Logic.Action; using Logic.AI; using Logic.CrashSight; +using Logic.Pool; using MemoryPack; using RuntimeData; using TH1_Logic.Core; @@ -36,13 +37,13 @@ namespace TH1_Logic.AITrain // 2 + 40 + 400 + 160 + 200 = 802 维度 public float[] GetMapState(MapData map, PlayerData selfPlayer) { - List state = new(); + using var pooledState = THCollectionPool.GetListHandle(out var state); // 1. 己方信息 - var selfUnits = new HashSet(); + using var pooledSelfUnits = THCollectionPool.GetHashSetHandle(out var selfUnits); map.GetUnitDataListByPlayerId(selfPlayer.Id, selfUnits); - var selfCities = new HashSet(); + using var pooledSelfCities = THCollectionPool.GetHashSetHandle(out var selfCities); map.GetCityDataListByPlayerId(selfPlayer.Id, selfCities); var maxScore = map.PlayerMap.GetMaxPlayerScore(); @@ -51,8 +52,8 @@ namespace TH1_Logic.AITrain // 我的 Player Index state.Add(GetPlayerIndex(map, selfPlayer.Id) / 10f); - var units = new List(); - var cities = new List(); + using var pooledUnits = THCollectionPool.GetListHandle(out var units); + using var pooledCities = THCollectionPool.GetListHandle(out var cities); foreach (var id in selfPlayer.Sight.SightGidSet) { //TODO 白哉确认 @@ -376,7 +377,7 @@ namespace TH1_Logic.AITrain private float GetUnitsScore(MapData mapData, PlayerData playerData) { float score = 0f; - var units = new HashSet(); + using var pooledUnits = THCollectionPool.GetHashSetHandle(out var units); mapData.GetUnitDataListByPlayerId(playerData.Id, units); foreach (var unit in mapData.UnitMap.UnitList) { @@ -392,7 +393,7 @@ namespace TH1_Logic.AITrain private float GetCityScore(MapData mapData, PlayerData playerData) { float score = 0f; - var cities = new HashSet(); + using var pooledCities = THCollectionPool.GetHashSetHandle(out var cities); mapData.GetCityDataListByPlayerId(playerData.Id, cities); foreach (var city in mapData.CityMap.CityList) { @@ -538,4 +539,4 @@ namespace TH1_Logic.AITrain return true; } } -} \ No newline at end of file +} diff --git a/Unity/Assets/Scripts/TH1_Logic/Achievement/AchievementCondition.cs b/Unity/Assets/Scripts/TH1_Logic/Achievement/AchievementCondition.cs index 96a2e811b..ddf16fce5 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Achievement/AchievementCondition.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Achievement/AchievementCondition.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using Logic.Pool; using RuntimeData; using UnityEngine; @@ -661,7 +662,7 @@ namespace Logic.Achievement map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf); _recordCount = 0; - var selfUnits = new HashSet(); + using var pooledSelfUnits = THCollectionPool.GetHashSetHandle(out var selfUnits); map.GetUnitDataListByPlayerId(map.PlayerMap.SelfPlayerId, selfUnits); foreach (var aroundGrid in _aroundBuf) { @@ -747,7 +748,7 @@ namespace Logic.Achievement map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf); _recordCount = 0; - var selfUnits = new HashSet(); + using var pooledSelfUnits = THCollectionPool.GetHashSetHandle(out var selfUnits); map.GetUnitDataListByPlayerId(map.PlayerMap.SelfPlayerId, selfUnits); foreach (var aroundGrid in _aroundBuf) { @@ -867,4 +868,4 @@ namespace Logic.Achievement return false; } } -} \ No newline at end of file +} diff --git a/Unity/Assets/Scripts/TH1_Logic/Action/ActionLogic.cs b/Unity/Assets/Scripts/TH1_Logic/Action/ActionLogic.cs index 8482c89e5..0eae73408 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Action/ActionLogic.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Action/ActionLogic.cs @@ -1214,7 +1214,6 @@ namespace Logic.Action && _actionId.ActionType != CommonActionType.TurnStart && _actionId.ActionType != CommonActionType.AIParamControl) { - LogSystem.LogWarning($"{Time.time}"); foreach (var pData in actionParams.MapData.PlayerMap.PlayerDataList) { pData.RefreshFeelingValue(actionParams.MapData); @@ -1231,9 +1230,10 @@ namespace Logic.Action EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateCulturePerTurn }); EventManager.Publish(new UpdateUITopTopBar() { UpdateType = UpdateTopBarType.UpdateFaith }); } - Main.PlayerLogic.Update(actionParams.MapData); if (actionParams.MapData == Main.MapData) { + // AI 演算不调用 PlayerLogic.Update,节省性能 + Main.PlayerLogic.Update(actionParams.MapData); MatchSettlementLogicFactory.RefreshMatchSettlementInfo(actionParams.MapData); foreach (var item in actionParams.PlayerData.MomentData.Items) { diff --git a/Unity/Assets/Scripts/TH1_Logic/City/CityLogic.cs b/Unity/Assets/Scripts/TH1_Logic/City/CityLogic.cs index 34f6ad516..648351d77 100644 --- a/Unity/Assets/Scripts/TH1_Logic/City/CityLogic.cs +++ b/Unity/Assets/Scripts/TH1_Logic/City/CityLogic.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Collections.Generic; using Logic.CrashSight; +using Logic.Pool; using MongoDB.Driver.Core.Misc; using ParadoxNotion; using UnityEngine; @@ -357,7 +358,7 @@ namespace Logic Main.PlayerLogic.UpdateSight_LogicView(mapData,playerData,mapData.GridMap.GetAroundGridIdList(2,gridData)); - var newTerritoryArea = new List(); + using var pooledNewTerritoryArea = THCollectionPool.GetListHandle(out var newTerritoryArea); foreach (var aroundGrid in _aroundBuf) { @@ -545,7 +546,7 @@ namespace Logic int x = gridData.Pos.X; int y = gridData.Pos.Y; bool ret = false; - HashSet haveType = new HashSet(); + using var pooledHaveType = THCollectionPool.GetHashSetHandle(out var haveType); for(int i = 0;i<=1;i++) for (int j = 0; j <= 1; j++) { diff --git a/Unity/Assets/Scripts/TH1_Logic/Map/MapGenerator.cs b/Unity/Assets/Scripts/TH1_Logic/Map/MapGenerator.cs index 6972371bc..c8d5e3758 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Map/MapGenerator.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Map/MapGenerator.cs @@ -10,6 +10,7 @@ using UnityEngine; using System; using System.Collections.Generic; using System.Linq; +using Logic.Pool; using RuntimeData; using TH1_Logic.Core; using Unity.VisualScripting; @@ -1140,14 +1141,14 @@ namespace Logic if (leyLineCount <= 0) return; // Step #2 构建首都排除区(仅首都±1范围,非首都村庄不排除) - var cradleExclude = new HashSet(); + using var pooledCradleExclude = THCollectionPool.GetHashSetHandle(out var cradleExclude); foreach (var cradle in PlayerCivOri) for (int x = cradle.X - 1; x <= cradle.X + 1; x++) for (int y = cradle.Y - 1; y <= cradle.Y + 1; y++) cradleExclude.Add(MapPosition.CalculatePosId(x, y)); // Step #3 收集候选格子:陆地 + 非CityCenter + 不在首都1格范围内 - var candidates = new List(); + using var pooledCandidates = THCollectionPool.GetListHandle(out var candidates); foreach (var gridData in mapData.GridMap.GridList) { if (gridData.Terrain != TerrainType.Land) continue; @@ -1207,4 +1208,4 @@ namespace Logic } -} \ No newline at end of file +} diff --git a/Unity/Assets/Scripts/TH1_Logic/Player/PlayerLogic.cs b/Unity/Assets/Scripts/TH1_Logic/Player/PlayerLogic.cs index fed4e99aa..639a2034a 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Player/PlayerLogic.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Player/PlayerLogic.cs @@ -6,6 +6,7 @@ using Logic.Action; using Logic.Audio; using Logic.Config; using Logic.CrashSight; +using Logic.Pool; using Logic.Skill; using TH1_Anim; using TH1_Anim.Fragments; @@ -485,7 +486,7 @@ namespace Logic //Step #6 处理占领城市的特效(所有领土会升起一面旗帜 - HashSet gridList = new HashSet(); + using var pooledGridList = THCollectionPool.GetHashSetHandle(out var gridList); cityData.Territory.GetAllTerritoryArea(gridList); foreach (var gd in gridList) { @@ -510,7 +511,8 @@ namespace Logic foreach (var tg in _tmpAroundBuf) tg.Renderer(mapData)?.InstantUpdateGrid(true); - List list = new List(cityData.Territory.TerritoryArea); + using var pooledTerritoryList = THCollectionPool.GetListHandle(out var list); + list.AddRange(cityData.Territory.TerritoryArea); //更新player的视野 Main.PlayerLogic.UpdateSight_LogicView(mapData, playerData, list); @@ -706,9 +708,9 @@ namespace Logic //step #1 初始化,将联通的城市存于Hashset中 if (playerData == null) return; if (!mapData.GetCapitalCityDataByPlayerId(playerData.Id, out var capitalCity)) return; - var cityList = new List(); + using var pooledCityList = THCollectionPool.GetListHandle(out var cityList); mapData.GetCityDataListByPlayerId(playerData.Id, cityList); - var connectList = new HashSet(); + using var pooledConnectList = THCollectionPool.GetHashSetHandle(out var connectList); //Step #2 如果玩家还有原始首都,计算联通情况,否则所有城市都是不联通 if (playerData.CradleCityId == capitalCity.Id) { @@ -731,7 +733,7 @@ namespace Logic var citySet = mapData.GetCityDataSetByPlayerId(playerData.Id); var gridSet = mapData.GetGridDataSetByPlayerId(playerData.Id); //获取所有视野内的grid,然后去除非盟友的有主海域,去除所有土地,这是所有港口可以计算最短路的格子,用来计算通路用的 - var waterRoadGidSet = new HashSet(); + using var pooledWaterRoadGidSet = THCollectionPool.GetHashSetHandle(out var waterRoadGidSet); foreach (var gid in playerData.Sight.SightGidSet) if (mapData.GridMap.GetGridDataByGid(gid, out var grid) && grid.Terrain != TerrainType.Land) { @@ -767,9 +769,9 @@ namespace Logic //Debug.Log($"candidatePort is {portCandidate.Id}"); // 记录前驱节点 - var prev = new Dictionary(); - var dist = new Dictionary(); - var visited = new HashSet(); + using var pooledPrev = THCollectionPool.GetDictionaryHandle(out var prev); + using var pooledDist = THCollectionPool.GetDictionaryHandle(out var dist); + using var pooledVisited = THCollectionPool.GetHashSetHandle(out var visited); // 初始港口格子 uint startId = portCandidate.Id; @@ -828,9 +830,9 @@ namespace Logic //如果step步以内已经可达targetPort,那么也不需要新增最短路 int step = 6; - var visitedSet = new HashSet(); - var startSet = new HashSet(); - var nextSet = new HashSet(); + using var pooledVisitedSet = THCollectionPool.GetHashSetHandle(out var visitedSet); + using var pooledStartSet = THCollectionPool.GetHashSetHandle(out var startSet); + using var pooledNextSet = THCollectionPool.GetHashSetHandle(out var nextSet); startSet.Add(portCandidate.Id); while(step > 0) { @@ -848,8 +850,10 @@ namespace Logic nextSet.Add(tmpAroundGrid.Id); } + var swap = startSet; startSet = nextSet; - nextSet = new HashSet(); + nextSet = swap; + nextSet.Clear(); step--; } @@ -912,7 +916,7 @@ namespace Logic //#1-5 从首都出发,进行floodfill,计算哪些城市可以被抵达。是否联通,只需要判断两个格子是否都具有road属性即可(不过有些文明要特殊判断) - var cn = new HashSet(); + using var pooledCn = THCollectionPool.GetHashSetHandle(out var cn); //floodfill算一遍从首都出发的连通性 if (!mapData.GetCapitalCityDataByPlayerId(playerData.Id, out var capital)) return; if (!mapData.GetGridDataByCityId(capital.Id, out var capitalGrid)) return; @@ -1110,7 +1114,11 @@ namespace Logic if (p1.TechTree.CheckIfHasTech(TechType.Diplomacy)) { if(map.GetGridIdByCityId(p2.CradleCityId, out var cradleGid)) - UpdateSight_LogicView(map,p1,new List{cradleGid}); + { + using var pooledGidList = THCollectionPool.GetListHandle(out var gidList); + gidList.Add(cradleGid); + UpdateSight_LogicView(map, p1, gidList); + } } //step #5 @@ -1219,7 +1227,11 @@ namespace Logic if (!atomInfo.IsAddSkill) continue; //是否给全员增加,还是有条件增加 bool forAll = atomInfo.AddSkillCondition.Count == 0; - var condition = new HashSet(atomInfo.AddSkillCondition); + using var pooledCondition = THCollectionPool.GetHashSetHandle(out var condition); + if (!forAll) + { + condition.UnionWith(atomInfo.AddSkillCondition); + } foreach (var unit in mapData.UnitMap.UnitList) { if (!mapData.CheckUnitIdBelongPlayerId(unit.Id, playerData.Id)) continue; @@ -1545,7 +1557,7 @@ namespace Logic public void DebugGetAllSight(MapData mapData, PlayerData playerData) { - var gidList = new List(); + using var pooledGidList = THCollectionPool.GetListHandle(out var gidList); foreach(var gridData in mapData.GridMap.GridList) gidList.Add(gridData.Id); UpdateSight_LogicView(mapData,playerData,gidList); @@ -1563,7 +1575,9 @@ namespace Logic if (player.Id == playerId) continue; if (!map.PlayerMap.GetPlayerDataByPlayerID(playerId, out var player2)) continue; if (!map.GetGridDataByCityId(player2.CradleCityId, out var grid)) continue; - UpdateSight_LogicView(map, player, new List { grid.Id }); + using var pooledGidList = THCollectionPool.GetListHandle(out var gidList); + gidList.Add(grid.Id); + UpdateSight_LogicView(map, player, gidList); } if (count != player.MeetPlayers.Count) continue; diff --git a/Unity/Assets/Scripts/TH1_Logic/Pool.meta b/Unity/Assets/Scripts/TH1_Logic/Pool.meta new file mode 100644 index 000000000..807a97981 --- /dev/null +++ b/Unity/Assets/Scripts/TH1_Logic/Pool.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 74a09dcb039c66b43b201022058a7491 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/Assets/Scripts/TH1_Logic/Pool/THCollectionPool.cs b/Unity/Assets/Scripts/TH1_Logic/Pool/THCollectionPool.cs new file mode 100644 index 000000000..666197d72 --- /dev/null +++ b/Unity/Assets/Scripts/TH1_Logic/Pool/THCollectionPool.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Logic.Pool +{ + /// + /// Lightweight collection pool for temporary List/Dictionary/HashSet allocations. + /// + public static class THCollectionPool + { + private const int DefaultMaxPoolSizePerType = 256; + + private static class TypePool where T : class, new() + { + internal static readonly Stack Items = new Stack(32); + internal static readonly object Sync = new object(); + internal static readonly Action Reset = BuildResetAction(); + + private static Action BuildResetAction() + { + var type = typeof(T); + if (typeof(IDictionary).IsAssignableFrom(type)) + { + return instance => ((IDictionary)instance).Clear(); + } + + if (typeof(IList).IsAssignableFrom(type)) + { + return instance => ((IList)instance).Clear(); + } + + var clearMethod = type.GetMethod("Clear", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null); + if (clearMethod == null) + { + return _ => { }; + } + + try + { + return (Action)Delegate.CreateDelegate(typeof(Action), null, clearMethod); + } + catch + { + return instance => clearMethod.Invoke(instance, null); + } + } + } + + public static T Get() where T : class, new() + { + var pool = TypePool.Items; + lock (TypePool.Sync) + { + if (pool.Count > 0) + { + return pool.Pop(); + } + } + + return new T(); + } + + public static void Release(T instance) where T : class, new() + { + if (instance == null) + { + return; + } + + TypePool.Reset(instance); + var pool = TypePool.Items; + lock (TypePool.Sync) + { + if (pool.Count >= DefaultMaxPoolSizePerType) + { + return; + } + + pool.Push(instance); + } + } + + public static List GetList() + { + return Get>(); + } + + public static Dictionary GetDictionary() + { + return Get>(); + } + + public static HashSet GetHashSet() + { + return Get>(); + } + + public static void ReleaseList(List instance) + { + Release(instance); + } + + public static void ReleaseDictionary(Dictionary instance) + { + Release(instance); + } + + public static void ReleaseHashSet(HashSet instance) + { + Release(instance); + } + + public static PooledHandle> GetListHandle(out List instance) + { + instance = GetList(); + return new PooledHandle>(instance); + } + + public static PooledHandle> GetDictionaryHandle(out Dictionary instance) + { + instance = GetDictionary(); + return new PooledHandle>(instance); + } + + public static PooledHandle> GetHashSetHandle(out HashSet instance) + { + instance = GetHashSet(); + return new PooledHandle>(instance); + } + } + + public readonly struct PooledHandle : IDisposable where T : class, new() + { + private readonly T _instance; + + public PooledHandle(T instance) + { + _instance = instance; + } + + public void Dispose() + { + THCollectionPool.Release(_instance); + } + } +} diff --git a/Unity/Assets/Scripts/TH1_Logic/Pool/THCollectionPool.cs.meta b/Unity/Assets/Scripts/TH1_Logic/Pool/THCollectionPool.cs.meta new file mode 100644 index 000000000..06d256b3b --- /dev/null +++ b/Unity/Assets/Scripts/TH1_Logic/Pool/THCollectionPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc6e12cd44d921444a16fd79b12c108d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/AutoHealSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/AutoHealSkill.cs index c040f5f4e..e8a30244d 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/AutoHealSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/AutoHealSkill.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; +using Logic.Pool; using RuntimeData; using MemoryPack; @@ -33,7 +34,7 @@ namespace Logic.Skill if (self == null) return; var player = self.Player(mapData); if (player == null) return; - var selfUnitList = new HashSet(); + using var pooledSelfUnitList = THCollectionPool.GetHashSetHandle(out var selfUnitList); mapData.GetUnitDataListByPlayerId(player.Id, selfUnitList); if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return; var aroundBuf = RentAroundBuf(); @@ -49,4 +50,4 @@ namespace Logic.Skill ReturnAroundBuf(); } } -} \ No newline at end of file +} diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KomeijiFearSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KomeijiFearSkill.cs index 40c397c88..d64c3b509 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KomeijiFearSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KomeijiFearSkill.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; +using Logic.Pool; using RuntimeData; using Logic.CrashSight; using TH1_Anim.Fragments; @@ -108,7 +109,7 @@ namespace Logic.Skill List visualSteps = (isMainMap && scope == null) ? new List() : null; // 收集需要刷新外观的存活单位 - var unitsToRefresh = new List(); + using var pooledUnitsToRefresh = THCollectionPool.GetListHandle(out var unitsToRefresh); if (_level >= 2) { diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KomeijiFearSplashSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KomeijiFearSplashSkill.cs index 18b41bb0f..9af32e3b7 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KomeijiFearSplashSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/KomeijiFearSplashSkill.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Logic.Pool; using RuntimeData; using MemoryPack; using TH1_Anim.Fragments; @@ -28,7 +29,7 @@ namespace Logic.Skill if (attackInfo.DamageOrigin == null || attackInfo.DamageTargetGrid == null) return; if (!mapData.GetPlayerDataByUnitId(attackInfo.DamageOrigin.Id, out var selfPlayer)) return; - var selfUnitList = new HashSet(); + using var pooledSelfUnitList = THCollectionPool.GetHashSetHandle(out var selfUnitList); mapData.GetUnitDataListByPlayerId(selfPlayer.Id, selfUnitList); bool isMainMap = mapData == Main.MapData; diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/PatchouliMoveProSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/PatchouliMoveProSkill.cs index aefe3a355..4dc4d22f2 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/PatchouliMoveProSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/PatchouliMoveProSkill.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using Logic.Pool; using MemoryPack; using RuntimeData; using UnityEngine; @@ -55,7 +56,7 @@ namespace Logic.Skill _moveFlag = true; var player = self.Player(mapData); if (player == null) return; - var selfUnitList = new HashSet(); + using var pooledSelfUnitList = THCollectionPool.GetHashSetHandle(out var selfUnitList); mapData.GetUnitDataListByPlayerId(player.Id, selfUnitList); if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return; diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/PathStompSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/PathStompSkill.cs index 12dc091d9..bb71e182b 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/PathStompSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/PathStompSkill.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using Logic.Pool; using MemoryPack; using RuntimeData; using TH1_Logic.Core; @@ -39,10 +40,10 @@ namespace Logic.Skill if (path == null) return; int pathRk = 0; //统计所有已经被伤害到的unit。每个unit只被伤害1次 - var damaged = new HashSet(); + using var pooledDamaged = THCollectionPool.GetHashSetHandle(out var damaged); // 收集所有需要延迟执行的视觉更新。Renderer 必须在 DamageSettlement 前缓存。 - var visualSteps = new List<(int pathIndex, UnitData unit, GridData grid, UnitRenderer renderer, int damage, bool wasKilled)>(); + using var pooledVisualSteps = THCollectionPool.GetListHandle<(int pathIndex, UnitData unit, GridData grid, UnitRenderer renderer, int damage, bool wasKilled)>(out var visualSteps); foreach (var vec2 in path) { diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SakuyaFlyProSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SakuyaFlyProSkill.cs index af7b01ed9..384a37581 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SakuyaFlyProSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SakuyaFlyProSkill.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using Logic.Pool; using MemoryPack; using RuntimeData; using UnityEngine; @@ -54,7 +55,7 @@ namespace Logic.Skill if (moveType != MoveType.SkillMove) return; var player = self.Player(mapData); if (player == null) return; - var selfUnitList = new HashSet(); + using var pooledSelfUnitList = THCollectionPool.GetHashSetHandle(out var selfUnitList); mapData.GetUnitDataListByPlayerId(player.Id, selfUnitList); if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return; diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SakuyaFlySkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SakuyaFlySkill.cs index d0fab1eb2..cb659ab8e 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SakuyaFlySkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SakuyaFlySkill.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using Logic.Pool; using MemoryPack; using RuntimeData; using UnityEngine; @@ -43,7 +44,7 @@ namespace Logic.Skill if (moveType != MoveType.SkillMove) return; var player = self.Player(mapData); if (player == null) return; - var selfUnitList = new HashSet(); + using var pooledSelfUnitList = THCollectionPool.GetHashSetHandle(out var selfUnitList); mapData.GetUnitDataListByPlayerId(player.Id, selfUnitList); if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return; @@ -65,4 +66,4 @@ namespace Logic.Skill if (isExcute) self.AddActionPoint(ActionPointType.Attack); } } -} \ No newline at end of file +} diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SplashSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SplashSkill.cs index 2283f152a..ef73011a1 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SplashSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/SplashSkill.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using RuntimeData; using System; using Logic.CrashSight; +using Logic.Pool; using TH1_Logic.Core; using TH1_Anim.Fragments; using TH1_Core.Managers; @@ -42,7 +43,7 @@ namespace Logic.Skill if (info.DamageOrigin == null )return;//|| info.DamageTarget == null) return; if (!mapData.GetPlayerDataByUnitId(info.DamageOrigin.Id, out var player)) return; - var selfUnitList = new HashSet(); + using var pooledSelfUnitList = THCollectionPool.GetHashSetHandle(out var selfUnitList); mapData.GetUnitDataListByPlayerId(player.Id, selfUnitList); if (info.DamageTargetGrid == null) @@ -53,7 +54,7 @@ namespace Logic.Skill // 收集需要延迟刷新的单位。注意:Renderer 必须在 DamageSettlement 前缓存, // 否则死亡后 ROUnitMap 若被其他路径清理将无法再查到。 - var unitsToRefresh = new List<(UnitData unit, GridData grid, UnitRenderer renderer, int damage, bool wasKilled)>(); + using var pooledUnitsToRefresh = THCollectionPool.GetListHandle<(UnitData unit, GridData grid, UnitRenderer renderer, int damage, bool wasKilled)>(out var unitsToRefresh); var aroundBuf = RentAroundBuf(); mapData.GridMap.GetAroundGridData(1, 1, info.DamageTargetGrid, aroundBuf); @@ -155,4 +156,4 @@ namespace Logic.Skill } } } -} \ No newline at end of file +} diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/StompSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/StompSkill.cs index 0fa0c7a32..791d967d5 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/StompSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/StompSkill.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using RuntimeData; using System; +using Logic.Pool; using TH1_Logic.Core; using TH1_Anim.Fragments; using TH1_Core.Managers; @@ -36,12 +37,12 @@ namespace Logic.Skill public override void OnMove(UnitData self, GridData grid, MapData mapData, MoveType moveType, List path = null) { - var selfUnitList = new HashSet(); + using var pooledSelfUnitList = THCollectionPool.GetHashSetHandle(out var selfUnitList); mapData.GetPlayerDataByUnitId(self.Id, out var selfPlayer); mapData.GetUnitDataListByPlayerId(selfPlayer.Id, selfUnitList); // 收集需要视觉更新的数据。Renderer 必须在 DamageSettlement 前缓存。 - var visualUpdates = new List<(UnitData unit, GridData grid, UnitRenderer renderer, int damage, bool wasKilled, GridRenderer gridRenderer)>(); + using var pooledVisualUpdates = THCollectionPool.GetListHandle<(UnitData unit, GridData grid, UnitRenderer renderer, int damage, bool wasKilled, GridRenderer gridRenderer)>(out var visualUpdates); //遍历会溅射的所有格子 var aroundBuf = RentAroundBuf(); @@ -146,4 +147,4 @@ namespace Logic.Skill } } } -} \ No newline at end of file +} diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/UtsuhoReadyMoveSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/UtsuhoReadyMoveSkill.cs index cbdd581ce..20c3ddc8c 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/UtsuhoReadyMoveSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/UtsuhoReadyMoveSkill.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; +using Logic.Pool; using RuntimeData; using TH1_Anim; using TH1_Anim.Fragments; @@ -117,7 +118,7 @@ namespace Logic.Skill bool hasRadiation = selfUnit.GetSkill(SkillType.UtsuhoRadiation, out _); if (hasRadiation) { - var splashedUnits = new HashSet(); + using var pooledSplashedUnits = THCollectionPool.GetHashSetHandle(out var splashedUnits); for (int i = 1; i < path.Count; i++) { if (!mapData.GridMap.GetGridDataByV2(path[i], out var pathGrid)) continue; diff --git a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/UtsuhoReadyMoveSuperSkill.cs b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/UtsuhoReadyMoveSuperSkill.cs index 080532de3..0ed2b9d65 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/UtsuhoReadyMoveSuperSkill.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Skill/AllSkill/UtsuhoReadyMoveSuperSkill.cs @@ -6,6 +6,7 @@ */ using System.Collections.Generic; +using Logic.Pool; using RuntimeData; using MemoryPack; using TH1_Anim; @@ -80,7 +81,7 @@ namespace Logic.Skill bool hasRadiation = selfUnit.GetSkill(SkillType.UtsuhoRadiation, out _); if (hasRadiation) { - var splashedUnits = new HashSet(); + using var pooledSplashedUnits = THCollectionPool.GetHashSetHandle(out var splashedUnits); for (int i = 1; i < path.Count; i++) { if (!mapData.GridMap.GetGridDataByV2(path[i], out var pathGrid)) continue; diff --git a/Unity/Assets/Scripts/TH1_Logic/Unit/UnitLogic.cs b/Unity/Assets/Scripts/TH1_Logic/Unit/UnitLogic.cs index f60bc7d10..3d308d007 100644 --- a/Unity/Assets/Scripts/TH1_Logic/Unit/UnitLogic.cs +++ b/Unity/Assets/Scripts/TH1_Logic/Unit/UnitLogic.cs @@ -14,6 +14,7 @@ using Animancer; using Logic.Action; using Logic.Audio; using Logic.CrashSight; +using Logic.Pool; using Logic.Skill; using ParadoxNotion; using UnityEngine; @@ -1157,7 +1158,7 @@ namespace Logic && cityAsPlayer.Id == playerData.Id) { //遍历所有我方城市 如果位置没有人且联通,就可以移动过去 - var cityDataList = new List(); + using var pooledCityDataList = THCollectionPool.GetListHandle(out var cityDataList); mapData.GetCityDataListByPlayerId(playerData.Id, cityDataList); foreach (var cityB in cityDataList) { @@ -1174,7 +1175,7 @@ namespace Logic if (unitData.GetSkill(SkillType.MORIYAKNIGHTMOVE,out var _) && unitData.Grid(mapData,out var curGrid) && (curGrid.Resource is ResourceType.MoriyaMilitary or ResourceType.CityCenter)) { //遍历所有我方城市和军营 如果位置没有人就可以移动过去 - var cityDataList = new List(); + using var pooledCityDataList = THCollectionPool.GetListHandle(out var cityDataList); mapData.GetCityDataListByPlayerId(playerData.Id, cityDataList); foreach (var targetCity in cityDataList) { @@ -1204,7 +1205,7 @@ namespace Logic var sanaeWindXSkill = skill as SanaeWindXSkill; if (sanaeWindXSkill != null) { - var targetVec2 = new List(); + using var pooledTargetVec2 = THCollectionPool.GetListHandle(out var targetVec2); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) @@ -1419,7 +1420,7 @@ namespace Logic } var queue = new Queue(); // 用字典记录路径来源,同时兼作“已访问”集合 - var cameFrom = new Dictionary(); + using var pooledCameFrom = THCollectionPool.GetDictionaryHandle(out var cameFrom); uint width = map.MapConfig.Width; uint height = map.MapConfig.Height; @@ -1577,13 +1578,13 @@ namespace Logic if (originInfo == null || targetInfo == null) return; bool useCache = unitData.FullTypeCache == new UnitFullType(targetType, giantType, unitLevel); - var skillCache = new Dictionary(); - var originSkills = new List(); + using var pooledSkillCache = THCollectionPool.GetDictionaryHandle(out var skillCache); + using var pooledOriginSkills = THCollectionPool.GetListHandle(out var originSkills); foreach (var t in unitData.Skills) originSkills.Add(t); foreach (var t in unitData.SkillCache) skillCache[t.GetSkillType()] = t; unitData.SkillCache.Clear(); - var reservedSkillTypes = new HashSet(); + using var pooledReservedSkillTypes = THCollectionPool.GetHashSetHandle(out var reservedSkillTypes); foreach (var skill in originSkills) { // if (targetInfo.Skills.Contains(skillType)) continue;