/* * @Author: 白哉 * @Description: * @Date: 2025年04月03日 星期四 11:04:31 * @Modify: */ using System; using System.Collections.Generic; using System.IO; using Logic; using Logic.Action; using Logic.AI; using Logic.CrashSight; using ParadoxNotion; using UnityEngine; namespace RuntimeData { public enum GameMode { PERFECT, DOMINATION, CREATIVE } // 一场游戏的设置数据 [Serializable] public class MapConfig { public uint Width; public uint Height; public uint PlayerCount; public AIDifficult AIDiff; public GameMode GameMode; public uint selfCivId; public uint selfForceId; public MapConfig(uint width, uint height, uint playerCount,uint civId, uint forceId, AIDifficult aiDiff = AIDifficult.LUNATIC) { Width = width; Height = height; PlayerCount = playerCount; AIDiff = aiDiff; selfCivId = civId; selfForceId = forceId; } } // 一场游戏的地图数据 [Serializable] public class MapData : ISerializationCallbackReceiver { //--------------- 基础核心数据 ---------------// // 地图 ID public uint MapID; // 地图配置数据 public MapConfig MapConfig; // 地块数据 public GridMapData GridMap; // 玩家数据 public PlayerMapData PlayerMap; // 城市数据 public CityMapData CityMap; // 小兵数据 public UnitMapData UnitMap; // 城市 -> 玩家, 将引用关系转化为ID关系 public Dictionary CityToPlayerDict; // 小兵 -> 城市, 将引用关系转化为ID关系 public Dictionary UnitToCityDict; // 小兵 -> 格子, 将引用关系转化为ID关系 public Dictionary UnitToGridDict; // 城市 -> 格子, 将引用关系转化为ID关系 public Dictionary CityToGridDict; //--------------- 核心数据派生的数据 ---------------// // 格子 -> 小兵, 缓存数据 private Dictionary _gridToUnitDict; // 格子 -> 城市, 缓存数据 private Dictionary _gridToCityDict; //--------------- 其他数据 ---------------// // 地图 ID 生成器 [SerializeField] private MapIdGenerator _idGenerator; public MapIdGenerator IdGenerator => _idGenerator; //--------------- 序列化临时数据 ---------------// public List CityToPlayerDictKey; public List CityToPlayerDictValue; public List UnitToCityDictKey; public List UnitToCityDictValue; public List UnitToGridDictKey; public List UnitToGridDictValue; public List CityToGridDictKey; public List CityToGridDictValue; //-------------- 读写城市方法 -------------------// // 通过格子 gid 找城市 cid public bool GetCityIdByGridId(uint gid, out uint cid) { return _gridToCityDict.TryGetValue(gid, out cid); } // 通过格子 gid 找城市数据 cityData public bool GetCityDataByGid(uint gid, out CityData cityData) { if (_gridToCityDict.TryGetValue(gid, out var cid)) { return CityMap.GetCityById(_gridToCityDict[gid], out cityData); } cityData = null; return false; } // 通过小兵 ID 找城市 cid public bool GetCityIdByUnitId(uint uid, out uint cid) { return UnitToCityDict.TryGetValue(uid, out cid); } // 通过小兵 ID 找城市 data public bool GetCityDataByUnitId(uint uid, out CityData cityData) { if (UnitToCityDict.TryGetValue(uid, out var cid)) { return CityMap.GetCityById(cid, out cityData); } cityData = null; return false; } // 通过领土格子 gid 找城市数据 cityData public bool GetCityDataByTerritoryGid(uint gid, out CityData cityData) { return CityMap.GetCityDataByTerritoryGridId(gid, out cityData); } // 通过玩家 ID 找城市列表 public void GetCityDataListByPlayerId(uint pid, List cityDataList=null) { if (cityDataList == null) cityDataList = new List(); foreach (var kv in CityToPlayerDict) { if (kv.Value != pid) continue; if (!CityMap.GetCityById(kv.Key, out var cityData)) continue; cityDataList.Add(cityData); } } // 通过玩家 ID 找城市Set public void GetCityDataListByPlayerId(uint pid, HashSet cityDataList=null) { if (cityDataList == null) cityDataList = new HashSet(); foreach (var kv in CityToPlayerDict) { if (kv.Value != pid) continue; if (!CityMap.GetCityById(kv.Key, out var cityData)) continue; cityDataList.Add(cityData); } } // 通过玩家 ID 找城市 Set public HashSet GetCityDataSetByPlayerId(uint pid) { var citySet = new HashSet(); foreach (var kv in CityToPlayerDict) { if (kv.Value != pid) continue; if (!CityMap.GetCityById(kv.Key, out var cityData)) continue; citySet.Add(cityData); } return citySet; } //通过玩家ID 找 领土Set public HashSet GetGridDataSetByPlayerId(uint pid) { var citySet = GetCityDataSetByPlayerId(pid); var gridSet = new HashSet(); foreach (var city in citySet) { var cityGridSet = new HashSet(); city.Territory.GetAllTerritoryArea(cityGridSet); foreach (var gid in cityGridSet) { GridMap.GetGridDataByGid(gid, out var grid); gridSet.Add(grid); } } return gridSet; } //通过玩家ID 找 领土ID Set public HashSet GetGridIdSetByPlayerId(uint pid) { var citySet = GetCityDataSetByPlayerId(pid); var gridSet = new HashSet(); foreach (var city in citySet) { var cityGridSet = new HashSet(); city.Territory.GetAllTerritoryArea(cityGridSet); gridSet.UnionWith(cityGridSet); } return gridSet; } // 通过玩家 ID 查找首都城市 cityData public bool GetCapitalCityDataByPlayerId(uint pid, out CityData cityData) { var cityList = new List(); GetCityDataListByPlayerId(pid, cityList); foreach (var city in cityList) { if (!city.IsCapital) continue; cityData = city; return true; } cityData = null; return false; } // 改变城市所属关系 public bool SetCityIdToPlayerId(uint cid, uint pid) { if (!GetPlayerDataByCityId(cid, out var oldPlayerData)) return false; if(!PlayerMap.GetPlayerDataByPlayerID(pid, out var newPlayerData)) return false; if (!GetCapitalCityDataByPlayerId(oldPlayerData.Id, out var oldPlayerCapitalCityData)) return false; if (!GetCapitalCityDataByPlayerId(pid, out var newPlayerCapitalCityData)) return false; if (!CityMap.GetCityById(cid, out var city)) return false; //playerData.RenderMark = true; //part #1 如果cid的老东家没有别的城市了,判负 if (GetCityCount(oldPlayerData.Id) == 1) { //step #1 玩家死亡(设置mark) oldPlayerData.Alive = false; oldPlayerData.DieMark = true; //step #2 所有unit都销毁 var unitDataList = new List(); GetUnitDataListByCityId(cid,unitDataList); foreach (var unitData in unitDataList) SetUnitDataDie(unitData); //step #3 撤销首都 city.IsCapital = false; } //否则要将所有unit转移到老东家的capital下面去 else { //如果cid的老东家的首都就是cid,那么老东家首先要更换首都 if (oldPlayerCapitalCityData.Id == cid) { //遍历cityList,找到第一个老东家的其他城市,让他变成新的首都 foreach (var tmpCityData in CityMap.CityList) { if (tmpCityData.Id == cid) continue; if (GetPlayerIdByCityId(tmpCityData.Id, out var tmpPlayerId) && tmpPlayerId == oldPlayerData.Id) { tmpCityData.IsCapital = true; oldPlayerCapitalCityData.IsCapital = false; oldPlayerCapitalCityData = tmpCityData; break; } } } //开始将所有cid的小兵都转移到oldPlayerCapitalCityData下去 var tmpUnitDataList = new List(); GetUnitDataListByCityId(cid, tmpUnitDataList); foreach(var tmpUnitData in tmpUnitDataList) SetUnitIdToCityId(tmpUnitData.Id,oldPlayerCapitalCityData.Id); oldPlayerCapitalCityData.RenderMark = true; } //如果这次这个城市是newPlayer的原始首都,那么new Player要更换首都 if (newPlayerData.CradleCityId == cid) { city.IsCapital = true; newPlayerCapitalCityData.IsCapital = false; } //正式更换城市归属 CityToPlayerDict[cid] = pid; if (CityMap.GetCityById(cid, out var cityData)) { cityData.RenderMark = true; if (GetGridDataByCityId(cid, out var gridData)) gridData.CityBuildingRenderMark = true; } return true; } //改变小兵的位置 public void SetUnitIdToGridId(uint uid, uint gid) { if (UnitToGridDict.TryGetValue(uid, out var oldGid)) { _gridToUnitDict.Remove(oldGid); } UnitToGridDict[uid] = gid; _gridToUnitDict[gid] = uid; if (UnitMap.GetUnitDataByUnitId(uid, out var unitData)) unitData.RenderMark = true; } public void SetUnitDataDie(UnitData unitData) { unitData.Alive = false; // 标记原city的rendermark if (GetCityDataByUnitId(unitData.Id, out var cityData)) cityData.CityInfoRenderMark = true; // 清除数据层绑定 RemoveUnitData(unitData.Id); if (GetGridIdByUnitId(unitData.Id, out var gridId)) _gridToUnitDict.Remove(gridId); UnitMap.UnitMapRenderMark = true; } //改变小兵到城市的所属关系 public void SetUnitIdToCityId(uint uid, uint cid) { UnitToCityDict[uid] = cid; //if (CityMap.GetCityById(cid, out var cityData)) cityData.RenderMark = true; //if (PlayerMap.GetPlayerDataByPlayerID(pid, out var playerData)) playerData.RenderMark = true; } //获得一个玩家有多少个城市 public int GetCityCount(uint pid) { int ret = 0; foreach (var cityData in CityMap.CityList) if (CityToPlayerDict.ContainsKey(cityData.Id) && CityToPlayerDict[cityData.Id] == pid) ret++; return ret; } //获得一共城市有多少单位 public int GetUnitCount(uint cid) { int ret = 0; foreach (var cityData in UnitMap.UnitList) if (UnitToCityDict.ContainsKey(cityData.Id) && UnitToCityDict[cityData.Id] == cid) ret++; return ret; } //-------------- 读写小兵方法 -------------------// // 通过格子 gid 找小兵 uid public bool GetUnitIdByGid(uint gid, out uint uid) { return _gridToUnitDict.TryGetValue(gid, out uid); } // 通过格子 gid 找小兵 data public bool GetUnitDataByGid(uint gid, out UnitData unitData) { unitData = null; /*foreach(var tt in UnitMap.UnitList) if (GetGridDataByUnitId(tt.Id,out var gridData)) if (gridData.Id == gid) { unitData = tt; return true; } return false;*/ //TODO _gridToUnitDict这个缓存有错,和unitToGrid没有对上。 暂时用了上面的办法,之后需要修改这里的缓存 if (_gridToUnitDict.TryGetValue(gid, out var uid)) { return UnitMap.GetUnitDataByUnitId(uid, out unitData); } return false; } // 通过城市 ID 找小兵列表 public void GetUnitDataListByCityId(uint cid, List unitDataList=null) { if (unitDataList == null) unitDataList = new List(); foreach (var kv in UnitToCityDict) { if (kv.Value != cid) continue; if (!UnitMap.GetUnitDataByUnitId(kv.Key, out var unitData)) continue; unitDataList.Add(unitData); } } // 通过玩家 ID 找小兵列表 public void GetUnitDataListByPlayerId(uint pid, List unitDataList=null) { if (unitDataList == null) unitDataList = new List(); foreach (var kv in CityToPlayerDict) { if (kv.Value != pid) continue; GetUnitDataListByCityId(kv.Key, unitDataList); } } // 通过城市 ID 找小兵 Set public void GetUnitDataListByCityId(uint cid, HashSet unitDataList=null) { if (unitDataList == null) unitDataList = new HashSet(); foreach (var kv in UnitToCityDict) { if (kv.Value != cid) continue; if (!UnitMap.GetUnitDataByUnitId(kv.Key, out var unitData)) continue; unitDataList.Add(unitData); } } // 通过玩家 ID 找小兵 Set public void GetUnitDataListByPlayerId(uint pid, HashSet unitDataList=null) { if (unitDataList == null) unitDataList = new HashSet(); foreach (var kv in CityToPlayerDict) { if (kv.Value != pid) continue; GetUnitDataListByCityId(kv.Key, unitDataList); } } // 通过玩家 ID 找敌方小兵列表 public void GetOtherUnitDataListByPlayerId(uint pid, List unitDataList=null) { if (unitDataList == null) unitDataList = new List(); foreach (var kv in CityToPlayerDict) { if (kv.Value == pid) continue; GetUnitDataListByCityId(kv.Key, unitDataList); } } //-------------- 读写玩家方法 -------------------// // 通过城市找玩家 pid public bool GetPlayerIdByCityId(uint cityId, out uint playerId) { return CityToPlayerDict.TryGetValue(cityId, out playerId); } // 通过城市找玩家 data public bool GetPlayerDataByCityId(uint cityId, out PlayerData playerData) { playerData = null; if (CityToPlayerDict.TryGetValue(cityId, out var playerId)) { playerData = PlayerMap.GetPlayerData(playerId); } return playerData != null; } // 通过小兵 uid 找城市 pid public bool GetPlayerIdByUnitId(uint uid, out uint pid) { if (UnitToCityDict.TryGetValue(uid, out var cid)) { return CityToPlayerDict.TryGetValue(cid, out pid); } pid = 0; return false; } // 通过小兵 uid 找城市数据 playerData public bool GetPlayerDataByUnitId(uint uid, out PlayerData playerData) { playerData = null; if (UnitToCityDict.TryGetValue(uid, out var cid)) { if (CityToPlayerDict.TryGetValue(cid, out var pid)) { playerData = PlayerMap.GetPlayerData(pid); } } return playerData != null; } // 通过领土位置找玩家 public bool GetPlayerDataByTerritoryGridId(uint gid, out PlayerData playerData) { if (CityMap.GetCityDataByTerritoryGridId(gid, out var cityData)) { return GetPlayerDataByCityId(cityData.Id, out playerData); } playerData = null; return false; } //判断playerA和playerB是否同一个联盟 //TODO 加入外交系统后要更新这个函数 public bool SameUnion(uint pidA, uint pidB) { return pidA == pidB; } //-------------- 查询格子方法 -------------------// // 通过小兵 uid 找格子 gid public bool GetGridIdByUnitId(uint uid, out uint gid) { return UnitToGridDict.TryGetValue(uid, out gid); } // 通过小兵 uid 找格子数据 data public bool GetGridDataByUnitId(uint uid, out GridData data) { if (UnitToGridDict.TryGetValue(uid, out var gid)) { return GridMap.GetGridDataByGid(gid, out data); } data = null; return false; } // 通过城市 cid 找格子 gid public bool GetGridIdByCityId(uint cid, out uint gid) { return CityToGridDict.TryGetValue(cid, out gid); } // 通过城市 cid 找格子数据 data public bool GetGridDataByCityId(uint cid, out GridData data) { if (CityToGridDict.TryGetValue(cid, out var gid)) { return GridMap.GetGridDataByGid(gid, out data); } data = null; return false; } //------------- 计算地图信息方法 -----------------// public bool CheckIfNearByGridSamePlayer(GridData gridData, int dir) { dir--; int x = gridData.Pos.X + dir % 3 - 1, y = gridData.Pos.Y + dir / 3 - 1; if(x < 0 || x >= MapConfig.Width || y < 0 || y >= MapConfig.Height) return false; if (GridMap.GetGridDataByPos(x, y, out GridData gridData2)) { GetPlayerDataByTerritoryGridId(gridData.Id,out var p1); GetPlayerDataByTerritoryGridId(gridData2.Id,out var p2); return p1 == p2; } return false; } public bool CheckIfNearByGridSameCity(GridData gridData, int dir) { dir--; int x = gridData.Pos.X + dir % 3 - 1, y = gridData.Pos.Y + dir / 3 - 1; if(x < 0 || x >= MapConfig.Width || y < 0 || y >= MapConfig.Height) return false; if (GridMap.GetGridDataByPos(x, y, out GridData gridData2)) { GetCityDataByTerritoryGid(gridData.Id,out var c1); GetCityDataByTerritoryGid(gridData2.Id,out var c2); return c1 == c2; } return false; } //返回在gid周围1格内,dir方向的那格是否是freeland public bool CheckIfNearByGridFreeland(GridData gridData, int dir,out GridData gridData2) { gridData2 = null; dir--; int x = (int)gridData.Pos.X + dir % 3 - 1, y = (int)gridData.Pos.Y + dir / 3 - 1; if(x < 0 || x >= MapConfig.Width || y < 0 || y >= MapConfig.Height) return false; if(GridMap.GetGridDataByPos(x, y, out gridData2)) return !GetPlayerDataByTerritoryGridId(gridData2.Id,out var playerData); return false; } //判断grid的dir方向是不是道路或者海路联通的。注意要区分 陆地港口桥梁 和 港口海域 两种情况,港口是两种情况都出现的 public bool CheckIfNearByGridRoadCanConnenct(GridData gridData, int dir) { int x = gridData.Pos.X + dir % 3 - 1, y = gridData.Pos.Y + dir / 3 - 1; if(x < 0 || x >= MapConfig.Width || y < 0 || y >= MapConfig.Height) return false; if (!GridMap.GetGridDataByPos(x, y, out var gridData2)) return false; //如果有一个没有road return if (gridData.Feature != TerrainFeature.Road || gridData2.Feature != TerrainFeature.Road) return false; //判断主权情况 均有主权且不是一个同盟要return false if (GetPlayerDataByTerritoryGridId(gridData.Id, out var playerData1) && GetPlayerDataByTerritoryGridId(gridData2.Id, out var playerData2) && !SameUnion(playerData1.Id, playerData2.Id)) return false; //排除一个是非港口海域,一个是陆地的情况 if (gridData.Terrain != TerrainType.Land && gridData.Resource != ResourceType.Port && gridData2.Terrain == TerrainType.Land) { //bridge的情况特判 if (gridData.Resource == ResourceType.Bridge) return true; return false; } if (gridData2.Terrain != TerrainType.Land && gridData2.Resource != ResourceType.Port && gridData.Terrain == TerrainType.Land) { //bridge的情况特判 if (gridData2.Resource == ResourceType.Bridge) return true; return false; } //剩下情况都是true return true; } //返回在gid周围1个内,dir方向的那格是不是land public bool CheckIfNearByGridIsLand(GridData gridData, int dir,out GridData gridData2) { gridData2 = null; dir--; int x = (int)gridData.Pos.X + dir % 3 - 1, y = (int)gridData.Pos.Y + dir / 3 - 1; if(x < 0 || x >= MapConfig.Width || y < 0 || y >= MapConfig.Height) return false; GridMap.GetGridDataByPos(x, y, out gridData2); return gridData2.Terrain == TerrainType.Land; } public List GetNearby1RadiusFreelandGidList(uint gid) { var ret = new List(); GridMap.GetGridDataByGid(gid,out GridData gridData); //遍历周围一圈方向,将所有freeland加入列表 for (int dir = 1; dir <= 9; dir++) if(CheckIfNearByGridFreeland(gridData, dir, out var gridData2)) ret.Add(gridData2.Id); return ret; } //返回在gridData上是否存在建设桥梁的基础地理条件 public bool HasBridgeSideLand(GridData gridData,out bool isMirror) { isMirror = false; if (gridData.Terrain == TerrainType.Land) return false; GridData t; if (CheckIfNearByGridIsLand(gridData, 2, out t) && CheckIfNearByGridIsLand(gridData, 8, out t)) return true; isMirror = true; if (CheckIfNearByGridIsLand(gridData, 4, out t) && CheckIfNearByGridIsLand(gridData, 6, out t)) return true; return false; } // 获取玩家的所有领土格子 ID public HashSet GetPlayerTerritoryGridIdSet(uint pid) { var gridSet = new HashSet(); var cityList = new List(); GetCityDataListByPlayerId(pid, cityList); foreach (var cityData in cityList) { cityData.Territory.GetAllTerritoryArea(gridSet); } return gridSet; } public bool CheckIfCityFullPopulation(CityData cityData) { if (cityData == null) { LogSystem.LogError($"CheckIfCityFullPopulation cityData is null"); return true; } return GetUnitCount(cityData.Id) >= cityData.Level; } public uint GetMapSize() { return MapConfig.Width * MapConfig.Height; } //-------------- 新建数据的方法 -------------------// // 新建城市数据 public CityData AddCityData(uint gid, uint pid) { uint civId = PlayerMap.GetPlayerData(pid).PlayerCivId; int cityRk = Table.Instance.cityNameLibraryHat[civId]; //如果是真Map if (this == Main.MapData) Table.Instance.cityNameLibraryHat[civId]++; Table.Instance.CivDataAssets.GetCivInfo(civId, out var civData); //避免越界 保险mod一下 if (cityRk >= civData.CityInfoList.Count) { LogSystem.LogError("MapData_AddCityData_CityInfoList_Array_OverFlow"); cityRk %= civData.CityInfoList.Count; } CityLibrary nameEnum = civData.CityInfoList[cityRk].CityNameEnum; CityData cityData = CityMap.AddCityData(GetNearby1RadiusFreelandGidList(gid), nameEnum, _idGenerator); CityToPlayerDict[cityData.Id] = pid; CityToGridDict[cityData.Id] = gid; _gridToCityDict[gid] = cityData.Id; //建立city会在改格子上自动建立road if (GridMap.GetGridDataByGid(gid, out var gridData)) gridData.Feature = TerrainFeature.Road; //处理rendermark var gridIdSet = GetPlayerTerritoryGridIdSet(pid); foreach(var gridId in gridIdSet) if (GridMap.GetGridDataByGid(gridId, out var gridDataTerr)) gridDataTerr.RenderMark = true; CityMap.CityMapRenderMark = true; cityData.RenderMark = true; cityData.CityInfoRenderMark = true; return cityData; } // 新建小兵数据 public UnitData AddUnitData(uint gid, uint cid, UnitType unitType,GiantType giantType = GiantType.None,uint unitLevel = 0) { UnitData unitData = UnitMap.AddUnitData(unitType,giantType,unitLevel, _idGenerator); UnitToCityDict[unitData.Id] = cid; UnitToGridDict[unitData.Id] = gid; _gridToUnitDict[gid] = unitData.Id; UnitMap.UnitMapRenderMark = true; unitData.RenderMark = true; //给角色新增skill if (!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitType, giantType, unitLevel,out var unitInfo)) return unitData; foreach (var skill in unitInfo.Skills) unitData.AddSkill(skill); if (!GetPlayerDataByUnitId(unitData.Id, out var playerData)) return unitData; var dict = ActionLogicFactory.GetActionLogicDict(); foreach (var action in dict.Keys) if(action.ActionType == CommonActionType.UnitSkill && playerData.TechTree.CheckActionCan(action)) unitData.AddSkill(action.SkillType); return unitData; } // 移除小兵数据 public void RemoveUnitData(uint uid) { UnitMap.RemoveUnitData(uid); if (UnitToGridDict.Remove(uid, out var gid)) { _gridToUnitDict.Remove(gid); } UnitToGridDict.Remove(uid); UnitToCityDict.Remove(uid); } // 获取所有 ID 单位 public List GetAllIdentifierBase() { var list = new List(); foreach (var idBase in PlayerMap.PlayerDataList) list.Add(idBase); foreach (var idBase in CityMap.CityList) list.Add(idBase); foreach (var idBase in UnitMap.UnitList) list.Add(idBase); foreach (var idBase in GridMap.GridList) list.Add(idBase); return list; } //-------------- 生命周期方法 -------------------// // 从地图配置初始化 public MapData(MapConfig mapCfg) { MapID = 0; MapConfig = mapCfg; _idGenerator = new MapIdGenerator(); GridMap = new GridMapData(mapCfg, _idGenerator); PlayerMap = new PlayerMapData(mapCfg, _idGenerator); CityMap = new CityMapData(); UnitMap = new UnitMapData(); CityToPlayerDict = new Dictionary(); UnitToCityDict = new Dictionary(); UnitToGridDict = new Dictionary(); CityToGridDict = new Dictionary(); _gridToCityDict = new Dictionary(); _gridToUnitDict = new Dictionary(); } public MapData(MapData copyMap) { MapConfig = copyMap.MapConfig; _idGenerator = copyMap._idGenerator.DeepCopy(); GridMap = new GridMapData(copyMap.GridMap); PlayerMap = new PlayerMapData(copyMap.PlayerMap); CityMap = new CityMapData(copyMap.CityMap); UnitMap = new UnitMapData(copyMap.UnitMap); CityToPlayerDict = new Dictionary(); UnitToCityDict = new Dictionary(); UnitToGridDict = new Dictionary(); CityToGridDict = new Dictionary(); _gridToCityDict = new Dictionary(); _gridToUnitDict = new Dictionary(); foreach (var kv in copyMap.CityToPlayerDict) CityToPlayerDict[kv.Key] = kv.Value; foreach (var kv in copyMap.UnitToCityDict) UnitToCityDict[kv.Key] = kv.Value; foreach (var kv in copyMap.UnitToGridDict) UnitToGridDict[kv.Key] = kv.Value; foreach (var kv in copyMap.CityToGridDict) CityToGridDict[kv.Key] = kv.Value; foreach (var kv in copyMap._gridToCityDict) _gridToCityDict[kv.Key] = kv.Value; foreach (var kv in copyMap._gridToUnitDict) _gridToUnitDict[kv.Key] = kv.Value; } // 获取深拷贝的一份新的地图数据 public MapData GetDeepCopyMapData() { return new MapData(this); } // 深度拷贝另一封 map 数据 public void DeepCopy(MapData copyMap) { MapConfig = copyMap.MapConfig; _idGenerator.DeepCopy(copyMap._idGenerator); GridMap.DeepCopy(copyMap.GridMap); PlayerMap.DeepCopy(copyMap.PlayerMap); CityMap.DeepCopy(copyMap.CityMap); UnitMap.DeepCopy(copyMap.UnitMap); CityToPlayerDict.Clear(); UnitToCityDict.Clear(); UnitToGridDict.Clear(); CityToGridDict.Clear(); _gridToCityDict.Clear(); _gridToUnitDict.Clear(); foreach (var kv in copyMap.CityToPlayerDict) CityToPlayerDict[kv.Key] = kv.Value; foreach (var kv in copyMap.UnitToCityDict) UnitToCityDict[kv.Key] = kv.Value; foreach (var kv in copyMap.UnitToGridDict) UnitToGridDict[kv.Key] = kv.Value; foreach (var kv in copyMap.CityToGridDict) CityToGridDict[kv.Key] = kv.Value; foreach (var kv in copyMap._gridToCityDict) _gridToCityDict[kv.Key] = kv.Value; foreach (var kv in copyMap._gridToUnitDict) _gridToUnitDict[kv.Key] = kv.Value; } // 序列化方法 public void OnBeforeSerialize() { CityToPlayerDictKey ??= new List(); CityToPlayerDictValue ??= new List(); UnitToCityDictKey ??= new List(); UnitToCityDictValue ??= new List(); UnitToGridDictKey ??= new List(); UnitToGridDictValue ??= new List(); CityToGridDictKey ??= new List(); CityToGridDictValue ??= new List(); CityToPlayerDictKey.Clear(); CityToPlayerDictValue.Clear(); UnitToCityDictKey.Clear(); UnitToCityDictValue.Clear(); UnitToGridDictKey.Clear(); UnitToGridDictValue.Clear(); CityToGridDictKey.Clear(); CityToGridDictValue.Clear(); foreach (var kv in CityToPlayerDict) { CityToPlayerDictKey.Add(kv.Key); CityToPlayerDictValue.Add(kv.Value); } foreach (var kv in UnitToCityDict) { UnitToCityDictKey.Add(kv.Key); UnitToCityDictValue.Add(kv.Value); } foreach (var kv in UnitToGridDict) { UnitToGridDictKey.Add(kv.Key); UnitToGridDictValue.Add(kv.Value); } foreach (var kv in CityToGridDict) { CityToGridDictKey.Add(kv.Key); CityToGridDictValue.Add(kv.Value); } } // 反序列化方法 public void OnAfterDeserialize() { CityToPlayerDict??= new Dictionary(); UnitToCityDict??= new Dictionary(); UnitToGridDict??= new Dictionary(); CityToGridDict??= new Dictionary(); _gridToCityDict??= new Dictionary(); _gridToUnitDict??= new Dictionary(); CityToPlayerDict.Clear(); UnitToCityDict.Clear(); UnitToGridDict.Clear(); CityToGridDict.Clear(); _gridToCityDict.Clear(); _gridToUnitDict.Clear(); for (int i = 0; i < CityToPlayerDictKey.Count; i++) CityToPlayerDict[CityToPlayerDictKey[i]] = CityToPlayerDictValue[i]; for (int i = 0; i < UnitToCityDictKey.Count; i++) UnitToCityDict[UnitToCityDictKey[i]] = UnitToCityDictValue[i]; for (int i = 0; i < UnitToGridDictKey.Count; i++) { UnitToGridDict[UnitToGridDictKey[i]] = UnitToGridDictValue[i]; _gridToUnitDict[UnitToGridDictValue[i]] = UnitToGridDictKey[i]; } for (int i = 0; i < CityToGridDictKey.Count; i++) { CityToGridDict[CityToGridDictKey[i]] = CityToGridDictValue[i]; _gridToCityDict[CityToGridDictValue[i]] = CityToGridDictKey[i]; } } // 当场上有小兵受伤时 public void OnUnitDamaged(SettlementInfo info) { foreach (var idBase in GetAllIdentifierBase()) { foreach (var skill in idBase.Skills) skill.OnUnitDamaged(idBase, this, info); } } // 当场上有小兵移动时 public void OnOtherUnitMove(UnitData moveUnit, GridData target) { foreach (var idBase in GetAllIdentifierBase()) { foreach (var skill in idBase.Skills) skill.OnOtherUnitMove(idBase, moveUnit, target, this); } } public static void SaveMapData(MapData map) { if (map == null) return; string path = Application.persistentDataPath + "/map_archive.json"; int retryCount = 3; while (retryCount > 0) { try { string json = JsonUtility.ToJson(map); using (StreamWriter writer = new StreamWriter(path, false)) { writer.Write(json); writer.Close(); } return; } catch (IOException ex) { retryCount--; if (retryCount <= 0) { LogSystem.LogError($"保存地图数据失败: {ex.Message}"); } } } } public static MapData GetMapData() { string path = Application.persistentDataPath + "/map_archive.json"; if (!File.Exists(path)) return null; int retryCount = 3; while (retryCount > 0) { try { string json; using (StreamReader reader = new StreamReader(path)) { json = reader.ReadToEnd(); reader.Close(); } return JsonUtility.FromJson(json); } catch (IOException ex) { retryCount--; if (retryCount <= 0) { LogSystem.LogError($"读取地图数据失败: {ex.Message}"); return null; } } } return null; } public GameRecord ExportGameRecord() { var gameRecord = new GameRecord(); gameRecord.Mode = MapConfig.GameMode; gameRecord.AIDiff = MapConfig.AIDiff; gameRecord.Turn = PlayerMap.SelfPlayerData.Turn; gameRecord.PlayerCivId = PlayerMap.SelfPlayerData.PlayerCivId; gameRecord.PlayerForceId = PlayerMap.SelfPlayerData.PlayerForceId; 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.MapWidth = MapConfig.Width; gameRecord.MapHeight = MapConfig.Height; gameRecord.PlayerCount = MapConfig.PlayerCount; return gameRecord; } #region --- 判断数据间关系的快捷方法 --- //判断gid是否属于pid public bool CheckIfGidBelongPid(uint gid,uint pid) { if(!GetPlayerDataByTerritoryGridId(gid, out var playerData)) return false; if (playerData.Id != pid) return false; return true; } //判断gid是否属于pid的联盟 public bool CheckIfGidBelongPidUnion(uint gid,uint pid) { if(!GetPlayerDataByTerritoryGridId(gid, out var playerData)) return false; return SameUnion(playerData.Id,pid); } public bool CheckCityIdBelongPlayerId(uint cid,uint pid) { return GetPlayerIdByCityId(cid, out var pid1) && pid1 == pid; } public bool CheckUnitIdBelongPlayerId(uint uid,uint pid) { return GetPlayerIdByUnitId(uid, out var pid1) && pid1 == pid; } //判断一个unit是否属于pid及其盟友 public bool CheckUnitIdBelongPlayerIdUnion(uint uid,uint pid) { //TODO #外交系统更新 return GetPlayerIdByUnitId(uid, out var pid1) && pid1 == pid; } //判断一个grid是否属于pid及其盟友 public bool CheckGridIdBelongPlayerIdUnion(uint gid,uint pid) { //TODO #外交系统更新 return GetPlayerDataByTerritoryGridId(gid, out var player) && player.Id == pid; } public bool CheckUnitIdBelongCityId(uint uid,uint cid) { return GetCityIdByUnitId(uid, out var cid1) && cid1 == cid; } public bool CheckCityIdBelongSelfPlayer(uint cid) { return GetPlayerIdByCityId(cid, out var pid1) && pid1 == PlayerMap.SelfPlayerData.Id; } public bool CheckUnitIdBelongSelfPlayer(uint uid) { return GetPlayerIdByUnitId(uid, out var pid1) && pid1 == PlayerMap.SelfPlayerData.Id; } #endregion //判断英雄的真实level public uint GetGiantRealLv(GiantType giantType, PlayerData player) { if (player == null) return 0; //获取unitTypeInfo,level=0时的信息 if(!Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(UnitType.Giant, giantType,0, out var Lv0Info)) return 0; //确认玩家最新的hero的unitLevel,获得level=realLv的info var realLv = Table.Instance.GiantExpToLevel(player.giantExp[(uint)Lv0Info.ChessType]); //判断有没有解锁科技,没有的话,realLv = 0 var action = new CommonActionId(); action.ActionType = CommonActionType.TrainUnit; action.UnitType = UnitType.Giant; action.GiantType = giantType; if (!player.TechTree.CheckActionCan(action)) realLv = 0; return (uint)realLv; } } // 地图 ID 生成器 [Serializable] public class MapIdGenerator { [SerializeField] private uint _idGenerator; public MapIdGenerator() { _idGenerator = 0; } public uint GeneratorId() { return ++_idGenerator; } public MapIdGenerator DeepCopy() { var copy = new MapIdGenerator(); copy._idGenerator = _idGenerator; return copy; } public void DeepCopy(MapIdGenerator copy) { _idGenerator = copy._idGenerator; } } }