/* * @Author: 白哉 * @Description: * @Date: 2025年04月03日 星期四 11:04:31 * @Modify: */ using System; using System.Collections.Generic; using Logic.Skill; using MemoryPack; using TH1_Logic.Core; using TH1Renderer; using UnityEngine; using UnityEngine.Animations; namespace RuntimeData { [MemoryPackable] public partial class GridMapData { public List GridList; private Dictionary _posToGridDict; private Dictionary _gridIdToGridDict; private Dictionary _gridIdToIndexDict; private MapConfig _mapCfg; [MemoryPackConstructor] public GridMapData() { GridList = new List(); _posToGridDict = new Dictionary(); _gridIdToGridDict = new Dictionary(); _gridIdToIndexDict = new Dictionary(); } public GridMapData(MapConfig mapCfg, MapIdGenerator idGenerator) { _mapCfg = mapCfg; GridList = new List(); _posToGridDict = new Dictionary(); _gridIdToGridDict = new Dictionary(); _gridIdToIndexDict = new Dictionary(); for (int x = 0; x < mapCfg.Width; x++) { for (int y = 0; y < mapCfg.Height; y++) { var gridData = new GridData(x, y, idGenerator,mapCfg); GridList.Add(gridData); _gridIdToGridDict[gridData.Id] = gridData; _posToGridDict[gridData.Pos.PosId] = gridData; } } for (int i = 0; i < GridList.Count; i++) { _gridIdToIndexDict[GridList[i].Id] = i; } } public GridMapData(GridMapData copyData) { _mapCfg = copyData._mapCfg; GridList = new List(); _posToGridDict = new Dictionary(); _gridIdToGridDict = new Dictionary(); _gridIdToIndexDict = new Dictionary(); foreach (var grid in copyData.GridList) { var gridData = new GridData(grid); GridList.Add(gridData); _gridIdToGridDict[gridData.Id] = gridData; _posToGridDict[gridData.Pos.PosId] = gridData; } for (int i = 0; i < GridList.Count; i++) { _gridIdToIndexDict[GridList[i].Id] = i; } } public void DeepCopy(GridMapData copyData) { _mapCfg = copyData._mapCfg; _posToGridDict.Clear(); _gridIdToGridDict.Clear(); _gridIdToIndexDict.Clear(); for (int i = 0; i < copyData.GridList.Count; i++) { var copyGrid = copyData.GridList[i]; if (i >= GridList.Count) { var gridData = new GridData(copyGrid); GridList.Add(gridData); _gridIdToGridDict[gridData.Id] = gridData; _posToGridDict[gridData.Pos.PosId] = gridData; } else { GridList[i].DeepCopy(copyGrid); _gridIdToGridDict[GridList[i].Id] = GridList[i]; _posToGridDict[GridList[i].Pos.PosId] = GridList[i]; } } for (int i = GridList.Count - 1; i >= copyData.GridList.Count; i--) { _gridIdToGridDict.Remove(GridList[i].Id); _posToGridDict.Remove(GridList[i].Pos.PosId); GridList.RemoveAt(i); } for (int i = 0; i < GridList.Count; i++) { _gridIdToIndexDict[GridList[i].Id] = i; } } [MemoryPackOnDeserialized] public void OnAfterMemoryPackDeserialize() { _posToGridDict ??= new Dictionary(); _gridIdToGridDict ??= new Dictionary(); _gridIdToIndexDict??= new Dictionary(); _posToGridDict.Clear(); _gridIdToGridDict.Clear(); _gridIdToIndexDict.Clear(); foreach (var grid in GridList) { _gridIdToGridDict[grid.Id] = grid; _posToGridDict[grid.Pos.PosId] = grid; } for (int i = 0; i < GridList.Count; i++) { _gridIdToIndexDict[GridList[i].Id] = i; } } public void BindMapConfig(MapConfig cfg) { _mapCfg = cfg; } public void OnTurnStart(MapData map) { foreach (var grid in GridList) grid.OnTurnStart(map); } public void OnTurnEnd(MapData map) { foreach (var grid in GridList) grid.OnTurnEnd(map); } public int GetGridIndexByGid(uint gid) { return _gridIdToIndexDict.GetValueOrDefault(gid, 0); } // 通过 gid 获取格子数据 public bool GetGridDataByGid(uint gid, out GridData data) { return _gridIdToGridDict.TryGetValue(gid, out data); } // 通过坐标获取格子数据 public bool GetGridDataByPos(int x, int y, out GridData gridData) { return _posToGridDict.TryGetValue(MapPosition.CalculatePosId(x, y), out gridData); } public bool GetGridDataByV2(Vector2 v2, out GridData gridData) { return GetGridDataByPos((int)v2.x, (int)v2.y, out gridData); } public bool GetGridDataByVector3Pos(Vector3 pos, out GridData gridData) { var p = Table.Instance.WorldToGrid(pos); return _posToGridDict.TryGetValue(MapPosition.CalculatePosId(p.x, p.y), out gridData); } // 获取目标周围的所有格子(含center) public List GetAroundGridData(int xOffset, int yOffset, GridData gridData) { List gridDataList = new List(); if (gridData == null) return gridDataList; int radius = Mathf.Max(xOffset, yOffset); //从内圈到外圈按顺序将格子加入list for (int r = 0; r <= radius; r++) { for (int x = gridData.Pos.X - xOffset; x <= gridData.Pos.X + xOffset; x++) { for (int y = gridData.Pos.Y - yOffset; y <= gridData.Pos.Y + yOffset; y++) { if (!GetGridDataByPos(x, y, out var aroundGridData)) continue; if (Mathf.Max(Mathf.Abs(x - gridData.Pos.X) , Mathf.Abs(y - gridData.Pos.Y)) != r) continue; gridDataList.Add(aroundGridData); } } } return gridDataList; } // 获取目标周围的所有格子(不含center) public HashSet GetAroundGridDataSet_NOCENTER(int xOffset, int yOffset, GridData gridData) { HashSet gridDataSet = new HashSet(); for (int x = gridData.Pos.X - xOffset; x <= gridData.Pos.X + xOffset; x++) { for (int y = gridData.Pos.Y - yOffset; y <= gridData.Pos.Y + yOffset; y++) { if (!GetGridDataByPos(x, y, out var aroundGridData)) continue; if (x == gridData.Pos.X && y == gridData.Pos.Y) continue; gridDataSet.Add(aroundGridData); } } return gridDataSet; } // 获取目标周围的所有格子,但是按照优先2468方向,返回有序的List public List GetAroundGridDataSetByOrder(int xOffset, int yOffset, GridData gridData) { List gridDataList = new List(); for (int i = 1; i <= 9; i++) { //下方的公式使得遍历顺序是 2468 13579 也就是优先bfs上下左右,再考虑斜的方向 int dirForHuman = (i <= 4) ? (2 * i) : (2 * (i - 5) + 1); int dirForComputer = dirForHuman - 1; int x = gridData.Pos.X + dirForComputer % 3 - 1; int y = gridData.Pos.Y + dirForComputer / 3 - 1; if (!GetGridDataByPos(x, y, out var aroundGridData)) continue; if (x == gridData.Pos.X && y == gridData.Pos.Y) continue; gridDataList.Add(aroundGridData); } return gridDataList; } public List GetAroundGridIdList(int radius, GridData gridData, bool remainCenter = false) { List gridIdList = new List(); //从内圈到外圈按顺序将格子加入list for (int r = 0; r <= radius; r++) { for (int x = gridData.Pos.X - radius; x <= gridData.Pos.X + radius; x++) { for (int y = gridData.Pos.Y - radius; y <= gridData.Pos.Y + radius; y++) { if (!GetGridDataByPos(x, y, out var aroundGridData)) continue; if (Mathf.Max(Mathf.Abs(x - gridData.Pos.X) , Mathf.Abs(y - gridData.Pos.Y)) != r) continue; if (!remainCenter && x == gridData.Pos.X && y == gridData.Pos.Y) continue; gridIdList.Add(aroundGridData.Id); } } } return gridIdList; } // 获取周围某个格子 public bool GetUpGridData(GridData gridData, int xOffset, int yOffset, out GridData upGridData) { return GetGridDataByPos(gridData.Pos.X + xOffset, gridData.Pos.Y + yOffset, out upGridData); } // 判断是否在左右边界 public bool IsInLeftOrRightBorder(GridData gridData) { return gridData.Pos.X == 0 || gridData.Pos.X == _mapCfg.Width - 1; } // 判断是否在上下边界 public bool IsInUpOrDownBorder(GridData gridData) { return gridData.Pos.Y == 0 || gridData.Pos.Y == _mapCfg.Height - 1; } //-------- 计算类方法 --------// //计算切比雪夫距离 public int CalcDistance(GridData gridDataA, GridData gridDataB) { return Mathf.Max(Mathf.Abs(gridDataA.Pos.X - gridDataB.Pos.X),Mathf.Abs(gridDataA.Pos.Y - gridDataB.Pos.Y)); } //计算曼哈顿距离 public int CalcManhattanDistance(GridData gridDataA, GridData gridDataB) { return Mathf.Abs(gridDataA.Pos.X - gridDataB.Pos.X) + Mathf.Abs(gridDataA.Pos.Y - gridDataB.Pos.Y); } public void RefreshConnectInfo() { } public bool CalcBridgeMirror(GridData gridData) { var x = gridData.Pos.X; var y = gridData.Pos.Y; if (!GetGridDataByPos(x, y - 1, out var grid1)) return true; if (!GetGridDataByPos(x, y + 1, out var grid2)) return true; if (grid1.Terrain != TerrainType.Land) return true; if (grid2.Terrain != TerrainType.Land) return true; return false; } } public enum GridSpType { None,RemiliaGrid,KaguyaGrid,RemiliaGridDark,Max } // 每个格子包含5个层次的信息 [MemoryPackable] public partial class GridData : IdentifierBase { //-------- BaseData ---------// // 位置信息 public MapPosition Pos; //public bool CityBuildingRenderMark = false; // 海陆层 public TerrainType Terrain; // 地形层 public TerrainFeature Feature; // 植被层 public Vegetation Vegetation; // 资源层+建筑层 public ResourceType Resource; public WonderLibrary Wonder; public ResourceType ResourceUnderBuilding; // 特殊效果层 public List SpTypeList; // Geo信息层 public List GeoIdList; public bool[] WaterRoadForceId; // 文明层 public uint CivId; public CivEnum CivEnum => Table.Instance.TransCivIdToCivEnum(CivId); //奇观Id //建筑level-只对部分建筑生效 public int buildingLevel; //海军基底提供的每回合恢复次数 , 目前天狗酒馆也采用这个次数 public int NavalBasePoint; //建筑的建立时间,目前只对temple有效 public uint BuildTime; //通用冷却cd参数,kaguyaFrenchAnimal吸引动物、EgyptianIrrigation生成农田,都会操纵这个参数 //建筑的kaguyaFrenchAnimal吸引量,每回合+1,>=2则可以在周围找个树林吸引一个动物,然后置0 public uint CommonColdTime; //-------- RenderData ---------// //cityborder相关的RenderMark [MemoryPackIgnore] public bool CityBorderRenderMark = false; [MemoryPackConstructor] public GridData() { SpTypeList = new List(); } public GridData(int x, int y,MapIdGenerator mapIdGenerator,MapConfig mapConfig) { SpTypeList = new List(); Pos = new MapPosition(x,y); Id = mapIdGenerator.GeneratorId(); WaterRoadForceId = new bool[Table.Instance.MaxForceCount]; } //仅用于AI计算data,不需要render的部分 public GridData(GridData copyData) { Pos = new MapPosition(copyData.Pos.X, copyData.Pos.Y); Id = copyData.Id; Terrain = copyData.Terrain; Feature = copyData.Feature; Vegetation = copyData.Vegetation; Resource = copyData.Resource; ResourceUnderBuilding = copyData.ResourceUnderBuilding; CivId = copyData.CivId; Wonder = copyData.Wonder; buildingLevel = copyData.buildingLevel; WaterRoadForceId = new bool[copyData.WaterRoadForceId.Length]; Array.Copy(copyData.WaterRoadForceId, WaterRoadForceId, copyData.WaterRoadForceId.Length); foreach (var skill in copyData.Skills) Skills.Add(skill.GetCopySkill()); //拷贝Grid的SpTypeList SpTypeList = new List(); SpTypeList.Clear(); foreach (var SpType in copyData.SpTypeList) SpTypeList.Add(SpType); } public void DeepCopy(GridData copyData) { Pos.X = copyData.Pos.X; Pos.Y = copyData.Pos.Y; Id = copyData.Id; Terrain = copyData.Terrain; Feature = copyData.Feature; Vegetation = copyData.Vegetation; Resource = copyData.Resource; ResourceUnderBuilding = copyData.ResourceUnderBuilding; CivId = copyData.CivId; Wonder = copyData.Wonder; buildingLevel = copyData.buildingLevel; WaterRoadForceId = new bool[copyData.WaterRoadForceId.Length]; Array.Copy(copyData.WaterRoadForceId, WaterRoadForceId, copyData.WaterRoadForceId.Length); //拷贝Grid的SpTypeList SpTypeList ??= new List(); SpTypeList.Clear(); foreach (var SpType in copyData.SpTypeList) SpTypeList.Add(SpType); Skills.Clear(); foreach (var skill in copyData.Skills) Skills.Add(skill.GetCopySkill()); } public void SetGridData(TerrainType ter,TerrainFeature fea,Vegetation veg, ResourceType res,uint civ) { Terrain = ter; Feature = fea; Vegetation = veg; Resource = res; ResourceUnderBuilding = ResourceType.None; CivId = civ; } public bool IsRoadBridgePort() { return Feature == TerrainFeature.Road || Resource == ResourceType.Port || Resource == ResourceType.Bridge; } public Vector3 V3() => Table.Instance.GridToWorld(this,""); public bool HasBuilding() { return !(Resource == ResourceType.None || Resource == ResourceType.Fruit || Resource == ResourceType.Crop || Resource == ResourceType.Starfish || Resource == ResourceType.Fish || Resource == ResourceType.Metal || Resource == ResourceType.Treasure); } public bool IsMainMap() { if (!Main.MapData.GridMap.GetGridDataByGid(Id, out var gridData) || gridData != this) return false; return true; } public bool InMainSight() { if (!IsMainMap()) return false; return Main.MapData.PlayerMap.SelfPlayerData.Sight.CheckIsInSight(Id); } //返回该格子周围是否存在没有视野的格子 public bool UnsightNearby(MapData map, PlayerData player) { var gridList = map.GridMap.GetAroundGridData(1, 1, this); foreach (var grid in gridList) { if (player.Sight.CheckIsInSight(grid.Id)) return true; } return false; } // 全局通知调用 public void OnTurnStart(MapData map) { //Step #1 处理海军点 TODO 将来要并入skill去 NavalBasePoint = 1; //Step #2 处理kaguyaFrenchAnimal(必须是该grid玩家的回合) if (Resource == ResourceType.KaguyaFrenchYard && map.CheckIfGidBelongPid(Id,map.CurPlayer.Id)) { CommonColdTime++; if (CommonColdTime >= 2) { var gridList = map.GridMap.GetAroundGridData(1, 1, this); if (map.GetPlayerDataByTerritoryGridId(Id, out var player)) foreach (var grid in gridList) { if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer)) continue; if (gridPlayer.Id != player.Id) continue; if (grid.Vegetation != Vegetation.Trees) continue; if (grid.Resource != ResourceType.None) continue; grid.Resource = ResourceType.Animal; grid.Renderer(map)?.InstantUpdateGrid(true); grid.Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Treasure)); CommonColdTime = 0; Main.CityLogic.UpdateGridBuildingData(map,this); Renderer(map)?.InstantUpdateGrid(true); Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Fog)); break; } } } //Step #3 处理EgyptianIrrigation(必须是该grid玩家的回合) if (Resource == ResourceType.EgyptianIrrigation && map.CheckIfGidBelongPid(Id,map.CurPlayer.Id)) { CommonColdTime++; if (CommonColdTime >= 2) { var gridList = map.GridMap.GetAroundGridData(1, 1, this); if (map.GetPlayerDataByTerritoryGridId(Id, out var player)) foreach (var grid in gridList) { if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer)) continue; if (gridPlayer.Id != player.Id) continue; if (grid.Terrain != TerrainType.Land) continue; if (grid.Vegetation == Vegetation.Trees) continue; if (grid.Feature == TerrainFeature.Mountain) continue; if (grid.Resource != ResourceType.None) continue; grid.Resource = ResourceType.Crop; grid.Renderer(map)?.InstantUpdateGrid(true); grid.Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Treasure)); CommonColdTime = 0; //Main.CityLogic.UpdateGridBuildingData(map,this); //Renderer(map)?.SetUpdateGrid(true); //Renderer(Main.MapData)?.PlayVFX(new GridVFXParams(GridVFXType.Fog)); break; } } } //Step #4 处理RemiliaMilitary if (Resource == ResourceType.RemiliaMilitary && map.CheckIfGidBelongPid(Id,map.CurPlayer.Id)) { if (!HasSpType(GridSpType.RemiliaGrid)) AddSpType(GridSpType.RemiliaGrid,map,null); Renderer(map)?.InstantUpdateGrid(); } //Step #5 处理MetalStation if (Resource == ResourceType.MetalStation && map.CheckIfGidBelongPid(Id,map.CurPlayer.Id)) { CommonColdTime++; if (CommonColdTime > 2) { Resource = ResourceType.Metal; //如果有moriyaRoad科技,更新连通性 if(map.CurPlayer.TechTree.CheckIfHasTechAtom(TechAtom.MoriyaRoad)) Main.PlayerLogic.UpdateCityConnect(map,map.CurPlayer); //Step #3 播放雾效,更新画面 if (InMainSight()) { Renderer(map)?.InstantUpdateGrid(true); Renderer(map)?.PlayVFX(new GridVFXParams(GridVFXType.Fog)); } } } //Step #6 处理所有技能 OnSkillsTurnStart(map); } public void OnTurnEnd(MapData map) { //Step #2 处理所有技能 OnSkillsTurnEnd(map); } //皮肤层的一些基础属性调用 public bool HasSpType(GridSpType type) { foreach(var t in SpTypeList) if (t == type) return true; return false; } public bool RemoveSpType(GridSpType type,MapData map) { foreach(var t in SpTypeList) if (t == type) { SpTypeList.Remove(t); if (type == GridSpType.RemiliaGrid && Unit(map, out var unit)) { unit.RemoveSkill(SkillType.ScarletMistRealTimeVampire,map); } return true; } return false; } public bool AddSpType(GridSpType type,MapData map, UnitData origin)// = null) { if (HasSpType(type)) return false; if (type == GridSpType.RemiliaGrid) { if(Resource == ResourceType.CityCenter) return false; if (Terrain != TerrainType.Land) return false; } SpTypeList.Add(type); origin?.HeroTask(map)?.OnAddSpType(map, type); //如果是remiliaGrid,且是斯卡雷特帝国的单位,给当前的unit填加skill if (type == GridSpType.RemiliaGrid && Unit(map,out var unit) && unit.Player(map,out var player) && player.PlayerCivId == 0) { unit.AddSkill(SkillType.ScarletMistRealTimeVampire, map); } return true; } public GridSpType GetOnlyOneSpType() { if (HasSpType(GridSpType.RemiliaGrid)) return GridSpType.RemiliaGrid; if (HasSpType(GridSpType.KaguyaGrid)) return GridSpType.KaguyaGrid; return SpTypeList.Count > 0 ? SpTypeList[0] : GridSpType.None; } public UnitData Unit(MapData map) { map.GetUnitDataByGid(Id, out var unit); return unit; } public bool Unit(MapData map,out UnitData unit) { return map.GetUnitDataByGid(Id, out unit); } public CityData City(MapData map) { map.GetCityDataByTerritoryGid(Id, out var city); return city; } public bool City(MapData map ,out CityData city) { return map.GetCityDataByTerritoryGid(Id, out city); } public CityData CityOnGrid(MapData map) { map.GetCityDataByGid(Id, out var city); return city; } public bool CityOnGrid(MapData map,out CityData city) { return map.GetCityDataByGid(Id, out city); } //返回当前grid提供了多少的cityExp public int CityExp() { if (!Table.Instance.GridAndResourceDataAssets.GetResourceInfo(Resource, out var resourceInfo)) return 0; if (resourceInfo.HasLevel) return resourceInfo.CityExpPerLevel * buildingLevel; return resourceInfo.Exp; } public GridRenderer Renderer(MapData map) { if (map != Main.MapData) return null; MapRenderer.Instance.ROGridMap.TryGetValue(Id, out var renderer); return renderer; } public PlayerData Player(MapData map) { map.GetPlayerDataByTerritoryGridId(Id, out var player); return player; } public List GetRealTimeGeoIdList() { var ret = new List(); foreach (var t in GeoIdList) { } foreach(var t in GeoIdList) if (Main.Instance.MapGeneratorLogic?.GeoDict?.TryGetValue(t, out var info)??false) { if (info.GeoBigClass == GeoBigClass.Forest && Vegetation == Vegetation.Trees) ret.Add(info.Id); if (info.GeoBigClass == GeoBigClass.Mountain && Feature == TerrainFeature.Mountain) ret.Add(info.Id); //平原要剔除有山的情况,如果已经有山就不加平原信息了 if (info.GeoBigClass == GeoBigClass.Plain && Feature != TerrainFeature.Mountain) ret.Add(info.Id); //水域要剔除有山的情况,如果已经有山就不加平原信息了 if (info.GeoBigClass == GeoBigClass.Water && Feature != TerrainFeature.Mountain)ret.Add(info.Id); if (info.GeoBigClass == GeoBigClass.Building) { if (info.GeoSmallClass == GeoSmallClass.Bridge && Resource == ResourceType.Bridge) ret.Add(info.Id); if (info.GeoSmallClass == GeoSmallClass.Port && Resource == ResourceType.Port) ret.Add(info.Id); if (info.GeoSmallClass == GeoSmallClass.Forge && Resource == ResourceType.Forge) ret.Add(info.Id); if (info.GeoSmallClass == GeoSmallClass.Sawmill && Resource == ResourceType.Sawmill) ret.Add(info.Id); if (info.GeoSmallClass == GeoSmallClass.Windmill&& Resource == ResourceType.Windmill) ret.Add(info.Id); if (info.GeoSmallClass == GeoSmallClass.Market&& Resource == ResourceType.Market) ret.Add(info.Id); if (info.GeoSmallClass == GeoSmallClass.Mine&& Resource == ResourceType.Mine) ret.Add(info.Id); if (info.GeoSmallClass == GeoSmallClass.NavelBase&& Resource == ResourceType.NavalBase) ret.Add(info.Id); if (info.GeoSmallClass == GeoSmallClass.Military&& Resource == ResourceType.Military) ret.Add(info.Id); } } return ret; } public void UpdateGeoInfo(MapData map) { bool bridge = false; bool port = false; bool forest = false; bool mountain = false; bool forge = false; bool sawmill = false; bool military = false; bool navelbase = false; bool windmill = false; bool market = false; bool mine = false; foreach(var t in GeoIdList) if (Main.Instance.MapGeneratorLogic?.GeoDict?.TryGetValue(t, out var info) ?? false) { if (info.GeoBigClass == GeoBigClass.Forest) forest = true; if (info.GeoBigClass == GeoBigClass.Mountain) mountain = true; if (info.GeoSmallClass == GeoSmallClass.Bridge) bridge = true; if (info.GeoSmallClass == GeoSmallClass.Port) port = true; if (info.GeoSmallClass == GeoSmallClass.Forge) forge = true; if (info.GeoSmallClass == GeoSmallClass.Sawmill) sawmill = true; if (info.GeoSmallClass == GeoSmallClass.Windmill) windmill = true; if (info.GeoSmallClass == GeoSmallClass.Market) market = true; if (info.GeoSmallClass == GeoSmallClass.Mine) mine = true; if (info.GeoSmallClass == GeoSmallClass.NavelBase) navelbase = true; if (info.GeoSmallClass == GeoSmallClass.Military) military = true; } var smallSet = new HashSet(); uint id; if (Vegetation == Vegetation.Trees && !forest) { if(Main.Instance.MapGeneratorLogic?.GetForestGeoId(map,this,out id)??false) GeoIdList.Add(id); } if (Feature == TerrainFeature.Mountain && !mountain) { smallSet.Add(GeoSmallClass.Volcano); smallSet.Add(GeoSmallClass.Mountain); smallSet.Add(GeoSmallClass.Hill); if(Main.Instance.MapGeneratorLogic?.GetGeoId(CivEnum,GeoBigClass.Mountain,smallSet,out id)??false) GeoIdList.Add(id); } if (Resource == ResourceType.Bridge && !bridge)smallSet.Add(GeoSmallClass.Bridge); if (Resource == ResourceType.Port && !port)smallSet.Add(GeoSmallClass.Port); if (Resource == ResourceType.Forge && !forge)smallSet.Add(GeoSmallClass.Forge); if (Resource == ResourceType.Sawmill && !sawmill)smallSet.Add(GeoSmallClass.Sawmill); if (Resource == ResourceType.Windmill && !windmill)smallSet.Add(GeoSmallClass.Windmill); if (Resource == ResourceType.Market && !market)smallSet.Add(GeoSmallClass.Market); if (Resource == ResourceType.Mine && !mine)smallSet.Add(GeoSmallClass.Mine); if (Resource == ResourceType.NavalBase && !navelbase)smallSet.Add(GeoSmallClass.NavelBase); if (Resource == ResourceType.Military && !military)smallSet.Add(GeoSmallClass.Military); if(Main.Instance.MapGeneratorLogic?.GetGeoId(CivEnum,GeoBigClass.Building,smallSet,out id)??false) GeoIdList.Add(id); } } // 位置基类 [MemoryPackable] public partial class MapPosition { public int X; public int Y; public uint PosId => CalculatePosId(X, Y); public Vector2Int V2() => new Vector2Int(X, Y); public static uint CalculatePosId(int x, int y) { return (uint)(x * 1000 + y); } [MemoryPackConstructor] public MapPosition() { X = 0; Y = 0; } public MapPosition(int x,int y) { X = x; Y = y; } public MapPosition(Vector2 v2) { X = (int)v2.x; Y = (int)v2.y; } public void SetPosition(MapPosition pos) { X = pos.X; Y = pos.Y; } // 重载 GetHashCode public override int GetHashCode() { return HashCode.Combine(X, Y); // 或者更简单的方式: // return X.GetHashCode() ^ Y.GetHashCode(); } // 重载 Equals(object) public override bool Equals(object obj) { return obj is MapPosition other && Equals(other); } // 实现 IEquatable public bool Equals(MapPosition other) { if (other == null) return false; return X == other.X && Y == other.Y; } // 重载 == 操作符(推荐) public static bool operator ==(MapPosition left, MapPosition right) { if (ReferenceEquals(left, right)) return true; if (left is null || right is null) return false; return left.Equals(right); } // 重载 != 操作符(推荐) public static bool operator !=(MapPosition left, MapPosition right) { return !(left == right); } } }