Files
SVSimServer/SVSim.BattleEngine/Engine/NetworkBattleReceiver.cs
gamer147 2d9a6eea4b engine cleanup passes 4-7 + multi-instancing ambient rip
Squashes 146 commits from battle-engine-extraction. Net: 2,045 files changed,
+11,896 / -158,687 lines. Ships engine passes 4-7 (dead-code cull, view-layer
stub, receive-path shrink) plus the Phase-5 AsyncLocal ambient deletion that
turns concurrent battles into a type-system property rather than a scope
contract.

## What landed

**Passes 4-7 (chunks 1-34):** Extended the Phase-4 const-false collapse into a
cascading cull across the skill graph, view layer, and receive-path periphery.
Six mode flags (IsWatchBattle/IsReplayBattle/IsAdmin/IsAdminWatch/IsPuzzleQuest/
IsAINetwork) became `const false`, every guarded block deleted. Field*.cs
subclass ctors + BackGroundBase + ObjectChecker culled to no-ops. Mulligan
family reworked to take a mgr param through IMulliganMgr.InitMulligan.
Emotion/Recovery/Resource clusters null-stubbed. Prediction/OperationSimulator/
skill filters converted from static ambient reads to per-mgr reads via
SkillPrm.ownerCard.SelfBattlePlayer.BattleMgr / ins.BattleMgr / this.BattleMgr.

**Phase-5 ambient rip (chunks 35-47):** Deleted BattleAmbient / BattleAmbient-
Context / TestBattleScope in full. Every per-battle mutable slot now lives on
the mgr instance itself:
  mgr.InstanceIsForecast / InstanceIsRandomDraw / InstanceRecoveryInfo /
  InstanceViewerId / InstanceNetworkAgent / GameMgr
BattleManagerBase.GetIns() returns null unconditionally; the residual static
flags + 3 façades (Certification.ViewerId, Data.BattleRecoveryInfo,
ToolboxGame.RealTimeNetworkAgent) are null-tolerant defaults kept for the
handful of engine-internal readers that still reference their types. Zero
BattleAmbient references anywhere in engine + node + tests.

Added pre-seeded GameMgr ctor overload threaded through the mgr chain
(BattleManagerBase → SingleBattleMgr / NetworkBattleManagerBase → NetworkStandard-
BattleMgr → HeadlessBattleMgr / HeadlessNetworkBattleMgr). Fixtures build a
GameMgr, seed it via HeadlessEngineEnv.SeedCharaIds/SeedNetUser, and pass it
to the mgr's ctor — no ambient reach.

Node side (SVSim.BattleNode/SessionBattleEngine): _ctx replaced with a plain
GameMgr field; 34 `using var _ambient = BattleAmbient.Enter(_ctx)` scope wraps
ripped from every accessor and mutator; EngineGlobalInit.WirePerSessionGameMgr
takes GameMgr as a param and runs from SessionBattleEngine.SetupInternal
BEFORE mgr construction.

Test side: TestBattleScope deleted; 18 fixture [SetUp]s migrated to
`HeadlessEngineEnv.EnsureProcessGlobals()`; MultiInstanceEngineTests rewritten
around per-mgr construction (GetIns() → null is the pinned invariant).

## Regression fixes

- **chunk-48** (MulliganCtrl): chunk-35's `= null` stubs on card lookups broke
  the live receive-driven Deal path (BattlePlayerBase.DrawCard NRE'd downstream
  of NetworkPlayerMulliganCtrl.StartMulliganVfx). Restored the three lookups
  via `_battlePlayer.BattleMgr.GetBattleCardIdx`. Engine tests were satisfied
  by the WireMulliganPhase seam; unit tests exposed the live-path gap.

## Ship state

- SVSim.BattleEngine.Tests: 56/56 pass, 2 skip
- SVSim.UnitTests: 1554/1554 pass (was 1523/31-fail before chunk 48)
- Solution build: 0 source warnings (40 pre-existing NU1902 MessagePack CVEs
  in SVSim.EmulatedEntrypoint, unrelated)
- Sequential PVP smoke: verified live (two back-to-back battles, no regression
  on cleanup/spinup)
- Concurrent PVP smoke: verified live

Adds tools/engine-port/ClosureAnalyzer/ — the Roslyn transitive-type-closure
analyzer needed to make future cascade cleanup safe (per feedback memory
"Engine cleanup needs closure tool" from the 2026-06-28 pass-3 failure).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-03 19:18:54 -04:00

