using System; using System.Collections.Generic; using Animancer; using Logic.AI; using Logic.Multilingual; using RuntimeData; using TH1_Logic.Core; using TH1_Logic.Net; using TH1_UI.View.Outside; using TH1Resource; using UnityEngine; using UnityEngine.UI; public class UIOutsideSelectCheckPanelMono : MonoBehaviour { public UIOutsideSelectOptionGroupMono GameMode; public UIOutsideSelectOptionGroupMono PlayerCount; public UIOutsideSelectOptionGroupMono MapSize; public UIOutsideSelectOptionGroupMono Diff; public UIOutsideSelectOptionGroupMono Water; public GameObject WinTitle; public UIOutsideSelectOptionGroupMono WinGroup; public GameObject AISettingTitle; public GameObject AISettingGroup; public GameObject AISettingRowPrefab; public GameObject TestTitle; public GameObject TestGroup; public Toggle ResumeToggle; public Toggle NearToggle; public Button StartButton; public Button CloseButton; public Button BlockerButton; public AnimancerComponent Animancer; private const string LAST_MAP_SIZE_INDEX_KEY = "LastCreativeMapSizeIndex"; private const string DISABLE_NEARBY_SPAWN_POINTS_PREFS_KEY = "DisableNearbySpawnPoints"; private static readonly uint[] CreativeWinMatchConfigIds = { 7, 9, 10 }; private static readonly List<(CivEnum Civ, ForceEnum Force)> FallbackForceOptions = new List<(CivEnum Civ, ForceEnum Force)> { (CivEnum.Egyptian, ForceEnum.Remilia), (CivEnum.French, ForceEnum.Kaguya), (CivEnum.Germany, ForceEnum.Kanako), (CivEnum.Indian, ForceEnum.Satori), }; private Action _onStartClick; private Empire _playerEmpire; private bool _playerEmpireIsRandom; private readonly List _aiSettings = new List(); private readonly List _aiSettingRows = new List(); private bool _aiSettingRowsCached; public uint WinSelectedIndex => WinGroup != null ? WinGroup.SelectedIndex : 0; public bool IsTestMode => GameMode != null && GameMode.SelectedIndex == 2 && ResumeToggle != null && ResumeToggle.isOn; public bool DisableNearbySpawnPoints => GameMode != null && GameMode.SelectedIndex == 2 && NearToggle != null && NearToggle.isOn; public IReadOnlyList AISettings => _aiSettings; public class AISettingData { public int SlotIndex; public uint CivId; public uint ForceId; public bool IsRandom; public int TeamId; public bool IsForceUserEdited; public bool IsTeamUserEdited; } public void Init(Action onStartClick) { InitSetting(); _onStartClick = onStartClick; StartButton.onClick.RemoveAllListeners(); StartButton.onClick.AddListener(() => _onStartClick?.Invoke()); CloseButton.onClick.RemoveAllListeners(); CloseButton.onClick.AddListener(Hide); BlockerButton.onClick.RemoveAllListeners(); BlockerButton.onClick.AddListener(Hide); } public void SetPlayerEmpire(Empire playerEmpire, bool isRandom = false) { _playerEmpire = playerEmpire; _playerEmpireIsRandom = isRandom; uint playerCount = PlayerCount != null ? PlayerCount.SelectedIndex + 2 : Main.Instance.MapConfig?.PlayerCount ?? 2; var preserveUserEdits = GameMode != null && GameMode.SelectedIndex == 2; InitAISettings(playerCount, preserveUserEdits, preserveUserEdits); RefreshAISettingRows(); } public void PrepareAISettingsForStart(uint playerCount, bool preserveUserEdits) { InitAISettings(playerCount, preserveUserEdits, preserveUserEdits); RefreshAISettingRows(); } public void InitSetting() { Main.Instance.MapConfig?.ResetTransientMatchOptions(); uint playerCount = 2; AIDifficult diff = AIDifficult.HARD; GameMode gameMode = RuntimeData.GameMode.PERFECT; uint matchConfigId = 7; if (Main.Instance.MapConfig != null) { playerCount = Main.Instance.MapConfig.PlayerCount; diff = Main.Instance.MapConfig.AIDiff; gameMode = Main.Instance.MapConfig.GameMode; matchConfigId = Main.Instance.MapConfig.Id; } uint playerCountIdx = playerCount >= 2 ? playerCount - 2 : 0; uint mapSizeIdx = gameMode == RuntimeData.GameMode.CREATIVE ? (uint)PlayerPrefs.GetInt(LAST_MAP_SIZE_INDEX_KEY, 3) : playerCount switch { 2 => 0, 3 => 1, 4 => 2, _ => 3 }; uint diffIdx = diff switch { AIDifficult.EASY => 0, AIDifficult.NORMAL => 1, AIDifficult.HARD => 2, _ => 3 }; uint gameModeIdx = gameMode switch { RuntimeData.GameMode.DOMINATION => 0, RuntimeData.GameMode.PERFECT => 1, RuntimeData.GameMode.CREATIVE => 2, _ => 2 }; uint waterIdx = gameMode == RuntimeData.GameMode.CREATIVE && Main.Instance.MapConfig != null ? (uint)Main.Instance.MapConfig.WaterType : 2; GameMode.OnOptionClicked = OnGameModeOptionClicked; PlayerCount.OnOptionClicked = OnPlayerOptionClicked; if (WinGroup != null) WinGroup.OnOptionClicked = OnWinOptionClicked; if (ResumeToggle != null) { ResumeToggle.onValueChanged.RemoveAllListeners(); ResumeToggle.onValueChanged.AddListener(OnTestModeChanged); } if (NearToggle != null) { NearToggle.onValueChanged.RemoveAllListeners(); NearToggle.onValueChanged.AddListener(OnNearToggleChanged); } SetNearToggleSavedValue(gameMode == RuntimeData.GameMode.CREATIVE); GameMode.Init(gameModeIdx); PlayerCount.Init(playerCountIdx); MapSize.Init(mapSizeIdx); Diff.Init(diffIdx); if (Water != null) Water.Init(waterIdx); if (WinGroup != null) WinGroup.Init(GetWinIndexByMatchConfigId(matchConfigId)); InitAISettings(playerCount, false, false); OnGameModeOptionClicked(gameModeIdx); } public void OnPlayerOptionClicked(uint idx) { var preserveUserEdits = GameMode != null && GameMode.SelectedIndex == 2; InitAISettings(idx + 2, preserveUserEdits, preserveUserEdits); RefreshAISettingRows(); if (GameMode.SelectedIndex == 2) return; uint mapSizeIdx = idx switch { 0 => 0, 1 => 1, 2 => 2, _ => 3 }; MapSize.Select(mapSizeIdx); } public void OnGameModeOptionClicked(uint idx) { bool isCreative = idx == 2; if (WinTitle != null) WinTitle.SetActive(isCreative); if (WinGroup != null) { WinGroup.gameObject.SetActive(isCreative); WinGroup.Init(WinGroup.SelectedIndex); } if (AISettingTitle != null) AISettingTitle.SetActive(isCreative); if (AISettingGroup != null) AISettingGroup.SetActive(isCreative); if (TestTitle != null) TestTitle.SetActive(isCreative); if (TestGroup != null) TestGroup.SetActive(isCreative); RefreshNearToggleVisibility(isCreative); RefreshAISettingRows(); if (isCreative) { MapSize.Passive = false; MapSize.Init(MapSize.SelectedIndex); if (Water != null) { Water.Passive = false; Water.Init(Water.SelectedIndex); } } else { MapSize.Passive = true; MapSize.Init(MapSize.SelectedIndex); OnPlayerOptionClicked(PlayerCount.SelectedIndex); if (Water != null) { Water.Passive = true; Water.Init(2); } } } public uint GetSelectedCreativeMatchConfigId() { return GetCreativeMatchConfigIdByWinIndex(WinSelectedIndex); } private void SetNearToggleSavedValue(bool isCreative) { if (NearToggle == null) return; NearToggle.SetIsOnWithoutNotify(isCreative && PlayerPrefs.GetInt(DISABLE_NEARBY_SPAWN_POINTS_PREFS_KEY, 0) == 1); } private void RefreshNearToggleVisibility(bool isCreative) { if (NearToggle == null) return; NearToggle.gameObject.SetActive(isCreative); NearToggle.interactable = isCreative; NearToggle.SetIsOnWithoutNotify(isCreative && PlayerPrefs.GetInt(DISABLE_NEARBY_SPAWN_POINTS_PREFS_KEY, 0) == 1); } private void OnNearToggleChanged(bool selected) { if (GameMode == null || GameMode.SelectedIndex != 2) return; SaveDisableNearbySpawnPointsPreference(selected); } public void SaveDisableNearbySpawnPointsPreference() { if (GameMode == null || GameMode.SelectedIndex != 2) return; SaveDisableNearbySpawnPointsPreference(NearToggle != null && NearToggle.isOn); } private static void SaveDisableNearbySpawnPointsPreference(bool selected) { PlayerPrefs.SetInt(DISABLE_NEARBY_SPAWN_POINTS_PREFS_KEY, selected ? 1 : 0); PlayerPrefs.Save(); } public void Show() { InitSetting(); gameObject.SetActive(true); Animancer.Play(ResourceCache.Instance.AnimCache.UICommonPanelFadeIn); Timer.Instance.TimerRegister(this, () => { GameMode.OnShow(); PlayerCount.OnShow(); MapSize.OnShow(); Diff.OnShow(); if (Water != null) Water.OnShow(); if (WinGroup != null && WinGroup.gameObject.activeInHierarchy) WinGroup.OnShow(); }, 0.01f, ""); } public void Hide() { var state = Animancer.Play(ResourceCache.Instance.AnimCache.UICommonPanelFadeOut); state.Events.OnEnd = () => { gameObject.SetActive(false); }; } private void InitAISettings(uint playerCount, bool preserveUserTeamEdits, bool preserveUserForceEdits) { int targetCount = Mathf.Max(0, (int)playerCount - 1); var usedPlayerOptions = new HashSet<(uint CivId, uint ForceId)>(); AddPlayerEmpireToUsedOptions(usedPlayerOptions); var nextSettings = new List(); for (int slotIndex = 1; slotIndex <= targetCount; slotIndex++) { var existingData = GetAISettingData(slotIndex); var slot = GetExistingPlayerSlot(slotIndex); var setting = CreateAISettingData(slotIndex, playerCount, usedPlayerOptions, existingData, slot, preserveUserTeamEdits, preserveUserForceEdits); nextSettings.Add(setting); if (!setting.IsRandom) usedPlayerOptions.Add((setting.CivId, setting.ForceId)); } _aiSettings.Clear(); _aiSettings.AddRange(nextSettings); } private AISettingData CreateAISettingData( int slotIndex, uint playerCount, HashSet<(uint CivId, uint ForceId)> usedPlayerOptions, AISettingData existingData, MemberCiv slot, bool preserveUserTeamEdits, bool preserveUserForceEdits) { if (preserveUserForceEdits && existingData != null && existingData.IsForceUserEdited && (existingData.IsRandom || IsValidPlayerOption(existingData.CivId, existingData.ForceId))) { return new AISettingData { SlotIndex = slotIndex, CivId = existingData.CivId, ForceId = existingData.ForceId, IsRandom = existingData.IsRandom, TeamId = GetPreferredTeamId(existingData, slotIndex, (int)playerCount, preserveUserTeamEdits), IsForceUserEdited = existingData.IsForceUserEdited, IsTeamUserEdited = preserveUserTeamEdits && existingData.IsTeamUserEdited }; } var playerOption = PickDefaultPlayerOption(Mathf.Max(0, slotIndex - 1), usedPlayerOptions); return new AISettingData { SlotIndex = slotIndex, CivId = playerOption.CivId, ForceId = playerOption.ForceId, IsRandom = false, TeamId = GetPreferredTeamId(existingData, slotIndex, (int)playerCount, preserveUserTeamEdits), IsForceUserEdited = false, IsTeamUserEdited = preserveUserTeamEdits && existingData?.IsTeamUserEdited == true }; } private void RefreshAISettingRows() { CacheExistingAISettingRows(); bool show = GameMode != null && GameMode.SelectedIndex == 2 && AISettingGroup != null; if (AISettingGroup != null) AISettingGroup.SetActive(show); if (!show) { for (int i = 0; i < _aiSettingRows.Count; i++) if (_aiSettingRows[i] != null) _aiSettingRows[i].gameObject.SetActive(false); RefreshAISettingLayout(); return; } var sameCountDict = BuildForceSameCountDict(); int maxTeamId = Mathf.Max(1, (int)(PlayerCount.SelectedIndex + 2)); int visibleRowCount = 0; RenderSelfPlayerRow(sameCountDict, maxTeamId); visibleRowCount++; for (int i = 0; i < _aiSettings.Count; i++) { int rowIndex = i + 1; var row = GetAISettingRow(rowIndex); if (row == null) continue; row.gameObject.SetActive(true); row.transform.SetSiblingIndex(rowIndex); var data = _aiSettings[i]; if (data.IsRandom) { row.SetRandomContent(data.TeamId, maxTeamId, direction => OnAIRowForceChanged(data.SlotIndex, direction), direction => OnAIRowTeamChanged(data.SlotIndex, direction)); visibleRowCount++; continue; } var civ = Table.Instance.TransCivIdToCivEnum(data.CivId); var force = Table.Instance.TransForceIdToForceEnum(data.ForceId); var forceNameOverride = GetForceNameOverride(data, civ, force, sameCountDict); row.SetContent(civ, force, data.TeamId, maxTeamId, forceNameOverride, direction => OnAIRowForceChanged(data.SlotIndex, direction), direction => OnAIRowTeamChanged(data.SlotIndex, direction)); visibleRowCount++; } for (int i = visibleRowCount; i < _aiSettingRows.Count; i++) { if (_aiSettingRows[i] == null) continue; _aiSettingRows[i].gameObject.SetActive(false); _aiSettingRows[i].transform.SetSiblingIndex(i); } RefreshAISettingLayout(); } private void RenderSelfPlayerRow(Dictionary<(CivEnum, ForceEnum), int> sameCountDict, int maxTeamId) { var row = GetAISettingRow(0); if (row == null) return; row.gameObject.SetActive(true); row.transform.SetSiblingIndex(0); if (_playerEmpireIsRandom) { row.SetRandomSelfContent(1, maxTeamId); return; } var playerEmpire = GetCurrentPlayerEmpire(); var forceNameOverride = GetSelfForceNameOverride(playerEmpire.Civ, playerEmpire.Force, sameCountDict); row.SetContent(playerEmpire.Civ, playerEmpire.Force, 1, maxTeamId, forceNameOverride, null, null, false, false); } private UIOutsideSelectAISettingRowMono GetAISettingRow(int index) { CacheExistingAISettingRows(); if (AISettingRowPrefab == null || AISettingGroup == null) return null; while (_aiSettingRows.Count <= index) { var item = Instantiate(AISettingRowPrefab, AISettingGroup.transform); item.SetActive(true); _aiSettingRows.Add(item.GetComponent()); } return _aiSettingRows[index]; } private void CacheExistingAISettingRows() { if (_aiSettingRowsCached || AISettingGroup == null) return; _aiSettingRowsCached = true; for (int i = 0; i < AISettingGroup.transform.childCount; i++) { var row = AISettingGroup.transform.GetChild(i).GetComponent(); if (row != null && !_aiSettingRows.Contains(row)) _aiSettingRows.Add(row); } } private void RefreshAISettingLayout() { if (AISettingGroup == null) return; var groupRect = AISettingGroup.GetComponent(); if (groupRect == null) return; Canvas.ForceUpdateCanvases(); LayoutRebuilder.ForceRebuildLayoutImmediate(groupRect); var parentRect = groupRect.parent as RectTransform; if (parentRect != null) LayoutRebuilder.ForceRebuildLayoutImmediate(parentRect); Canvas.ForceUpdateCanvases(); } private Dictionary<(CivEnum, ForceEnum), int> BuildForceSameCountDict() { var sameCountDict = new Dictionary<(CivEnum, ForceEnum), int>(); if (!_playerEmpireIsRandom) { var playerEmpire = GetCurrentPlayerEmpire(); AddSameCount(playerEmpire.Civ, playerEmpire.Force); } foreach (var data in _aiSettings) { if (data.IsRandom) continue; AddSameCount(Table.Instance.TransCivIdToCivEnum(data.CivId), Table.Instance.TransForceIdToForceEnum(data.ForceId)); } return sameCountDict; void AddSameCount(CivEnum civ, ForceEnum force) { if (civ == CivEnum.Common || force == ForceEnum.Common) return; var key = (civ, force); sameCountDict.TryGetValue(key, out var prevCnt); sameCountDict[key] = prevCnt + 1; } } private string GetForceNameOverride(AISettingData data, CivEnum civ, ForceEnum force, Dictionary<(CivEnum, ForceEnum), int> sameCountDict) { if (data != null && data.IsRandom) return null; if (!sameCountDict.TryGetValue((civ, force), out var sameCnt) || sameCnt < 2) return null; if (!Table.Instance.PlayerDataAssets.GetPlayerInfo(civ, force, out var pi)) return null; var raw = MultilingualManager.Instance.GetMultilingualTextSafe(pi.ForceName); return $"{raw} {data.SlotIndex + 1}P"; } private string GetSelfForceNameOverride(CivEnum civ, ForceEnum force, Dictionary<(CivEnum, ForceEnum), int> sameCountDict) { if (!sameCountDict.TryGetValue((civ, force), out var sameCnt) || sameCnt < 2) return null; if (!Table.Instance.PlayerDataAssets.GetPlayerInfo(civ, force, out var pi)) return null; var raw = MultilingualManager.Instance.GetMultilingualTextSafe(pi.ForceName); return $"{raw} 1P"; } private void OnAIRowForceChanged(int slotIndex, int direction) { var data = GetAISettingData(slotIndex); if (data == null) return; var next = GetNextAIForce(data.CivId, data.ForceId, direction); data.IsRandom = next.Civ == CivEnum.Common && next.Force == ForceEnum.Common; if (data.IsRandom) { data.CivId = MapConfig.RandomCivId; data.ForceId = MapConfig.RandomForceId; } else { data.CivId = Table.Instance.TransCivEnumToCivId(next.Civ); data.ForceId = Table.Instance.TransForceEnumToForceId(next.Force); } data.IsForceUserEdited = true; RefreshAISettingRows(); } private void OnAIRowTeamChanged(int slotIndex, int direction) { var data = GetAISettingData(slotIndex); if (data == null) return; data.TeamId = GetNextTeamId(data.TeamId, direction); data.IsTeamUserEdited = true; RefreshAISettingRows(); } private AISettingData GetAISettingData(int slotIndex) { for (int i = 0; i < _aiSettings.Count; i++) if (_aiSettings[i].SlotIndex == slotIndex) return _aiSettings[i]; return null; } private int GetNextTeamId(int teamId, int direction) { int maxTeamId = Mathf.Max(1, (int)(PlayerCount.SelectedIndex + 2)); teamId += direction; if (teamId < 1) return maxTeamId; if (teamId > maxTeamId) return 1; return teamId; } private (CivEnum Civ, ForceEnum Force) GetNextAIForce(uint civId, uint forceId, int direction) { var options = GetAIForceOptionsWithRandom(); var isRandom = MapConfig.IsRandomPlayerSlotCiv(civId, forceId, false); var civ = isRandom ? CivEnum.Common : Table.Instance.TransCivIdToCivEnum(civId); var force = isRandom ? ForceEnum.Common : Table.Instance.TransForceIdToForceEnum(forceId); int index = 0; for (int i = 0; i < options.Count; i++) { if (options[i].Civ == civ && options[i].Force == force) { index = i; break; } } index = (index + direction + options.Count) % options.Count; return options[index]; } private IReadOnlyList<(CivEnum Civ, ForceEnum Force)> GetAIForceOptionsWithRandom() { var options = new List<(CivEnum Civ, ForceEnum Force)> { (CivEnum.Common, ForceEnum.Common) }; options.AddRange(GetAIForceOptions()); return options; } private IReadOnlyList<(CivEnum Civ, ForceEnum Force)> GetAIForceOptions() { var assets = Table.Instance.PlayerDataAssets; var options = new List<(CivEnum Civ, ForceEnum Force)>(); var optionSet = new HashSet<(CivEnum Civ, ForceEnum Force)>(); if (assets?.PlayerDataList != null) { foreach (var info in assets.PlayerDataList) { if (info == null) continue; var civ = Table.Instance.TransCivIdToCivEnum(info.CivId); var force = Table.Instance.TransForceIdToForceEnum(info.ForceId); if (civ == CivEnum.Common || force == ForceEnum.Common) continue; if (!ContentGate.CanUseEmpire(new Empire(civ, force))) continue; if (!optionSet.Add((civ, force))) continue; options.Add((civ, force)); } } if (options.Count > 0) return options; foreach (var fallback in FallbackForceOptions) { if (ContentGate.CanUseEmpire(new Empire(fallback.Civ, fallback.Force))) options.Add(fallback); } if (options.Count == 0) options.Add((CivEnum.Egyptian, ForceEnum.Remilia)); return options; } private bool IsValidPlayerOption(uint civId, uint forceId) { var civ = Table.Instance.TransCivIdToCivEnum(civId); var force = Table.Instance.TransForceIdToForceEnum(forceId); if (civ == CivEnum.Common || force == ForceEnum.Common) return false; if (!ContentGate.CanUseEmpire(new Empire(civ, force))) return false; return Table.Instance.PlayerDataAssets.GetPlayerInfo(civ, force, out _); } private static int GetPreferredTeamId(AISettingData existingData, int slotIndex, int playerCount, bool preserveUserTeamEdits) { if (preserveUserTeamEdits && existingData != null && existingData.IsTeamUserEdited) return GetValidTeamId(existingData.TeamId, slotIndex, playerCount); return GetDefaultTeamId(slotIndex, playerCount); } private static int GetValidTeamId(int teamId, int slotIndex, int playerCount) { int maxTeamId = Mathf.Max(1, playerCount); if (teamId >= 1 && teamId <= maxTeamId) return teamId; return GetDefaultTeamId(slotIndex, playerCount); } private static int GetDefaultTeamId(int slotIndex, int playerCount) { return Mathf.Clamp(slotIndex + 1, 1, Mathf.Max(1, playerCount)); } private void AddPlayerEmpireToUsedOptions(HashSet<(uint CivId, uint ForceId)> usedPlayerOptions) { if (_playerEmpireIsRandom) return; var playerEmpire = GetCurrentPlayerEmpire(); if (playerEmpire.Civ != CivEnum.Common && playerEmpire.Force != ForceEnum.Common) { var civId = Table.Instance.TransCivEnumToCivId(playerEmpire.Civ); var forceId = Table.Instance.TransForceEnumToForceId(playerEmpire.Force); if (IsValidPlayerOption(civId, forceId)) { usedPlayerOptions.Add((civId, forceId)); return; } } var selfSlot = GetExistingPlayerSlot(0); if (selfSlot != null && IsValidPlayerOption(selfSlot.CivId, selfSlot.ForceId)) { usedPlayerOptions.Add((selfSlot.CivId, selfSlot.ForceId)); } } private Empire GetCurrentPlayerEmpire() { if (_playerEmpire.Civ != CivEnum.Common && _playerEmpire.Force != ForceEnum.Common && ContentGate.CanUseEmpire(_playerEmpire)) return _playerEmpire; var selfSlot = GetExistingPlayerSlot(0); if (selfSlot != null) { var civ = Table.Instance.TransCivIdToCivEnum(selfSlot.CivId); var force = Table.Instance.TransForceIdToForceEnum(selfSlot.ForceId); var empire = new Empire(civ, force); if (civ != CivEnum.Common && force != ForceEnum.Common && ContentGate.CanUseEmpire(empire)) return empire; } var options = GetAIForceOptions(); var fallback = options[0]; return new Empire(fallback.Civ, fallback.Force); } private (uint CivId, uint ForceId) PickDefaultPlayerOption(int preferredIndex, HashSet<(uint CivId, uint ForceId)> usedPlayerOptions) { var options = GetAIForceOptions(); for (int offset = 0; offset < options.Count; offset++) { int index = (preferredIndex + offset) % options.Count; var option = options[index]; var ids = ( Table.Instance.TransCivEnumToCivId(option.Civ), Table.Instance.TransForceEnumToForceId(option.Force)); if (!usedPlayerOptions.Contains(ids)) return ids; } var fallback = options[preferredIndex % options.Count]; return ( Table.Instance.TransCivEnumToCivId(fallback.Civ), Table.Instance.TransForceEnumToForceId(fallback.Force)); } private static MemberCiv GetExistingPlayerSlot(int slotIndex) { var slots = Main.Instance.MapConfig?.MultiCivs; if (slots == null || slotIndex < 0 || slotIndex >= slots.Count) return null; return slots[slotIndex]; } private void OnWinOptionClicked(uint idx) { } private void OnTestModeChanged(bool isOn) { } private static uint GetWinIndexByMatchConfigId(uint matchConfigId) { for (int i = 0; i < CreativeWinMatchConfigIds.Length; i++) { if (CreativeWinMatchConfigIds[i] == matchConfigId) return (uint)i; } return 0; } private static uint GetCreativeMatchConfigIdByWinIndex(uint idx) { return idx < CreativeWinMatchConfigIds.Length ? CreativeWinMatchConfigIds[(int)idx] : CreativeWinMatchConfigIds[0]; } }