Compare commits
3 Commits
954a07a0c3
...
d9a4924e2e
| Author | SHA1 | Date | |
|---|---|---|---|
| d9a4924e2e | |||
| c88a608e47 | |||
| 674c881ac1 |
859
MD/代码优化标准.md
Normal file
859
MD/代码优化标准.md
Normal file
@ -0,0 +1,859 @@
|
||||
# 🔧 TH1 代码优化标准
|
||||
|
||||
> **适用范围**: TH1 回合制4X策略游戏全模块
|
||||
> **核心目标**: 减少GC分配 · 加快计算速度 · 保证输入输出不变
|
||||
> **约束条件**: 不改变整体逻辑 · 兼容 MemoryPack 本地/网络序列化 · 保持多人同步正确性
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
- [第一章 总则与核心原则](#第一章-总则与核心原则)
|
||||
- [第二章 序列化安全规范](#第二章-序列化安全规范)
|
||||
- [第三章 GC优化标准](#第三章-gc优化标准)
|
||||
- [第四章 计算优化标准](#第四章-计算优化标准)
|
||||
- [第五章 模块专项优化指南](#第五章-模块专项优化指南)
|
||||
- [第六章 优化验证清单](#第六章-优化验证清单)
|
||||
- [附录A 已知GC热点清单](#附录a-已知gc热点清单)
|
||||
- [附录B 禁止与允许操作速查表](#附录b-禁止与允许操作速查表)
|
||||
|
||||
---
|
||||
|
||||
## 第一章 总则与核心原则
|
||||
|
||||
### 1.1 优化铁律
|
||||
|
||||
| 编号 | 规则 | 说明 |
|
||||
|------|------|------|
|
||||
| **R-01** | **输入输出不变** | 任何优化不得改变方法的参数签名、返回值语义和副作用。对外行为必须与优化前完全一致 |
|
||||
| **R-02** | **逻辑等价** | 优化只能改变"怎么做",不能改变"做什么"。所有分支路径、计算结果、状态变更必须等价 |
|
||||
| **R-03** | **序列化安全** | 任何新增缓存/查找表字段必须加 `[MemoryPackIgnore]`,不得影响存档文件和网络消息的二进制格式 |
|
||||
| **R-04** | **确定性一致** | 多人联网场景下,优化后的计算必须保持确定性(相同输入产生相同输出),不得引入浮点精度差异 |
|
||||
| **R-05** | **渐进式优化** | 每次只优化一个点,优化后必须验证,确认无误后再优化下一个 |
|
||||
|
||||
### 1.2 优化优先级
|
||||
|
||||
```
|
||||
优先级从高到低:
|
||||
P0 - 消除热路径中的 GC 分配(每帧/每回合执行的代码)
|
||||
P1 - 缓存重复计算结果(空间换时间,需考虑序列化)
|
||||
P2 - 算法复杂度优化(O(n²) → O(n) 或 O(n log n))
|
||||
P3 - 减少非热路径的 GC 分配(初始化/低频调用)
|
||||
P4 - 微优化(方法内联、分支预测等)
|
||||
```
|
||||
|
||||
### 1.3 不优化原则
|
||||
|
||||
以下情况**不应**进行优化:
|
||||
|
||||
- 仅在游戏初始化时执行一次的代码(如 `SkillFactory` 首次反射扫描)
|
||||
- 仅在加载/存档时执行的代码(除非造成明显卡顿)
|
||||
- UI 层的低频更新代码
|
||||
- 已经足够高效且无 GC 问题的代码
|
||||
|
||||
---
|
||||
|
||||
## 第二章 序列化安全规范
|
||||
|
||||
### 2.1 TH1 序列化架构概览
|
||||
|
||||
TH1 存在三种序列化场景,任何"空间换时间"优化必须同时考虑:
|
||||
|
||||
| 场景 | 序列化方式 | 频率 | 敏感度 |
|
||||
|------|-----------|------|--------|
|
||||
| **本地存档** | MemoryPack → `.dat` 文件 | 每回合一次 | 向后兼容(旧存档能读取) |
|
||||
| **网络同步** | MemoryPack → Steam P2P | 每个Action、每2秒心跳 | 双向兼容(多客户端版本) |
|
||||
| **训练数据** | MemoryPack / JSON → `.jsonl` | `#if ENABLE_TRAIN` 时每步一次 | 格式稳定 |
|
||||
|
||||
### 2.2 核心 MemoryPackable 类清单
|
||||
|
||||
以下类直接参与序列化,新增字段时**必须**遵守规范:
|
||||
|
||||
```
|
||||
MapData ─ 游戏世界根节点(包含以下所有子结构)
|
||||
├── MapConfig ─ 对局配置
|
||||
├── GridMapData ─ 所有格子
|
||||
│ └── GridData ─ 单个格子(附带 Skills)
|
||||
├── PlayerMapData─ 所有玩家
|
||||
│ └── PlayerData─ 单个玩家(附带 Skills, DiplomacyData, TechTreeData)
|
||||
├── CityMapData ─ 所有城市
|
||||
│ └── CityData ─ 单个城市(附带 TerritoryData, Skills)
|
||||
├── UnitMapData ─ 所有部队
|
||||
│ └── UnitData ─ 单个部队(附带 Skills, ActionPoint)
|
||||
└── NetData ─ 网络状态(含 Actions 历史, 随机种子)
|
||||
|
||||
CommonActionParams ─ Action参数(网络传输)
|
||||
BaseMessage (16种) ─ 网络消息(含 GameStartMessage 携带完整 MapData)
|
||||
SkillBase (242种子类)─ 技能多态序列化
|
||||
```
|
||||
|
||||
### 2.3 新增缓存字段的标准做法
|
||||
|
||||
#### ✅ 正确做法:`[MemoryPackIgnore]` + 重建逻辑
|
||||
|
||||
```csharp
|
||||
[MemoryPackable]
|
||||
public partial class UnitData : IdentifierBase
|
||||
{
|
||||
// 已有的序列化字段
|
||||
public List<SkillBase> Skills;
|
||||
|
||||
// ===== 新增的缓存字段 =====
|
||||
[MemoryPackIgnore]
|
||||
private Dictionary<SkillType, SkillBase> _skillLookup;
|
||||
|
||||
/// <summary>
|
||||
/// O(1) 技能查找,替代 Skills 列表的 O(n) 线性搜索。
|
||||
/// 缓存在反序列化后自动重建。
|
||||
/// </summary>
|
||||
public SkillBase GetSkillFast(SkillType type)
|
||||
{
|
||||
if (_skillLookup == null) RebuildSkillLookup();
|
||||
return _skillLookup.TryGetValue(type, out var skill) ? skill : null;
|
||||
}
|
||||
|
||||
// 当 Skills 列表发生变更时调用
|
||||
public void InvalidateSkillLookup()
|
||||
{
|
||||
_skillLookup = null; // 延迟重建,下次查找时自动构建
|
||||
}
|
||||
|
||||
private void RebuildSkillLookup()
|
||||
{
|
||||
_skillLookup ??= new Dictionary<SkillType, SkillBase>(Skills.Count);
|
||||
_skillLookup.Clear();
|
||||
foreach (var skill in Skills)
|
||||
_skillLookup[skill.GetSkillType()] = skill;
|
||||
}
|
||||
|
||||
[MemoryPackOnDeserialized]
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
_skillLookup = null; // 反序列化后标记为需要重建
|
||||
// 不在此处立即重建,延迟到首次使用
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### ❌ 错误做法
|
||||
|
||||
```csharp
|
||||
// 错误1:缓存字段没有加 [MemoryPackIgnore]
|
||||
[MemoryPackable]
|
||||
public partial class UnitData
|
||||
{
|
||||
public Dictionary<SkillType, SkillBase> _skillLookup; // ❌ 会被序列化,增大存档/网络包体积
|
||||
}
|
||||
|
||||
// 错误2:在 [MemoryPackOnDeserialized] 中执行重量级初始化
|
||||
[MemoryPackOnDeserialized]
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
RebuildSkillLookup(); // ❌ 网络同步的每次反序列化都会触发
|
||||
RecalcAllTerritoryBonuses(); // ❌ 高频反序列化时造成卡顿
|
||||
}
|
||||
|
||||
// 错误3:修改序列化字段的类型或移除字段
|
||||
public uint LegionId; // ❌ 如果改名或移除,旧存档无法反序列化
|
||||
```
|
||||
|
||||
### 2.4 序列化兼容性检查清单
|
||||
|
||||
每次涉及 `[MemoryPackable]` 类的修改,必须检查:
|
||||
|
||||
- [ ] 新增字段是否加了 `[MemoryPackIgnore]`?
|
||||
- [ ] 是否修改/删除/重排了已有的序列化字段?(**禁止**)
|
||||
- [ ] 缓存重建逻辑是否在 `[MemoryPackOnDeserialized]` 中以**延迟方式**处理?
|
||||
- [ ] 旧存档能否正常加载?(MemoryPack 对新增 Ignore 字段透明)
|
||||
- [ ] 多人游戏中不同客户端版本能否互通?
|
||||
|
||||
### 2.5 网络消息的特殊约束
|
||||
|
||||
对于 `CommonActionParams` 和 `BaseMessage` 子类:
|
||||
|
||||
- **绝不**新增序列化字段(增加每次 Action 的网络开销)
|
||||
- 如需传递额外数据,使用已有字段编码(如 `Value1`-`Value4` 通用数值字段)
|
||||
- 对于高频消息(心跳、Action确认),任何字节增长都会累积
|
||||
|
||||
### 2.6 反序列化重建的性能规范
|
||||
|
||||
```
|
||||
[MemoryPackOnDeserialized] 回调中:
|
||||
├── ✅ 可以做:设置标志位、置空缓存引用
|
||||
├── ✅ 可以做:O(1) 的简单赋值
|
||||
├── ⚠️ 谨慎做:O(n) 的字典/集合重建(仅在必要时)
|
||||
└── ❌ 禁止做:O(n²) 或更复杂的计算、涉及其他对象的查询
|
||||
```
|
||||
|
||||
理由:网络同步时,`ForceUpdateMessage` 和 `GameStartMessage` 会反序列化完整 `MapData`,触发所有子对象的 `[MemoryPackOnDeserialized]` 回调。如果每个回调都做重量级初始化,会造成瞬间卡顿。
|
||||
|
||||
---
|
||||
|
||||
## 第三章 GC优化标准
|
||||
|
||||
### 3.1 集合分配优化
|
||||
|
||||
#### 3.1.1 复用集合替代重复创建
|
||||
|
||||
**问题模式**:在频繁调用的方法中 `new List<T>()` / `new HashSet<T>()` / `new Dictionary<K,V>()`
|
||||
|
||||
```csharp
|
||||
// ❌ 每次调用都分配新集合
|
||||
public List<GridData> GetAroundGridData(GridData center, int radius)
|
||||
{
|
||||
List<GridData> result = new List<GridData>(); // GC 分配
|
||||
// ... 填充 result
|
||||
return result;
|
||||
}
|
||||
|
||||
// ✅ 方案A:调用方传入缓冲区
|
||||
public void GetAroundGridData(GridData center, int radius, List<GridData> buffer)
|
||||
{
|
||||
buffer.Clear();
|
||||
// ... 填充 buffer
|
||||
}
|
||||
|
||||
// ✅ 方案B:类级别复用集合(非线程安全,单线程游戏逻辑可用)
|
||||
private static readonly List<GridData> _sharedGridBuffer = new List<GridData>(64);
|
||||
|
||||
public List<GridData> GetAroundGridData(GridData center, int radius)
|
||||
{
|
||||
_sharedGridBuffer.Clear();
|
||||
// ... 填充 _sharedGridBuffer
|
||||
return _sharedGridBuffer; // 注意:调用方不应持有引用或修改
|
||||
}
|
||||
```
|
||||
|
||||
**适用范围**:
|
||||
|
||||
| 方法 | 当前问题 | 建议方案 |
|
||||
|------|---------|---------|
|
||||
| `GridMapData.GetAroundGridData()` (4个重载) | 每次 new List/HashSet | 传入缓冲区 |
|
||||
| `GridMapData.GetAroundGridIdList()` | 每次 new List\<uint\> | 传入缓冲区 |
|
||||
| `MapData.GetPlayerTerritoryGridIdSet()` | 每次 new HashSet + new List | 玩家级缓存 + 脏标记 |
|
||||
| `MapData.GetUnitDataListByPlayerId()` | null 参数时 new List | 必须传入缓冲区 |
|
||||
| `MapData.GetUnitDataListByCityId()` | null 参数时 new List | 必须传入缓冲区 |
|
||||
| `MapData.GetCityDataListByPlayerId()` | null 参数时 new List | 必须传入缓冲区 |
|
||||
|
||||
#### 3.1.2 集合预分配容量
|
||||
|
||||
```csharp
|
||||
// ❌ 默认容量,后续频繁扩容
|
||||
var list = new List<UnitData>();
|
||||
|
||||
// ✅ 预分配合理容量
|
||||
var list = new List<UnitData>(expectedCount);
|
||||
|
||||
// ✅ 字典也需要预分配
|
||||
var dict = new Dictionary<uint, CityData>(CityList.Count);
|
||||
```
|
||||
|
||||
**预分配容量参考**:
|
||||
|
||||
| 集合用途 | 建议初始容量 |
|
||||
|---------|-------------|
|
||||
| 格子周围列表(radius=1) | 9 |
|
||||
| 格子周围列表(radius=2) | 25 |
|
||||
| 玩家城市列表 | 8 |
|
||||
| 玩家部队列表 | 32 |
|
||||
| 城市领土格子集合 | 64 |
|
||||
| 技能列表 | 8 |
|
||||
|
||||
#### 3.1.3 消除默认参数创建集合
|
||||
|
||||
```csharp
|
||||
// ❌ 可选参数导致隐式分配
|
||||
public void GetUnitDataListByPlayerId(uint pid, List<UnitData> list = null)
|
||||
{
|
||||
if (list == null) list = new List<UnitData>(); // 隐式 GC 分配
|
||||
// ...
|
||||
}
|
||||
|
||||
// ✅ 强制调用方提供缓冲区(消除隐式分配)
|
||||
public void GetUnitDataListByPlayerId(uint pid, List<UnitData> buffer)
|
||||
{
|
||||
buffer.Clear();
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 字符串优化
|
||||
|
||||
#### 3.2.1 避免热路径中的字符串操作
|
||||
|
||||
```csharp
|
||||
// ❌ 循环中拼接字符串
|
||||
foreach (var unit in units)
|
||||
{
|
||||
string key = "Unit_" + unit.Id.ToString(); // 每次循环产生 2 次分配
|
||||
Debug.Log($"Processing {key}"); // 插值字符串再分配
|
||||
}
|
||||
|
||||
// ✅ 调试日志使用条件编译
|
||||
#if UNITY_EDITOR
|
||||
foreach (var unit in units)
|
||||
{
|
||||
Debug.Log($"Processing Unit_{unit.Id}");
|
||||
}
|
||||
#endif
|
||||
|
||||
// ✅ 需要运行时字符串时使用 StringBuilder 复用
|
||||
private static readonly StringBuilder _sb = new StringBuilder(256);
|
||||
|
||||
public string GetDebugInfo()
|
||||
{
|
||||
_sb.Clear();
|
||||
_sb.Append("Unit_").Append(unit.Id);
|
||||
return _sb.ToString(); // 仅产生一次分配
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2.2 枚举转字符串缓存
|
||||
|
||||
```csharp
|
||||
// ❌ 每次调用都装箱 + 反射
|
||||
string name = skillType.ToString(); // 装箱 + 内部反射查找
|
||||
|
||||
// ✅ 预建枚举字符串映射表
|
||||
private static readonly Dictionary<SkillType, string> _skillTypeNames;
|
||||
|
||||
static SkillHelper()
|
||||
{
|
||||
var values = (SkillType[])Enum.GetValues(typeof(SkillType));
|
||||
_skillTypeNames = new Dictionary<SkillType, string>(values.Length);
|
||||
foreach (var v in values) _skillTypeNames[v] = v.ToString();
|
||||
}
|
||||
|
||||
public static string GetSkillTypeName(SkillType type) => _skillTypeNames[type];
|
||||
```
|
||||
|
||||
### 3.3 对象创建优化
|
||||
|
||||
#### 3.3.1 技能工厂优化(SkillFactory)
|
||||
|
||||
```csharp
|
||||
// ❌ 当前:每次创建技能都用 Activator.CreateInstance(反射开销大)
|
||||
public static SkillBase GetSkillBySkillType(SkillType type)
|
||||
{
|
||||
return Activator.CreateInstance(_skillDict[type]) as SkillBase; // 反射 + 装箱
|
||||
}
|
||||
|
||||
// ✅ 使用编译时委托替代反射
|
||||
private static Dictionary<SkillType, Func<SkillBase>> _skillCreators;
|
||||
|
||||
static void InitCreators()
|
||||
{
|
||||
_skillCreators = new Dictionary<SkillType, Func<SkillBase>>();
|
||||
foreach (var kv in _skillDict)
|
||||
{
|
||||
var type = kv.Value;
|
||||
// 编译一次,后续调用零反射
|
||||
var constructor = type.GetConstructor(Type.EmptyTypes);
|
||||
var newExp = Expression.New(constructor);
|
||||
var lambda = Expression.Lambda<Func<SkillBase>>(newExp).Compile();
|
||||
_skillCreators[kv.Key] = lambda;
|
||||
}
|
||||
}
|
||||
|
||||
public static SkillBase GetSkillBySkillType(SkillType type)
|
||||
{
|
||||
return _skillCreators[type](); // 无反射,接近 new 的性能
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.3.2 避免闭包和委托分配
|
||||
|
||||
```csharp
|
||||
// ❌ Lambda 捕获外部变量产生闭包对象
|
||||
int threshold = 5;
|
||||
var filtered = units.Where(u => u.Level > threshold).ToList(); // 闭包 + List 分配
|
||||
|
||||
// ✅ 手动循环,零分配
|
||||
private static readonly List<UnitData> _tempFilteredUnits = new List<UnitData>(32);
|
||||
|
||||
public List<UnitData> GetUnitsAboveLevel(List<UnitData> units, int threshold)
|
||||
{
|
||||
_tempFilteredUnits.Clear();
|
||||
for (int i = 0; i < units.Count; i++)
|
||||
{
|
||||
if (units[i].Level > threshold)
|
||||
_tempFilteredUnits.Add(units[i]);
|
||||
}
|
||||
return _tempFilteredUnits;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 LINQ 禁用规范
|
||||
|
||||
**在热路径中完全禁止使用 LINQ**,包括但不限于:
|
||||
|
||||
| 禁止操作 | 原因 | 替代方案 |
|
||||
|---------|------|---------|
|
||||
| `.Where().ToList()` | 分配迭代器 + 新 List | 手动 for 循环 + 预分配 List |
|
||||
| `.Select().ToArray()` | 分配迭代器 + 新 Array | 手动 for 循环 + 预分配 Array |
|
||||
| `.Any(predicate)` | 分配闭包对象 | 手动 for 循环 + bool 标志 |
|
||||
| `.Count(predicate)` | 分配闭包对象 | 手动 for 循环 + int 计数 |
|
||||
| `.First() / .FirstOrDefault()` | 分配迭代器 | 手动 for 循环 + break |
|
||||
| `.OrderBy()` | 分配排序缓冲区 | 原地排序或插入排序 |
|
||||
| `.ToDictionary()` | 分配新 Dictionary | 预分配 + 手动填充 |
|
||||
| `.Sum() / .Max() / .Min()` | 分配迭代器 | 手动累加 |
|
||||
|
||||
**热路径定义**:每帧、每回合、每个 Action、AI 决策循环中执行的代码。
|
||||
|
||||
**非热路径**(允许使用 LINQ):初始化、UI 事件响应(低频点击)、加载/存档。
|
||||
|
||||
### 3.5 装箱避免
|
||||
|
||||
```csharp
|
||||
// ❌ 值类型传给 object 参数
|
||||
void Log(object value) { } // 调用 Log(42) 会装箱 int
|
||||
|
||||
// ❌ 枚举作为字典键(如果没有实现 IEqualityComparer)
|
||||
Dictionary<SkillType, SkillBase> dict; // SkillType 是 enum,默认比较器会装箱
|
||||
|
||||
// ✅ 为枚举字典提供专用比较器
|
||||
public struct SkillTypeComparer : IEqualityComparer<SkillType>
|
||||
{
|
||||
public bool Equals(SkillType x, SkillType y) => x == y;
|
||||
public int GetHashCode(SkillType obj) => (int)obj;
|
||||
}
|
||||
|
||||
var dict = new Dictionary<SkillType, SkillBase>(new SkillTypeComparer());
|
||||
```
|
||||
|
||||
### 3.6 struct 使用规范
|
||||
|
||||
```csharp
|
||||
// ✅ 短期使用、小数据量、值语义的数据适合 struct
|
||||
public struct AttackResult // 战斗结果传递,无需 GC
|
||||
{
|
||||
public int Damage;
|
||||
public bool IsKill;
|
||||
public bool IsCritical;
|
||||
}
|
||||
|
||||
// ✅ 事件系统已经使用 struct(UIEvents),保持不变
|
||||
public struct ShowUINotifyMoment // 零 GC 事件分发
|
||||
{
|
||||
public MomentType MomentType;
|
||||
public CityData CityData; // 引用类型成员不影响 struct 本身
|
||||
}
|
||||
```
|
||||
|
||||
**struct 使用条件**:
|
||||
- 大小不超过 64 字节
|
||||
- 不需要继承
|
||||
- 创建后不会被修改(或修改成本可接受)
|
||||
- 不会被装箱(不存入 object 或接口引用)
|
||||
|
||||
---
|
||||
|
||||
## 第四章 计算优化标准
|
||||
|
||||
### 4.1 缓存 + 脏标记模式
|
||||
|
||||
适用于结果稳定、查询频繁但修改不频繁的计算。
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// 玩家领土格子集合缓存。
|
||||
/// 仅在领土变更时置脏,查询时按需重建。
|
||||
/// </summary>
|
||||
[MemoryPackable]
|
||||
public partial class PlayerData
|
||||
{
|
||||
// ===== 已有序列化字段(不动)=====
|
||||
|
||||
// ===== 缓存字段 =====
|
||||
[MemoryPackIgnore] private HashSet<uint> _territoryCache;
|
||||
[MemoryPackIgnore] private bool _territoryDirty = true;
|
||||
|
||||
public HashSet<uint> GetTerritoryGridIdSet(MapData map)
|
||||
{
|
||||
if (_territoryDirty || _territoryCache == null)
|
||||
{
|
||||
_territoryCache ??= new HashSet<uint>();
|
||||
_territoryCache.Clear();
|
||||
// 从城市列表中收集领土
|
||||
foreach (var city in map.CityMap.CityList)
|
||||
{
|
||||
if (map.CityToPlayerDict.TryGetValue(city.Id, out var pid) && pid == Id)
|
||||
city.Territory.GetAllTerritoryArea(_territoryCache);
|
||||
}
|
||||
_territoryDirty = false;
|
||||
}
|
||||
return _territoryCache;
|
||||
}
|
||||
|
||||
/// <summary>领土变更时调用(城市升级、征服、丢失城市)</summary>
|
||||
public void InvalidateTerritoryCache() => _territoryDirty = true;
|
||||
}
|
||||
```
|
||||
|
||||
**适用场景**:
|
||||
|
||||
| 缓存对象 | 失效条件 | 查询频率 |
|
||||
|---------|---------|---------|
|
||||
| 玩家领土集合 | 城市升级 / 征服 / 丢失 | 每回合多次(AI评分、视野、建筑升级) |
|
||||
| 玩家部队列表 | 部队创建 / 阵亡 / 城市易主 | 每回合多次(AI决策) |
|
||||
| 技能查找字典 | 技能添加 / 移除 | 战斗计算、回合结算 |
|
||||
| 城市驻军列表 | 部队移动 / 阵亡 | 每次攻击判定 |
|
||||
|
||||
### 4.2 查找表优化
|
||||
|
||||
#### 4.2.1 O(n) 线性搜索 → O(1) 字典查找
|
||||
|
||||
```csharp
|
||||
// ❌ 当前:遍历所有城市查找领土归属
|
||||
public bool GetCityDataByTerritoryGridId(uint gid, out CityData cityData)
|
||||
{
|
||||
foreach (var city in CityList) // O(城市数)
|
||||
{
|
||||
if (city.CheckIsInTerritory(gid)) // O(领土格子数)
|
||||
{
|
||||
cityData = city;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
|
||||
// ✅ 维护 格子ID → 城市 的反向映射
|
||||
[MemoryPackIgnore]
|
||||
private Dictionary<uint, CityData> _gridToCityLookup;
|
||||
|
||||
public bool GetCityDataByTerritoryGridId_Fast(uint gid, out CityData cityData)
|
||||
{
|
||||
if (_gridToCityLookup == null) RebuildGridToCityLookup();
|
||||
return _gridToCityLookup.TryGetValue(gid, out cityData); // O(1)
|
||||
}
|
||||
|
||||
// 城市领土变更时调用
|
||||
public void InvalidateGridToCityLookup() => _gridToCityLookup = null;
|
||||
```
|
||||
|
||||
#### 4.2.2 MapData 中已有的映射表利用
|
||||
|
||||
MapData 中已维护以下映射关系,优化时**优先使用已有映射**,避免重复建表:
|
||||
|
||||
```
|
||||
CityToPlayerDict 城市ID → 玩家ID
|
||||
UnitToCityDict 部队ID → 城市ID
|
||||
UnitToGridDict 部队ID → 格子ID
|
||||
CityToGridDict 城市ID → 格子ID
|
||||
GridToCityDict 格子ID → 城市ID(中心格子)
|
||||
```
|
||||
|
||||
### 4.3 算法复杂度优化
|
||||
|
||||
#### 4.3.1 BFS/邻居搜索优化
|
||||
|
||||
`GetAroundGridData` 是最高频的空间查询方法,当前实现为三重嵌套循环:
|
||||
|
||||
```csharp
|
||||
// ❌ 当前:triple nested loop + 距离判断冗余
|
||||
for (int r = 0; r <= radius; r++)
|
||||
for (int x = center.X - offset; x <= center.X + offset; x++)
|
||||
for (int y = center.Y - offset; y <= center.Y + offset; y++)
|
||||
if (Mathf.Max(Mathf.Abs(x-cx), Mathf.Abs(y-cy)) != r) continue;
|
||||
|
||||
// ✅ 优化:直接按距离环遍历,消除冗余条件判断
|
||||
// 对于小 radius(1-3),使用预计算偏移表
|
||||
private static readonly Vector2Int[][] _neighborOffsets = PrecomputeOffsets(maxRadius: 5);
|
||||
|
||||
public void GetAroundGridData(GridData center, int radius, List<GridData> buffer)
|
||||
{
|
||||
buffer.Clear();
|
||||
buffer.Add(center); // 中心格子
|
||||
for (int r = 1; r <= radius; r++)
|
||||
{
|
||||
var offsets = _neighborOffsets[r];
|
||||
for (int i = 0; i < offsets.Length; i++)
|
||||
{
|
||||
int x = center.Pos.x + offsets[i].x;
|
||||
int y = center.Pos.y + offsets[i].y;
|
||||
if (GetGridDataByPos(x, y, out var grid))
|
||||
buffer.Add(grid);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.3.2 O(n²) 外交计算优化
|
||||
|
||||
```csharp
|
||||
// ❌ 当前:O(玩家数²) 的外交关系计算
|
||||
foreach (var p1 in players)
|
||||
foreach (var p2 in players)
|
||||
foreach (var strategy in p1.GetFeelingStrategies(p2))
|
||||
Calculate(strategy);
|
||||
|
||||
// ✅ 优化:增量计算 + 仅在外交事件触发时更新
|
||||
// 方案:事件驱动的增量更新
|
||||
public void OnDiplomacyEvent(uint player1Id, uint player2Id)
|
||||
{
|
||||
// 只重算涉及的两个玩家的外交关系
|
||||
RecalcFeelingBetween(player1Id, player2Id);
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.3.3 视野计算优化
|
||||
|
||||
```csharp
|
||||
// ❌ 当前:每次移动都完整重算所有部队+城市的视野集合
|
||||
UpdateSight_LogicView(player); // 遍历所有部队、所有城市领土
|
||||
|
||||
// ✅ 增量视野更新
|
||||
public void UpdateSightIncremental(MapData map, PlayerData player,
|
||||
UnitData movedUnit, Vector2Int oldPos, Vector2Int newPos)
|
||||
{
|
||||
// 1. 移除旧位置视野贡献
|
||||
RemoveSightContribution(movedUnit, oldPos);
|
||||
// 2. 添加新位置视野贡献
|
||||
AddSightContribution(movedUnit, newPos);
|
||||
// 比完整重算快 O(部队数 × 视野范围²) → O(视野范围²)
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 循环优化
|
||||
|
||||
#### 4.4.1 for 替代 foreach(仅对 List\<T\>)
|
||||
|
||||
```csharp
|
||||
// ✅ List<T> 使用 for 循环(避免 enumerator 分配,虽然 List 的 enumerator 是 struct)
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
var item = list[i];
|
||||
// ...
|
||||
}
|
||||
|
||||
// ✅ Dictionary 的 foreach 是安全的(struct enumerator)
|
||||
foreach (var kv in dict) { } // OK
|
||||
|
||||
// ✅ HashSet 的 foreach 也是安全的(struct enumerator)
|
||||
foreach (var item in set) { } // OK
|
||||
```
|
||||
|
||||
#### 4.4.2 提前退出优化
|
||||
|
||||
```csharp
|
||||
// ❌ 遍历完整列表仅为找到一个元素
|
||||
foreach (var unit in allUnits)
|
||||
{
|
||||
if (unit.IsAlive() && unit.OwnerId == playerId)
|
||||
{
|
||||
result = unit;
|
||||
// 没有 break,继续遍历...
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ 找到即退出
|
||||
foreach (var unit in allUnits)
|
||||
{
|
||||
if (unit.IsAlive() && unit.OwnerId == playerId)
|
||||
{
|
||||
result = unit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.4.3 条件外提
|
||||
|
||||
```csharp
|
||||
// ❌ 循环内重复计算不变量
|
||||
for (int i = 0; i < units.Count; i++)
|
||||
{
|
||||
var grid = map.GridMap.GetGridDataByGid(units[i].GridId);
|
||||
var player = map.PlayerMap.GetPlayerById(playerId); // 每次循环都查找同一个 player
|
||||
// ...
|
||||
}
|
||||
|
||||
// ✅ 循环不变量外提
|
||||
var player = map.PlayerMap.GetPlayerById(playerId);
|
||||
for (int i = 0; i < units.Count; i++)
|
||||
{
|
||||
var grid = map.GridMap.GetGridDataByGid(units[i].GridId);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 数学计算优化
|
||||
|
||||
```csharp
|
||||
// ❌ 使用 Mathf(浮点 + Unity 函数调用开销)
|
||||
int dist = Mathf.Max(Mathf.Abs(x1 - x2), Mathf.Abs(y1 - y2));
|
||||
|
||||
// ✅ 使用纯整数数学
|
||||
int dist = Math.Max(Math.Abs(x1 - x2), Math.Abs(y1 - y2));
|
||||
|
||||
// ❌ 重复计算距离
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
float dist = Vector2.Distance(pos, targets[i].Pos); // sqrt 开销
|
||||
if (dist < minDist) { ... }
|
||||
}
|
||||
|
||||
// ✅ 使用距离平方比较(避免 sqrt)
|
||||
for (int i = 0; i < targets.Count; i++)
|
||||
{
|
||||
float distSq = (pos - targets[i].Pos).sqrMagnitude;
|
||||
if (distSq < minDistSq) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第五章 模块专项优化指南
|
||||
|
||||
### 5.1 数据层(TH1_Data)
|
||||
|
||||
| 优化项 | 当前问题 | 优化方案 | 序列化影响 | 优先级 |
|
||||
|-------|---------|---------|-----------|--------|
|
||||
| `GetPlayerTerritoryGridIdSet` | 每次调用 new HashSet + new List | 玩家级缓存 + 脏标记 | `[MemoryPackIgnore]` 无影响 | P0 |
|
||||
| `GetCityDataByTerritoryGridId` | O(城市数×领土数) 线性搜索,代码中标注 TODO | 维护格子→城市反向映射 | `[MemoryPackIgnore]` 无影响 | P0 |
|
||||
| `GetAroundGridData` (4个重载) | 每次调用 new List/HashSet | 传入缓冲区模式 | 无 | P0 |
|
||||
| `GetAroundGridIdList` | 每次调用 new List | 传入缓冲区模式 | 无 | P0 |
|
||||
| `GetUnitDataListByPlayerId` | null 参数时隐式分配 | 强制传入缓冲区 | 无 | P1 |
|
||||
| `GetCityDataListByPlayerId` | null 参数时隐式分配 | 强制传入缓冲区 | 无 | P1 |
|
||||
| OnAfterMemoryPackDeserialize | 每次反序列化重建全部字典 | 延迟初始化(首次访问时重建) | 无 | P1 |
|
||||
|
||||
### 5.2 技能系统(TH1_Logic/Skill)
|
||||
|
||||
| 优化项 | 当前问题 | 优化方案 | 序列化影响 | 优先级 |
|
||||
|-------|---------|---------|-----------|--------|
|
||||
| SkillFactory | 每次创建技能用 Activator.CreateInstance | 编译时委托缓存 | 无 | P1 |
|
||||
| 技能查找 | Skills 列表 O(n) 线性搜索 | `[MemoryPackIgnore]` 字典缓存 + 脏标记 | 无影响 | P1 |
|
||||
| GetAttackAdditionParam | 遍历所有技能聚合加成值 | 缓存加成总值 + 技能变更时置脏 | `[MemoryPackIgnore]` 无影响 | P2 |
|
||||
| OnTurnStart/End 技能回调 | 逐个遍历调用虚方法 | 仅遍历注册了该回调的技能(分类桶) | `[MemoryPackIgnore]` 无影响 | P2 |
|
||||
|
||||
### 5.3 AI系统(TH1_Logic/AI)
|
||||
|
||||
| 优化项 | 当前问题 | 优化方案 | 序列化影响 | 优先级 |
|
||||
|-------|---------|---------|-----------|--------|
|
||||
| AIActionGenerator.Init | 复制领土到新 List,冗余遍历 | 直接引用已有缓存,减少拷贝 | 无 | P0 |
|
||||
| AILogic 主循环 | 循环内 new List\<uint\>() | 预分配 NodeRecords 池 | 无 | P1 |
|
||||
| 评分计算器 | 7个集合每次 Init 重建 | 复用集合 + Clear | 无 | P1 |
|
||||
| AI 合法 Action 生成 | 生成大量临时 CommonActionParams | 对象池复用 | 无 | P2 |
|
||||
| `validActions.Select().ToArray()` | LINQ 链式分配 | 预分配数组 + 手动填充 | 无 | P1 |
|
||||
|
||||
### 5.4 逻辑模块(City/Unit/Player Logic)
|
||||
|
||||
| 优化项 | 当前问题 | 优化方案 | 序列化影响 | 优先级 |
|
||||
|-------|---------|---------|-----------|--------|
|
||||
| 视野完整重算 | 每次移动重算全部视野 | 增量视野更新 | 无 | P1 |
|
||||
| 外交好感度 O(n²) | 每帧/每回合全量重算 | 事件驱动增量更新 | 无 | P2 |
|
||||
| 领土建筑升级遍历 | 遍历领土两遍(普通+学院/市场) | 单次遍历 + 分类处理 | 无 | P2 |
|
||||
| BFS 城市连通性 | 每回合完整 BFS | 仅在道路/领土变化时重算 | 无 | P2 |
|
||||
| 每回合资源计算 | 遍历所有领土格子 | 缓存产出总值 + 建筑变更时增量更新 | `[MemoryPackIgnore]` 无影响 | P3 |
|
||||
|
||||
### 5.5 渲染与动画(TH1_Renderer / TH1_Anim)
|
||||
|
||||
| 优化项 | 当前问题 | 优化方案 | 优先级 |
|
||||
|-------|---------|---------|--------|
|
||||
| Fragment 创建 | FragmentFactory 每次创建新对象 | 对象池复用 Fragment 实例 | P2 |
|
||||
| UnitAtomAnim | 每次创建新动画对象 | 对象池复用 | P2 |
|
||||
| 投射物 | ProjectileRenderer 每次实例化 | 已有 PrefabPool,确保使用 | P3 |
|
||||
|
||||
### 5.6 事件系统(TH1_Core/Events)
|
||||
|
||||
事件系统已使用 struct 事件,零 GC 分配,**保持现有设计,不需优化**。
|
||||
|
||||
---
|
||||
|
||||
## 第六章 优化验证清单
|
||||
|
||||
### 6.1 每次优化必须验证
|
||||
|
||||
- [ ] **功能等价**:优化前后方法的输入参数和返回结果完全一致
|
||||
- [ ] **单人游戏**:完整对局流程无报错、无异常行为
|
||||
- [ ] **多人游戏**:两个客户端对局,Action 同步正确、MapConfirm 校验通过
|
||||
- [ ] **存档兼容**:用优化前版本创建的存档能被优化后版本正常加载
|
||||
- [ ] **AI 行为**:AI 对局结果分布无异常偏移(相同种子应产生相同决策路径)
|
||||
|
||||
### 6.2 性能验证方法
|
||||
|
||||
```
|
||||
1. Unity Profiler → 对比优化前后:
|
||||
- GC Alloc (bytes/frame)
|
||||
- 目标方法的 CPU 时间 (ms)
|
||||
|
||||
2. Deep Profile 模式 → 确认热路径 GC 分配降为 0
|
||||
|
||||
3. 多人对局 → 确认 MapConfirm 哈希始终一致
|
||||
|
||||
4. 存档测试 → 加载旧存档 → 进行 10 回合 → 再次存档 → 加载验证
|
||||
```
|
||||
|
||||
### 6.3 回归测试范围
|
||||
|
||||
| 优化区域 | 最小测试范围 |
|
||||
|---------|------------|
|
||||
| 数据层(MapData/GridData) | 单人完整对局 + 多人2人对局 |
|
||||
| 技能系统 | 包含全部8文明的对局 + 英雄技能触发 |
|
||||
| AI系统 | 8人AI全自动对局(200回合) |
|
||||
| 逻辑模块 | 征服他国 + 联盟 + 奇迹建造 |
|
||||
| 视野/领土 | 大地图 + 地形多样 |
|
||||
|
||||
---
|
||||
|
||||
## 附录A 已知GC热点清单
|
||||
|
||||
### 按严重程度排序
|
||||
|
||||
| # | 热点 | 位置 | 调用频率 | 分配类型 | 严重度 |
|
||||
|---|------|------|---------|---------|--------|
|
||||
| 1 | `GetAroundGridData` (4个重载) | GridData.cs | 每回合 100+ 次 | new List / new HashSet | 🔴 严重 |
|
||||
| 2 | `GetPlayerTerritoryGridIdSet` | MapData.cs | 每回合 3-10 次 | new HashSet + new List | 🔴 严重 |
|
||||
| 3 | `OnAfterMemoryPackDeserialize` (4处) | CityData/GridData/UnitData | 每次网络同步 | Dictionary 重建 | 🔴 严重 |
|
||||
| 4 | `AIActionGenerator.Init` | AIActionGenerator.cs | 每个AI回合 | 列表拷贝 + HashSet | 🟡 中等 |
|
||||
| 5 | `SkillFactory.GetSkillBySkillType` | SkillFactory.cs | 技能创建时 | Activator.CreateInstance | 🟡 中等 |
|
||||
| 6 | `GetUnitDataListByPlayerId/ByCityId` | MapData.cs | 每回合多次 | null 参数时 new List | 🟡 中等 |
|
||||
| 7 | AI主循环 NodeRecords | AILogic.cs | 每AI步 | new List\<uint\>() | 🟡 中等 |
|
||||
| 8 | `validActions.Select().ToArray()` | AILogic.cs | AI 推理时 | LINQ 链分配 | 🟡 中等 |
|
||||
| 9 | `UpdateTerritoryAllBuildingLevel` | PlayerLogic.cs | 每回合 | 领土集合分配 x2 | 🟢 轻度 |
|
||||
| 10 | `GetCityDataByTerritoryGridId` | MapData.cs | 按需调用 | 仅 CPU 开销(O(n²)) | 🟢 轻度 |
|
||||
|
||||
---
|
||||
|
||||
## 附录B 禁止与允许操作速查表
|
||||
|
||||
### 🟢 允许的优化操作
|
||||
|
||||
| 操作 | 条件 |
|
||||
|------|------|
|
||||
| 新增 `[MemoryPackIgnore]` 字段作为缓存 | 配合延迟初始化和脏标记 |
|
||||
| 将 `new List<T>()` 改为传入缓冲区模式 | 调用方和被调用方同步修改 |
|
||||
| 用 for 循环替代 LINQ | 保证结果等价 |
|
||||
| 新增 static readonly 共享缓冲区 | 仅限单线程游戏逻辑 |
|
||||
| 预计算偏移表/查找表 | 只读数据,初始化时构建 |
|
||||
| 对象池复用 | 正确的获取/归还生命周期 |
|
||||
| 增量计算替代全量计算 | 脏标记在所有修改路径上正确设置 |
|
||||
|
||||
### 🔴 禁止的操作
|
||||
|
||||
| 操作 | 原因 |
|
||||
|------|------|
|
||||
| 向 `[MemoryPackable]` 类新增序列化字段 | 破坏存档兼容性和网络协议 |
|
||||
| 删除或重命名已有的序列化字段 | 旧存档无法加载 |
|
||||
| 修改方法的返回值类型或语义 | 违反 R-01 规则 |
|
||||
| 在缓存中引入浮点累积误差 | 多人同步会出现不一致 |
|
||||
| 使用多线程/异步优化游戏逻辑计算 | 破坏确定性 |
|
||||
| 跳过 null 检查以"加速" | 引入崩溃风险 |
|
||||
| 改变遍历顺序导致不同的执行结果 | 影响确定性(AI/战斗/随机数消费) |
|
||||
|
||||
### 🟡 需审慎评估的操作
|
||||
|
||||
| 操作 | 评估点 |
|
||||
|------|--------|
|
||||
| 修改 `[MemoryPackOnDeserialized]` 逻辑 | 确保所有缓存在反序列化后正确重建 |
|
||||
| static 共享缓冲区 | 确保单线程下无递归/重入问题 |
|
||||
| 缓存失效策略 | 确保所有修改路径都调用 Invalidate |
|
||||
| 移除冗余集合 | 确认没有外部引用依赖该集合 |
|
||||
| 改变内部数据结构(如 List → Array) | 确认所有增删操作都适配 |
|
||||
|
||||
---
|
||||
|
||||
> **文档版本**: 1.0
|
||||
> **最后更新**: 2026-04-16
|
||||
> **适用项目**: TH1 回合制4X策略游戏
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -21,6 +23,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
{
|
||||
public bool GreaterThan = true;
|
||||
public float Count = 0;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
|
||||
protected override string desc
|
||||
@ -50,8 +53,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
{
|
||||
var selfCount = 0;
|
||||
var otherCount = 0;
|
||||
var arounds = data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid);
|
||||
foreach (var around in arounds)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid, _aroundBuf);
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
around.VisibleUnit(data.value.TargetParam.MapData,selfPlayer,out var unit);
|
||||
if (unit == null || unit == selfUnit) continue;
|
||||
|
||||
@ -23,6 +23,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
public class AIParamAroundNoUnitCity : BaseActionTask
|
||||
{
|
||||
public int Offset;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
protected override string desc
|
||||
{
|
||||
@ -56,8 +57,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
Vector2Int[] targetPath = null;
|
||||
var selfCity = new HashSet<CityData>();
|
||||
param.MapData.GetCityDataListByPlayerId(param.PlayerData.Id, selfCity);
|
||||
var aroundGrid = param.MapData.GridMap.GetAroundGridData(Offset, Offset, unitGrid);
|
||||
foreach (var grid in aroundGrid)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(Offset, Offset, unitGrid, _aroundBuf);
|
||||
foreach (var grid in _aroundBuf)
|
||||
{
|
||||
if (!param.MapData.GetCityDataByGid(grid.Id, out var city)) continue;
|
||||
if (grid.RealUnit(param.MapData, out var cityUnit)) continue;
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -19,7 +21,8 @@ namespace NodeCanvas.Tasks.Actions
|
||||
[Serializable]
|
||||
public class AIParamAroundOtherCity : BaseActionTask
|
||||
{
|
||||
protected override string desc => $"(移动力+射程)周围有敌方城市";
|
||||
private static List<GridData> _aroundBuf;
|
||||
protected override string desc=> $"(移动力+射程)周围有敌方城市";
|
||||
|
||||
|
||||
protected override void OnExecute()
|
||||
@ -40,8 +43,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
if (selfGrid != null && selfPlayer != null)
|
||||
{
|
||||
var range = selfUnit.GetMoveRange(map) + selfUnit.GetAttackRange(map);
|
||||
var arounds = data.value.TargetParam.MapData.GridMap.GetAroundGridData(range, range, selfGrid);
|
||||
foreach (var around in arounds)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
data.value.TargetParam.MapData.GridMap.GetAroundGridData(range, range, selfGrid, _aroundBuf);
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
if (around == selfGrid) continue;
|
||||
var city = around.CityOnGrid(map);
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -21,6 +23,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
{
|
||||
public bool GreaterThan = true;
|
||||
public float Count = 0;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
|
||||
protected override string desc
|
||||
@ -49,8 +52,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
if (selfGrid != null && selfPlayer != null)
|
||||
{
|
||||
var count = 0;
|
||||
var arounds = data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid);
|
||||
foreach (var around in arounds)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid, _aroundBuf);
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
around.VisibleUnit(data.value.TargetParam.MapData,selfPlayer,out var unit);
|
||||
if (unit == null || unit == selfUnit) continue;
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -21,6 +23,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
{
|
||||
public bool GreaterThan = true;
|
||||
public float Count = 0;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
|
||||
protected override string desc
|
||||
@ -49,8 +52,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
if (selfGrid != null && selfPlayer != null)
|
||||
{
|
||||
var count = 0;
|
||||
var arounds = data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid);
|
||||
foreach (var around in arounds)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid, _aroundBuf);
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
around.VisibleUnit(data.value.TargetParam.MapData,selfPlayer,out var unit);
|
||||
if (unit == null || unit == selfUnit) continue;
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -21,6 +23,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
{
|
||||
public bool GreaterThan = true;
|
||||
public float Count = 0;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
|
||||
protected override string desc
|
||||
@ -49,8 +52,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
if (selfGrid != null && selfPlayer != null)
|
||||
{
|
||||
var count = 0;
|
||||
var arounds = data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid);
|
||||
foreach (var around in arounds)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid, _aroundBuf);
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
around.VisibleUnit(data.value.TargetParam.MapData,selfPlayer,out var unit);
|
||||
if (unit == null || unit == selfUnit) continue;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
@ -23,6 +24,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
public bool GreaterThan = true;
|
||||
public float Count = 0;
|
||||
public GridSpType SpType;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
|
||||
protected override string desc
|
||||
@ -50,8 +52,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
if (selfGrid != null)
|
||||
{
|
||||
var count = 0;
|
||||
var arounds = data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid);
|
||||
foreach (var around in arounds) if (around.HasSpType(SpType)) count++;
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid, _aroundBuf);
|
||||
foreach (var around in _aroundBuf) if (around.HasSpType(SpType)) count++;
|
||||
if (GreaterThan) EndAction(count >= Count);
|
||||
else EndAction(count <= Count);
|
||||
return;
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -20,6 +22,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
public class AIParamAroundTargetSkillUnit : BaseActionTask
|
||||
{
|
||||
public SkillType TargetSkill;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
|
||||
protected override string desc => $"目标点附近存在不满血的拥有 {TargetSkill} 的友方单位";
|
||||
@ -41,9 +44,11 @@ namespace NodeCanvas.Tasks.Actions
|
||||
var map = data.value.AIActions[i].Param.MapData;
|
||||
var selfUnit = data.value.AIActions[i].Param.UnitData;
|
||||
var targetGrid = data.value.AIActions[i].Param.GridData;
|
||||
var arounds = map.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, targetGrid, _aroundBuf);
|
||||
var hasTarget = false;
|
||||
foreach (var around in arounds)
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
if (around == targetGrid) continue;
|
||||
around.RealUnit(map, out var unit);
|
||||
|
||||
@ -24,7 +24,8 @@ namespace NodeCanvas.Tasks.Actions
|
||||
[Serializable]
|
||||
public class AIParamDefendTrainUnit : BaseActionTask
|
||||
{
|
||||
protected override string desc => string.Format($"空城紧急造兵");
|
||||
private static List<GridData> _aroundBuf;
|
||||
protected override string desc=> string.Format($"空城紧急造兵");
|
||||
|
||||
protected override void OnExecute()
|
||||
{
|
||||
@ -49,8 +50,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
bool needTrain = false;
|
||||
var selfUnit = new HashSet<UnitData>();
|
||||
map.GetUnitDataListByPlayerId(data.value.TargetParam.PlayerData.Id, selfUnit);
|
||||
var around = map.GridMap.GetAroundGridData(1, 1, cityGrid);
|
||||
foreach (var grid in around)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, cityGrid, _aroundBuf);
|
||||
foreach (var grid in _aroundBuf)
|
||||
{
|
||||
//TODO check player is right
|
||||
if (!grid.VisibleUnit(map,player, out var attacker)) continue;
|
||||
|
||||
@ -23,6 +23,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
public class AIParamExplore : BaseActionTask
|
||||
{
|
||||
public int Offset = 3;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
|
||||
protected override string desc
|
||||
@ -50,10 +51,12 @@ namespace NodeCanvas.Tasks.Actions
|
||||
|
||||
var selfCity = new HashSet<CityData>();
|
||||
param.MapData.GetCityDataListByPlayerId(param.PlayerData.Id, selfCity);
|
||||
var aroundGrids = param.MapData.GridMap.GetAroundGridData(Offset, Offset, unitGrid);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(Offset, Offset, unitGrid, _aroundBuf);
|
||||
var targetGrids = new List<List<GridData>>();
|
||||
for (int i = 0; i < 4; i++) targetGrids.Add(new List<GridData>());
|
||||
foreach (var grid in aroundGrids)
|
||||
foreach (var grid in _aroundBuf)
|
||||
{
|
||||
if (grid == unitGrid) continue;
|
||||
if (grid.Resource == ResourceType.CityCenter && param.MapData.GetCityDataByGid(grid.Id, out var city) &&
|
||||
@ -96,10 +99,11 @@ namespace NodeCanvas.Tasks.Actions
|
||||
new (unitGrid.Pos.X, unitGrid.Pos.Y), new (target.Pos.X, target.Pos.Y), param.MapData, param.PlayerData,param.UnitData);
|
||||
if (!path.found) continue;
|
||||
|
||||
aroundGrids = param.MapData.GridMap.GetAroundGridData(3, 3, target);
|
||||
_aroundBuf.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(3, 3, target, _aroundBuf);
|
||||
var selfScore = 0f;
|
||||
var enemyScore = 0f;
|
||||
foreach (var grid in aroundGrids)
|
||||
foreach (var grid in _aroundBuf)
|
||||
{
|
||||
if (unitGrid.Id == grid.Id) continue;
|
||||
if (!grid.VisibleUnit(param.MapData,param.PlayerData, out var unit)) continue;
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -19,7 +21,8 @@ namespace NodeCanvas.Tasks.Actions
|
||||
[Serializable]
|
||||
public class AIParamIsAroundUnitHealthInCondi : BaseActionTask
|
||||
{
|
||||
protected override string desc => $"周围存在己方单位兵血量 <= Condi?";
|
||||
private static List<GridData> _aroundBuf;
|
||||
protected override string desc=> $"周围存在己方单位兵血量 <= Condi?";
|
||||
|
||||
|
||||
protected override void OnExecute()
|
||||
@ -43,8 +46,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
var selfPlayer = selfUnit.Player(data.value.TargetParam.MapData);
|
||||
if (selfGrid != null && selfPlayer != null)
|
||||
{
|
||||
var arounds = data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid);
|
||||
foreach (var around in arounds)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid, _aroundBuf);
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
around.VisibleUnit(data.value.TargetParam.MapData,selfPlayer,out var unit);
|
||||
var player = unit.Player(data.value.TargetParam.MapData);
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -19,7 +21,8 @@ namespace NodeCanvas.Tasks.Actions
|
||||
[Serializable]
|
||||
public class AIParamIsAroundUnitInOtherCity : BaseActionTask
|
||||
{
|
||||
protected override string desc => $"周围己方单位是否占据了敌方城市?";
|
||||
private static List<GridData> _aroundBuf;
|
||||
protected override string desc=> $"周围己方单位是否占据了敌方城市?";
|
||||
|
||||
|
||||
protected override void OnExecute()
|
||||
@ -38,8 +41,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
var selfPlayer = selfUnit.Player(data.value.TargetParam.MapData);
|
||||
if (selfGrid != null && selfPlayer != null)
|
||||
{
|
||||
var arounds = data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid);
|
||||
foreach (var around in arounds)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
data.value.TargetParam.MapData.GridMap.GetAroundGridData(1, 1, selfGrid, _aroundBuf);
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
around.VisibleUnit(data.value.TargetParam.MapData,selfPlayer,out var unit);
|
||||
var player = unit.Player(data.value.TargetParam.MapData);
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -20,8 +22,9 @@ namespace NodeCanvas.Tasks.Actions
|
||||
public class AIParamIsTargetGridAroundSkillAttacker : BaseActionTask
|
||||
{
|
||||
public SkillType TargetSkill;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
protected override string desc => "目标格子周围有指定技能敌军";
|
||||
protected override string desc=> "目标格子周围有指定技能敌军";
|
||||
|
||||
|
||||
protected override void OnExecute()
|
||||
@ -41,9 +44,11 @@ namespace NodeCanvas.Tasks.Actions
|
||||
var selfUnit = data.value.AIActions[i].Param.UnitData;
|
||||
if (!selfUnit.Player(map, out var selfPlayer)) continue;
|
||||
var targetGrid = data.value.AIActions[i].Param.GridData;
|
||||
var arounds = map.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, targetGrid, _aroundBuf);
|
||||
var hasAttacker = false;
|
||||
foreach (var around in arounds)
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
if (around == targetGrid) continue;
|
||||
around.VisibleUnit(map,selfPlayer,out var unit);
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -19,6 +21,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
[Serializable]
|
||||
public class AIParamIsTargetGridHasAttacker : BaseActionTask
|
||||
{
|
||||
private static List<GridData> _aroundBuf;
|
||||
protected override string desc => "目标格子周围有敌军";
|
||||
|
||||
|
||||
@ -39,9 +42,11 @@ namespace NodeCanvas.Tasks.Actions
|
||||
var selfUnit = data.value.AIActions[i].Param.UnitData;
|
||||
if (!selfUnit.Player(map, out var selfPlayer)) continue;
|
||||
var targetGrid = data.value.AIActions[i].Param.GridData;
|
||||
var arounds = map.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, targetGrid, _aroundBuf);
|
||||
var hasAttacker = false;
|
||||
foreach (var around in arounds)
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
if (around == targetGrid) continue;
|
||||
around.VisibleUnit(map,selfPlayer,out var unit);
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -19,6 +21,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
[Serializable]
|
||||
public class AIParamIsTargetGridHasHeroAndAttacker : BaseActionTask
|
||||
{
|
||||
private static List<GridData> _aroundBuf;
|
||||
protected override string desc => "目标格子周围有英雄且有敌军";
|
||||
|
||||
|
||||
@ -44,10 +47,12 @@ namespace NodeCanvas.Tasks.Actions
|
||||
continue;
|
||||
}
|
||||
var map = data.value.AIActions[i].Param.MapData;
|
||||
var arounds = map.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, targetGrid, _aroundBuf);
|
||||
var hasHero = false;
|
||||
var hasAttacker = false;
|
||||
foreach (var around in arounds)
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
around.VisibleUnit(map,selfPlayer,out var unit);
|
||||
var unitPlayer = unit?.Player(map);
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -21,6 +23,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
{
|
||||
public bool GreaterThan = true;
|
||||
public float Ratio = 0.5f;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
protected override string desc
|
||||
{
|
||||
@ -54,9 +57,11 @@ namespace NodeCanvas.Tasks.Actions
|
||||
continue;
|
||||
}
|
||||
var map = data.value.AIActions[i].Param.MapData;
|
||||
var arounds = map.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, targetGrid, _aroundBuf);
|
||||
var match = false;
|
||||
foreach (var around in arounds)
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
around.VisibleUnit(map,selfPlayer,out var unit);
|
||||
var unitPlayer = unit?.Player(map);
|
||||
|
||||
@ -21,7 +21,8 @@ namespace NodeCanvas.Tasks.Actions
|
||||
[Serializable]
|
||||
public class AIParamMustGarrison : BaseActionTask
|
||||
{
|
||||
protected override string desc => "必须驻守城市";
|
||||
private static List<GridData> _aroundBuf;
|
||||
protected override string desc=> "必须驻守城市";
|
||||
|
||||
protected override void OnExecute()
|
||||
{
|
||||
@ -57,8 +58,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
}
|
||||
|
||||
|
||||
var around = map.GridMap.GetAroundGridData(1, 1, unitGrid);
|
||||
foreach (var grid in around)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, unitGrid, _aroundBuf);
|
||||
foreach (var grid in _aroundBuf)
|
||||
{
|
||||
if (!grid.VisibleUnit(map,player, out var attacker)) continue;
|
||||
if (selfUnit.Contains(attacker)) continue;
|
||||
|
||||
@ -24,6 +24,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
public bool MoreThan;
|
||||
public float Value;
|
||||
public int Offset;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
protected override string desc
|
||||
{
|
||||
@ -56,8 +57,10 @@ namespace NodeCanvas.Tasks.Actions
|
||||
}
|
||||
|
||||
var dangerValue = 0f;
|
||||
var arounds = map.GridMap.GetAroundGridData(Offset, Offset, grid);
|
||||
foreach (var around in arounds)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(Offset, Offset, grid, _aroundBuf);
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
if (around == grid) continue;
|
||||
if(!around.VisibleUnit(map,player,out var attacker)) continue;
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.AI;
|
||||
using NodeCanvas.Framework;
|
||||
using ParadoxNotion.Design;
|
||||
using RuntimeData;
|
||||
|
||||
|
||||
namespace NodeCanvas.Tasks.Actions
|
||||
@ -20,6 +22,7 @@ namespace NodeCanvas.Tasks.Actions
|
||||
public class AIParamTargetCityInAttackRange : BaseActionTask
|
||||
{
|
||||
public bool CheckInAttackRange = true;
|
||||
private static List<GridData> _aroundBuf;
|
||||
|
||||
|
||||
protected override string desc
|
||||
@ -56,9 +59,11 @@ namespace NodeCanvas.Tasks.Actions
|
||||
return;
|
||||
}
|
||||
|
||||
var set = param.MapData.GridMap.GetAroundGridData(range, range, unitGrid);
|
||||
if (CheckInAttackRange) EndAction(set.Contains(param.TargetGridData));
|
||||
EndAction(!set.Contains(param.TargetGridData));
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(range, range, unitGrid, _aroundBuf);
|
||||
if (CheckInAttackRange) EndAction(_aroundBuf.Contains(param.TargetGridData));
|
||||
EndAction(!_aroundBuf.Contains(param.TargetGridData));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -183,13 +183,12 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
|
||||
// 获取目标周围的所有格子(含center)
|
||||
public List<GridData> GetAroundGridData(int xOffset, int yOffset, GridData gridData)
|
||||
// 获取目标周围的所有格子(含center) - Buffer版本,减少GC
|
||||
public void GetAroundGridData(int xOffset, int yOffset, GridData gridData, List<GridData> buffer)
|
||||
{
|
||||
List<GridData> gridDataList = new List<GridData>();
|
||||
if (gridData == null) return gridDataList;
|
||||
buffer.Clear();
|
||||
if (gridData == null) return;
|
||||
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++)
|
||||
@ -198,15 +197,36 @@ namespace RuntimeData
|
||||
{
|
||||
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);
|
||||
buffer.Add(aroundGridData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取目标周围的所有格子(含center) - 兼容版本(会分配新List)
|
||||
public List<GridData> GetAroundGridData(int xOffset, int yOffset, GridData gridData)
|
||||
{
|
||||
var gridDataList = new List<GridData>();
|
||||
GetAroundGridData(xOffset, yOffset, gridData, gridDataList);
|
||||
return gridDataList;
|
||||
}
|
||||
|
||||
// 获取目标周围的所有格子(不含center)
|
||||
// 获取目标周围的所有格子(不含center) - Buffer版本,减少GC
|
||||
public void GetAroundGridDataSet_NOCENTER(int xOffset, int yOffset, GridData gridData, List<GridData> buffer)
|
||||
{
|
||||
buffer.Clear();
|
||||
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;
|
||||
buffer.Add(aroundGridData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取目标周围的所有格子(不含center) - 兼容版本(会分配新HashSet)
|
||||
public HashSet<GridData> GetAroundGridDataSet_NOCENTER(int xOffset, int yOffset, GridData gridData)
|
||||
{
|
||||
HashSet<GridData> gridDataSet = new HashSet<GridData>();
|
||||
@ -223,29 +243,34 @@ namespace RuntimeData
|
||||
return gridDataSet;
|
||||
}
|
||||
|
||||
// 获取目标周围的所有格子,但是按照优先2468方向,返回有序的List
|
||||
public List<GridData> GetAroundGridDataSetByOrder(int xOffset, int yOffset, GridData gridData)
|
||||
// 获取目标周围的所有格子,按照优先2468方向 - Buffer版本,减少GC
|
||||
public void GetAroundGridDataSetByOrder(int xOffset, int yOffset, GridData gridData, List<GridData> buffer)
|
||||
{
|
||||
List<GridData> gridDataList = new List<GridData>();
|
||||
buffer.Clear();
|
||||
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);
|
||||
buffer.Add(aroundGridData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取目标周围的所有格子,按照优先2468方向 - 兼容版本(会分配新List)
|
||||
public List<GridData> GetAroundGridDataSetByOrder(int xOffset, int yOffset, GridData gridData)
|
||||
{
|
||||
var gridDataList = new List<GridData>();
|
||||
GetAroundGridDataSetByOrder(xOffset, yOffset, gridData, gridDataList);
|
||||
return gridDataList;
|
||||
}
|
||||
|
||||
public List<uint> GetAroundGridIdList(int radius, GridData gridData, bool remainCenter = false)
|
||||
// 获取周围格子ID列表 - Buffer版本,减少GC
|
||||
public void GetAroundGridIdList(int radius, GridData gridData, List<uint> buffer, bool remainCenter = false)
|
||||
{
|
||||
List<uint> gridIdList = new List<uint>();
|
||||
//从内圈到外圈按顺序将格子加入list
|
||||
buffer.Clear();
|
||||
for (int r = 0; r <= radius; r++)
|
||||
{
|
||||
for (int x = gridData.Pos.X - radius; x <= gridData.Pos.X + radius; x++)
|
||||
@ -255,11 +280,17 @@ namespace RuntimeData
|
||||
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);
|
||||
buffer.Add(aroundGridData.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取周围格子ID列表 - 兼容版本(会分配新List)
|
||||
public List<uint> GetAroundGridIdList(int radius, GridData gridData, bool remainCenter = false)
|
||||
{
|
||||
var gridIdList = new List<uint>();
|
||||
GetAroundGridIdList(radius, gridData, gridIdList, remainCenter);
|
||||
return gridIdList;
|
||||
}
|
||||
|
||||
@ -342,6 +373,9 @@ namespace RuntimeData
|
||||
public TerrainType Terrain;
|
||||
// 地形层
|
||||
public TerrainFeature Feature;
|
||||
|
||||
// UpdateGeoInfo 复用的HashSet缓冲区
|
||||
private static HashSet<GeoSmallClass> _geoSmallSetBuffer;
|
||||
// 植被层
|
||||
public Vegetation Vegetation;
|
||||
// 资源层+建筑层
|
||||
@ -501,10 +535,14 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
//返回该格子周围是否存在没有视野的格子
|
||||
[MemoryPackIgnore]
|
||||
private List<GridData> _aroundBuffer;
|
||||
|
||||
public bool UnsightNearby(MapData map, PlayerData player)
|
||||
{
|
||||
var gridList = map.GridMap.GetAroundGridData(1, 1, this);
|
||||
foreach (var grid in gridList)
|
||||
_aroundBuffer ??= new List<GridData>();
|
||||
map.GridMap.GetAroundGridData(1, 1, this, _aroundBuffer);
|
||||
foreach (var grid in _aroundBuffer)
|
||||
{
|
||||
if (player.Sight.CheckIsInSight(grid.Id)) return true;
|
||||
}
|
||||
@ -523,10 +561,11 @@ namespace RuntimeData
|
||||
CommonColdTime++;
|
||||
if (CommonColdTime >= 2)
|
||||
{
|
||||
var gridList = map.GridMap.GetAroundGridData(1, 1, this);
|
||||
_aroundBuffer ??= new List<GridData>();
|
||||
map.GridMap.GetAroundGridData(1, 1, this, _aroundBuffer);
|
||||
|
||||
if (map.GetPlayerDataByTerritoryGridId(Id, out var player))
|
||||
foreach (var grid in gridList)
|
||||
foreach (var grid in _aroundBuffer)
|
||||
{
|
||||
if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer)) continue;
|
||||
if (gridPlayer.Id != player.Id) continue;
|
||||
@ -553,10 +592,11 @@ namespace RuntimeData
|
||||
CommonColdTime++;
|
||||
if (CommonColdTime >= 2)
|
||||
{
|
||||
var gridList = map.GridMap.GetAroundGridData(1, 1, this);
|
||||
_aroundBuffer ??= new List<GridData>();
|
||||
map.GridMap.GetAroundGridData(1, 1, this, _aroundBuffer);
|
||||
|
||||
if (map.GetPlayerDataByTerritoryGridId(Id, out var player))
|
||||
foreach (var grid in gridList)
|
||||
foreach (var grid in _aroundBuffer)
|
||||
{
|
||||
if (!map.GetPlayerDataByTerritoryGridId(grid.Id, out var gridPlayer)) continue;
|
||||
if (gridPlayer.Id != player.Id) continue;
|
||||
@ -819,7 +859,8 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
|
||||
var smallSet = new HashSet<GeoSmallClass>() { };
|
||||
var smallSet = _geoSmallSetBuffer ??= new HashSet<GeoSmallClass>();
|
||||
smallSet.Clear();
|
||||
|
||||
uint id;
|
||||
if (Vegetation == Vegetation.Trees && !forest)
|
||||
|
||||
@ -364,9 +364,8 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
// 通过玩家 ID 找城市列表
|
||||
public void GetCityDataListByPlayerId(uint pid, List<CityData> cityDataList=null)
|
||||
public void GetCityDataListByPlayerId(uint pid, List<CityData> cityDataList)
|
||||
{
|
||||
if (cityDataList == null) cityDataList = new List<CityData>();
|
||||
foreach (var kv in CityToPlayerDict)
|
||||
{
|
||||
if (kv.Value != pid) continue;
|
||||
@ -376,9 +375,8 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
// 通过玩家 ID 找城市Set
|
||||
public void GetCityDataListByPlayerId(uint pid, HashSet<CityData> cityDataList=null)
|
||||
public void GetCityDataListByPlayerId(uint pid, HashSet<CityData> cityDataList)
|
||||
{
|
||||
if (cityDataList == null) cityDataList = new HashSet<CityData>();
|
||||
foreach (var kv in CityToPlayerDict)
|
||||
{
|
||||
if (kv.Value != pid) continue;
|
||||
@ -638,9 +636,8 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
// 通过城市 ID 找小兵列表
|
||||
public void GetUnitDataListByCityId(uint cid, List<UnitData> unitDataList=null)
|
||||
public void GetUnitDataListByCityId(uint cid, List<UnitData> unitDataList)
|
||||
{
|
||||
if (unitDataList == null) unitDataList = new List<UnitData>();
|
||||
foreach (var kv in UnitToCityDict)
|
||||
{
|
||||
if (kv.Value != cid) continue;
|
||||
@ -650,9 +647,8 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
// 通过玩家 ID 找小兵列表
|
||||
public void GetUnitDataListByPlayerId(uint pid, List<UnitData> unitDataList=null)
|
||||
public void GetUnitDataListByPlayerId(uint pid, List<UnitData> unitDataList)
|
||||
{
|
||||
if (unitDataList == null) unitDataList = new List<UnitData>();
|
||||
foreach (var kv in CityToPlayerDict)
|
||||
{
|
||||
if (kv.Value != pid) continue;
|
||||
@ -661,9 +657,8 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
// 通过城市 ID 找小兵 Set
|
||||
public void GetUnitDataListByCityId(uint cid, HashSet<UnitData> unitDataList=null)
|
||||
public void GetUnitDataListByCityId(uint cid, HashSet<UnitData> unitDataList)
|
||||
{
|
||||
if (unitDataList == null) unitDataList = new HashSet<UnitData>();
|
||||
foreach (var kv in UnitToCityDict)
|
||||
{
|
||||
if (kv.Value != cid) continue;
|
||||
@ -673,9 +668,8 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
// 通过玩家 ID 找小兵 Set
|
||||
public void GetUnitDataListByPlayerId(uint pid, HashSet<UnitData> unitDataList=null)
|
||||
public void GetUnitDataListByPlayerId(uint pid, HashSet<UnitData> unitDataList)
|
||||
{
|
||||
if (unitDataList == null) unitDataList = new HashSet<UnitData>();
|
||||
foreach (var kv in CityToPlayerDict)
|
||||
{
|
||||
if (kv.Value != pid) continue;
|
||||
@ -684,9 +678,8 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
// 通过玩家 ID 找敌方小兵列表
|
||||
public void GetOtherUnitDataListByPlayerId(uint pid, List<UnitData> unitDataList=null)
|
||||
public void GetOtherUnitDataListByPlayerId(uint pid, List<UnitData> unitDataList)
|
||||
{
|
||||
if (unitDataList == null) unitDataList = new List<UnitData>();
|
||||
foreach (var kv in CityToPlayerDict)
|
||||
{
|
||||
if (kv.Value == pid) continue;
|
||||
@ -1016,16 +1009,23 @@ namespace RuntimeData
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取玩家的所有领土格子 ID
|
||||
public HashSet<uint> GetPlayerTerritoryGridIdSet(uint pid)
|
||||
// 获取玩家的所有领土格子 ID - Buffer版本
|
||||
private readonly List<CityData> _territoryTmpCityList = new List<CityData>();
|
||||
public void GetPlayerTerritoryGridIdSet(uint pid, HashSet<uint> gridSet)
|
||||
{
|
||||
var gridSet = new HashSet<uint>();
|
||||
var cityList = new List<CityData>();
|
||||
GetCityDataListByPlayerId(pid, cityList);
|
||||
foreach (var cityData in cityList)
|
||||
_territoryTmpCityList.Clear();
|
||||
GetCityDataListByPlayerId(pid, _territoryTmpCityList);
|
||||
foreach (var cityData in _territoryTmpCityList)
|
||||
{
|
||||
cityData.Territory.GetAllTerritoryArea(gridSet);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取玩家的所有领土格子 ID - 兼容版本(会分配新集合)
|
||||
public HashSet<uint> GetPlayerTerritoryGridIdSet(uint pid)
|
||||
{
|
||||
var gridSet = new HashSet<uint>();
|
||||
GetPlayerTerritoryGridIdSet(pid, gridSet);
|
||||
return gridSet;
|
||||
}
|
||||
|
||||
|
||||
@ -338,6 +338,13 @@ namespace RuntimeData
|
||||
// 玩家是否存活要用这条来判断
|
||||
public bool IsSurvival => !IsSurrender && Alive;
|
||||
|
||||
// 复用的临时集合,避免每回合外交计算GC
|
||||
[MemoryPackIgnore] private HashSet<UnitData> _tmpUnitSetBuf;
|
||||
[MemoryPackIgnore] private HashSet<UnitData> _tmpUnitSetBuf2;
|
||||
[MemoryPackIgnore] private HashSet<uint> _tmpOriginCityBuf;
|
||||
[MemoryPackIgnore] private List<CityData> _tmpCityListBuf;
|
||||
[MemoryPackIgnore] private HashSet<CityData> _tmpCitySetBuf;
|
||||
|
||||
// 无参数初始化
|
||||
[MemoryPackConstructor]
|
||||
public PlayerData()
|
||||
@ -659,11 +666,15 @@ namespace RuntimeData
|
||||
maxScorePlayer = player.Id;
|
||||
}
|
||||
|
||||
var originCity = new HashSet<uint>();
|
||||
_tmpOriginCityBuf ??= new HashSet<uint>();
|
||||
_tmpOriginCityBuf.Clear();
|
||||
foreach (var player in map.PlayerMap.PlayerDataList)
|
||||
{
|
||||
originCity.Add(player.CradleCityId);
|
||||
_tmpOriginCityBuf.Add(player.CradleCityId);
|
||||
}
|
||||
|
||||
_tmpUnitSetBuf ??= new HashSet<UnitData>();
|
||||
_tmpUnitSetBuf2 ??= new HashSet<UnitData>();
|
||||
|
||||
foreach (var player in map.PlayerMap.PlayerDataList)
|
||||
{
|
||||
@ -736,19 +747,19 @@ namespace RuntimeData
|
||||
|
||||
// 强大的 弱小的
|
||||
var selfScore = 0f;
|
||||
var playerScore = 0f;
|
||||
var selfUnit = new HashSet<UnitData>();
|
||||
map.GetUnitDataListByPlayerId(Id, selfUnit);
|
||||
var targetUnit = new HashSet<UnitData>();
|
||||
map.GetUnitDataListByPlayerId(player.Id, targetUnit);
|
||||
foreach (var unit in selfUnit) selfScore += unit.GetMilitary();
|
||||
foreach (var unit in targetUnit) playerScore += unit.GetMilitary();
|
||||
if (selfScore < playerScore)
|
||||
var playerScore2 = 0f;
|
||||
_tmpUnitSetBuf.Clear();
|
||||
map.GetUnitDataListByPlayerId(Id, _tmpUnitSetBuf);
|
||||
_tmpUnitSetBuf2.Clear();
|
||||
map.GetUnitDataListByPlayerId(player.Id, _tmpUnitSetBuf2);
|
||||
foreach (var unit in _tmpUnitSetBuf) selfScore += unit.GetMilitary();
|
||||
foreach (var unit in _tmpUnitSetBuf2) playerScore2 += unit.GetMilitary();
|
||||
if (selfScore < playerScore2)
|
||||
{
|
||||
score += 15;
|
||||
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Powerful);
|
||||
}
|
||||
if (selfScore > playerScore)
|
||||
if (selfScore > playerScore2)
|
||||
{
|
||||
score -= 15;
|
||||
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Weak);
|
||||
@ -766,13 +777,13 @@ namespace RuntimeData
|
||||
}
|
||||
|
||||
// 威胁的
|
||||
var playerUnit = new HashSet<UnitData>();
|
||||
map.GetUnitDataListByPlayerId(player.Id, playerUnit);
|
||||
_tmpUnitSetBuf2.Clear();
|
||||
map.GetUnitDataListByPlayerId(player.Id, _tmpUnitSetBuf2);
|
||||
var selfTerritory = map.GetPlayerTerritoryGridIdSet(Id);
|
||||
foreach (var gridId in selfTerritory)
|
||||
{
|
||||
if (!map.GridMap.GetGridDataByGid(gridId, out var gridData)) continue;
|
||||
foreach (var unit in playerUnit)
|
||||
foreach (var unit in _tmpUnitSetBuf2)
|
||||
{
|
||||
if (!map.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
|
||||
var dis = map.GridMap.CalcDistance(unitGrid, gridData);
|
||||
@ -805,14 +816,15 @@ namespace RuntimeData
|
||||
var count = 0f;
|
||||
if (maxScorePlayer == player.Id)
|
||||
{
|
||||
var otherCity = new List<CityData>();
|
||||
map.GetCityDataListByPlayerId(player.Id, otherCity);
|
||||
foreach (var city in otherCity)
|
||||
_tmpCityListBuf ??= new List<CityData>();
|
||||
_tmpCityListBuf.Clear();
|
||||
map.GetCityDataListByPlayerId(player.Id, _tmpCityListBuf);
|
||||
foreach (var city in _tmpCityListBuf)
|
||||
{
|
||||
if (originCity.Contains(city.Id)) count++;
|
||||
if (_tmpOriginCityBuf.Contains(city.Id)) count++;
|
||||
}
|
||||
|
||||
if (count >= originCity.Count * 0.5f)
|
||||
if (count >= _tmpOriginCityBuf.Count * 0.5f)
|
||||
{
|
||||
score -= 15;
|
||||
selfToPlayer.FeelingStrategyList.Add(FeelingStrategy.Dominative);
|
||||
@ -846,9 +858,10 @@ namespace RuntimeData
|
||||
// 如果上一回合回合内双方未发生战斗,则该回合开始时变为中立关系
|
||||
//判断有没有对方单位站在我方city上
|
||||
bool otherPlayerOnSelfCity = false;
|
||||
var cityList = new HashSet<CityData>();
|
||||
map.GetCityDataListByPlayerId(Id,cityList);
|
||||
foreach (var city in cityList)
|
||||
_tmpCitySetBuf ??= new HashSet<CityData>();
|
||||
_tmpCitySetBuf.Clear();
|
||||
map.GetCityDataListByPlayerId(Id,_tmpCitySetBuf);
|
||||
foreach (var city in _tmpCitySetBuf)
|
||||
{
|
||||
if(!map.GetGridDataByCityId(city.Id,out var grid))continue;
|
||||
if(!map.GetUnitDataByGid_Core(grid.Id,out var unit))continue;
|
||||
@ -1429,6 +1442,7 @@ namespace RuntimeData
|
||||
public List<UnitFullType> HeroList;
|
||||
public GiantType LeaderGiantType;
|
||||
public Dictionary<UnitFullType, HeroTaskContentBase> HeroTaskDict;
|
||||
[MemoryPackIgnore] private List<GridData> _tmpGridListBuf;
|
||||
|
||||
[MemoryPackConstructor]
|
||||
public PlayerHeroData()
|
||||
@ -1487,9 +1501,11 @@ namespace RuntimeData
|
||||
map.GetCapitalCityDataByPlayerId(player.Id, out var city);
|
||||
var cityGrid = city?.Grid(map);
|
||||
if (cityGrid == null) continue;
|
||||
var gridList = map.GridMap.GetAroundGridData(1, 1, cityGrid);
|
||||
_tmpGridListBuf ??= new List<GridData>();
|
||||
_tmpGridListBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, cityGrid, _tmpGridListBuf);
|
||||
var randomList = new List<GridData>();
|
||||
foreach (var grid in gridList)
|
||||
foreach (var grid in _tmpGridListBuf)
|
||||
{
|
||||
if (grid == cityGrid) continue;
|
||||
if (grid.RealUnit(map,out _)) continue;
|
||||
|
||||
@ -218,7 +218,7 @@ namespace RuntimeData
|
||||
|
||||
private void RefreshSkillDict()
|
||||
{
|
||||
if (_skillDict == null) _skillDict = new Dictionary<SkillType, SkillBase>();
|
||||
_skillDict ??= new Dictionary<SkillType, SkillBase>();
|
||||
if (_skillDict.Count != Skills.Count)
|
||||
{
|
||||
_skillDict.Clear();
|
||||
@ -235,10 +235,16 @@ namespace RuntimeData
|
||||
foreach (var skill in Skills) _skillDict[skill.GetSkillType()] = skill;
|
||||
}
|
||||
|
||||
// 共享的技能迭代缓冲区,避免每次OnSkillsTurnStart/End都new List
|
||||
[MemoryPackIgnore]
|
||||
private List<SkillBase> _skillIterBuffer;
|
||||
|
||||
protected virtual void OnSkillsTurnStart(MapData map)
|
||||
{
|
||||
var copy = new List<SkillBase>(Skills);
|
||||
foreach (var skill in copy)
|
||||
_skillIterBuffer ??= new List<SkillBase>();
|
||||
_skillIterBuffer.Clear();
|
||||
_skillIterBuffer.AddRange(Skills);
|
||||
foreach (var skill in _skillIterBuffer)
|
||||
{
|
||||
skill.BeforeTurnStart();
|
||||
if (skill.IsFinished())
|
||||
@ -253,8 +259,10 @@ namespace RuntimeData
|
||||
|
||||
protected virtual void OnSkillsAfterTurnStart(MapData map)
|
||||
{
|
||||
var copy = new List<SkillBase>(Skills);
|
||||
foreach (var skill in copy)
|
||||
_skillIterBuffer ??= new List<SkillBase>();
|
||||
_skillIterBuffer.Clear();
|
||||
_skillIterBuffer.AddRange(Skills);
|
||||
foreach (var skill in _skillIterBuffer)
|
||||
{
|
||||
skill.OnAfterTurnStart(this, map);
|
||||
}
|
||||
@ -262,8 +270,10 @@ namespace RuntimeData
|
||||
|
||||
protected virtual void OnSkillsTurnEnd(MapData map)
|
||||
{
|
||||
var copy = new List<SkillBase>(Skills);
|
||||
foreach (var skill in copy) skill.OnTurnEnd(this, map);
|
||||
_skillIterBuffer ??= new List<SkillBase>();
|
||||
_skillIterBuffer.Clear();
|
||||
_skillIterBuffer.AddRange(Skills);
|
||||
foreach (var skill in _skillIterBuffer) skill.OnTurnEnd(this, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -95,11 +95,15 @@ namespace RuntimeData
|
||||
}
|
||||
}
|
||||
|
||||
[MemoryPackIgnore]
|
||||
private List<UnitData> _turnUnitBuffer;
|
||||
|
||||
public void OnTurnStart(MapData map, PlayerData player)
|
||||
{
|
||||
var units = new List<UnitData>();
|
||||
map.GetUnitDataListByPlayerId(player.Id, units);
|
||||
foreach (var unit in units)
|
||||
_turnUnitBuffer ??= new List<UnitData>();
|
||||
_turnUnitBuffer.Clear();
|
||||
map.GetUnitDataListByPlayerId(player.Id, _turnUnitBuffer);
|
||||
foreach (var unit in _turnUnitBuffer)
|
||||
{
|
||||
Main.UnitLogic.StartNextTurn(map, unit);
|
||||
unit.OnTurnStart(map);
|
||||
@ -108,9 +112,10 @@ namespace RuntimeData
|
||||
|
||||
public void OnAfterTurnStart(MapData map, PlayerData player)
|
||||
{
|
||||
var units = new List<UnitData>();
|
||||
map.GetUnitDataListByPlayerId(player.Id, units);
|
||||
foreach (var unit in units)
|
||||
_turnUnitBuffer ??= new List<UnitData>();
|
||||
_turnUnitBuffer.Clear();
|
||||
map.GetUnitDataListByPlayerId(player.Id, _turnUnitBuffer);
|
||||
foreach (var unit in _turnUnitBuffer)
|
||||
{
|
||||
unit.OnAfterTurnStart(map);
|
||||
}
|
||||
@ -118,10 +123,11 @@ namespace RuntimeData
|
||||
|
||||
public void OnTurnEnd(MapData map, PlayerData player)
|
||||
{
|
||||
var units = new List<UnitData>();
|
||||
map.GetUnitDataListByPlayerId(player.Id, units);
|
||||
_turnUnitBuffer ??= new List<UnitData>();
|
||||
_turnUnitBuffer.Clear();
|
||||
map.GetUnitDataListByPlayerId(player.Id, _turnUnitBuffer);
|
||||
|
||||
foreach (var unit in units)
|
||||
foreach (var unit in _turnUnitBuffer)
|
||||
{
|
||||
Main.UnitLogic.UnitEndTurn(map, unit);
|
||||
unit.OnTurnEnd(map);
|
||||
|
||||
@ -238,6 +238,12 @@ namespace Logic.AI
|
||||
public List<UnitData> ForeachUnit;
|
||||
public List<uint> ForeachLegion;
|
||||
public List<CityData> ForeachCity;
|
||||
|
||||
// 复用的临时集合,供静态Calculate方法使用
|
||||
public List<GridData> AroundGridBuffer;
|
||||
public HashSet<UnitData> TmpUnitSetBuffer;
|
||||
public List<CityData> TmpCityListBuffer;
|
||||
public HashSet<CityData> TmpCitySetBuffer;
|
||||
|
||||
public bool IsFinish;
|
||||
public AIDiffInfo AiDiffInfo;
|
||||
@ -258,6 +264,10 @@ namespace Logic.AI
|
||||
ForeachLegion = new List<uint>();
|
||||
ForeachCity = new List<CityData>();
|
||||
TargetList = new List<uint>();
|
||||
AroundGridBuffer = new List<GridData>();
|
||||
TmpUnitSetBuffer = new HashSet<UnitData>();
|
||||
TmpCityListBuffer = new List<CityData>();
|
||||
TmpCitySetBuffer = new HashSet<CityData>();
|
||||
|
||||
MilitaryScore = new Dictionary<uint, float>();
|
||||
DevelopmentScore = new Dictionary<uint, float>();
|
||||
@ -819,8 +829,9 @@ namespace Logic.AI
|
||||
{
|
||||
var citySet = new HashSet<CityData>();
|
||||
var centerGrid = LegionGrid[kv.Key];
|
||||
var aroundGrids = Map.GridMap.GetAroundGridData(4, 4, centerGrid);
|
||||
foreach (var grid in aroundGrids)
|
||||
AroundGridBuffer.Clear();
|
||||
Map.GridMap.GetAroundGridData(4, 4, centerGrid, AroundGridBuffer);
|
||||
foreach (var grid in AroundGridBuffer)
|
||||
{
|
||||
if (!Map.GetCityDataByGid(grid.Id, out var cityData)) continue;
|
||||
citySet.Add(cityData);
|
||||
@ -1068,9 +1079,10 @@ namespace Logic.AI
|
||||
}
|
||||
|
||||
// 如果2直线距离内,交战国的敌军总分-友军总分>=6且自由人距离最近的我方城市中心距离>2则执行撤退战略
|
||||
var aroundGrids = Map.GridMap.GetAroundGridData(2, 2, unitGrid);
|
||||
AroundGridBuffer.Clear();
|
||||
Map.GridMap.GetAroundGridData(2, 2, unitGrid, AroundGridBuffer);
|
||||
var score = 0f;
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
foreach (var aroundGrid in AroundGridBuffer)
|
||||
{
|
||||
if (!aroundGrid.VisibleUnit(Map,Player, out var attacker)) continue;
|
||||
if (!selfUnit.Contains(attacker)) score += attacker.GetMilitary();
|
||||
@ -1443,9 +1455,10 @@ namespace Logic.AI
|
||||
|
||||
if (self.UnitType == UnitType.Catapult && map.GetGridDataByUnitId(self.Id, out var grid))
|
||||
{
|
||||
var gridList = Map.GridMap.GetAroundGridData(1, 1, grid);
|
||||
AroundGridBuffer.Clear();
|
||||
Map.GridMap.GetAroundGridData(1, 1, grid, AroundGridBuffer);
|
||||
bool isSea = true;
|
||||
foreach (var aroundGrid in gridList)
|
||||
foreach (var aroundGrid in AroundGridBuffer)
|
||||
{
|
||||
if (aroundGrid.Terrain == TerrainType.Land) isSea = false;
|
||||
}
|
||||
@ -1563,8 +1576,9 @@ namespace Logic.AI
|
||||
foreach (var city in selfCity)
|
||||
{
|
||||
if (!Map.GetGridDataByCityId(city.Id, out var cityGrid)) continue;
|
||||
var gridList = Map.GridMap.GetAroundGridData(5, 5, cityGrid);
|
||||
foreach (var grid in gridList)
|
||||
AroundGridBuffer.Clear();
|
||||
Map.GridMap.GetAroundGridData(5, 5, cityGrid, AroundGridBuffer);
|
||||
foreach (var grid in AroundGridBuffer)
|
||||
{
|
||||
if (grid.Resource != ResourceType.CityCenter) continue;
|
||||
if (Map.GetCityDataByGid(grid.Id, out var _)) continue;
|
||||
@ -1625,8 +1639,9 @@ namespace Logic.AI
|
||||
{
|
||||
if (hasCityCenter) break;
|
||||
if (!Map.GetGridDataByCityId(city.Id, out var cityGrid)) continue;
|
||||
var gridList = Map.GridMap.GetAroundGridData(8, 8, cityGrid);
|
||||
foreach (var grid in gridList)
|
||||
AroundGridBuffer.Clear();
|
||||
Map.GridMap.GetAroundGridData(8, 8, cityGrid, AroundGridBuffer);
|
||||
foreach (var grid in AroundGridBuffer)
|
||||
{
|
||||
if (grid.Resource != ResourceType.CityCenter) continue;
|
||||
if (Map.GetCityDataByGid(grid.Id, out var _)) continue;
|
||||
@ -2082,8 +2097,9 @@ namespace Logic.AI
|
||||
// 检查半径 1, 2, 3 范围内的威胁
|
||||
for (int r = 1; r <= 3; r++)
|
||||
{
|
||||
var aroundGrids = map.GridMap.GetAroundGridData(r, r, grid);
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
AroundGridBuffer.Clear();
|
||||
map.GridMap.GetAroundGridData(r, r, grid, AroundGridBuffer);
|
||||
foreach (var aroundGrid in AroundGridBuffer)
|
||||
{
|
||||
// 获取该格子上的单位
|
||||
if (!aroundGrid.VisibleUnit(map,player, out var enemyUnit)) continue;
|
||||
@ -2120,8 +2136,9 @@ namespace Logic.AI
|
||||
// 计算单位的最终射程
|
||||
var attackRange = unit.GetAttackRange(map);
|
||||
// 检查射程范围内的敌方单位
|
||||
var aroundGrids = map.GridMap.GetAroundGridData(attackRange, attackRange, grid);
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
AroundGridBuffer.Clear();
|
||||
map.GridMap.GetAroundGridData(attackRange, attackRange, grid, AroundGridBuffer);
|
||||
foreach (var aroundGrid in AroundGridBuffer)
|
||||
{
|
||||
// 获取该格子上的单位
|
||||
if (!aroundGrid.VisibleUnit(map,player, out var enemyUnit)) continue;
|
||||
@ -2157,8 +2174,9 @@ namespace Logic.AI
|
||||
// 计算单位的最终射程
|
||||
var attackRange = unit.GetAttackRange(map);
|
||||
// 检查射程范围内的敌方单位
|
||||
var aroundGrids = map.GridMap.GetAroundGridData(attackRange, attackRange, grid);
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
AroundGridBuffer.Clear();
|
||||
map.GridMap.GetAroundGridData(attackRange, attackRange, grid, AroundGridBuffer);
|
||||
foreach (var aroundGrid in AroundGridBuffer)
|
||||
{
|
||||
// 获取该格子上的单位
|
||||
if (!aroundGrid.VisibleUnit(map,player, out var enemyUnit)) continue;
|
||||
|
||||
@ -29,6 +29,10 @@ namespace Logic.AI
|
||||
public AIActionType ActionType => (AIActionType)(_actionRecord % (int)AIActionType.Max);
|
||||
|
||||
|
||||
private HashSet<uint> _territoryGridSet;
|
||||
private List<UnitData> _tmpUnitList;
|
||||
private List<CityData> _tmpCityList;
|
||||
|
||||
public void Init(MapData map, PlayerData player)
|
||||
{
|
||||
_mapData = map;
|
||||
@ -40,15 +44,19 @@ namespace Logic.AI
|
||||
_waitGrids.Clear();
|
||||
_waitCity.Clear();
|
||||
|
||||
var gridSet = map.GetPlayerTerritoryGridIdSet(player.Id);
|
||||
var unitList = new List<UnitData>();
|
||||
map.GetUnitDataListByPlayerId(player.Id, unitList);
|
||||
var cityList = new List<CityData>();
|
||||
map.GetCityDataListByPlayerId(player.Id, cityList);
|
||||
foreach (var unit in unitList) _waitUnits.Add(unit);
|
||||
foreach (var city in cityList) _waitCity.Add(city);
|
||||
_territoryGridSet ??= new HashSet<uint>();
|
||||
_territoryGridSet.Clear();
|
||||
map.GetPlayerTerritoryGridIdSet(player.Id, _territoryGridSet);
|
||||
_tmpUnitList ??= new List<UnitData>();
|
||||
_tmpUnitList.Clear();
|
||||
map.GetUnitDataListByPlayerId(player.Id, _tmpUnitList);
|
||||
_tmpCityList ??= new List<CityData>();
|
||||
_tmpCityList.Clear();
|
||||
map.GetCityDataListByPlayerId(player.Id, _tmpCityList);
|
||||
foreach (var unit in _tmpUnitList) _waitUnits.Add(unit);
|
||||
foreach (var city in _tmpCityList) _waitCity.Add(city);
|
||||
foreach (var grid in _mapData.GridMap.GridList)
|
||||
if(gridSet.Contains(grid.Id)) _waitGrids.Add(grid);
|
||||
if(_territoryGridSet.Contains(grid.Id)) _waitGrids.Add(grid);
|
||||
|
||||
_actionRecord = 0;
|
||||
_recordCount = 0;
|
||||
|
||||
@ -83,6 +83,13 @@ namespace Logic.AI
|
||||
private Dictionary<UnitData, float> _unitAttack;
|
||||
private Dictionary<UnitData, float> _unitDefend;
|
||||
private bool _hasUnitMoney;
|
||||
|
||||
// 复用的临时集合,避免每次计算分配
|
||||
private HashSet<UnitData> _tmpSelfUnitsSet;
|
||||
private List<UnitData> _tmpSelfUnitsList;
|
||||
private List<CityData> _tmpCityListBuf;
|
||||
private List<GridData> _tmpGridListBuf;
|
||||
private HashSet<CityData> _tmpCitySetBuf;
|
||||
|
||||
public static MapData CalMap;
|
||||
|
||||
@ -160,15 +167,16 @@ namespace Logic.AI
|
||||
{
|
||||
if (mapData.UnitMap.UnitList.Count == 0) return;
|
||||
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, selfUnits);
|
||||
_tmpSelfUnitsSet ??= new HashSet<UnitData>();
|
||||
_tmpSelfUnitsSet.Clear();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, _tmpSelfUnitsSet);
|
||||
|
||||
float score = 0f;
|
||||
foreach (var unit in mapData.UnitMap.UnitList)
|
||||
{
|
||||
if (!unit.IsAlive()) continue;
|
||||
var unitScore = CalculateOneUnitScore(mapData, playerData, unit) * _cfg.UnitScore;
|
||||
if (selfUnits.Contains(unit)) score += unitScore;
|
||||
if (_tmpSelfUnitsSet.Contains(unit)) score += unitScore;
|
||||
else score -= unitScore;
|
||||
_unitScore.TryAdd(unit, unitScore);
|
||||
}
|
||||
@ -184,15 +192,13 @@ namespace Logic.AI
|
||||
unitData.GetAllAttackValue(mapData) + unitData.GetAllDefenseValue(mapData);
|
||||
foreach (var skill in unitData.Skills) unitScore += skill.GetScore();
|
||||
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, selfUnits);
|
||||
|
||||
// 复用 _tmpSelfUnitsSet (由调用方 CalculateUnitScore 已填充)
|
||||
var restraintScore = 0f;
|
||||
var restraintUnitCount = 0f;
|
||||
foreach (var otherUnit in mapData.UnitMap.UnitList)
|
||||
{
|
||||
if (!otherUnit.IsAlive()) continue;
|
||||
if (selfUnits.Contains(otherUnit)) continue;
|
||||
if (_tmpSelfUnitsSet.Contains(otherUnit)) continue;
|
||||
restraintScore += GetRestraintScore(mapData,unitData, otherUnit);
|
||||
restraintUnitCount++;
|
||||
}
|
||||
@ -218,8 +224,9 @@ namespace Logic.AI
|
||||
private void CalculateCityScore(MapData mapData, PlayerData playerData, CalculateResult result)
|
||||
{
|
||||
if (mapData.CityMap.CityList.Count == 0) return;
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, selfUnits);
|
||||
_tmpSelfUnitsSet ??= new HashSet<UnitData>();
|
||||
_tmpSelfUnitsSet.Clear();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, _tmpSelfUnitsSet);
|
||||
|
||||
float score = 0f;
|
||||
foreach (var city in mapData.CityMap.CityList)
|
||||
@ -275,14 +282,15 @@ namespace Logic.AI
|
||||
private void RefreshUnitPos(MapData mapData, PlayerData playerData, CalculateResult result)
|
||||
{
|
||||
var selfCities = mapData.GetCityDataSetByPlayerId(playerData.Id);
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, selfUnits);
|
||||
_tmpSelfUnitsSet ??= new HashSet<UnitData>();
|
||||
_tmpSelfUnitsSet.Clear();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, _tmpSelfUnitsSet);
|
||||
|
||||
foreach (var city in selfCities)
|
||||
{
|
||||
foreach (var unit in mapData.UnitMap.UnitList)
|
||||
{
|
||||
if (selfUnits.Contains(unit)) continue;
|
||||
if (_tmpSelfUnitsSet.Contains(unit)) continue;
|
||||
if (!mapData.GetGridDataByUnitId(unit.Id, out var unitData)) continue;
|
||||
if (!city.Territory.TerritoryArea.Contains(unitData.Id)) continue;
|
||||
_unitInCityTerritory.Add(unit);
|
||||
@ -352,11 +360,12 @@ namespace Logic.AI
|
||||
private void RefreshUnitExploreScore(MapData mapData, PlayerData playerData, CalculateResult result)
|
||||
{
|
||||
if (playerData.Sight.SightGidSet.Count == mapData.GridMap.GridList.Count) return;
|
||||
var selfUnits = new List<UnitData>();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, selfUnits);
|
||||
if (selfUnits.Count == 0) return;
|
||||
_tmpSelfUnitsList ??= new List<UnitData>();
|
||||
_tmpSelfUnitsList.Clear();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, _tmpSelfUnitsList);
|
||||
if (_tmpSelfUnitsList.Count == 0) return;
|
||||
|
||||
foreach (var unit in selfUnits)
|
||||
foreach (var unit in _tmpSelfUnitsList)
|
||||
{
|
||||
if (!mapData.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
|
||||
GridData targetGrid = null;
|
||||
@ -390,24 +399,26 @@ namespace Logic.AI
|
||||
// 小兵探索村庄评分
|
||||
private void RefreshUnitExploreCityCenterScore(MapData mapData, PlayerData playerData, CalculateResult result)
|
||||
{
|
||||
var selfUnits = new List<UnitData>();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, selfUnits);
|
||||
if (selfUnits.Count == 0) return;
|
||||
_tmpSelfUnitsList ??= new List<UnitData>();
|
||||
_tmpSelfUnitsList.Clear();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, _tmpSelfUnitsList);
|
||||
if (_tmpSelfUnitsList.Count == 0) return;
|
||||
|
||||
var targetGrids = new List<GridData>();
|
||||
_tmpGridListBuf ??= new List<GridData>();
|
||||
_tmpGridListBuf.Clear();
|
||||
foreach (var gridData in _canMoveGrid)
|
||||
{
|
||||
if (gridData.Resource == ResourceType.CityCenter)
|
||||
{
|
||||
if (mapData.GetCityDataByGid(gridData.Id, out var _)) continue;
|
||||
targetGrids.Add(gridData);
|
||||
_tmpGridListBuf.Add(gridData);
|
||||
}
|
||||
}
|
||||
if (targetGrids.Count == 0) return;
|
||||
if (_tmpGridListBuf.Count == 0) return;
|
||||
|
||||
foreach (var grid in targetGrids)
|
||||
foreach (var grid in _tmpGridListBuf)
|
||||
{
|
||||
foreach (var unit in selfUnits)
|
||||
foreach (var unit in _tmpSelfUnitsList)
|
||||
{
|
||||
if (!mapData.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
|
||||
var path = PathFinder.FindPath((int)mapData.MapConfig.Width, (int)mapData.MapConfig.Height, new (unitGrid.Pos.X, unitGrid.Pos.Y), new (grid.Pos.X, grid.Pos.Y), mapData, playerData);
|
||||
@ -422,20 +433,22 @@ namespace Logic.AI
|
||||
// 刷新小兵探索遗迹评分
|
||||
private void RefreshUnitExploreTreasureScore(MapData mapData, PlayerData playerData, CalculateResult result)
|
||||
{
|
||||
var selfUnits = new List<UnitData>();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, selfUnits);
|
||||
if (selfUnits.Count == 0) return;
|
||||
_tmpSelfUnitsList ??= new List<UnitData>();
|
||||
_tmpSelfUnitsList.Clear();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, _tmpSelfUnitsList);
|
||||
if (_tmpSelfUnitsList.Count == 0) return;
|
||||
|
||||
var targetGrids = new List<GridData>();
|
||||
_tmpGridListBuf ??= new List<GridData>();
|
||||
_tmpGridListBuf.Clear();
|
||||
foreach (var gridData in _canMoveGrid)
|
||||
{
|
||||
if (gridData.Resource == ResourceType.Treasure) targetGrids.Add(gridData);
|
||||
if (gridData.Resource == ResourceType.Treasure) _tmpGridListBuf.Add(gridData);
|
||||
}
|
||||
if (targetGrids.Count == 0) return;
|
||||
if (_tmpGridListBuf.Count == 0) return;
|
||||
|
||||
foreach (var grid in targetGrids)
|
||||
foreach (var grid in _tmpGridListBuf)
|
||||
{
|
||||
foreach (var unit in selfUnits)
|
||||
foreach (var unit in _tmpSelfUnitsList)
|
||||
{
|
||||
if (!mapData.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
|
||||
var path = PathFinder.FindPath((int)mapData.MapConfig.Width, (int)mapData.MapConfig.Height, new (unitGrid.Pos.X, unitGrid.Pos.Y), new (grid.Pos.X, grid.Pos.Y), mapData, playerData);
|
||||
@ -452,20 +465,22 @@ namespace Logic.AI
|
||||
{
|
||||
if (!playerData.TechTree.CheckIfHasTech(TechType.Navigation)) return;
|
||||
|
||||
var selfUnits = new List<UnitData>();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, selfUnits);
|
||||
if (selfUnits.Count == 0) return;
|
||||
_tmpSelfUnitsList ??= new List<UnitData>();
|
||||
_tmpSelfUnitsList.Clear();
|
||||
mapData.GetUnitDataListByPlayerId(playerData.Id, _tmpSelfUnitsList);
|
||||
if (_tmpSelfUnitsList.Count == 0) return;
|
||||
|
||||
var targetGrids = new List<GridData>();
|
||||
_tmpGridListBuf ??= new List<GridData>();
|
||||
_tmpGridListBuf.Clear();
|
||||
foreach (var gridData in _canMoveGrid)
|
||||
{
|
||||
if (gridData.Resource == ResourceType.Starfish) targetGrids.Add(gridData);
|
||||
if (gridData.Resource == ResourceType.Starfish) _tmpGridListBuf.Add(gridData);
|
||||
}
|
||||
if (targetGrids.Count == 0) return;
|
||||
if (_tmpGridListBuf.Count == 0) return;
|
||||
|
||||
foreach (var grid in targetGrids)
|
||||
foreach (var grid in _tmpGridListBuf)
|
||||
{
|
||||
foreach (var unit in selfUnits)
|
||||
foreach (var unit in _tmpSelfUnitsList)
|
||||
{
|
||||
if (!mapData.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
|
||||
var path = PathFinder.FindPath((int)mapData.MapConfig.Width, (int)mapData.MapConfig.Height, new (unitGrid.Pos.X, unitGrid.Pos.Y), new (grid.Pos.X, grid.Pos.Y), mapData, playerData);
|
||||
@ -848,9 +863,10 @@ namespace Logic.AI
|
||||
{
|
||||
if (param.UnitData == null) return;
|
||||
if (!param.MapData.GetGridDataByUnitId(param.UnitData.Id, out var unitGrid)) return;
|
||||
var around = param.MapData.GridMap.GetAroundGridData(5, 5, unitGrid);
|
||||
data.AroundGridBuffer.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(5, 5, unitGrid, data.AroundGridBuffer);
|
||||
var score = 0f;
|
||||
foreach (var grid in around)
|
||||
foreach (var grid in data.AroundGridBuffer)
|
||||
{
|
||||
if (!grid.VisibleUnit(param.MapData,param.PlayerData, out var attackUnit)) continue;
|
||||
if (attackUnit == param.UnitData) continue;
|
||||
@ -865,9 +881,10 @@ namespace Logic.AI
|
||||
{
|
||||
if (param.UnitData == null) return;
|
||||
if (!param.MapData.GetGridDataByUnitId(param.UnitData.Id, out var unitGrid)) return;
|
||||
var around = param.MapData.GridMap.GetAroundGridData(1, 1, unitGrid);
|
||||
data.AroundGridBuffer.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(1, 1, unitGrid, data.AroundGridBuffer);
|
||||
var score = 0f;
|
||||
foreach (var grid in around)
|
||||
foreach (var grid in data.AroundGridBuffer)
|
||||
{
|
||||
if (!grid.VisibleUnit(param.MapData,param.PlayerData, out var attackUnit)) continue;
|
||||
if (attackUnit == param.UnitData) continue;
|
||||
@ -883,8 +900,9 @@ namespace Logic.AI
|
||||
var unit = param.UnitData;
|
||||
var grid = unit?.Grid(map);
|
||||
if (unit == null || grid == null) return;
|
||||
var arounds = map.GridMap.GetAroundGridData(3, 3, grid);
|
||||
foreach (var around in arounds)
|
||||
data.AroundGridBuffer.Clear();
|
||||
map.GridMap.GetAroundGridData(3, 3, grid, data.AroundGridBuffer);
|
||||
foreach (var around in data.AroundGridBuffer)
|
||||
{
|
||||
if (around == grid) continue;
|
||||
if (!unit.Player(map,out var unitPlayer) || !around.VisibleUnit(map,unitPlayer, out var attacker)) continue;
|
||||
@ -893,7 +911,7 @@ namespace Logic.AI
|
||||
if (dis > attacker.GetAttackRange(map)) continue;
|
||||
result.Score[CalculateType.AroundAttackerDangerMin] -= Table.Instance.CalcDamage(map, attacker, unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CalculateGridMiscCreateMountain(AICalculatorData data, CommonActionParams param, CalculateResult result)
|
||||
{
|
||||
@ -907,8 +925,9 @@ namespace Logic.AI
|
||||
private static void CalculateGridMiscGrowTree(AICalculatorData data, CommonActionParams param, CalculateResult result)
|
||||
{
|
||||
result.Score[CalculateType.GridMiscGrowTree] = 0;
|
||||
var aroundGrids = param.MapData.GridMap.GetAroundGridData(1, 1, param.GridData);
|
||||
foreach (var around in aroundGrids)
|
||||
data.AroundGridBuffer.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(1, 1, param.GridData, data.AroundGridBuffer);
|
||||
foreach (var around in data.AroundGridBuffer)
|
||||
{
|
||||
if (around == param.GridData) continue;
|
||||
if (around.Resource == ResourceType.Sawmill) result.Score[CalculateType.GridMiscGrowTree] += 5;
|
||||
@ -920,9 +939,10 @@ namespace Logic.AI
|
||||
{
|
||||
if (param.UnitData == null) return;
|
||||
if (!param.MapData.GetGridDataByUnitId(param.UnitData.Id, out var unitGrid)) return;
|
||||
var around = param.MapData.GridMap.GetAroundGridData(1, 1, unitGrid);
|
||||
data.AroundGridBuffer.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(1, 1, unitGrid, data.AroundGridBuffer);
|
||||
var score = 0f;
|
||||
foreach (var grid in around)
|
||||
foreach (var grid in data.AroundGridBuffer)
|
||||
{
|
||||
if (!grid.VisibleUnit(param.MapData,param.PlayerData, out var attackUnit)) continue;
|
||||
if (attackUnit == param.UnitData) continue;
|
||||
@ -937,9 +957,10 @@ namespace Logic.AI
|
||||
{
|
||||
if (param.UnitData == null) return;
|
||||
if (!param.MapData.GetGridDataByUnitId(param.UnitData.Id, out var unitGrid)) return;
|
||||
var around = param.MapData.GridMap.GetAroundGridData(1, 1, unitGrid);
|
||||
data.AroundGridBuffer.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(1, 1, unitGrid, data.AroundGridBuffer);
|
||||
var score = 0f;
|
||||
foreach (var grid in around)
|
||||
foreach (var grid in data.AroundGridBuffer)
|
||||
{
|
||||
if (!grid.VisibleUnit(param.MapData,param.PlayerData, out var attackUnit)) continue;
|
||||
if (attackUnit == param.UnitData) continue;
|
||||
@ -954,9 +975,10 @@ namespace Logic.AI
|
||||
{
|
||||
if (param.UnitData == null) return;
|
||||
if (!param.MapData.GetGridDataByUnitId(param.UnitData.Id, out var unitGrid)) return;
|
||||
var around = param.MapData.GridMap.GetAroundGridData(1, 1, unitGrid);
|
||||
data.AroundGridBuffer.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(1, 1, unitGrid, data.AroundGridBuffer);
|
||||
var score = 0f;
|
||||
foreach (var grid in around)
|
||||
foreach (var grid in data.AroundGridBuffer)
|
||||
{
|
||||
if (!grid.VisibleUnit(param.MapData,param.PlayerData, out var unit)) continue;
|
||||
if (unit == param.UnitData) continue;
|
||||
@ -995,11 +1017,11 @@ namespace Logic.AI
|
||||
private static void CalculateLegionDevelopmentKill(AICalculatorData data, CommonActionParams param, CalculateResult result)
|
||||
{
|
||||
var score = 0f;
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, selfUnits);
|
||||
data.TmpUnitSetBuffer.Clear();
|
||||
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, data.TmpUnitSetBuffer);
|
||||
foreach (var unit in param.MapData.UnitMap.UnitList)
|
||||
{
|
||||
if (selfUnits.Contains(unit)) continue;
|
||||
if (data.TmpUnitSetBuffer.Contains(unit)) continue;
|
||||
score += unit.GetMilitary();
|
||||
}
|
||||
result.Score[CalculateType.LegionDevelopmentKill] = 1f / (score + 1);
|
||||
@ -1063,9 +1085,9 @@ namespace Logic.AI
|
||||
newParam.MainObjectType = MainObjectType.City;
|
||||
newParam.MapData = param.MapData;
|
||||
newParam.PlayerData = param.PlayerData;
|
||||
var cityList = new List<CityData>();
|
||||
param.MapData.GetCityDataListByPlayerId(param.PlayerData.Id, cityList);
|
||||
foreach (var city in cityList)
|
||||
data.TmpCityListBuffer.Clear();
|
||||
param.MapData.GetCityDataListByPlayerId(param.PlayerData.Id, data.TmpCityListBuffer);
|
||||
foreach (var city in data.TmpCityListBuffer)
|
||||
{
|
||||
newParam.CityData = city;
|
||||
newParam.OnParamChanged();
|
||||
@ -1099,14 +1121,15 @@ namespace Logic.AI
|
||||
var path = PathFinder.FindPath((int)param.MapData.MapConfig.Width, (int)param.MapData.MapConfig.Height,
|
||||
new (unitGrid.Pos.X, unitGrid.Pos.Y), new (targetGrid.Pos.X, targetGrid.Pos.Y), param.MapData, param.PlayerData,param.UnitData);
|
||||
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, selfUnits);
|
||||
var around = param.MapData.GridMap.GetAroundGridData(1, 1, unitGrid);
|
||||
data.TmpUnitSetBuffer.Clear();
|
||||
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, data.TmpUnitSetBuffer);
|
||||
data.AroundGridBuffer.Clear();
|
||||
param.MapData.GridMap.GetAroundGridData(1, 1, unitGrid, data.AroundGridBuffer);
|
||||
var score = 0f;
|
||||
foreach (var aroundGrid in around)
|
||||
foreach (var aroundGrid in data.AroundGridBuffer)
|
||||
{
|
||||
if (!aroundGrid.VisibleUnit(param.MapData,param.PlayerData, out var aroundUnit)) continue;
|
||||
if (!selfUnits.Contains(aroundUnit)) continue;
|
||||
if (!data.TmpUnitSetBuffer.Contains(aroundUnit)) continue;
|
||||
score += aroundUnit.GetMilitary();
|
||||
}
|
||||
result.Score[CalculateType.LegionDefendMove] = 1 / ((float)path.length + 1) * 1000 + score / 1000f;
|
||||
@ -1156,13 +1179,13 @@ namespace Logic.AI
|
||||
if (!param.MapData.GetGridDataByCityId(param.CityData.Id, out var cityGrid)) return;
|
||||
if (!cityGrid.VisibleUnit(param.MapData,param.PlayerData, out var newUnit)) return;
|
||||
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, selfUnits);
|
||||
data.TmpUnitSetBuffer.Clear();
|
||||
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, data.TmpUnitSetBuffer);
|
||||
|
||||
var score = 0f;
|
||||
foreach (var unit in param.MapData.UnitMap.UnitList)
|
||||
{
|
||||
if (selfUnits.Contains(unit)) continue;
|
||||
if (data.TmpUnitSetBuffer.Contains(unit)) continue;
|
||||
if (!param.MapData.GetPlayerIdByUnitId(unit.Id, out var ownerId)) continue;
|
||||
if (!param.PlayerData.LastAttackPlayers.Contains(ownerId) &&
|
||||
!param.PlayerData.CurAttackPlayers.Contains(ownerId)) continue;
|
||||
@ -1176,13 +1199,13 @@ namespace Logic.AI
|
||||
if (!param.MapData.GetGridDataByCityId(param.CityData.Id, out var cityGrid)) return;
|
||||
if (!cityGrid.VisibleUnit(param.MapData,param.PlayerData, out var newUnit)) return;
|
||||
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, selfUnits);
|
||||
data.TmpUnitSetBuffer.Clear();
|
||||
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, data.TmpUnitSetBuffer);
|
||||
|
||||
var score = 0f;
|
||||
foreach (var unit in param.MapData.UnitMap.UnitList)
|
||||
{
|
||||
if (selfUnits.Contains(unit)) continue;
|
||||
if (data.TmpUnitSetBuffer.Contains(unit)) continue;
|
||||
if (!param.MapData.GetGridDataByUnitId(unit.Id, out var unitGrid)) continue;
|
||||
var dis = param.MapData.GridMap.CalcDistance(cityGrid, unitGrid);
|
||||
if (dis > 3) continue;
|
||||
@ -1196,13 +1219,13 @@ namespace Logic.AI
|
||||
if (!param.MapData.GetGridDataByCityId(param.CityData.Id, out var cityGrid)) return;
|
||||
if (!cityGrid.VisibleUnit(param.MapData,param.PlayerData, out var newUnit)) return;
|
||||
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, selfUnits);
|
||||
data.TmpUnitSetBuffer.Clear();
|
||||
param.MapData.GetUnitDataListByPlayerId(param.PlayerData.Id, data.TmpUnitSetBuffer);
|
||||
|
||||
var score = 0f;
|
||||
foreach (var unit in param.MapData.UnitMap.UnitList)
|
||||
{
|
||||
if (selfUnits.Contains(unit)) continue;
|
||||
if (data.TmpUnitSetBuffer.Contains(unit)) continue;
|
||||
if (!param.MapData.GetPlayerIdByUnitId(unit.Id, out var ownerId)) continue;
|
||||
if (!param.PlayerData.LastAttackPlayers.Contains(ownerId) &&
|
||||
!param.PlayerData.CurAttackPlayers.Contains(ownerId)) continue;
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Logic.Action;
|
||||
using Logic.CrashSight;
|
||||
using NodeCanvas.BehaviourTrees;
|
||||
@ -64,6 +63,7 @@ namespace Logic.AI
|
||||
private int _actionCount;
|
||||
private List<float> _actionBitCodec;
|
||||
private int _sameCount;
|
||||
private List<List<uint>> _nodeRecords;
|
||||
|
||||
public static uint CurrentAIPlayerId;
|
||||
public static Dictionary<uint, List<AIRecord>> AIRecordsDict;
|
||||
@ -155,17 +155,23 @@ namespace Logic.AI
|
||||
#endif
|
||||
|
||||
var index = 0;
|
||||
var nodeRecords = new List<List<uint>>();
|
||||
_nodeRecords ??= new List<List<uint>>();
|
||||
for (int i = 0; i < _nodeRecords.Count; i++) _nodeRecords[i].Clear();
|
||||
var nodeRecordsUsed = 0;
|
||||
while (true)
|
||||
{
|
||||
if (MainEditor.Instance.IsEditor && !MainEditor.Instance.IsGo) return;
|
||||
index++;
|
||||
if (index > nodeRecords.Count) nodeRecords.Add(new List<uint>());
|
||||
if (index > nodeRecordsUsed)
|
||||
{
|
||||
nodeRecordsUsed = index;
|
||||
if (index > _nodeRecords.Count) _nodeRecords.Add(new List<uint>());
|
||||
}
|
||||
_data.ClearCache();
|
||||
nodeRecords[index - 1].Add(MainEditor.Instance.BTNodeId);
|
||||
_nodeRecords[index - 1].Add(MainEditor.Instance.BTNodeId);
|
||||
_btOwner.UpdateBehaviour();
|
||||
MainEditor.Instance.IsGo = false;
|
||||
nodeRecords[index - 1].Add(MainEditor.Instance.BTNodeId);
|
||||
_nodeRecords[index - 1].Add(MainEditor.Instance.BTNodeId);
|
||||
if (_data.MaxAiAction != null || _data.IsFinish) break;
|
||||
|
||||
if (index > 150)
|
||||
@ -260,7 +266,9 @@ namespace Logic.AI
|
||||
{
|
||||
reward += 10;
|
||||
}
|
||||
TrainingDataRecorder.Instance.RecordStep(curPlayer.Id, state, validActions.Select(x => x.ToArray()).ToArray(), packed.ToArray(), reward);
|
||||
var actionsArray = new float[validActions.Count][];
|
||||
for (int ai = 0; ai < validActions.Count; ai++) actionsArray[ai] = validActions[ai].ToArray();
|
||||
TrainingDataRecorder.Instance.RecordStep(curPlayer.Id, state, actionsArray, packed.ToArray(), reward);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -349,7 +357,9 @@ namespace Logic.AI
|
||||
LogSystem.LogError($"占领!!!");
|
||||
reward += 10;
|
||||
}
|
||||
TrainingDataRecorder.Instance.RecordStep(curPlayer.Id, state, validActions.Select(x => x.ToArray()).ToArray(), packed.ToArray(), reward);
|
||||
var actionsArray2 = new float[validActions.Count][];
|
||||
for (int ai = 0; ai < validActions.Count; ai++) actionsArray2[ai] = validActions[ai].ToArray();
|
||||
TrainingDataRecorder.Instance.RecordStep(curPlayer.Id, state, actionsArray2, packed.ToArray(), reward);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -74,6 +74,8 @@ namespace Logic.Achievement
|
||||
[Serializable]
|
||||
public abstract class AchievementConditionBase : ISerializationCallbackReceiver
|
||||
{
|
||||
protected static List<GridData> _aroundBuf;
|
||||
|
||||
public virtual void OnBeforeSerialize() { }
|
||||
public virtual void OnAfterDeserialize() { }
|
||||
|
||||
@ -484,8 +486,10 @@ namespace Logic.Achievement
|
||||
|
||||
if (gridData == null) return false;
|
||||
_gridId = gridData.Id;
|
||||
var aroundGrids = map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData);
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf);
|
||||
foreach (var aroundGrid in _aroundBuf)
|
||||
{
|
||||
if (Terrain != TerrainType.None && aroundGrid.Terrain == Terrain) _recordCount++;
|
||||
if (Feature != TerrainFeature.None && aroundGrid.Feature == Feature) _recordCount++;
|
||||
@ -571,8 +575,10 @@ namespace Logic.Achievement
|
||||
|
||||
if (gridData == null) return false;
|
||||
_gridId = gridData.Id;
|
||||
var aroundGrids = map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData);
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf);
|
||||
foreach (var aroundGrid in _aroundBuf)
|
||||
{
|
||||
if (aroundGrid.Wonder == AroundWonder) _recordCount++;
|
||||
}
|
||||
@ -650,12 +656,14 @@ namespace Logic.Achievement
|
||||
|
||||
if (gridData == null) return false;
|
||||
_gridId = gridData.Id;
|
||||
var aroundGrids = map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf);
|
||||
|
||||
_recordCount = 0;
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
map.GetUnitDataListByPlayerId(map.PlayerMap.SelfPlayerId, selfUnits);
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
foreach (var aroundGrid in _aroundBuf)
|
||||
{
|
||||
if (!aroundGrid.RealUnit(map, out var unit)) continue;
|
||||
if (selfUnits.Contains(unit)) continue;
|
||||
@ -734,12 +742,14 @@ namespace Logic.Achievement
|
||||
|
||||
if (gridData == null) return false;
|
||||
_gridId = gridData.Id;
|
||||
var aroundGrids = map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf);
|
||||
|
||||
_recordCount = 0;
|
||||
var selfUnits = new HashSet<UnitData>();
|
||||
map.GetUnitDataListByPlayerId(map.PlayerMap.SelfPlayerId, selfUnits);
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
foreach (var aroundGrid in _aroundBuf)
|
||||
{
|
||||
if (!aroundGrid.RealUnit(map, out var unit)) continue;
|
||||
if (!selfUnits.Contains(unit)) continue;
|
||||
@ -818,10 +828,12 @@ namespace Logic.Achievement
|
||||
|
||||
if (gridData == null) return false;
|
||||
_gridId = gridData.Id;
|
||||
var aroundGrids = map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(OffsetX, OffsetY, gridData, _aroundBuf);
|
||||
|
||||
_recordCount = 0;
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
foreach (var aroundGrid in _aroundBuf)
|
||||
{
|
||||
if (!map.GetCityDataByTerritoryGid(aroundGrid.Id, out var city)) continue;
|
||||
if (city.CityInfo != TargetCity) continue;
|
||||
|
||||
@ -1038,6 +1038,9 @@ namespace Logic.Action
|
||||
set => _duration = value;
|
||||
}
|
||||
|
||||
// 所有ActionLogic共享的临时集合(行为是顺序执行的,不会并发)
|
||||
protected static List<GridData> _sharedAroundBuf;
|
||||
|
||||
public ActionLogicBase(CommonActionId id)
|
||||
{
|
||||
_actionId = id;
|
||||
|
||||
@ -76,8 +76,10 @@ namespace Logic.Action
|
||||
actionParams.GridData.Feature = TerrainFeature.Road;
|
||||
|
||||
//更新周围各自的道路图案
|
||||
var tlist = actionParams.MapData.GridMap.GetAroundGridData(1, 1, actionParams.GridData);
|
||||
foreach (var tgrid in tlist)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
actionParams.MapData.GridMap.GetAroundGridData(1, 1, actionParams.GridData, _sharedAroundBuf);
|
||||
foreach (var tgrid in _sharedAroundBuf)
|
||||
tgrid.Renderer(actionParams.MapData)?.InstantUpdateGrid(true);
|
||||
}
|
||||
//处理bridge或者road
|
||||
@ -88,8 +90,9 @@ namespace Logic.Action
|
||||
actionParams.GridData.Resource = ResourceType.Bridge;
|
||||
|
||||
//更新周围各自的道路图案
|
||||
var tlist = actionParams.MapData.GridMap.GetAroundGridData(1, 1, actionParams.GridData);
|
||||
foreach (var tgrid in tlist)
|
||||
_sharedAroundBuf.Clear();
|
||||
actionParams.MapData.GridMap.GetAroundGridData(1, 1, actionParams.GridData, _sharedAroundBuf);
|
||||
foreach (var tgrid in _sharedAroundBuf)
|
||||
tgrid.Renderer(actionParams.MapData)?.InstantUpdateGrid(true);
|
||||
}
|
||||
//处理temple
|
||||
@ -582,8 +585,10 @@ namespace Logic.Action
|
||||
{
|
||||
var map = actionParam.MapData;
|
||||
var grid = actionParam.GridData;
|
||||
var list = map.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var g in list)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var g in _sharedAroundBuf)
|
||||
if (g.Resource == _actionId.ResourceType)
|
||||
return true;
|
||||
return false;
|
||||
@ -978,9 +983,11 @@ namespace Logic.Action
|
||||
if (grid.Feature == TerrainFeature.Mountain) return false;
|
||||
if (grid.Vegetation == Vegetation.Trees) return false;
|
||||
if (!(grid.Resource is ResourceType.None or ResourceType.Fruit or ResourceType.Crop)) return false;
|
||||
var list = actionParams.MapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
actionParams.MapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
int waterSide = 0;
|
||||
foreach (var g in list)
|
||||
foreach (var g in _sharedAroundBuf)
|
||||
{
|
||||
if (Mathf.Abs(g.Pos.X - grid.Pos.X) + Mathf.Abs(g.Pos.Y - grid.Pos.Y) != 1) continue;
|
||||
if (g.Terrain is TerrainType.ShallowSea) waterSide++;
|
||||
@ -995,9 +1002,11 @@ namespace Logic.Action
|
||||
return false;
|
||||
if (grid.Terrain != TerrainType.ShallowSea) return false;
|
||||
if (!(grid.Resource is ResourceType.None or ResourceType.Fish or ResourceType.Starfish)) return false;
|
||||
var list = actionParams.MapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
actionParams.MapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
int landSide = 0;
|
||||
foreach (var g in list)
|
||||
foreach (var g in _sharedAroundBuf)
|
||||
{
|
||||
if (Mathf.Abs(g.Pos.X - grid.Pos.X) + Mathf.Abs(g.Pos.Y - grid.Pos.Y) != 1) continue;
|
||||
if (g.Terrain is TerrainType.Land) landSide++;
|
||||
|
||||
@ -781,8 +781,10 @@ namespace Logic.Action
|
||||
var unit = actionParams.UnitData;
|
||||
if (map == null || unit == null) return false;
|
||||
if (!map.GetGridDataByUnitId(actionParams.UnitData.Id, out var targetGrid)) return false;
|
||||
var roundGrid = map.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
foreach (var grid in roundGrid)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (!grid.RealUnit(map, out var tunit)) continue;
|
||||
if(tunit.Id == unit.Id)continue;
|
||||
@ -831,8 +833,10 @@ namespace Logic.Action
|
||||
if(selfGrid == null)
|
||||
if(!actionParams.MapData.GetGridDataByUnitId(selfUnit.Id, out selfGrid)) return false;
|
||||
if (!actionParams.MapData.GetPlayerDataByUnitId(selfUnit.Id, out var selfPlayer)) return false;
|
||||
var gridList = actionParams.MapData.GridMap.GetAroundGridData(1,1,selfGrid);
|
||||
foreach (var grid in gridList)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
actionParams.MapData.GridMap.GetAroundGridData(1,1,selfGrid, _sharedAroundBuf);
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (grid == selfGrid) continue;
|
||||
if(!grid.RealUnit(actionParams.MapData,out var targetUnit))continue;
|
||||
@ -888,8 +892,10 @@ namespace Logic.Action
|
||||
if (!actionParams.MapData.GetGridDataByUnitId(selfUnit.Id, out selfGrid)) return false;
|
||||
}
|
||||
if (!actionParams.MapData.GetPlayerDataByUnitId(selfUnit.Id, out var selfPlayer)) return false;
|
||||
var gridList = actionParams.MapData.GridMap.GetAroundGridData(1,1,selfGrid);
|
||||
foreach (var grid in gridList)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
actionParams.MapData.GridMap.GetAroundGridData(1,1,selfGrid, _sharedAroundBuf);
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (grid == selfGrid) continue;
|
||||
|
||||
@ -958,8 +964,10 @@ namespace Logic.Action
|
||||
if(selfGrid == null)
|
||||
if(!actionParams.MapData.GetGridDataByUnitId(selfUnit.Id, out selfGrid)) return false;
|
||||
if (!actionParams.MapData.GetPlayerDataByUnitId(selfUnit.Id, out var selfPlayer)) return false;
|
||||
var gridList = actionParams.MapData.GridMap.GetAroundGridData(1,1,selfGrid);
|
||||
foreach (var grid in gridList)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
actionParams.MapData.GridMap.GetAroundGridData(1,1,selfGrid, _sharedAroundBuf);
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (grid == selfGrid) continue;
|
||||
if(!grid.RealUnit(actionParams.MapData,out var targetUnit))continue;
|
||||
@ -1135,8 +1143,10 @@ namespace Logic.Action
|
||||
if(selfGrid == null)
|
||||
if(!actionParams.MapData.GetGridDataByUnitId(selfUnit.Id, out selfGrid)) return false;
|
||||
if (!actionParams.MapData.GetPlayerDataByUnitId(selfUnit.Id, out var selfPlayer)) return false;
|
||||
var gridList = actionParams.MapData.GridMap.GetAroundGridData(1,1,selfGrid);
|
||||
foreach (var grid in gridList)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
actionParams.MapData.GridMap.GetAroundGridData(1,1,selfGrid, _sharedAroundBuf);
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (grid.Resource == ResourceType.CityCenter) continue;
|
||||
if (grid.Terrain != TerrainType.Land) continue;
|
||||
@ -1250,9 +1260,10 @@ namespace Logic.Action
|
||||
|
||||
//Step #2 清除红雾
|
||||
int count = 0;
|
||||
var gridSet = actionParams.MapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, grid);
|
||||
gridSet.Add(grid);
|
||||
foreach (var tgrid in gridSet)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
actionParams.MapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var tgrid in _sharedAroundBuf)
|
||||
{
|
||||
if (!tgrid.HasSpType(GridSpType.RemiliaGrid)) continue;
|
||||
count++;
|
||||
@ -1291,10 +1302,11 @@ namespace Logic.Action
|
||||
//#step #4 check 当前grid是否是remiliaGrid
|
||||
|
||||
if (!actionParams.UnitData.Grid(actionParams.MapData, out var grid))return false;
|
||||
var gridSet = actionParams.MapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, grid);
|
||||
gridSet.Add(grid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
actionParams.MapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
bool hasRemiliaGrid = false;
|
||||
foreach (var tgrid in gridSet)
|
||||
foreach (var tgrid in _sharedAroundBuf)
|
||||
if (tgrid.HasSpType(GridSpType.RemiliaGrid))
|
||||
{
|
||||
hasRemiliaGrid = true;
|
||||
@ -1617,8 +1629,10 @@ namespace Logic.Action
|
||||
if (unit == null || !unit.Grid(map, out var grid)) return false;
|
||||
|
||||
//Step #1 对周围1格范围的单位(不包括自己)造成2点溅射伤害并添加1层KomeijiFear
|
||||
var arounds = map.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var around in arounds)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
if (!around.RealUnit(map, out var target)) continue;
|
||||
if (target.Id == unit.Id) continue;
|
||||
|
||||
@ -22,6 +22,8 @@ namespace Logic
|
||||
int explorerStep = 0;
|
||||
Vector2Int explorerNowPos = new Vector2Int();
|
||||
CityData explorerCityData;
|
||||
|
||||
private List<GridData> _aroundBuf;
|
||||
|
||||
|
||||
public void GenerateTribe(MapData mapData, Vector2Int tpos, int cid)
|
||||
@ -349,12 +351,14 @@ namespace Logic
|
||||
{
|
||||
if (!mapData.GetGridDataByCityId(cityData.Id, out var gridData)) return;
|
||||
if (!mapData.GetPlayerDataByCityId(cityData.Id, out var playerData)) return;
|
||||
var aroundGridList = mapData.GridMap.GetAroundGridData(2, 2, gridData);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(2, 2, gridData, _aroundBuf);
|
||||
|
||||
Main.PlayerLogic.UpdateSight_LogicView(mapData,playerData,mapData.GridMap.GetAroundGridIdList(2,gridData));
|
||||
|
||||
var newTerritoryArea = new List<uint>();
|
||||
foreach (var aroundGrid in aroundGridList)
|
||||
foreach (var aroundGrid in _aroundBuf)
|
||||
{
|
||||
|
||||
if (mapData.GetPlayerDataByTerritoryGridId(aroundGrid.Id, out var playerData1)) continue;
|
||||
@ -398,7 +402,9 @@ namespace Logic
|
||||
|
||||
|
||||
//获得周围一圈的grid,必须是我方
|
||||
var aroundGridList = mapData.GridMap.GetAroundGridData(1,1,gridData);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1,1,gridData, _aroundBuf);
|
||||
level = 0;
|
||||
bool ret = false;
|
||||
|
||||
@ -427,7 +433,7 @@ namespace Logic
|
||||
}
|
||||
|
||||
//其他建筑处理
|
||||
foreach (var grid in aroundGridList)
|
||||
foreach (var grid in _aroundBuf)
|
||||
{
|
||||
//如果就是中间这个格子,跳过
|
||||
//if (grid == gridData) continue;
|
||||
@ -514,7 +520,7 @@ namespace Logic
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var grid in aroundGridList)
|
||||
foreach (var grid in _aroundBuf)
|
||||
{
|
||||
if (grid == gridData) continue;
|
||||
if (grid.HasSpType(GridSpType.LeyLine))
|
||||
@ -570,10 +576,12 @@ namespace Logic
|
||||
public bool CheckAroundGridHasSomeResourceBelongPlayer(MapData mapData, GridData gridData,PlayerData playerData, ResourceType buildingType)
|
||||
{
|
||||
//step #1 获得周围一圈的grid,不管是不是我方
|
||||
var aroundGridList = mapData.GridMap.GetAroundGridData(1,1,gridData);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1,1,gridData, _aroundBuf);
|
||||
|
||||
//step #2 逐一判断每个周围的grid
|
||||
foreach (var grid in aroundGridList)
|
||||
foreach (var grid in _aroundBuf)
|
||||
{
|
||||
//如果不是player的领土,continue
|
||||
if (!mapData.CheckIfGidBelongPid(grid.Id, mapData.PlayerMap.SelfPlayerId)) continue;
|
||||
|
||||
@ -147,7 +147,7 @@ namespace Logic.Editor
|
||||
private GUIStyle _redBoxStyle;
|
||||
private GUIStyle _whiteBoxStyle;
|
||||
|
||||
private string Path = "F:/2026.3.19oss";
|
||||
private string Path = "";
|
||||
|
||||
// 筛选类
|
||||
private OssStatisticType _statisticType;
|
||||
@ -194,6 +194,15 @@ namespace Logic.Editor
|
||||
GUI.skin.button.wordWrap = true;
|
||||
_barPosition = EditorGUILayout.BeginScrollView(_barPosition);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Path = EditorGUILayout.TextField("分析文件夹", Path);
|
||||
if (GUILayout.Button("浏览...", GUILayout.Width(60)))
|
||||
{
|
||||
var selected = EditorUtility.OpenFolderPanel("选择分析文件夹", "", "");
|
||||
if (!string.IsNullOrEmpty(selected)) Path = selected;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
InspectorUtils.InspectorTextWidthRich($"<b> 筛选类型 : </b>");
|
||||
_statisticType = (OssStatisticType) EditorGUILayout.EnumPopup(_statisticType, GUILayout.Width(200));
|
||||
@ -381,11 +390,11 @@ namespace Logic.Editor
|
||||
try
|
||||
{
|
||||
var bytes = File.ReadAllBytes(file);
|
||||
var ossData = MemoryPackSerializer.Deserialize<OssData>(bytes);
|
||||
if (ossData?.CollectData == null) continue;
|
||||
var collectData = MemoryPackSerializer.Deserialize<CollectData>(bytes);
|
||||
if (collectData == null) continue;
|
||||
|
||||
_validFileCount++;
|
||||
ProcessCollectData(ossData.CollectData, _unitResult);
|
||||
ProcessCollectData(collectData, _unitResult);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
@ -425,11 +434,11 @@ namespace Logic.Editor
|
||||
try
|
||||
{
|
||||
var bytes = File.ReadAllBytes(file);
|
||||
var ossData = MemoryPackSerializer.Deserialize<OssData>(bytes);
|
||||
if (ossData?.CollectData == null) continue;
|
||||
var collectData = MemoryPackSerializer.Deserialize<CollectData>(bytes);
|
||||
if (collectData == null) continue;
|
||||
|
||||
_validFileCount++;
|
||||
ProcessCollectData(ossData.CollectData, _techResult);
|
||||
ProcessCollectData(collectData, _techResult);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
@ -463,11 +472,11 @@ namespace Logic.Editor
|
||||
try
|
||||
{
|
||||
var bytes = File.ReadAllBytes(file);
|
||||
var ossData = MemoryPackSerializer.Deserialize<OssData>(bytes);
|
||||
if (ossData?.CollectData == null) continue;
|
||||
var collectData = MemoryPackSerializer.Deserialize<CollectData>(bytes);
|
||||
if (collectData == null) continue;
|
||||
|
||||
_validFileCount++;
|
||||
ProcessCollectData(ossData.CollectData, _empireResult);
|
||||
ProcessCollectData(collectData, _empireResult);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
|
||||
@ -47,6 +47,7 @@ namespace Logic
|
||||
|
||||
public class MapGenerator
|
||||
{
|
||||
private static List<GridData> _aroundBuf;
|
||||
private Main _main;
|
||||
private MapData _mapData;
|
||||
|
||||
@ -1016,9 +1017,11 @@ namespace Logic
|
||||
|
||||
//获得首都4格内的遗迹视野
|
||||
if(city.Id !=player.CradleCityId)continue;
|
||||
var gridList = mapData.GridMap.GetAroundGridData(4, 4, city.Grid(mapData));
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(4, 4, city.Grid(mapData), _aroundBuf);
|
||||
var gidList = new List<uint>();
|
||||
foreach(var grid in gridList)
|
||||
foreach(var grid in _aroundBuf)
|
||||
if(grid.Resource == ResourceType.Treasure)
|
||||
gidList.Add(grid.Id);
|
||||
Main.PlayerLogic.UpdateSight_LogicView(mapData, player, gidList);
|
||||
@ -1158,19 +1161,21 @@ namespace Logic
|
||||
if (!mapData.GridMap.GetGridDataByPos(PlayerCivOri[rk].X, PlayerCivOri[rk].Y, out var cradleGrid)) continue;
|
||||
|
||||
// 检查2格内是否已有地脉
|
||||
var aroundGrids = mapData.GridMap.GetAroundGridData(2, 2, cradleGrid);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(2, 2, cradleGrid, _aroundBuf);
|
||||
bool hasLeyLine = false;
|
||||
foreach (var g in aroundGrids)
|
||||
foreach (var g in _aroundBuf)
|
||||
if (g.HasSpType(GridSpType.LeyLine)) { hasLeyLine = true; break; }
|
||||
if (hasLeyLine) continue;
|
||||
|
||||
// 没有则强制在2格内随机选一个合法格子放置
|
||||
for (int i = aroundGrids.Count - 1; i > 0; i--)
|
||||
for (int i = _aroundBuf.Count - 1; i > 0; i--)
|
||||
{
|
||||
int j = Random.Range(0, i + 1);
|
||||
(aroundGrids[i], aroundGrids[j]) = (aroundGrids[j], aroundGrids[i]);
|
||||
(_aroundBuf[i], _aroundBuf[j]) = (_aroundBuf[j], _aroundBuf[i]);
|
||||
}
|
||||
foreach (var g in aroundGrids)
|
||||
foreach (var g in _aroundBuf)
|
||||
{
|
||||
if (g.Terrain != TerrainType.Land) continue;
|
||||
if (g.Resource == ResourceType.CityCenter) continue;
|
||||
|
||||
@ -27,6 +27,10 @@ namespace Logic
|
||||
private static readonly WonderTypeEnum[] _cachedWonderTypes =
|
||||
(WonderTypeEnum[])System.Enum.GetValues(typeof(WonderTypeEnum));
|
||||
|
||||
// 复用的临时集合
|
||||
private HashSet<uint> _tmpTerritoryBuf;
|
||||
private List<GridData> _tmpAroundBuf;
|
||||
|
||||
public PlayerLogic(Main main)
|
||||
{
|
||||
_main = main;
|
||||
@ -404,8 +408,10 @@ namespace Logic
|
||||
//Step #7 更新该城镇3范围内的所有单元格(包括可交互物体的glow以及边界的更新)
|
||||
if (!mapData.GetGridDataByCityId(cityData.Id, out var grid))
|
||||
return;
|
||||
var gridList2 = mapData.GridMap.GetAroundGridData(3, 3, grid);
|
||||
foreach (var tg in gridList2)
|
||||
_tmpAroundBuf ??= new List<GridData>();
|
||||
_tmpAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(3, 3, grid, _tmpAroundBuf);
|
||||
foreach (var tg in _tmpAroundBuf)
|
||||
tg.Renderer(mapData)?.InstantUpdateGrid(true);
|
||||
|
||||
List<uint> list = new List<uint>(cityData.Territory.TerritoryArea);
|
||||
@ -505,10 +511,12 @@ namespace Logic
|
||||
public List<GridData> GetPlayerResourceNearbyList(MapData mapData, PlayerData playerData, GridData gridData, ResourceType resourceType)
|
||||
{
|
||||
var aroundGridList = new List<GridData>();
|
||||
var aroundGrid = mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, gridData);
|
||||
_tmpAroundBuf ??= new List<GridData>();
|
||||
_tmpAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, gridData, _tmpAroundBuf);
|
||||
|
||||
//var territoryGidSet = mapData.GetPlayerTerritoryGridIdSet(playerData.Id);
|
||||
foreach (var grid in aroundGrid)
|
||||
foreach (var grid in _tmpAroundBuf)
|
||||
{
|
||||
//如果不是玩家的领土
|
||||
if(mapData.GetPlayerDataByTerritoryGridId(grid.Id, out var player)
|
||||
@ -525,10 +533,12 @@ namespace Logic
|
||||
public List<GridData> GetPlayerFeatureNearbyList(MapData mapData, PlayerData playerData, GridData gridData, TerrainFeature feature)
|
||||
{
|
||||
var aroundGridList = new List<GridData>();
|
||||
var aroundGrid = mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, gridData);
|
||||
_tmpAroundBuf ??= new List<GridData>();
|
||||
_tmpAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, gridData, _tmpAroundBuf);
|
||||
var territoryGidSet = mapData.GetPlayerTerritoryGridIdSet(playerData.Id);
|
||||
|
||||
foreach (var grid in aroundGrid)
|
||||
foreach (var grid in _tmpAroundBuf)
|
||||
{
|
||||
if (!territoryGidSet.Contains(grid.Id)) continue;
|
||||
if (grid.Feature != feature) continue;
|
||||
@ -686,8 +696,10 @@ namespace Logic
|
||||
continue;
|
||||
|
||||
// 获取相邻格子
|
||||
var neighbors = mapData.GridMap.GetAroundGridDataSetByOrder(1, 1, curGrid);
|
||||
foreach (var neighbor in neighbors)
|
||||
_tmpAroundBuf ??= new List<GridData>();
|
||||
_tmpAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSetByOrder(1, 1, curGrid, _tmpAroundBuf);
|
||||
foreach (var neighbor in _tmpAroundBuf)
|
||||
{
|
||||
uint nextId = neighbor.Id;
|
||||
|
||||
@ -731,8 +743,9 @@ namespace Logic
|
||||
foreach (var tmpStartId in startSet)
|
||||
{
|
||||
mapData.GridMap.GetGridDataByGid(tmpStartId, out var tmpStartGrid);
|
||||
var aroundGridSet = mapData.GridMap.GetAroundGridData(1, 1, tmpStartGrid);
|
||||
foreach(var tmpAroundGrid in aroundGridSet)
|
||||
_tmpAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, tmpStartGrid, _tmpAroundBuf);
|
||||
foreach(var tmpAroundGrid in _tmpAroundBuf)
|
||||
if (playerData.PlayerForceId < tmpAroundGrid.WaterRoadForceId.Length
|
||||
&& tmpAroundGrid.WaterRoadForceId[playerData.PlayerForceId]
|
||||
&& !visitedSet.Contains(tmpAroundGrid.Id))
|
||||
@ -793,8 +806,9 @@ namespace Logic
|
||||
{
|
||||
grid.Feature = isRoad ? TerrainFeature.Road : TerrainFeature.None;
|
||||
grid.Renderer(mapData)?.InstantUpdateGrid(true);
|
||||
var neighbors = mapData.GridMap.GetAroundGridDataSetByOrder(1, 1, grid);
|
||||
foreach (var nearbyGrid in neighbors)
|
||||
_tmpAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSetByOrder(1, 1, grid, _tmpAroundBuf);
|
||||
foreach (var nearbyGrid in _tmpAroundBuf)
|
||||
nearbyGrid.Renderer(mapData)?.InstantUpdateGrid(true);
|
||||
}
|
||||
|
||||
@ -815,7 +829,9 @@ namespace Logic
|
||||
var head = li.Dequeue();
|
||||
|
||||
if (!mapData.GridMap.GetGridDataByGid(head, out var headGrid)) continue;
|
||||
foreach (var aroundGrid in mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, headGrid))
|
||||
_tmpAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, headGrid, _tmpAroundBuf);
|
||||
foreach (var aroundGrid in _tmpAroundBuf)
|
||||
{
|
||||
//Step #1如果不是我方领土或者中立领土,不行
|
||||
if (mapData.GetPlayerDataByTerritoryGridId(aroundGrid.Id, out var _) &&
|
||||
|
||||
@ -36,8 +36,10 @@ namespace Logic.Skill
|
||||
var selfUnitList = new HashSet<UnitData>();
|
||||
mapData.GetUnitDataListByPlayerId(player.Id, selfUnitList);
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
foreach (var grid in roundGrid)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (!grid.VisibleUnit(mapData, player,out var unit)) continue;
|
||||
if (!selfUnitList.Contains(unit)) continue;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
using TH1_Logic.Core;
|
||||
@ -35,8 +36,10 @@ namespace Logic.Skill
|
||||
if (!self.IsAlive()) return;
|
||||
if (!self.Grid(mapData, out var grid)) return;
|
||||
if (!self.Player(mapData, out var player)) return;
|
||||
var gridSet = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach(var targetGrid in gridSet)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach(var targetGrid in _sharedAroundBuf)
|
||||
//周围1格内的盟友
|
||||
if(targetGrid.VisibleUnit(mapData,player,out var targetUnit) && targetUnit.Player(mapData,out var targetPlayer) && mapData.SameUnion(targetPlayer.Id,player.Id))
|
||||
{
|
||||
|
||||
@ -35,9 +35,11 @@ namespace Logic.Skill
|
||||
|
||||
var targetGrid = info.DamageTargetGrid;
|
||||
if (targetGrid == null) return;
|
||||
var aroundGrids = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
if (!mapData.GetPlayerDataByUnitId(info.DamageOrigin.Id, out var originPlayer)) return;
|
||||
foreach (var grid in aroundGrids)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (!grid.VisibleUnit(mapData,originPlayer, out var unitData)) continue;
|
||||
var tplayer = unitData.Player(mapData);
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
|
||||
@ -33,7 +34,10 @@ namespace Logic.Skill
|
||||
var grid = self.Grid(mapData);
|
||||
if (grid == null) return 0f;
|
||||
var mountainCount = 0;
|
||||
foreach (var around in mapData.GridMap.GetAroundGridData(1, 1, grid))
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
if (around.Feature != TerrainFeature.Mountain) continue;
|
||||
mountainCount++;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
|
||||
@ -29,9 +30,11 @@ namespace Logic.Skill
|
||||
|
||||
public override float GetAttackAdditionParam(MapData mapData, UnitData self, UnitData target = null)
|
||||
{
|
||||
var round = mapData.GridMap.GetAroundGridData(1, 1, self.Grid(mapData));
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, self.Grid(mapData), _sharedAroundBuf);
|
||||
float ret = 0f;
|
||||
foreach(var grid in round)
|
||||
foreach(var grid in _sharedAroundBuf)
|
||||
if (grid.Resource == ResourceType.Academy)
|
||||
ret += 0.5f;
|
||||
return ret;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
|
||||
@ -29,8 +30,10 @@ namespace Logic.Skill
|
||||
|
||||
public override float GetAttackAdditionParam(MapData mapData, UnitData self, UnitData target = null)
|
||||
{
|
||||
var round = mapData.GridMap.GetAroundGridData(1, 1, self.Grid(mapData));
|
||||
foreach(var grid in round)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, self.Grid(mapData), _sharedAroundBuf);
|
||||
foreach(var grid in _sharedAroundBuf)
|
||||
if (grid.Resource == ResourceType.Academy)
|
||||
return 0.5f;
|
||||
return 0;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
|
||||
@ -29,9 +30,11 @@ namespace Logic.Skill
|
||||
|
||||
public override int GetExtraMoveRange(MapData map,UnitData self)
|
||||
{
|
||||
var round = map.GridMap.GetAroundGridData(1, 1, self.Grid(map));
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, self.Grid(map), _sharedAroundBuf);
|
||||
int ret = 0;
|
||||
foreach(var grid in round)
|
||||
foreach(var grid in _sharedAroundBuf)
|
||||
if (grid.Resource == ResourceType.MoriyaMilitary)
|
||||
ret++;
|
||||
return ret;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
|
||||
@ -29,8 +30,10 @@ namespace Logic.Skill
|
||||
|
||||
public override int GetExtraMoveRange(MapData map,UnitData self)
|
||||
{
|
||||
var round = map.GridMap.GetAroundGridData(1, 1, self.Grid(map));
|
||||
foreach(var grid in round)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, self.Grid(map), _sharedAroundBuf);
|
||||
foreach(var grid in _sharedAroundBuf)
|
||||
if (grid.Resource == ResourceType.MoriyaMilitary)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
@ -35,8 +35,10 @@ namespace Logic.Skill
|
||||
{
|
||||
if (self == null || grid == null || mapData == null) return;
|
||||
|
||||
var arounds = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var around in arounds)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
if (!around.RealUnit(mapData, out var target)) continue;
|
||||
if (target.Id == self.Id) continue;
|
||||
|
||||
@ -32,8 +32,10 @@ namespace Logic.Skill
|
||||
{
|
||||
var grid = self.Grid(mapData);
|
||||
if (grid == null) return;
|
||||
var aroundGrids = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var around in aroundGrids)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
if (around == grid) continue;
|
||||
around.RealUnit(mapData,out var target);
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using RuntimeData;
|
||||
using Logic.CrashSight;
|
||||
using TH1_Logic.Core;
|
||||
@ -110,8 +111,10 @@ namespace Logic.Skill
|
||||
|
||||
// 先对周围1格范围造成伤害(必须在自伤之前,否则自伤死亡会清除grid绑定,
|
||||
// 导致后续DamageSettlement因找不到origin的grid而失败)
|
||||
var arounds = map.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var around in arounds)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
if (!around.RealUnit(map, out var target)) continue;
|
||||
|
||||
@ -162,8 +165,10 @@ namespace Logic.Skill
|
||||
// 1层爆炸:只有非链内爆炸才传播恐惧
|
||||
if (canSpread)
|
||||
{
|
||||
var arounds = map.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var around in arounds)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
if (!around.RealUnit(map, out var target)) continue;
|
||||
|
||||
|
||||
@ -29,9 +29,11 @@ namespace Logic.Skill
|
||||
mapData.GetUnitDataListByPlayerId(selfPlayer.Id, selfUnitList);
|
||||
|
||||
var unitsToRefresh = new List<uint>();
|
||||
var aroundGrids = mapData.GridMap.GetAroundGridData(1, 1, attackInfo.DamageTargetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, attackInfo.DamageTargetGrid, _sharedAroundBuf);
|
||||
|
||||
foreach (var grid in aroundGrids)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (!grid.RealUnit(mapData, out var unit)) continue;
|
||||
// 跳过攻击目标本身(FearMaker已经处理)
|
||||
|
||||
@ -44,9 +44,11 @@ namespace Logic.Skill
|
||||
}
|
||||
else
|
||||
{
|
||||
var gridList = mapData.GridMap.GetAroundGridData(1, 1, info.DamageOriginGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, info.DamageOriginGrid, _sharedAroundBuf);
|
||||
var randomList = new List<GridData>();
|
||||
foreach (var grid in gridList)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (grid == info.DamageOriginGrid) continue;
|
||||
if (grid.RealUnit(mapData,out var _)) continue;
|
||||
|
||||
@ -34,10 +34,12 @@ namespace Logic.Skill
|
||||
var self = identifier as UnitData;
|
||||
if (self == null) return;
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
|
||||
var hasBuffUnit = new HashSet<UnitData>();
|
||||
foreach (var grid in roundGrid)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (!mapData.GetUnitDataByGid(grid.Id, out var unit)) continue;
|
||||
hasBuffUnit.Add(unit);
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
|
||||
@ -37,8 +38,10 @@ namespace Logic.Skill
|
||||
if (selfPlayer == null) return;
|
||||
|
||||
var aroundHero = false;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, grid1);
|
||||
foreach (var gridData in roundGrid)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid1, _sharedAroundBuf);
|
||||
foreach (var gridData in _sharedAroundBuf)
|
||||
{
|
||||
if (!gridData.RealUnit(mapData, out var unit)) continue;
|
||||
if (!unit.TreatedAsHero(mapData,info.DamageOrigin)) continue;
|
||||
@ -50,8 +53,9 @@ namespace Logic.Skill
|
||||
}
|
||||
if (!aroundHero) return;
|
||||
aroundHero = false;
|
||||
roundGrid = mapData.GridMap.GetAroundGridData(1, 1, grid2);
|
||||
foreach (var gridData in roundGrid)
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid2, _sharedAroundBuf);
|
||||
foreach (var gridData in _sharedAroundBuf)
|
||||
{
|
||||
if(!gridData.RealUnit(mapData,out var unit))continue;
|
||||
if(!unit.TreatedAsHero(mapData,info.DamageOrigin)) continue;
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using RuntimeData;
|
||||
using TH1_Logic.Core;
|
||||
using System.Linq;
|
||||
@ -96,8 +97,10 @@ namespace Logic.Skill
|
||||
if (selfPlayer == null) return;
|
||||
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
foreach (var gridData in roundGrid)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
foreach (var gridData in _sharedAroundBuf)
|
||||
{
|
||||
if (gridData == targetGrid) continue;
|
||||
if(!gridData.RealUnit(mapData,out var unit))continue;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
|
||||
@ -34,7 +35,10 @@ namespace Logic.Skill
|
||||
if (!self.Player(mapData, out var player)) return;
|
||||
var grid = self.Grid(mapData);
|
||||
|
||||
foreach (var around in mapData.GridMap.GetAroundGridData(1, 1, grid))
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
if (around == grid) continue;
|
||||
around.VisibleUnit(mapData,player,out var unit);
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
|
||||
@ -34,8 +35,10 @@ namespace Logic.Skill
|
||||
public override float GetGridMoveFloor(MapData mapData, UnitData origin, GridData target)
|
||||
{
|
||||
if (target == null || origin == null) return 0;
|
||||
var gridList = mapData.GridMap.GetAroundGridData(1, 1, target);
|
||||
foreach(var grid in gridList)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, target, _sharedAroundBuf);
|
||||
foreach(var grid in _sharedAroundBuf)
|
||||
if (grid.RealUnit(mapData, out var unit) && unit.GetSkill(SkillType.MOMIJIPREY, out var _))
|
||||
//少量在Momijiprey附近的目标可以赦免
|
||||
return 0;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
|
||||
@ -41,7 +42,10 @@ namespace Logic.Skill
|
||||
{
|
||||
var grid = unitData.Grid(mapData);
|
||||
if (grid == null) return;
|
||||
foreach (var around in mapData.GridMap.GetAroundGridData(1, 1, grid))
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
around.AddSkill_Legacy(SkillType.GRIDMOMIJIPREY, mapData, false,1,false,-1,false,SpecialAddSkillType.Force,originId);
|
||||
}
|
||||
|
||||
@ -59,8 +59,10 @@ namespace Logic.Skill
|
||||
{
|
||||
var newSights = new List<uint>();
|
||||
if (!self.Player(mapData, out var player)) return newSights;
|
||||
var aroundGrids = mapData.GridMap.GetAroundGridData(_range, _range, grid);
|
||||
foreach (var around in aroundGrids)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(_range, _range, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
around.VisibleUnit(mapData,player,out var unit);
|
||||
if (unit == null || !unit.IsAlive()) continue;
|
||||
|
||||
@ -32,9 +32,11 @@ namespace Logic.Skill
|
||||
var self = identifier as UnitData;
|
||||
if (self == null) return;
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
|
||||
foreach (var grid in roundGrid)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (!mapData.GetUnitDataByGid(grid.Id, out var unit)) continue;
|
||||
unit.AddSkill(SkillType.MOONPRINCESS, mapData);
|
||||
|
||||
@ -37,9 +37,11 @@ namespace Logic.Skill
|
||||
if (!info.IsKill) return;
|
||||
|
||||
if (!mapData.GetGridDataByUnitId(info.DamageTarget.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
|
||||
foreach (var grid in roundGrid)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (!mapData.GetUnitDataByGid(grid.Id, out var unit)) continue;
|
||||
if (unit == info.DamageTarget) continue;
|
||||
@ -55,9 +57,11 @@ namespace Logic.Skill
|
||||
if (self == null) return;
|
||||
if (Turns < TurnsLimit) return;
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
|
||||
foreach (var grid in roundGrid)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (!mapData.GetUnitDataByGid(grid.Id, out var unit)) continue;
|
||||
if (unit == self) continue;
|
||||
|
||||
@ -59,8 +59,10 @@ namespace Logic.Skill
|
||||
mapData.GetUnitDataListByPlayerId(player.Id, selfUnitList);
|
||||
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
foreach (var gridData in roundGrid)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
foreach (var gridData in _sharedAroundBuf)
|
||||
{
|
||||
if (!gridData.VisibleUnit(mapData,player, out var unit)) continue;
|
||||
if (gridData == targetGrid) continue;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.CrashSight;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
@ -44,8 +45,10 @@ namespace Logic.Skill
|
||||
//self.GetSkill(SkillType.PATCHOULIEARTH, out var earth);
|
||||
//earth?.AddLevel(mapData, self, self, 1);
|
||||
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var gridData in roundGrid)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var gridData in _sharedAroundBuf)
|
||||
{
|
||||
if (gridData.Terrain == TerrainType.Land) continue;
|
||||
self.AddSkill_Legacy(SkillType.PATCHOULIWATER, mapData,true,-1,true,1,true,SpecialAddSkillType.AddLevel,self.Id);
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Logic.CrashSight;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
@ -45,8 +46,10 @@ namespace Logic.Skill
|
||||
//self.GetSkill(SkillType.PATCHOULIEARTH, out var earth);
|
||||
//earth?.AddLevel(mapData, self, self, 1);
|
||||
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var gridData in roundGrid)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var gridData in _sharedAroundBuf)
|
||||
{
|
||||
if (gridData.Terrain == TerrainType.Land) continue;
|
||||
self.AddSkill_Legacy(SkillType.PATCHOULIWATER, mapData,true,-1,true,1,true,SpecialAddSkillType.AddLevel,self.Id);
|
||||
|
||||
@ -40,8 +40,10 @@ namespace Logic.Skill
|
||||
foreach (var vec2 in path)
|
||||
{
|
||||
if (!mapData.GridMap.GetGridDataByPos(vec2.x, vec2.y, out var pathGrid)) continue;
|
||||
var gridSet = mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, pathGrid);
|
||||
foreach(var roundGrid in gridSet)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1, 1, pathGrid, _sharedAroundBuf);
|
||||
foreach(var roundGrid in _sharedAroundBuf)
|
||||
{
|
||||
roundGrid.RealUnit(mapData,out var unit);
|
||||
if (unit == null || !unit.IsAlive()) continue;
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using RuntimeData;
|
||||
using UnityEngine;
|
||||
|
||||
@ -29,9 +30,11 @@ namespace Logic.Skill
|
||||
{
|
||||
var grid = self.Grid(mapData);
|
||||
if (grid == null) return 0;
|
||||
var arounds = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
var count = 0;
|
||||
foreach (var around in arounds)
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
if (!around.HasSpType(GridSpType.RemiliaGrid)) continue;
|
||||
count++;
|
||||
|
||||
@ -58,9 +58,11 @@ namespace Logic.Skill
|
||||
mapData.GetUnitDataListByPlayerId(player.Id, selfUnitList);
|
||||
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
bool isExcute = false;
|
||||
foreach (var gridData in roundGrid)
|
||||
foreach (var gridData in _sharedAroundBuf)
|
||||
{
|
||||
gridData.VisibleUnit(mapData,player,out var unit);
|
||||
if (unit == null || unit == self) continue;
|
||||
|
||||
@ -47,9 +47,11 @@ namespace Logic.Skill
|
||||
mapData.GetUnitDataListByPlayerId(player.Id, selfUnitList);
|
||||
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
bool isExcute = false;
|
||||
foreach (var gridData in roundGrid)
|
||||
foreach (var gridData in _sharedAroundBuf)
|
||||
{
|
||||
if (targetGrid == gridData) continue;
|
||||
gridData.VisibleUnit(mapData,player,out var unit);
|
||||
|
||||
@ -35,9 +35,11 @@ namespace Logic.Skill
|
||||
if (info.DamageOrigin == null || info.DamageTarget == null || info.DamageType == DamageType.KillSelf) return;
|
||||
|
||||
if (!mapData.GetGridDataByUnitId(info.DamageTarget.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
|
||||
foreach (var gridData in roundGrid)
|
||||
foreach (var gridData in _sharedAroundBuf)
|
||||
{
|
||||
gridData.RealUnit(mapData,out var unit);
|
||||
if (unit == null) continue;
|
||||
|
||||
@ -219,8 +219,10 @@ namespace Logic.Skill
|
||||
ProjectileTypeInfo projInfo = null;
|
||||
if (targetGrid.InMainSight() || (originUnit.Grid(mapData)?.InMainSight()??false))
|
||||
Table.Instance.ProjectileTypeDataAssets.GetProjectileTypeInfo(ProjectileType.SanaeOmikuji, out projInfo);
|
||||
var gridSet = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var round in gridSet)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var round in _sharedAroundBuf)
|
||||
{
|
||||
if (!round.RealUnit(mapData, out var unit)) continue;
|
||||
if (!unit.IsAlive()) continue;
|
||||
@ -258,8 +260,10 @@ namespace Logic.Skill
|
||||
ProjectileTypeInfo projInfo = null;
|
||||
if (targetGrid.InMainSight() || (originUnit.Grid(mapData)?.InMainSight()??false))
|
||||
Table.Instance.ProjectileTypeDataAssets.GetProjectileTypeInfo(ProjectileType.SanaeOmikuji, out projInfo);
|
||||
var gridSet = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var round in gridSet)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var round in _sharedAroundBuf)
|
||||
{
|
||||
if (!round.RealUnit(mapData, out var unit)) continue;
|
||||
bool sameUnion = mapData.SameUnionByUnitId(unit.Id, originUnit.Id);
|
||||
|
||||
@ -46,7 +46,10 @@ namespace Logic.Skill
|
||||
if (self == null || !self.IsAlive()) return;
|
||||
var grid = self.Grid(mapData);
|
||||
if (grid == null) return;
|
||||
foreach (var around in mapData.GridMap.GetAroundGridData(3, 3, grid))
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(3, 3, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
around.AddSkill(SkillType.GRIDSANAENINECONTINUEDAMAGE, mapData, self.Id);
|
||||
}
|
||||
|
||||
@ -34,7 +34,10 @@ namespace Logic.Skill
|
||||
if (path == null || path.Count < 2) return;
|
||||
int range = self.GetSkill(SkillType.SANAEMOVE,out var _) ? 1: 0 ;
|
||||
if (!self.Player(mapData, out var player)) return;
|
||||
foreach (var around in mapData.GridMap.GetAroundGridData(range, range, grid))
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(range, range, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
//if (around == grid) continue;
|
||||
around.VisibleUnit(mapData,player,out var unit);
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
|
||||
using System.Collections.Generic;
|
||||
using RuntimeData;
|
||||
using Logic.CrashSight;
|
||||
using TH1Renderer;
|
||||
@ -39,8 +40,10 @@ namespace Logic.Skill
|
||||
|
||||
var unitsToRefresh = new System.Collections.Generic.List<uint>();
|
||||
|
||||
var arounds = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var around in arounds)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var around in _sharedAroundBuf)
|
||||
{
|
||||
if (around == grid) continue;
|
||||
around.RealUnit(mapData,out var target);
|
||||
|
||||
@ -46,8 +46,10 @@ namespace Logic.Skill
|
||||
LogSystem.LogError($"SplashSkill info.DamageTarget is null");
|
||||
return;
|
||||
}
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, info.DamageTargetGrid);
|
||||
foreach (var grid in roundGrid)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, info.DamageTargetGrid, _sharedAroundBuf);
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
|
||||
if (!grid.RealUnit(mapData, out var unit)) continue;
|
||||
|
||||
@ -38,8 +38,10 @@ namespace Logic.Skill
|
||||
mapData.GetUnitDataListByPlayerId(selfPlayer.Id, selfUnitList);
|
||||
|
||||
//遍历会溅射的所有格子
|
||||
var roundGrids = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var roundGrid in roundGrids)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var roundGrid in _sharedAroundBuf)
|
||||
{
|
||||
var ROgrid = MapRenderer.Instance.ROGridMap[roundGrid.Id];
|
||||
//如果格子上没有单位,播放地震动画
|
||||
|
||||
@ -34,8 +34,10 @@ namespace Logic.Skill
|
||||
//移动到友方伟人身边的时候,才会恢复AP点
|
||||
if (moveType == MoveType.ActiveMove)
|
||||
{
|
||||
var gridList = mapData.GridMap.GetAroundGridData(1, 1, grid);
|
||||
foreach (var gd in gridList)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, grid, _sharedAroundBuf);
|
||||
foreach (var gd in _sharedAroundBuf)
|
||||
{
|
||||
//如果就是自己这个格子,跳过
|
||||
if (gd.Id == grid.Id) continue;
|
||||
|
||||
@ -34,10 +34,12 @@ namespace Logic.Skill
|
||||
if (self != null && self is UnitData unitData)
|
||||
{
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var grid)) return;
|
||||
var arround = mapData.GridMap.GetAroundGridData(4, 4, grid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(4, 4, grid, _sharedAroundBuf);
|
||||
if (!mapData.GetPlayerDataByUnitId(self.Id, out var player)) return;
|
||||
var up = new List<uint>();
|
||||
foreach (var t in arround)
|
||||
foreach (var t in _sharedAroundBuf)
|
||||
{
|
||||
if (t.Resource == ResourceType.Treasure) up.Add(t.Id);
|
||||
}
|
||||
@ -47,10 +49,12 @@ namespace Logic.Skill
|
||||
|
||||
public override void OnMove(UnitData self, GridData grid, MapData mapData, MoveType moveType, List<Vector2Int> path = null)
|
||||
{
|
||||
var arround = mapData.GridMap.GetAroundGridData(4, 4, grid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(4, 4, grid, _sharedAroundBuf);
|
||||
if (!mapData.GetPlayerDataByUnitId(self.Id, out var player)) return;
|
||||
var up = new List<uint>();
|
||||
foreach(var t in arround)
|
||||
foreach(var t in _sharedAroundBuf)
|
||||
if (t.Resource == ResourceType.Treasure)
|
||||
up.Add(t.Id);
|
||||
Main.PlayerLogic.UpdateSight_LogicView(mapData,player,up);
|
||||
|
||||
@ -38,10 +38,12 @@ namespace Logic.Skill
|
||||
mapData.GetUnitDataListByPlayerId(player.Id, selfUnitList);
|
||||
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
|
||||
var hasBuffUnit = new HashSet<UnitData>();
|
||||
foreach (var grid in roundGrid)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (!mapData.GetUnitDataByGid(grid.Id, out var unit)) continue;
|
||||
if (selfUnitList.Contains(unit)) continue;
|
||||
|
||||
@ -54,9 +54,11 @@ namespace Logic.Skill
|
||||
}
|
||||
else
|
||||
{
|
||||
var gridList = mapData.GridMap.GetAroundGridData(1, 1, info.DamageTargetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, info.DamageTargetGrid, _sharedAroundBuf);
|
||||
var randomList = new List<GridData>();
|
||||
foreach (var grid in gridList)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (grid == info.DamageTargetGrid) continue;
|
||||
if (grid.RealUnit(mapData,out var _)) continue;
|
||||
|
||||
@ -121,8 +121,10 @@ namespace Logic.Skill
|
||||
for (int i = 1; i < path.Count; i++)
|
||||
{
|
||||
if (!mapData.GridMap.GetGridDataByV2(path[i], out var pathGrid)) continue;
|
||||
var aroundGrids = mapData.GridMap.GetAroundGridData(1, 1, pathGrid);
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, pathGrid, _sharedAroundBuf);
|
||||
foreach (var aroundGrid in _sharedAroundBuf)
|
||||
{
|
||||
if (!aroundGrid.RealUnit(mapData, out var splashTarget)) continue;
|
||||
if (splashTarget.Id == selfUnit.Id) continue;
|
||||
|
||||
@ -84,8 +84,10 @@ namespace Logic.Skill
|
||||
for (int i = 1; i < path.Count; i++)
|
||||
{
|
||||
if (!mapData.GridMap.GetGridDataByV2(path[i], out var pathGrid)) continue;
|
||||
var aroundGrids = mapData.GridMap.GetAroundGridData(1, 1, pathGrid);
|
||||
foreach (var aroundGrid in aroundGrids)
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, pathGrid, _sharedAroundBuf);
|
||||
foreach (var aroundGrid in _sharedAroundBuf)
|
||||
{
|
||||
if (!aroundGrid.RealUnit(mapData, out var splashTarget)) continue;
|
||||
if (splashTarget.Id == selfUnit.Id) continue;
|
||||
|
||||
@ -32,9 +32,11 @@ namespace Logic.Skill
|
||||
var self = identifier as UnitData;
|
||||
if (self == null) return;
|
||||
if (!mapData.GetGridDataByUnitId(self.Id, out var targetGrid)) return;
|
||||
var roundGrid = mapData.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
|
||||
foreach (var grid in roundGrid)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (!mapData.GetUnitDataByGid(grid.Id, out var unit)) continue;
|
||||
unit.AddSkill(SkillType.SPEEDUP, mapData,false,0,false,-1,false,SpecialAddSkillType.AddTurnLimit,0);
|
||||
|
||||
@ -108,9 +108,11 @@ namespace Logic.Skill
|
||||
// 击杀英雄不生成骨堆
|
||||
if (target.UnitFullType.UnitType != UnitType.Giant)
|
||||
{
|
||||
var gridList = map.GridMap.GetAroundGridData(1, 1, targetGrid);
|
||||
_sharedAroundBuf ??= new List<GridData>();
|
||||
_sharedAroundBuf.Clear();
|
||||
map.GridMap.GetAroundGridData(1, 1, targetGrid, _sharedAroundBuf);
|
||||
var randomList = new List<GridData>();
|
||||
foreach (var grid in gridList)
|
||||
foreach (var grid in _sharedAroundBuf)
|
||||
{
|
||||
if (grid == targetGrid) continue;
|
||||
if (grid.RealUnit(map,out _)) continue;
|
||||
|
||||
@ -576,6 +576,9 @@ namespace Logic.Skill
|
||||
[MemoryPackable]
|
||||
public abstract partial class SkillBase : ISkill
|
||||
{
|
||||
// 所有技能共享的临时集合(技能逻辑顺序执行,不并发)
|
||||
protected static List<GridData> _sharedAroundBuf;
|
||||
|
||||
[MemoryPackInclude]
|
||||
protected bool IsPermanent;
|
||||
//是否叠层
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
@ -15,30 +16,35 @@ namespace Logic.Skill
|
||||
{
|
||||
public class SkillFactory
|
||||
{
|
||||
private static Dictionary<SkillType, Type> _skillDict;
|
||||
// 使用编译后的工厂委托替代 Activator.CreateInstance,消除反射开销
|
||||
private static Dictionary<SkillType, Func<SkillBase>> _skillFactoryDict;
|
||||
|
||||
|
||||
public static SkillBase GetSkillBySkillType(SkillType skillType)
|
||||
{
|
||||
if (_skillDict == null)
|
||||
if (_skillFactoryDict == null)
|
||||
{
|
||||
_skillDict = new Dictionary<SkillType, Type>();
|
||||
Assembly assembly = typeof(SkillBase).Assembly; // 获取基类所在程序集
|
||||
_skillFactoryDict = new Dictionary<SkillType, Func<SkillBase>>();
|
||||
Assembly assembly = typeof(SkillBase).Assembly;
|
||||
foreach (Type skillClassType in assembly.GetTypes())
|
||||
{
|
||||
if (skillClassType.IsSubclassOf(typeof(SkillBase)) && !skillClassType.IsAbstract)
|
||||
{
|
||||
var skillObj = Activator.CreateInstance(skillClassType);
|
||||
var skillBase = skillObj as SkillBase;
|
||||
if (skillBase == null) continue;
|
||||
_skillDict[skillBase.GetSkillType()] = skillClassType;
|
||||
var ctor = skillClassType.GetConstructor(Type.EmptyTypes);
|
||||
if (ctor == null) continue;
|
||||
// 编译 () => new ConcreteSkillType() 委托,后续调用零反射
|
||||
var factory = Expression.Lambda<Func<SkillBase>>(
|
||||
Expression.New(ctor)).Compile();
|
||||
var tmpSkill = factory();
|
||||
if (tmpSkill == null) continue;
|
||||
_skillFactoryDict[tmpSkill.GetSkillType()] = factory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_skillDict.TryGetValue(skillType, out var skillClass))
|
||||
if (_skillFactoryDict.TryGetValue(skillType, out var skillFactory))
|
||||
{
|
||||
var skillObj = Activator.CreateInstance(skillClass) as SkillBase;
|
||||
var skillObj = skillFactory();
|
||||
if (skillObj != null && Table.Instance.SkillDataAssets.GetSkillInfo(skillType, out var skillInfo))
|
||||
{
|
||||
skillObj.SetSkillPriority(skillInfo.skillPriority);
|
||||
|
||||
@ -117,6 +117,10 @@ namespace Logic
|
||||
bool[,] TransMap;//在常规移动之外,额外赋予的特殊可传送格子
|
||||
bool[,] SanaeMap;//在常规移动之外,额外赋予的特殊可抵达格子
|
||||
|
||||
// 复用的临时集合
|
||||
private List<GridData> _aroundBuf;
|
||||
private List<GridData> _aroundBuf2;
|
||||
|
||||
|
||||
|
||||
public UnitLogic()
|
||||
@ -907,8 +911,10 @@ namespace Logic
|
||||
mapData.GetGridDataByUnitId(B.Id, out var gridDataB);
|
||||
//盟友则不会有控制区域
|
||||
if (mapData.SameUnion(playerDataB.Id ,playerData.Id)) continue;
|
||||
var targetGridDataList = mapData.GridMap.GetAroundGridDataSet_NOCENTER(1,1,gridDataB);
|
||||
foreach (var targetGridData in targetGridDataList)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1,1,gridDataB, _aroundBuf);
|
||||
foreach (var targetGridData in _aroundBuf)
|
||||
{
|
||||
int x = targetGridData.Pos.X, y = targetGridData.Pos.Y;
|
||||
MovementCostMap[x, y] = (MovementCostMap[x, y] < 0) ? -1 : 999;
|
||||
@ -955,8 +961,10 @@ namespace Logic
|
||||
breakTime--;
|
||||
if (!mapData.GridMap.GetGridDataByGid(q.Dequeue(), out var gridDataX)) continue;
|
||||
if (MovementRemainMap[gridDataX.Pos.X, gridDataX.Pos.Y] < 0.1f) continue;
|
||||
var nearby = mapData.GridMap.GetAroundGridDataSet_NOCENTER(1,1,gridDataX);
|
||||
foreach (var gridDataY in nearby)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1,1,gridDataX, _aroundBuf);
|
||||
foreach (var gridDataY in _aroundBuf)
|
||||
{
|
||||
float cost = MovementCostMap[gridDataY.Pos.X, gridDataY.Pos.Y];
|
||||
//如果不可达区
|
||||
@ -1059,8 +1067,10 @@ namespace Logic
|
||||
{
|
||||
|
||||
mapData.GetGridDataByUnitId(unitA.Id, out var gridB);
|
||||
var nearby = mapData.GridMap.GetAroundGridDataSet_NOCENTER(1,1,gridB);
|
||||
foreach (var gridC in nearby){
|
||||
_aroundBuf2 ??= new List<GridData>();
|
||||
_aroundBuf2.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1,1,gridB, _aroundBuf2);
|
||||
foreach (var gridC in _aroundBuf2){
|
||||
int xx = gridC.Pos.X, yy = gridC.Pos.Y;
|
||||
if(CheckUnitAbleForGrid_OfflineStatus(mapData,playerData,unitData,gridC)
|
||||
&& !gridC.VisibleUnit(mapData,playerData,out var tt))
|
||||
@ -1268,10 +1278,12 @@ namespace Logic
|
||||
else if(unitDataA.GetSkill(SkillType.KANAKOBATTLEFIELDPRO,out var _) && unitDataA.GetSkill(SkillType.KANAKOSITTING,out var _))
|
||||
//不在攻击范围内,有一种可能 kanako
|
||||
{
|
||||
var tmpSet = mapData.GridMap.GetAroundGridDataSet_NOCENTER(1,1,gridDataB);
|
||||
_aroundBuf2 ??= new List<GridData>();
|
||||
_aroundBuf2.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(1,1,gridDataB, _aroundBuf2);
|
||||
bool can = false;
|
||||
//kanako 的3级技能,可以攻击任意远的我方英雄/hebi周围1格敌人
|
||||
foreach(var tmpGrid in tmpSet)
|
||||
foreach(var tmpGrid in _aroundBuf2)
|
||||
if(tmpGrid.VisibleUnit(mapData,playerDataA,out var tmpUnit) && tmpUnit.Player(mapData) == gridDataA.Player(mapData)
|
||||
&& (tmpUnit.GiantType != GiantType.None ||
|
||||
(tmpUnit.UnitType == UnitType.MoriyaHebi && tmpUnit.UnitLevel >= 3))
|
||||
@ -1585,8 +1597,10 @@ namespace Logic
|
||||
|
||||
GridData bestGrid = null;
|
||||
int score = -1;
|
||||
var gridList = mapData.GridMap.GetAroundGridData(1,1,gridData);
|
||||
foreach (var targetGrid in gridList)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridData(1,1,gridData, _aroundBuf);
|
||||
foreach (var targetGrid in _aroundBuf)
|
||||
{
|
||||
if (targetGrid == gridData)
|
||||
continue;
|
||||
|
||||
@ -23,6 +23,7 @@ namespace TH1Renderer
|
||||
public class MapRenderer
|
||||
{
|
||||
private Main _main;
|
||||
private static List<GridData> _aroundBuf;
|
||||
private MapData _mapData;
|
||||
private Transform _unitRenderMap;
|
||||
private Transform _gridRenderMap;
|
||||
@ -577,9 +578,11 @@ namespace TH1Renderer
|
||||
//unitLogic.DebugOutputMoveInfo();
|
||||
int r = Mathf.Max((Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitData.UnitType,unitData.GiantType,unitData.UnitLevel,out var info)?info.MoveRange:0) * 2,
|
||||
Table.Instance.UnitTypeDataAssets.GetUnitTypeInfo(unitData.UnitType,unitData.GiantType,unitData.UnitLevel,out var info2)?info2.AttackRange:0);
|
||||
var targetGridDataList = Main.MapData.GridMap.GetAroundGridDataSet_NOCENTER(r,r,gridData);
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
Main.MapData.GridMap.GetAroundGridDataSet_NOCENTER(r,r,gridData, _aroundBuf);
|
||||
bool hasUtsuhoBase2 = unitData.GetSkill(SkillType.UtsuhoBase, out var _);
|
||||
foreach(var targetGridData in targetGridDataList)
|
||||
foreach(var targetGridData in _aroundBuf)
|
||||
{
|
||||
//如果不在视野 跳过(UtsuhoBase无视视野限制)
|
||||
if (!hasUtsuhoBase2 && !playerData.Sight.CheckIsInSight(targetGridData.Id)) continue;
|
||||
@ -1022,8 +1025,10 @@ namespace TH1Renderer
|
||||
{
|
||||
//如果不是真map,不操作
|
||||
if (mapData != Main.MapData) return false;
|
||||
var set = mapData.GridMap.GetAroundGridDataSet_NOCENTER(3, 3, grid);
|
||||
foreach (var aroundGrid in set)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
mapData.GridMap.GetAroundGridDataSet_NOCENTER(3, 3, grid, _aroundBuf);
|
||||
foreach (var aroundGrid in _aroundBuf)
|
||||
{
|
||||
//如果是玩家的unit 那么更新高亮
|
||||
if (aroundGrid.MainSelfPlayerVisibleUnit( out var unit)
|
||||
|
||||
@ -17,6 +17,7 @@ namespace TH1_Renderer
|
||||
{
|
||||
private uint _unitId;
|
||||
private UnitData _unitData;
|
||||
private static List<GridData> _aroundBuf;
|
||||
private PlayerData _playerData;
|
||||
private GridData _gridData;
|
||||
private GameObject _ROUnit;
|
||||
@ -464,8 +465,10 @@ namespace TH1_Renderer
|
||||
var curGrid = _unitData.Grid(Main.MapData);
|
||||
if (_playerData != null && _playerData.IsSelfPlayer() && curGrid != null)
|
||||
{
|
||||
var arounds = Main.MapData.GridMap.GetAroundGridData(1, 1, curGrid);
|
||||
foreach (var around in arounds)
|
||||
_aroundBuf ??= new List<GridData>();
|
||||
_aroundBuf.Clear();
|
||||
Main.MapData.GridMap.GetAroundGridData(1, 1, curGrid, _aroundBuf);
|
||||
foreach (var around in _aroundBuf)
|
||||
{
|
||||
if (around == curGrid) continue;
|
||||
if (!around.RealUnit(Main.MapData, out var nearUnit)) continue;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user