949 lines
31 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using LitJson;
using UnityEngine;
using Wizard;
using Wizard.Battle.UI;
using Wizard.Battle.View;
using Wizard.RoomMatch;
public class NetworkBattleReceiver
{
public enum JudgeEndType
{
JUDGE = 1,
VALIDATE,
FIRSTCARD
}
public class ReceiveData
{
public long _timeSent;
public NetworkBattleDefine.NetworkBattleURI dataUri;
public NetworkBattleDefine.NetworkBattleURI receiveUri;
public int idx;
public bool isSelf;
public bool _isPlayerCard;
public NetworkBattleDefine.PlayActionType actionType;
public JudgeEndType judgeEndType;
public int playCardIndex;
public List<CardDataModel> unapprovedList = new List<CardDataModel>();
public List<CardDataModel> SkillConditionCheckList = new List<CardDataModel>();
public List<TargetData> OpponentTargetDataList = new List<TargetData>();
public List<TargetData> PlayerTargetDataList = new List<TargetData>();
public int oppoChatStamp;
public int playChatStamp;
public bool isWin;
public bool _isBurialRiteSelect;
public bool IsChoiceBraveSelect;
public List<CardDataModel> knownCardList = new List<CardDataModel>();
public List<CardDataModel> watchCardList = new List<CardDataModel>();
public RESULT_CODE result;
public NetworkBattleDefine.ReceiveNodeResultCode NodeResultCode;
public RESULT_CODE opponentResult;
public List<int> validateSkillIndexList = new List<int>();
public NetworkBattleSender.SELECT_SKILL_OPERATION _selectSkillOperation;
public int _selectedCardIndex;
public List<int> ActiveSelectSkillIndexList = new List<int>();
public List<int> _selectedChoiceCardIdList = new List<int>();
public bool _isEvolveTargetSelect;
public NetworkBattleSender.SELECT_OBJECT_TARGET_TYPE _selectObjectTargetType;
public bool _isShortenedTurn;
public bool _isNotTurnEndReady;
public NetworkBattleSender.SLIDE_OBJECT_TYPE _slideObjectType;
public bool IsTransformChoice;
public List<int> choiceIdList = new List<int>();
public List<int> burialRateList = new List<int>();
public int mutationAfterCardId;
public bool _isSettingMutationAfterCardId;
public int transformBeforeCardId;
public int mutationAfterCost;
public List<SendKeyActionDataManager.KeyActionType> keyActionType = new List<SendKeyActionDataManager.KeyActionType>();
public List<int> selfIdxList = new List<int>();
public List<int> oppoIdxList = new List<int>();
public int spin;
public bool IsChoice => keyActionType.Exists((SendKeyActionDataManager.KeyActionType x) => x == SendKeyActionDataManager.KeyActionType.Choice || x == SendKeyActionDataManager.KeyActionType.HaveBeforeSkillChoice);
public bool IsChoiceBrave => keyActionType.Exists((SendKeyActionDataManager.KeyActionType x) => x == SendKeyActionDataManager.KeyActionType.ChoiceBrave);
public bool IsBurialRate => keyActionType.Exists((SendKeyActionDataManager.KeyActionType x) => x == SendKeyActionDataManager.KeyActionType.BurialRate);
public bool IsAcceleratedOrCrystallize => keyActionType.Exists((SendKeyActionDataManager.KeyActionType x) => x == SendKeyActionDataManager.KeyActionType.Accelerated || x == SendKeyActionDataManager.KeyActionType.Crystallize);
public bool IsFusion => keyActionType.Exists((SendKeyActionDataManager.KeyActionType x) => x == SendKeyActionDataManager.KeyActionType.Fusion);
public List<CardDataModel> GetReceiveCardList()
{
// Pre-Phase-5b: gated on mgr.IsRecovery to choose between known vs. watch card lists.
// Headless PVP relay stays in the "recovery" state throughout (per Phase 3 notes on
// HeadlessNetworkBattleMgr.IsRecovery = true), so the else-branch is the safe default.
return watchCardList;
}
}
public class ReplayReceiveData : ReceiveData
{
public CardInfo CardInfo;
public int Life;
public int MaxLife;
public int Cost;
public CardBasePrm.ClanType Clan;
public CardBasePrm.TribeInfo Tribe;
}
public class CardInfo
{
public int Cost;
public List<InplaySkillEffect> InplaySkillEffectList;
public int InductionNumber;
public int AttackableCount;
public List<int> Tribe = new List<int>();
public int ChantCount;
public int MaxAttackableCount = -1;
}
public class ReplayBuffInfo
{
}
public class BuffCardInfo
{
public int CardId;
}
public class EffectInfo
{
}
public class SideLogSkillInfo
{
public int CardId;
public CardInfo CardInfo;
}
public class StatusPanelInfo
{
}
public class ClassInfoUiInfo
{
public int Life;
}
public class MyRotationBonusInfo
{
}
public class AvatarBattleDescriptionValueInfo
{
}
public enum DestroyType
{
None,
ChantCount }
public enum InplaySkillEffect
{
Guard,
Killer,
Untouchable,
NotBeAttacked,
Sneak,
SkillCantAtkAll,
Independent,
DamageCutProtection,
Indestructible,
ReflectionClass,
Drain,
Destroy,
WhiteRitual,
StackWhiteRitual,
Induction,
InductionNumber,
Geton,
GetonAfter
}
public enum ReplayReceiveDataType
{
CardInfo,
Cost,
Life,
MaxLife,
CardId,
Clan,
Tribe }
public enum ReplayOperationType
{
TurnStart,
GainPowerDown,
Necromance }
public enum ReplayItemType
{
Turn,
Cost,
Atk,
Life,
MaxLife,
MaxAttackableCount,
AttackableCount,
Player,
Enemy,
Tribe,
ChantCount}
public enum ReplayBuffType
{
None }
public enum ReplayBuffInfoTextType
{
Cost }
public enum ReplayParameterModifierType
{
}
public class TargetData
{
public int TargetIndex { get; private set; }
public int ViewId { get; private set; }
public bool IsSelf { get; private set; }
public List<int> SelectSkillIndexList { get; private set; }
public TargetData(int target, int viewId, bool isSelf, List<int> selectSkillIndexList)
{
TargetIndex = target;
ViewId = viewId;
IsSelf = isSelf;
SelectSkillIndexList = selectSkillIndexList;
}
}
public struct ReplayBuffInfoLabel
{
public ReplayBuffInfoTextType Type { get; set; }
public int Value { get; set; }
public ReplayBuffInfoLabel(ReplayBuffInfoTextType type, int value = -1)
{
Type = type;
Value = value;
}
}
public enum RESULT_CODE
{
NotFinish = 0,
NoContest = 1,
Invalid = 2,
LifeWin = 101,
LifeLose = 102,
DeckoutWin = 103,
DeckoutLose = 104,
RetireWin = 105,
RetireLose = 106,
SpecialWin = 107,
SpecialLose = 108,
DisconnectWin = 201,
DisconnectLose = 202,
FirstcardWin = 203,
FirstcardLose = 204,
TurnendWin = 205,
TurnendLose = 206,
TurnstartWin = 207,
TurnstartLose = 208,
MaxTurnLose = 210,
Error = 999
}
protected NetworkBattleManagerBase networkBattleMgr;
protected ReceiveData _receiveData;
protected bool receiveStop;
public NetworkBattleReceiver(NetworkBattleManagerBase battlemgr)
{
networkBattleMgr = battlemgr;
_receiveData = new ReceiveData();
}
public bool ReceivedMessage(NetworkBattleDefine.NetworkBattleURI uri, bool isHaveSequence, Dictionary<string, object> data, bool isPlayer = false, WatchDataHandler handler = null, bool checkBreakData = true)
{
if (!ConvertReceiveDataToMakeData(uri, isHaveSequence, data, isPlayer, handler) && !RealTimeNetworkAgent.IsFromResumeData(data) && checkBreakData)
{
return false;
}
if (receiveStop)
{
return true;
}
if (isHaveSequence)
{
networkBattleMgr.ConductReceiveData(_receiveData, isPlayer);
}
else
{
networkBattleMgr.ConductReceiveData_NotHaveSequence(_receiveData, isPlayer);
}
return true;
}
public virtual void ReceivedTouchData(NetworkBattleDefine.NetworkBattleURI uri, bool isHaveSequence, Dictionary<string, object> data, bool isPlayer = false, WatchDataHandler handler = null)
{
}
protected virtual bool ConvertReceiveDataToMakeData(NetworkBattleDefine.NetworkBattleURI uri, bool isHaveSequence, Dictionary<string, object> datas, bool isPlayer = false, WatchDataHandler handler = null)
{
if (isHaveSequence)
{
_receiveData = new ReceiveData();
}
_receiveData.dataUri = uri;
string text = "URI : " + uri;
try
{
foreach (KeyValuePair<string, object> data in datas)
{
if (!Enum.IsDefined(typeof(NetworkBattleDefine.NetworkParameter), data.Key.ToString()))
{
continue;
}
text = text + ", " + data.Key;
if (data.Value is List<object> list)
{
text += "[";
for (int i = 0; i < list.Count; i++)
{
if (!(list[i] is Dictionary<string, object> dictionary))
{
continue;
}
foreach (KeyValuePair<string, object> item in dictionary)
{
text = text + item.Key + " : " + item.Value.ToString() + ",";
}
}
text += "]";
}
else
{
text = text + " : " + data.Value.ToString();
}
switch ((NetworkBattleDefine.NetworkParameter)Enum.Parse(typeof(NetworkBattleDefine.NetworkParameter), data.Key.ToString()))
{
case NetworkBattleDefine.NetworkParameter.time:
_receiveData._timeSent = long.Parse(data.Value.ToString());
break;
case NetworkBattleDefine.NetworkParameter.idx:
_receiveData.idx = ConvertToInt(data.Value);
break;
case NetworkBattleDefine.NetworkParameter.self:
_receiveData.selfIdxList = MakeReceiveCardIndexSortList(data.Value as List<object>);
break;
case NetworkBattleDefine.NetworkParameter.oppo:
_receiveData.oppoIdxList = MakeReceiveCardIndexSortList(data.Value as List<object>);
break;
case NetworkBattleDefine.NetworkParameter.isSelf:
_receiveData.isSelf = ConvertToInt(data.Value) == 1;
break;
case NetworkBattleDefine.NetworkParameter.type:
_receiveData.actionType = (NetworkBattleDefine.PlayActionType)ConvertToInt(data.Value);
break;
case NetworkBattleDefine.NetworkParameter.endType:
_receiveData.judgeEndType = (JudgeEndType)ConvertToInt(data.Value);
break;
case NetworkBattleDefine.NetworkParameter.targetUri:
_receiveData.receiveUri = (NetworkBattleDefine.NetworkBattleURI)Enum.Parse(typeof(NetworkBattleDefine.NetworkBattleURI), data.Value.ToString());
break;
case NetworkBattleDefine.NetworkParameter.playIdx:
_receiveData.playCardIndex = ConvertToInt(data.Value);
break;
case NetworkBattleDefine.NetworkParameter.cards:
_receiveData.watchCardList = MakeReceiveCardDataList(data.Value as List<object>, networkBattleMgr, handler);
switch (uri)
{
case NetworkBattleDefine.NetworkBattleURI.Deal:
_receiveData.selfIdxList = (from model in _receiveData.watchCardList
where !model.isOpponent
orderby model.RedrawCardPosition
select model.Index).ToList();
_receiveData.oppoIdxList = (from model in _receiveData.watchCardList
where model.isOpponent
orderby model.RedrawCardPosition
select model.Index).ToList();
break;
case NetworkBattleDefine.NetworkBattleURI.Swap:
case NetworkBattleDefine.NetworkBattleURI.Ready:
_receiveData.selfIdxList = GetSwappedIndexList(isPlayer: true, _receiveData.watchCardList);
_receiveData.oppoIdxList = GetSwappedIndexList(isPlayer: false, _receiveData.watchCardList);
break;
}
break;
case NetworkBattleDefine.NetworkParameter.idxChangeSeed:
networkBattleMgr.CreateXorShift(ConvertToInt(data.Value));
break;
case NetworkBattleDefine.NetworkParameter.oppoIdxChangeSeed:
networkBattleMgr.CreateXorShift(-1, ConvertToInt(data.Value));
break;
case NetworkBattleDefine.NetworkParameter.targetList:
{
List<TargetData> list3 = CreateTargetList(data, isWatch: true, handler);
if (isPlayer)
{
_receiveData.PlayerTargetDataList = list3;
}
else
{
_receiveData.OpponentTargetDataList = list3;
}
break;
}
case NetworkBattleDefine.NetworkParameter.oppoTargetList:
_receiveData.OpponentTargetDataList = CreateTargetList(data);
break;
case NetworkBattleDefine.NetworkParameter.chatStamp:
if (data.Value is Dictionary<string, object> dictionary3)
{
int num2 = ConvertToInt(dictionary3[NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.stamp]]);
if (isPlayer)
{
_receiveData.playChatStamp = num2;
}
else
{
_receiveData.oppoChatStamp = num2;
}
}
break;
case NetworkBattleDefine.NetworkParameter.isWin:
_receiveData.isWin = ((ConvertToInt(data.Value) != 0) ? true : false);
break;
case NetworkBattleDefine.NetworkParameter.knownList:
_receiveData.knownCardList = MakeReceiveCardDataList(data.Value as List<object>, networkBattleMgr, handler);
break;
case NetworkBattleDefine.NetworkParameter.uList:
_receiveData.unapprovedList = MakeReceiveCardDataList(data.Value as List<object>, networkBattleMgr, handler);
break;
case NetworkBattleDefine.NetworkParameter.result:
_receiveData.result = (RESULT_CODE)ConvertToInt(data.Value);
break;
case NetworkBattleDefine.NetworkParameter.resultCode:
_receiveData.NodeResultCode = (NetworkBattleDefine.ReceiveNodeResultCode)Convert.ToInt32(data.Value);
break;
case NetworkBattleDefine.NetworkParameter.keyAction:
{
List<object> obj = data.Value as List<object>;
bool flag = false;
foreach (object item2 in obj)
{
Dictionary<string, object> dictionary2 = item2 as Dictionary<string, object>;
SendKeyActionDataManager.KeyActionType keyActionType = (SendKeyActionDataManager.KeyActionType)Enum.Parse(typeof(SendKeyActionDataManager.KeyActionType), dictionary2[SendKeyActionDataManager.KeyActionParameter.type.ToString()].ToString());
_receiveData.keyActionType.Add(keyActionType);
if (dictionary2.ContainsKey(SendKeyActionDataManager.KeyActionParameter.cardId.ToString()) && (!flag || keyActionType != SendKeyActionDataManager.KeyActionType.Choice))
{
_receiveData.transformBeforeCardId = ConvertToInt(dictionary2[SendKeyActionDataManager.KeyActionParameter.cardId.ToString()]);
if (keyActionType == SendKeyActionDataManager.KeyActionType.Accelerated)
{
flag = true;
}
}
switch (keyActionType)
{
case SendKeyActionDataManager.KeyActionType.Choice:
case SendKeyActionDataManager.KeyActionType.HaveBeforeSkillChoice:
case SendKeyActionDataManager.KeyActionType.ChoiceEvolution:
{
_receiveData.choiceIdList = new List<int>();
if (dictionary2 != null && dictionary2.ContainsKey(SendKeyActionDataManager.KeyActionParameter.selectCard.ToString()))
{
_receiveData.choiceIdList = ConvertToListInt(dictionary2[SendKeyActionDataManager.KeyActionParameter.selectCard.ToString()]);
}
CardParameter cardParameterFromId = CardMaster.GetInstanceForBattle().GetCardParameterFromId(_receiveData.transformBeforeCardId);
BattleCardBase battleCardBase = networkBattleMgr.CreateBattleCard(cardParameterFromId.BaseCardId, isPlayer: false, null, cardParameterFromId, networkBattleMgr.BattlePlayer, 0);
UnityEngine.Object.DestroyImmediate(battleCardBase.BattleCardView.GameObject);
bool isEvol = _receiveData.actionType == NetworkBattleDefine.PlayActionType.EVOLUTION || _receiveData.actionType == NetworkBattleDefine.PlayActionType.EVOLUTION_SELECT;
if (!(NetworkBattleGenericTool.GetChoiceSkill(battleCardBase, isEvol) is Skill_transform))
{
break;
}
_receiveData.IsTransformChoice = true;
if (_receiveData.choiceIdList.Count <= 0)
{
break;
}
string text2 = BattleLogManager.ConvertPremiumIdToNormalId(_receiveData.choiceIdList[0]).ToString();
if (!(battleCardBase.Skills.FirstOrDefault((SkillBase s) => s is Skill_choice) as Skill_choice).OptionValue.GetString(SkillFilterCreator.ContentKeyword.card_id).Contains(text2))
{
LocalLog.AccumulateTraceLog("Illegal Choice Id Received !" + text2);
List<int> list2 = new List<int>();
for (int num = 0; num < _receiveData.choiceIdList.Count; num++)
{
list2.Add((_receiveData.choiceIdList[num] == 100011010) ? 100011020 : 100011010);
}
_receiveData.choiceIdList = list2;
}
break;
}
case SendKeyActionDataManager.KeyActionType.ChoiceBrave:
_receiveData.choiceIdList = new List<int>();
if (dictionary2 != null && dictionary2.ContainsKey(SendKeyActionDataManager.KeyActionParameter.selectCard.ToString()))
{
_receiveData.choiceIdList = ConvertToListInt(dictionary2[SendKeyActionDataManager.KeyActionParameter.selectCard.ToString()]);
}
break;
case SendKeyActionDataManager.KeyActionType.BurialRate:
_receiveData.burialRateList = ConvertToListInt(dictionary2[SendKeyActionDataManager.KeyActionParameter.cardIdx.ToString()]);
break;
}
}
break;
}
case NetworkBattleDefine.NetworkParameter.spin:
_receiveData.spin = GetSpinCount(data.Value);
break;
}
}
if (networkBattleMgr.IsRecovery && uri != NetworkBattleDefine.NetworkBattleURI.OppoDisconnect && uri != NetworkBattleDefine.NetworkBattleURI.RecoveryStart && uri != NetworkBattleDefine.NetworkBattleURI.RecoveryEnd)
{
networkBattleMgr._lastReceivedData = _receiveData;
}
return true;
}
catch
{
LocalLog.AccumulateLastTraceLog("ConvertReciveDataToMakeData Error\n" + text);
Debug.LogError("ConvertReciveDataToMakeData Error");
return false;
}
}
protected void CreateSlideObjectReceiveData(string startPoint, string endPoint)
{
_receiveData._slideObjectType = (NetworkBattleSender.SLIDE_OBJECT_TYPE)Enum.Parse(typeof(NetworkBattleSender.SLIDE_OBJECT_TYPE), startPoint[0].ToString());
switch (_receiveData._slideObjectType)
{
case NetworkBattleSender.SLIDE_OBJECT_TYPE.Attack:
_receiveData.idx = int.Parse(startPoint.Substring(1, startPoint.Length - 1));
_receiveData._selectedCardIndex = int.Parse(endPoint);
break;
case NetworkBattleSender.SLIDE_OBJECT_TYPE.Evolve:
_receiveData._selectedCardIndex = int.Parse(endPoint);
break;
case NetworkBattleSender.SLIDE_OBJECT_TYPE.Cancel:
break;
}
}
private List<TargetData> CreateTargetList(KeyValuePair<string, object> data, bool isWatch = false, WatchDataHandler handler = null)
{
List<object> obj = data.Value as List<object>;
List<TargetData> list = new List<TargetData>();
_receiveData.validateSkillIndexList = new List<int>();
foreach (object item2 in obj)
{
int target = 0;
int num = 0;
bool isSelf = false;
Dictionary<string, object> dictionary = item2 as Dictionary<string, object>;
string key = NetworkBattleDefine.NetworkParameter.targetIdx.ToString();
if (dictionary.ContainsKey(key))
{
target = ConvertToInt(dictionary[key]);
}
if (isWatch)
{
key = NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.vid];
if (dictionary.ContainsKey(key))
{
num = ConvertToInt(dictionary[key].ToString());
// Phase-5 chunk 39: dropped ambient PlayerStaticData.UserViewerID fallback in favor
// of the mgr's InstanceViewerId — recovery branch compares wire vid to the mgr's
// bound viewer id, live branch stays on handler.isOwner.
isSelf = ((!networkBattleMgr.IsRecovery) ? (!handler.isOwner(dictionary[key].ToString())) : ((num != networkBattleMgr.InstanceViewerId) ? true : false));
}
}
else
{
key = NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.isSelf];
if (dictionary.ContainsKey(key))
{
isSelf = ConvertToInt(dictionary[key]) == 1;
}
}
key = NetworkBattleDefine.NetworkParameter.skillIndex.ToString();
if (dictionary.ContainsKey(key))
{
foreach (int item3 in ConvertToListInt(dictionary[key]))
{
_receiveData.validateSkillIndexList.Add(item3);
}
}
List<int> selectSkillIndexList = new List<int>();
key = NetworkBattleDefine.NetworkParameter.selectSkillIndex.ToString();
if (dictionary.ContainsKey(key))
{
selectSkillIndexList = ConvertToListInt(dictionary[key]);
}
TargetData item = new TargetData(target, num, isSelf, selectSkillIndexList);
list.Add(item);
}
return list;
}
public void ReceiveStop()
{
LocalLog.AccumulateLastTraceLog("ReceiveBattleFinish StopReceiveData");
receiveStop = true;
}
protected virtual void CheckDuplicateDataAddtoList(List<CardDataModel> list, CardDataModel cardDataModel)
{
list.Add(cardDataModel);
}
private List<int> MakeReceiveCardIndexSortList(List<object> mulliganList)
{
Dictionary<int, int> dictionary = new Dictionary<int, int>();
foreach (object mulligan in mulliganList)
{
Dictionary<string, object> dictionary2 = mulligan as Dictionary<string, object>;
int key = ConvertToInt(dictionary2[NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.pos]]);
int value = ConvertToInt(dictionary2[NetworkBattleDefine.NetworkParameter.idx.ToString()]);
dictionary.Add(key, value);
}
return (from data in dictionary
orderby data.Key
select data.Value).ToList();
}
private List<int> GetSwappedIndexList(bool isPlayer, List<CardDataModel> cardList)
{
List<CardDataModel> list = (from param in cardList
where param.isOpponent == !isPlayer
where param.ToStateList.First() == NetworkBattleDefine.NetworkCardPlaceState.Hand
select param).ToList();
List<int> list2 = (isPlayer ? new List<int>(networkBattleMgr.MulliganMgr.PlayerMlgCtrl.DealIdxList) : new List<int>(networkBattleMgr.MulliganMgr.OpponentMlgCtrl.DealIdxList));
for (int num = 0; num < list.Count; num++)
{
int redrawCardPosition = list[num].RedrawCardPosition;
list2[redrawCardPosition] = list[num].Index;
}
return list2;
}
private List<CardDataModel> MakeReceiveCardDataList(List<object> cardData, BattleManagerBase mgr, WatchDataHandler handler)
{
List<CardDataModel> list = new List<CardDataModel>();
foreach (object cardDatum in cardData)
{
if (!(cardDatum as Dictionary<string, object>).ContainsKey(NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.activate]) && !(cardDatum as Dictionary<string, object>).ContainsKey(NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.count]) && !(cardDatum as Dictionary<string, object>).ContainsKey(NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.callCount]) && !(cardDatum as Dictionary<string, object>).ContainsKey(NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.param]))
{
foreach (CardDataModel item in MakeReceiveCardData(cardDatum, mgr, handler))
{
CheckDuplicateDataAddtoList(list, item);
}
continue;
}
foreach (CardDataModel item2 in MakeReceiveCardData(cardDatum, mgr, handler))
{
_receiveData.SkillConditionCheckList.Add(item2);
}
}
List<CardDataModel> list2 = new List<CardDataModel>();
foreach (CardDataModel skillConditionCheck in _receiveData.SkillConditionCheckList)
{
if (list2.Contains(skillConditionCheck))
{
continue;
}
int num = 0;
foreach (CardDataModel skillConditionCheck2 in _receiveData.SkillConditionCheckList)
{
if (skillConditionCheck.Index == skillConditionCheck2.Index && skillConditionCheck.publishedActiveSkillCount == skillConditionCheck2.publishedActiveSkillCount)
{
skillConditionCheck2.skillMovementNum = num;
num++;
list2.Add(skillConditionCheck2);
}
}
}
if (!_receiveData._isSettingMutationAfterCardId && _receiveData.IsAcceleratedOrCrystallize)
{
_receiveData._isSettingMutationAfterCardId = true;
_receiveData.mutationAfterCardId = list[0].CardId;
_receiveData.mutationAfterCost = list[0].playCardCost;
list[0].CardId = _receiveData.transformBeforeCardId;
}
return list;
}
protected virtual List<CardDataModel> MakeReceiveCardData(object cardData, BattleManagerBase mgr, WatchDataHandler handler)
{
Dictionary<string, object> dictionary = cardData as Dictionary<string, object>;
List<CardDataModel> list = new List<CardDataModel>();
List<int> list2 = new List<int>();
if (dictionary.ContainsKey(NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.idx]))
{
list2.Add(ConvertToInt(dictionary[NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.idx]]));
}
else if (dictionary.ContainsKey(NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.idxList]))
{
list2 = ConvertToListInt(dictionary[NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.idxList]]);
}
else
{
Debug.LogError("BaseMakeReceiveCardData Not idx ");
}
for (int i = 0; i < list2.Count; i++)
{
CardDataModel cardDataModel = new CardDataModel();
cardDataModel.Index = list2[i];
foreach (KeyValuePair<string, object> item in dictionary)
{
if (!Enum.IsDefined(typeof(NetworkBattleDefine.NetworkParameter), item.Key))
{
continue;
}
switch ((NetworkBattleDefine.NetworkParameter)Enum.Parse(typeof(NetworkBattleDefine.NetworkParameter), item.Key))
{
case NetworkBattleDefine.NetworkParameter.cardId:
cardDataModel.CardId = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.to:
cardDataModel.ToStateList.Add((NetworkBattleDefine.NetworkCardPlaceState)ConvertToInt(item.Value));
break;
case NetworkBattleDefine.NetworkParameter.isSelf:
cardDataModel.isOpponent = ConvertToInt(item.Value) != 1;
break;
case NetworkBattleDefine.NetworkParameter.skillKeyCardIdx:
{
cardDataModel.skillKeyCardIdxList = new List<int>();
if (item.Value is List<object>)
{
cardDataModel.skillKeyCardIdxList = ConvertToListInt(item.Value);
break;
}
JsonData jsonData = item.Value as JsonData;
for (int j = 0; j < jsonData.Count; j++)
{
cardDataModel.skillKeyCardIdxList.Add(jsonData[j].ToInt());
}
break;
}
case NetworkBattleDefine.NetworkParameter.pos:
cardDataModel.RedrawCardPosition = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.cost:
cardDataModel.playCardCost = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.activate:
cardDataModel.activate = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.addLife:
cardDataModel.AddLife = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.setLife:
cardDataModel.SetLife = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.addAtk:
cardDataModel.AddAtk = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.setAtk:
cardDataModel.SetAtk = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.clan:
cardDataModel.Clan = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.tribe:
cardDataModel.Tribe = item.Value.ToString();
break;
case NetworkBattleDefine.NetworkParameter.skillIdx:
cardDataModel.SkillIndex = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.skillCount:
cardDataModel.publishedActiveSkillCount = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.count:
cardDataModel.activate = 1;
cardDataModel.SkillValueCount = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.callCount:
cardDataModel.activate = 1;
cardDataModel.SkillCallCount = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.param:
cardDataModel.activate = 1;
cardDataModel.SkillValueParameter = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.attachTarget:
cardDataModel.SetAttachTarget(item.Value.ToString());
break;
case NetworkBattleDefine.NetworkParameter.highlander:
cardDataModel.IsHighlander = ConvertToInt(item.Value) == 1;
break;
case NetworkBattleDefine.NetworkParameter.spellboost:
cardDataModel.Spellboost = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.addChantCount:
cardDataModel.AddChantCount = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.setChantCount:
cardDataModel.SetChantCount = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.unionburst:
cardDataModel.UnionBurstCount = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.skyboundArt:
cardDataModel.SkyboundArtCount = ConvertToInt(item.Value);
break;
case NetworkBattleDefine.NetworkParameter.isInvoke:
cardDataModel.IsInvoked = ConvertToInt(item.Value) == 1;
break;
case NetworkBattleDefine.NetworkParameter.skill:
{
string[] array = item.Value.ToString().Split('|');
cardDataModel.skillCardIndex = int.Parse(array[0]);
cardDataModel.publishedActiveSkillCount = int.Parse(array[1]);
cardDataModel.skillMovementNum = int.Parse(array[2]);
break;
}
case NetworkBattleDefine.NetworkParameter.is_open:
cardDataModel.IsOpen = ConvertToInt(item.Value) == 1;
break;
case NetworkBattleDefine.NetworkParameter.randomTargetIdx:
{
List<int> list3 = ConvertToListInt(item.Value);
if (i < list3.Count)
{
cardDataModel.RandomTargetIndex = list3[i];
}
break;
}
case NetworkBattleDefine.NetworkParameter.fusion:
cardDataModel.FusionIngredientList = ConvertToListInt(item.Value);
break;
}
}
if (mgr != null)
{
if (dictionary.ContainsKey(NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.from]))
{
cardDataModel.fromState = (NetworkBattleDefine.NetworkCardPlaceState)ConvertToInt(dictionary[NetworkBattleDefine.NetworkParameterNames[NetworkBattleDefine.NetworkParameter.from]]);
}
else
{
cardDataModel.fromState = NetworkBattleGenericTool.GetCardPlaceState(mgr.GetBattlePlayer(cardDataModel.isOpponent), cardDataModel.Index);
}
}
list.Add(cardDataModel);
}
return list;
}
protected virtual int ConvertToInt(object intStr)
{
return Convert.ToInt32(intStr.ToString());
}
protected int GetSpinCount(object receivedObject)
{
string s = receivedObject.ToString();
int result = 0;
if (int.TryParse(s, out result))
{
return ConvertToInt(receivedObject);
}
if (receivedObject is Dictionary<string, object> dictionary && dictionary.Keys.Contains("vid") && dictionary.Keys.Contains("value"))
{
int num = int.Parse(dictionary["vid"].ToString());
if (networkBattleMgr.GameMgr.GetNetworkUserInfoData().GetSelfViewerId() == num)
{
return int.Parse(dictionary["value"].ToString());
}
}
return 0;
}
private List<int> ConvertToListInt(object listObject)
{
List<object> obj = listObject as List<object>;
List<int> list = new List<int>();
foreach (object item in obj)
{
list.Add(ConvertToInt(item));
}
return list;
}
}