2025-07-16 15:41:43 +08:00

511 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: 白哉
* @Description:
* @Date: 2025年04月03日 星期四 11:04:31
* @Modify:
*/
using System;
using System.Collections.Generic;
using Logic;
using TH1Renderer;
using UnityEngine;
namespace RuntimeData
{
[Serializable]
public class GridMapData : ISerializationCallbackReceiver
{
public List<GridData> GridList;
private Dictionary<uint, GridData> _posToGridDict;
private Dictionary<uint, GridData> _gridIdToGridDict;
private MapConfig _mapCfg;
public GridMapData()
{
GridList = new List<GridData>();
_posToGridDict = new Dictionary<uint, GridData>();
_gridIdToGridDict = new Dictionary<uint, GridData>();
}
public GridMapData(MapConfig mapCfg, MapIdGenerator idGenerator)
{
_mapCfg = mapCfg;
GridList = new List<GridData>();
_posToGridDict = new Dictionary<uint, GridData>();
_gridIdToGridDict = new Dictionary<uint, GridData>();
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;
}
}
}
public GridMapData(GridMapData copyData)
{
_mapCfg = copyData._mapCfg;
GridList = new List<GridData>();
_posToGridDict = new Dictionary<uint, GridData>();
_gridIdToGridDict = new Dictionary<uint, GridData>();
foreach (var grid in copyData.GridList)
{
var gridData = new GridData(grid);
GridList.Add(gridData);
_gridIdToGridDict[gridData.Id] = gridData;
_posToGridDict[gridData.Pos.PosId] = gridData;
}
}
public void DeepCopy(GridMapData copyData)
{
_mapCfg = copyData._mapCfg;
_posToGridDict.Clear();
_gridIdToGridDict.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);
}
}
public void OnBeforeSerialize()
{
}
public void OnAfterDeserialize()
{
_posToGridDict ??= new Dictionary<uint, GridData>();
_gridIdToGridDict ??= new Dictionary<uint, GridData>();
_posToGridDict.Clear();
_gridIdToGridDict.Clear();
foreach (var grid in GridList)
{
_gridIdToGridDict[grid.Id] = grid;
_posToGridDict[grid.Pos.PosId] = grid;
}
}
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);
}
// 通过 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 GetGridDataByVector3Pos(Vector3 pos, out GridData gridData)
{
var p = Table.Instance.WorldToGrid(pos);
return _posToGridDict.TryGetValue(MapPosition.CalculatePosId(p.x, p.y), out gridData);
}
// 获取目标周围的所有格子
public List<GridData> GetAroundGridData(int xOffset, int yOffset, GridData gridData)
{
List<GridData> gridDataList = new List<GridData>();
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;
gridDataList.Add(aroundGridData);
}
}
return gridDataList;
}
// 获取目标周围的所有格子
public HashSet<GridData> GetAroundGridDataSet(int xOffset, int yOffset, GridData gridData)
{
HashSet<GridData> gridDataSet = new HashSet<GridData>();
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<GridData> GetAroundGridDataSetByOrder(int xOffset, int yOffset, GridData gridData)
{
List<GridData> gridDataList = new List<GridData>();
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<uint> GetAroundGridIdList(int radius, GridData gridData, bool remainCenter = false)
{
List<uint> gridIdList = new List<uint>();
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 (!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 void RefreshConnectInfo()
{
}
}
public class GridVFXRenderMark
{
//1play 0stop
public GridVFXType Type;
public bool PlayOrStop;
public bool RenderMark;
public uint CivId;
public int Damage;
public GridVFXRenderMark(GridVFXType gridVFXType,bool renderMark = true, bool playOrStop = true)
{
Type = gridVFXType;
RenderMark = renderMark;
PlayOrStop = playOrStop;
}
public void CopyFrom(GridVFXRenderMark other)
{
if (other == null) return;
Type = other.Type;
PlayOrStop = other.PlayOrStop;
RenderMark = other.RenderMark;
CivId = other.CivId;
Damage = other.Damage;
}
}
// 每个格子包含5个层次的信息
[Serializable]
public 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 bool[] WaterRoadForceId;
// 文明层
public uint CivId;
//奇观Id
//建筑level-只对部分建筑生效
public int buildingLevel;
//建筑的建立时间目前只对temple有效
public uint BuildTime;
//-------- RenderData ---------//
//gridVFX相关的RenderMark
public bool VFXRenderMarkHurt = false;
public bool VFXRenderMarkDie = false;
public bool VFXRenderMarkDieHintStart = false;
public int VFXRenderMarkDieHintStartParam = 0;
public bool VFXRenderMarkDieHintEnd = false;
public bool VFXRenderMarkTreasure = false;
public bool VFXRenderMarkHeal = false;
public bool VFXRenderMarkFlag = false;
public uint VFXRenderMarkFlagCivId = 0;
public bool VFXRenderMarkFog = false;
public bool VFXRenderMark = false;
public Dictionary<GridVFXType, GridVFXRenderMark> RenderMarkVFXDict;
//cityborder相关的RenderMark
public bool CityBorderRenderMark = false;
//用来设置vfxRenderMark, 单独做成一个方法是为了避免dict值为空的情况
public void SetGridVFXRenderMark(GridVFXRenderMark tmp)
{
if (RenderMarkVFXDict == null || !RenderMarkVFXDict.TryGetValue(tmp.Type, out var target))
{
InitRenderMark();
if (!RenderMarkVFXDict.TryGetValue(tmp.Type, out target))
return;
}
target.CopyFrom(tmp);
}
public void InitRenderMark()
{
RenderMarkVFXDict = new Dictionary<GridVFXType,GridVFXRenderMark>();
foreach(GridVFXType type in Enum.GetValues(typeof(GridVFXType)))
RenderMarkVFXDict[type] = new GridVFXRenderMark(type,false);
}
public GridData(int x, int y,MapIdGenerator mapIdGenerator,MapConfig mapConfig)
{
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());
}
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);
foreach (var skill in copyData.Skills)
{
AddSkill(skill.GetSkillType());
if (!GetSkill(skill.GetSkillType(), out var selfSkill)) continue;
selfSkill.DeepCopy(skill);
}
for (int i = Skills.Count - 1; i >= 0; i--)
{
if (copyData.GetSkill(Skills[i].GetSkillType(), out _)) continue;
Skills.RemoveAt(i);
}
}
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 void OnTurnStart(MapData map)
{
for (int i = Skills.Count - 1; i >= 0; i--)
{
var skill = Skills[i];
if (skill.IsFinished())
{
Skills.RemoveAt(i);
continue;
}
skill.OnTurnStart(this, map);
}
//TODO 不应该写在这里应该由CityLogic处理或者PlayerLogic处理反正应该在Logic模块StartNextTurn那个函数处理
//处理神庙升级的模块
if (map.GetPlayerDataByTerritoryGridId(Id, out var player)
&&
(Resource == ResourceType.Temple
|| Resource == ResourceType.WaterTemple
|| Resource == ResourceType.ForestTemple
|| Resource == ResourceType.MountainTemple)
)
{
int newLevel = (int)(player.Turn - BuildTime) / 2 + 1;
if (newLevel > 5) newLevel = 5;
if (newLevel != buildingLevel)
{
int delta = newLevel - buildingLevel;
buildingLevel = newLevel;
RenderMark = true;
VFXRenderMarkFog = true;
if (delta > 0)
{
var main = GameObject.Find("Main").GetComponent<Main>();
//如果既是非AI的真实mapdata又是玩家的各自
if (Main.MapData == map && player.Id == map.PlayerMap.SelfPlayerId)
{
var faithPanel = GameObject.Find("UICanvas/TopBarPanel/FaithPanel/Icon").transform;
var startPos = Table.Instance.GridToWorld(this);
var endPos = Camera.main.ScreenToWorldPoint(faithPanel.position);
MapRenderer.Instance.ProjectileManager.CreateProjectile(main,map,startPos,endPos,ProjectileType.Faith,ProjectileMoveType.CoinParabola,delta * 50);
}
}
}
}
}
public void OnTurnEnd(MapData map)
{
foreach (var skill in Skills) skill.OnTurnEnd(this, map);
}
}
// 位置基类
[Serializable]
public class MapPosition
{
public int X;
public int Y;
public uint PosId => CalculatePosId(X, Y);
public static uint CalculatePosId(int x, int y)
{
return (uint)(x * 1000 + y);
}
public MapPosition()
{
X = 0;
Y = 0;
}
public MapPosition(int x,int y)
{
X = x;
Y = y;
}
public void SetPosition(MapPosition pos)
{
X = pos.X;
Y = pos.Y;
}
}
}