feat(battle-engine): full Unity/VFX/god-object shims + expanded copy closure (2570 files)
Authored Unity primitive/object-model shim, VFX layer (control-flow-preserving, InstantVfx never invokes its action -- headless suppression), god-object stubs (GameMgr/EffectMgr/UIManager with faithfully-extracted nested enums), View/UI/Touch tree, LitJson+BetterList+Tuple copied, third-party stubs. Discovered Roslyn header-error masking: fixing class-header type errors unmasks body references, so the true copy closure is ~2570 files (was 782 under masking). Errors: masked-25720 -> 268; our shim files compile clean. Remaining: ~50 residual shim/external types, 24 NGUI UI-base overrides, static-type fixes, plus likely 1-2 more unmask waves.
This commit is contained in:
204
SVSim.BattleEngine/Engine/Wizard/BestOpenSpaceAttackAI.cs
Normal file
204
SVSim.BattleEngine/Engine/Wizard/BestOpenSpaceAttackAI.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cute;
|
||||
|
||||
namespace Wizard;
|
||||
|
||||
public class BestOpenSpaceAttackAI
|
||||
{
|
||||
private EnemyAI AI;
|
||||
|
||||
public AIVirtualActionInfo Cr_FirstActionInfo;
|
||||
|
||||
public PlayPtnWithToken Cr_BestPlayPtnWithToken;
|
||||
|
||||
private ulong[] _defaultPlayptnHashArray;
|
||||
|
||||
public BestOpenSpaceAttackAI(EnemyAI ai)
|
||||
{
|
||||
AI = ai;
|
||||
}
|
||||
|
||||
public IEnumerator _CrSimulate(AIVirtualField originalField, PlayPtnWithToken[] bestPlayPtnsWithToken)
|
||||
{
|
||||
AI.IsInVirutalSimulation = true;
|
||||
float maxFieldValue = float.MinValue;
|
||||
int bestFirstDeadActionIndex = int.MaxValue;
|
||||
List<AIVirtualActionInfo> bestActionInfoSequence = null;
|
||||
AIVirtualField bestField = originalField;
|
||||
Cr_BestPlayPtnWithToken = null;
|
||||
Cr_FirstActionInfo = null;
|
||||
_defaultPlayptnHashArray = AISimulationUtility.CalculatePlayptnWithTokenHashs(originalField, bestPlayPtnsWithToken);
|
||||
ParallelJob job = ParallelJob.Dispatch(delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
int count = originalField.AllyInplayCards.Count;
|
||||
List<int> list = new List<int>();
|
||||
for (int i = 0; i < originalField.AllyInplayCards.Count; i++)
|
||||
{
|
||||
AIVirtualCard aIVirtualCard = originalField.AllyInplayCards[i];
|
||||
int num = 0;
|
||||
for (num = 0; num < list.Count && !(aIVirtualCard.Value < originalField.AllyInplayCards[list[num]].Value); num++)
|
||||
{
|
||||
}
|
||||
list.Insert(num, i);
|
||||
}
|
||||
int num2 = (1 << originalField.AllyInplayCards.Count) - 1;
|
||||
List<ulong> list2 = new List<ulong>();
|
||||
for (int j = 0; j <= num2; j++)
|
||||
{
|
||||
if (IsValidBreakIndex(originalField.AllyInplayCards, list, j))
|
||||
{
|
||||
if (AI.IsBattleEnd || AI.IsRunWeakLogic)
|
||||
{
|
||||
break;
|
||||
}
|
||||
int[] allyAttackers = GetAllyAttackers(originalField, list, j);
|
||||
ulong item = AISimulationUtility.CalculateAttackSequenceHash(allyAttackers, originalField);
|
||||
if (!list2.Contains(item))
|
||||
{
|
||||
List<int> list3 = new List<int>();
|
||||
for (int k = 0; k < originalField.EnemyInplayCards.Count; k++)
|
||||
{
|
||||
if (originalField.EnemyInplayCards[k].IsUnit)
|
||||
{
|
||||
list3.Add(k);
|
||||
}
|
||||
}
|
||||
if (AI.IsRunWeakLogic)
|
||||
{
|
||||
break;
|
||||
}
|
||||
List<int[]> list4 = AIMathematicsLibrary.EnumeratePermutations(list3).ToList();
|
||||
List<ulong> list5 = new List<ulong>();
|
||||
for (int l = 0; l < list4.Count; l++)
|
||||
{
|
||||
List<int> enemyTargetIndexes = list4[l].ToList();
|
||||
if (AISimulationUtility.IsValidEnemyTargetIndexes(originalField.EnemyInplayCards, enemyTargetIndexes))
|
||||
{
|
||||
ulong item2 = AISimulationUtility.CalculateTargetSequenceHash(list4[l], originalField);
|
||||
if (!list5.Contains(item2))
|
||||
{
|
||||
int num3 = (1 << allyAttackers.Length) - 1;
|
||||
for (int m = 0; m <= num3; m++)
|
||||
{
|
||||
if (AI.IsRunWeakLogic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool[] attackLeaderOrFollowerFlags = GetAttackLeaderOrFollowerFlags(m, allyAttackers.Length);
|
||||
AIVirtualField aIVirtualField = new AIVirtualField(originalField);
|
||||
List<AIVirtualActionInfo> actionInfoSequence = AISimulationUtility.GetActionInfoSequence(aIVirtualField, allyAttackers, attackLeaderOrFollowerFlags, -1);
|
||||
List<AIVirtualCard> enemyTargetSequence = AISimulationUtility.GetEnemyTargetSequence(aIVirtualField, enemyTargetIndexes);
|
||||
BattleSequencer.ExecSimulation(aIVirtualField, actionInfoSequence, enemyTargetSequence, new SimulationSetting(isHandRemovalValid: true, useLeaderAttackPreCheck: false, noSkipAttack: true));
|
||||
_ = aIVirtualField.EnemyClass.IsDead;
|
||||
if (AI.IsRunWeakLogic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
float num4 = AISimulationUtility.EvaluateField(aIVirtualField, EvaluationType.SIMPLE);
|
||||
if (AI.IsRunWeakLogic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int openCount = count - aIVirtualField.AllyInplayCards.Count((AIVirtualCard c) => !c.IsDead);
|
||||
PlayPtnWithToken bestPlayPtnWithToken = null;
|
||||
int bestFirstDeadActionIndex2 = int.MaxValue;
|
||||
float num5 = AISimulationUtility.EvaluateLegalPlayPtnAfterSimulation(aIVirtualField, actionInfoSequence, bestPlayPtnsWithToken, openCount, _defaultPlayptnHashArray, out bestPlayPtnWithToken, out bestFirstDeadActionIndex2);
|
||||
float num6 = num4 + num5;
|
||||
if (AI.IsRunWeakLogic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (EnemyAI.IsLargerThan(num6, maxFieldValue) || (EnemyAI.IsSameValue(num6, maxFieldValue) && bestFirstDeadActionIndex2 < bestFirstDeadActionIndex))
|
||||
{
|
||||
maxFieldValue = num6;
|
||||
bestFirstDeadActionIndex = bestFirstDeadActionIndex2;
|
||||
Cr_BestPlayPtnWithToken = bestPlayPtnWithToken;
|
||||
bestActionInfoSequence = actionInfoSequence;
|
||||
bestField = aIVirtualField;
|
||||
}
|
||||
}
|
||||
list5.Add(item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
list2.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
});
|
||||
while (!job.isDone)
|
||||
{
|
||||
yield return null;
|
||||
if (AI.IsRunWeakLogic)
|
||||
{
|
||||
AI.IsInVirutalSimulation = false;
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
if (AI.IsBattleEnd)
|
||||
{
|
||||
AI.IsInVirutalSimulation = false;
|
||||
yield break;
|
||||
}
|
||||
if (bestActionInfoSequence.Count > 0)
|
||||
{
|
||||
Cr_FirstActionInfo = BattleSequencer.GetFirstActionInfo(bestActionInfoSequence, bestField, Cr_BestPlayPtnWithToken.PlayPtn);
|
||||
}
|
||||
AI.IsInVirutalSimulation = false;
|
||||
}
|
||||
|
||||
private bool IsValidBreakIndex(List<AIVirtualCard> allyCards, List<int> sortedInplayIndex, int sortedBreakIndex)
|
||||
{
|
||||
for (int i = 0; i < allyCards.Count; i++)
|
||||
{
|
||||
if (((sortedBreakIndex >> i) & 1) > 0)
|
||||
{
|
||||
AIVirtualCard aIVirtualCard = allyCards[sortedInplayIndex[i]];
|
||||
if (aIVirtualCard.IsAmulet || aIVirtualCard.AttackableCount <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int[] GetAllyAttackers(AIVirtualField field, List<int> sortedInplayIndex, int sortedBreakIndex)
|
||||
{
|
||||
List<int> list = new List<int>();
|
||||
for (int i = 0; i < sortedInplayIndex.Count; i++)
|
||||
{
|
||||
if (!field.AllyInplayCards[sortedInplayIndex[i]].IsAmulet && ((sortedBreakIndex >> i) & 1) > 0)
|
||||
{
|
||||
list.Add(sortedInplayIndex[i]);
|
||||
}
|
||||
}
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
private bool[] GetAttackLeaderOrFollowerFlags(int index, int attackerCount)
|
||||
{
|
||||
bool[] array = new bool[attackerCount];
|
||||
for (int i = 0; i < attackerCount; i++)
|
||||
{
|
||||
if (((index >> i) & 1) > 0)
|
||||
{
|
||||
array[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
array[i] = false;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user