表現1
配置是標准,休閑模式
然后一直重復提示
select desire deck
select causal mode
表現2
配置是狂野,休閑模式
然后一直提示
切換到狂野
切換到標准
把模式切換到auto好像就可以了
[QuestPlus] You don't have the deck name 'sqs' for the class 'PALADIN'. Please correct this DeckName or re-Cache Custom Decks.
在default bot頁面勾選,重新cache卡組
后面觀察發現,設置Mode為Ranked,設置RuleSet為Standard。也可以正常工作,雖然最后是在狂野,休閑模式下打的。
這樣的話,只會在排名模式下運行。
切換到休閑模式的話,在上面的模式運行的過程中,切換模式到休閑。
等游戲結束,或者自己stop,然后手動投降。下一局開始的時候,還是不行。
開始之后,會一直提示,不管,直接再把模式改為ranked,然后就會在休閑模式打了。
查看完整的啟動流程
[Start] Now creating the BotThread.
[Stats] Start
Load settings for Control
current alpha is 0.5
set enemy-face-hp to: 15
set weaponOnlyAttackMobsUntilEnfacehp to: 0
set maxwide to: 3000
calculate the second turn of the 0 best boards
playing arround secrets is true
Control settings are loaded.
[Combo] Load combos for Control
read _combo.txt...
[Combo] 0 combos loaded successfully, 0 values loaded successfully
[RulesEngine] _rules.txt - read error. We continue without user-defined rules. Only the default rules.
[CollectionManagerScene]
[CollectionManagerScene_COLLECTION]
[CollectionManagerScene_COLLECTION] Waiting to be in this state longer.
[CollectionManagerScene]
[CollectionManagerScene_COLLECTION]
[CollectionManagerScene_COLLECTION] We have the contents of this deck already.
[DefaultBotSettings] NeedsToCacheCustomDecks = False.
[CollectionManagerScene]
[CollectionManagerScene_COLLECTION]
[CollectionManagerScene_COLLECTION] Waiting to be in this state longer.
[CollectionManagerScene]
[CollectionManagerScene_COLLECTION]
[CollectionManagerScene_COLLECTION] We do not need to cache custom decks. Now leaving the "Collection Manager".
[IsClientInUsableState] SceneMgr.IsTransitioning.
[HubScene]
[HubScene] The bot needs to cache quests. Now clicking on the "Quest Log" button.
[HubScene]
[HandleQuests]
[GameEventManagerOnQuestUpdate]
[GameEventManagerOnQuestUpdate][1176]正義凜然: 使用20張聖騎士職業牌。 (3 / 20) [50x GOLD]
[GameEventManagerOnQuestUpdate][2420]火焰節快樂!: 使用30張卡牌。 (6 / 30) [1x BOOSTER_PACK]
[HubScene] Now clicking to close the "Quest Log" screen.
[DefaultBotSettings] NeedsToCacheQuests = False.
[HubScene]
[HubScene] Now clicking on the "Play" button.
[IsClientInUsableState] SceneMgr.IsTransitioning.
[IsClientInUsableState] !SceneMgr.IsSceneLoaded.
[IsClientInUsableState] !SceneMgr.IsSceneLoaded.
[IsClientInUsableState] Box.IsBusy.
[TournamentScene]
從這里開始,就一直在切換狂野和休閑模式
[TournamentScene_DeckPicker] Now changing the game ruleset to 'Wild'.
[TournamentScene]
[TournamentScene_DeckPicker] Now changing the game ruleset to 'Wild'.
[TournamentScene]
[TournamentScene_DeckPicker] Now changing the game ruleset to 'Wild'.
[Stop] Now requesting the BotThread to stop.
[Stats] Stop
[DefaultBotSettings] ForceConcedeAtMulligan = False.
在源碼中搜索Assembly-Csharper中搜索TournamentScene找到一個叫DefaultBot的類,
[TournamentScene_DeckPicker] Now changing the game ruleset
在類里面搜索ruleset
else if (DefaultBotSettings.Instance.ConstructedGameRule == GameRule.Wild) { if (!@bool) { flag = true; DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now changing the game ruleset to 'Wild'.", Array.Empty<object>()); } }
方法是method_49
private async Task method_49(TournamentScene tournamentScene_0) { if (DefaultBotSettings.Instance.ClientBackAttempts >= 5) { DefaultBot.ilog_0.ErrorFormat("[TournamentScene_DeckPicker] The client has been detected to be in a broken state. Please restart it as soon as possible as it cannot leave the current scene.", Array.Empty<object>()); DefaultBotSettings.Instance.ClientBroken = true; } GameEventManager.Instance.method_6(); await Coroutine.Yield(); if (!DefaultBotSettings.Instance.ClientBroken && (DefaultBotSettings.Instance.NeedsToCacheQuests || DefaultBotSettings.Instance.NeedsToCacheCustomDecks)) { DefaultBotSettings.Instance.ClientBackAttempts++; DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now returning to the Hub to cache quests/decks.", Array.Empty<object>()); TaskAwaiter taskAwaiter = this.method_50(tournamentScene_0).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; TaskAwaiter taskAwaiter2; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } else { GameEventManager.Instance.method_7(); TaskAwaiter taskAwaiter = Coroutine.Yield().GetAwaiter(); TaskAwaiter taskAwaiter2; if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); if (DefaultBotSettings.Instance.GameMode != GameMode.Constructed) { if (DefaultBotSettings.Instance.ClientBroken) { BotManager.Stop(); DefaultBot.ilog_0.ErrorFormat("[TournamentScene_DeckPicker] Your client needs to be restarted before continuing.", Array.Empty<object>()); taskAwaiter = Coroutine.Yield().GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } else { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now returning to the Hub to change the game type.", Array.Empty<object>()); taskAwaiter = this.method_50(tournamentScene_0).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } } else { DeckPickerTrayDisplay deckPickerTrayDisplay = DeckPickerTrayDisplay.Get(); if (deckPickerTrayDisplay == null) { DefaultBot.ilog_0.DebugFormat("[TournamentScene_DeckPicker] DeckPickerTrayDisplay is null", Array.Empty<object>()); } else if (!deckPickerTrayDisplay.IsLoaded()) { DefaultBot.ilog_0.DebugFormat("[TournamentScene_DeckPicker] !DeckPickerTrayDisplay.IsLoaded", Array.Empty<object>()); } else if (string.IsNullOrEmpty(DefaultBotSettings.Instance.ConstructedCustomDeck)) { DefaultBot.ilog_0.ErrorFormat("[TournamentScene_DeckPicker] Please type a name for ConstructedCustomDeck!", Array.Empty<object>()); BotManager.Stop(); taskAwaiter = Coroutine.Yield().GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } else { bool @bool = Options.Get().GetBool(Option.IN_WILD_MODE); bool flag = false; if (DefaultBotSettings.Instance.ConstructedGameRule == GameRule.Auto) { CustomDeckCache customDeckCache = MainSettings.Instance.CustomDecks.FirstOrDefault(new Func<CustomDeckCache, bool>(DefaultBot.Class224.<>9.method_2)); if (customDeckCache != null) { if (customDeckCache.IsWild) { if (!@bool) { flag = true; } } else if (@bool) { flag = true; } } } else if (DefaultBotSettings.Instance.ConstructedGameRule == GameRule.Wild) { if (!@bool) { flag = true; DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now changing the game ruleset to 'Wild'.", Array.Empty<object>()); } } else { if (DefaultBotSettings.Instance.ConstructedGameRule != GameRule.Standard) { DefaultBot.ilog_0.ErrorFormat("[TournamentScene_DeckPicker] Unprocessed ConstructedGameRule: {0}.", DefaultBotSettings.Instance.ConstructedGameRule); BotManager.Stop(); taskAwaiter = Coroutine.Yield().GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); return; } if (@bool) { flag = true; DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now changing the game ruleset to 'Standard'.", Array.Empty<object>()); } } if (flag) { Client.LeftClickAt(deckPickerTrayDisplay.m_switchFormatButton.Transform.Position); taskAwaiter = Coroutine.Sleep(1500).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } else { List<CustomDeckPage> customPages = deckPickerTrayDisplay.m_customPages; if (customPages != null) { using (List<CustomDeckPage>.Enumerator enumerator = customPages.GetEnumerator()) { while (enumerator.MoveNext()) { if (!enumerator.Current.AreAllCustomDecksReady()) { DefaultBot.ilog_0.DebugFormat("[TournamentScene_DeckPicker] !AreAllCustomDecksReady", Array.Empty<object>()); await Coroutine.Sleep(1000); return; } } } List<CustomDeckPage>.Enumerator enumerator = default(List<CustomDeckPage>.Enumerator); DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now attempting to select the desired custom deck.", Array.Empty<object>()); if (!(await DefaultBot.smethod_5("TournamentScene_DeckPicker", deckPickerTrayDisplay.m_selectedCustomDeckBox, customPages, deckPickerTrayDisplay, DefaultBotSettings.Instance.ConstructedCustomDeck))) { DefaultBotSettings.Instance.NeedsToCacheQuests = true; return; } } else { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now attempting to select the desired basic deck.", Array.Empty<object>()); TaskAwaiter<bool> taskAwaiter3 = DefaultBot.smethod_4("TournamentScene_DeckPicker", deckPickerTrayDisplay.m_selectedHeroButton, deckPickerTrayDisplay.m_heroButtons, deckPickerTrayDisplay, DefaultBotSettings.Instance.ConstructedCustomDeck).GetAwaiter(); if (!taskAwaiter3.IsCompleted) { await taskAwaiter3; TaskAwaiter<bool> taskAwaiter4; taskAwaiter3 = taskAwaiter4; taskAwaiter4 = default(TaskAwaiter<bool>); } bool result = taskAwaiter3.GetResult(); taskAwaiter3 = default(TaskAwaiter<bool>); if (!result) { DefaultBotSettings.Instance.NeedsToCacheQuests = true; return; } } if (deckPickerTrayDisplay.m_rankedPlayButtons == null) { DefaultBot.ilog_0.DebugFormat("[TournamentScene_DeckPicker] DeckPickerTrayDisplay.m_rankedPlayButtons == null.", Array.Empty<object>()); } else { bool bool2 = Options.Get().GetBool(Option.IN_RANKED_PLAY_MODE); if (DefaultBotSettings.Instance.ConstructedMode == ConstructedMode.Casual) { if (bool2) { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now changing to \"Casual\" constructed.", Array.Empty<object>()); Client.LeftClickAt(deckPickerTrayDisplay.m_rankedPlayButtons.m_casualButton.Transform.Position); taskAwaiter = Coroutine.Sleep(1500).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); return; } } else { if (DefaultBotSettings.Instance.ConstructedMode != ConstructedMode.Ranked) { DefaultBot.ilog_0.ErrorFormat("[TournamentScene_DeckPicker] Unprocessed ConstructedMode: {0}.", DefaultBotSettings.Instance.ConstructedMode); BotManager.Stop(); taskAwaiter = Coroutine.Yield().GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); return; } if (!bool2) { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now changing to \"Ranked\" constructed.", Array.Empty<object>()); Client.LeftClickAt(deckPickerTrayDisplay.m_rankedPlayButtons.m_rankedButton.Transform.Position); taskAwaiter = Coroutine.Sleep(1500).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); return; } } DefaultBotSettings.Instance.ClientBackAttempts = 0; TransitionPopup transitionPopup = GameMgr.Get().m_transitionPopup; if (transitionPopup != null && transitionPopup.IsShown()) { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] The \"Matching\" popup is showing.", Array.Empty<object>()); taskAwaiter = Coroutine.Sleep(1000).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } else { PlayButton playButton = deckPickerTrayDisplay.m_playButton; UberText newPlayButtonText = playButton.m_newPlayButtonText; if (!playButton.IsEnabled()) { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] The \"{0}\" is not enabled.", newPlayButtonText.Text); } else { UberText newPlayButtonText2 = playButton.m_newPlayButtonText; Vector3 center = newPlayButtonText2.m_TextMeshGameObject.Renderer.Bounds.m_Center; DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now clicking the \"{0}\" button.", newPlayButtonText2.Text); Client.LeftClickAt(center); taskAwaiter = Coroutine.Sleep(3000).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } } } } } } } }
analyze
Triton.Bot.Logic.Bots.DefaultBot.DefaultBot.method_49(TournamentScene) : Task @060013A0
Used By
Triton.Bot.Logic.Bots.DefaultBot.DefaultBot.method_48(TournamentScene) : Task @0600139F
Used By
Triton.Bot.Logic.Bots.DefaultBot.DefaultBot.method_21() : Task @06001384
Used By
Triton.Bot.Logic.Bots.DefaultBot.DefaultBot.method_17() : void @0600137D
Triton.Bot.Logic.Bots.DefaultBot.DefaultBot.Start() : void @0600137A
從DefaultBot.method_17()開始的調用
private void method_17() { this.coroutine_0.Dispose(); this.coroutine_0 = new Coroutine(new Func<Task>(this.method_54)); }
[CompilerGenerated] private Task method_54() { return this.method_21(); }
從DefaultBot.Start()開始的調用
public void Start() { this.coroutine_0 = new Coroutine(new Func<Task>(this.method_53)); this.bool_2 = false; GameEventManager.Instance.Start(); PluginManager.Start(); RoutineManager.Start(); ProcessHookManager.Enable(); GameEventManager.NewGame += this.method_18; GameEventManager.GameOver += this.method_19; GameEventManager.MulliganConfirm += this.method_16; InactivePlayerKicker inactivePlayerKicker = InactivePlayerKicker.Get(); if (inactivePlayerKicker != null) { inactivePlayerKicker.SetShouldCheckForInactivity(false); } }
[CompilerGenerated] private Task method_53() { return this.method_21(); }
從DefaultBot.method_21()開始的調用
private Task method_21() { DefaultBot.Struct60 @struct; @struct.defaultBot_0 = this; @struct.asyncTaskMethodBuilder_0 = AsyncTaskMethodBuilder.Create(); @struct.int_0 = -1; AsyncTaskMethodBuilder asyncTaskMethodBuilder_ = @struct.asyncTaskMethodBuilder_0; asyncTaskMethodBuilder_.Start<DefaultBot.Struct60>(ref @struct); return @struct.asyncTaskMethodBuilder_0.Task; }
不太明白method_21是怎么調用method_48的,查看代碼的話,只是使用了this。
查看DefaultBot的類,發現有繼承關系
public class DefaultBot : IRunnable, IAuthored, IBase, IBot, IConfigurable
猜測是因為繼承了IRunnable,所以還有其他邏輯在進行啟動
public interface IRunnable { // Token: 0x06001162 RID: 4450 void Start(); // Token: 0x06001163 RID: 4451 void Tick(); // Token: 0x06001164 RID: 4452 void Stop(); }
可以考慮查看start方法,usedby哪些類
AsyncTaskMethodBuilder在這里的使用,說明源碼里面使用了async關鍵字進行異步編程,
可以看下面這篇文章里面的分析
C# Under the Hood: async/await
ILSpy好像可以正常反編譯async
https://github.com/0xd4d/dnSpy/issues/687#issuecomment-354990427
await
is just synthetic sugar for what you see in the decompiled code. Usually ILSpy converts this back to what a programmer would normally write, but the version that dnSpy uses didn't have that implemented yet. You can find all implemented language features for the latest version of ILSpy here, but keep in mind that dnSpy still uses ILSpy 2.x, not 3.x.
奇怪的是,上面的method_49是正常識別了async的語法的,不知道為什么method_21無法識別
private async Task method_48(TournamentScene tournamentScene_0) { DefaultBot.ilog_0.InfoFormat("[TournamentScene]", Array.Empty<object>()); if (!tournamentScene_0.IsLoaded()) { DefaultBot.ilog_0.DebugFormat("[TournamentScene] !TournamentScene.IsLoaded.", Array.Empty<object>()); } else if (!tournamentScene_0.m_deckPickerIsLoaded) { DefaultBot.ilog_0.DebugFormat("[TournamentScene] !m_deckPickerIsLoaded.", Array.Empty<object>()); } else { PresenceMgr presenceMgr = PresenceMgr.Get(); if (presenceMgr == null) { DefaultBot.ilog_0.DebugFormat("[TournamentScene] PresenceMgr is null.", Array.Empty<object>()); } else { List<MonoEnum> statusEnums = presenceMgr.GetStatusEnums(BnetPresenceMgr.Get().GetMyPlayer()); if (statusEnums != null && statusEnums.Count != 0) { foreach (MonoEnum monoEnum in statusEnums) { PresenceStatus presenceStatus = monoEnum.AsEnum<PresenceStatus>(); TritonHs.smethod_4(presenceMgr, ref presenceStatus); if (presenceStatus == PresenceStatus.PLAY_DECKPICKER) { TaskAwaiter taskAwaiter = this.method_49(tournamentScene_0).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; TaskAwaiter taskAwaiter2; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } else if (presenceStatus == PresenceStatus.PLAY_QUEUE) { TaskAwaiter taskAwaiter = this.method_51(tournamentScene_0).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; TaskAwaiter taskAwaiter2; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } else { TaskAwaiter taskAwaiter; TaskAwaiter taskAwaiter2; if (presenceStatus != PresenceStatus.HUB) { DefaultBot.ilog_0.ErrorFormat("[TournamentScene] Unhandled presence status detected: {0}. Please restart your client and try again. If the error is still not fixed, please report this message.", monoEnum); BotManager.Stop(); taskAwaiter = Coroutine.Yield().GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); return; } DefaultBot.ilog_0.DebugFormat("[TournamentScene] Presence status [{0}] detected. Now waiting for it to update.", monoEnum); taskAwaiter = Coroutine.Sleep(5000).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } monoEnum = null; } List<MonoEnum>.Enumerator enumerator = default(List<MonoEnum>.Enumerator); } else { DefaultBot.ilog_0.DebugFormat("[TournamentScene] PresenceMgr.GetStatus is null or empty.", Array.Empty<object>()); } } } }
TaskAwaiter taskAwaiter = this.method_49(tournamentScene_0).GetAwaiter();
上面這段代碼,應該是調用method_49的
解決方案,在以下這段代碼中
bool @bool = Options.Get().GetBool(Option.IN_WILD_MODE);
if (flag) { Client.LeftClickAt(deckPickerTrayDisplay.m_switchFormatButton.Transform.Position); taskAwaiter = Coroutine.Sleep(1500).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } else { List<CustomDeckPage> customPages = deckPickerTrayDisplay.m_customPages; if (customPages != null) { using (List<CustomDeckPage>.Enumerator enumerator = customPages.GetEnumerator()) { while (enumerator.MoveNext()) { if (!enumerator.Current.AreAllCustomDecksReady()) { DefaultBot.ilog_0.DebugFormat("[TournamentScene_DeckPicker] !AreAllCustomDecksReady", Array.Empty<object>()); await Coroutine.Sleep(1000); return; } } } List<CustomDeckPage>.Enumerator enumerator = default(List<CustomDeckPage>.Enumerator); DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now attempting to select the desired custom deck.", Array.Empty<object>()); if (!(await DefaultBot.smethod_5("TournamentScene_DeckPicker", deckPickerTrayDisplay.m_selectedCustomDeckBox, customPages, deckPickerTrayDisplay, DefaultBotSettings.Instance.ConstructedCustomDeck))) { DefaultBotSettings.Instance.NeedsToCacheQuests = true; return; } } else { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now attempting to select the desired basic deck.", Array.Empty<object>()); TaskAwaiter<bool> taskAwaiter3 = DefaultBot.smethod_4("TournamentScene_DeckPicker", deckPickerTrayDisplay.m_selectedHeroButton, deckPickerTrayDisplay.m_heroButtons, deckPickerTrayDisplay, DefaultBotSettings.Instance.ConstructedCustomDeck).GetAwaiter(); if (!taskAwaiter3.IsCompleted) { await taskAwaiter3; TaskAwaiter<bool> taskAwaiter4; taskAwaiter3 = taskAwaiter4; taskAwaiter4 = default(TaskAwaiter<bool>); } bool result = taskAwaiter3.GetResult(); taskAwaiter3 = default(TaskAwaiter<bool>); if (!result) { DefaultBotSettings.Instance.NeedsToCacheQuests = true; return; } } if (deckPickerTrayDisplay.m_rankedPlayButtons == null) { DefaultBot.ilog_0.DebugFormat("[TournamentScene_DeckPicker] DeckPickerTrayDisplay.m_rankedPlayButtons == null.", Array.Empty<object>()); } else { bool bool2 = Options.Get().GetBool(Option.IN_RANKED_PLAY_MODE); if (DefaultBotSettings.Instance.ConstructedMode == ConstructedMode.Casual) { if (bool2) { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now changing to \"Casual\" constructed.", Array.Empty<object>()); Client.LeftClickAt(deckPickerTrayDisplay.m_rankedPlayButtons.m_casualButton.Transform.Position); taskAwaiter = Coroutine.Sleep(1500).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); return; } } else { if (DefaultBotSettings.Instance.ConstructedMode != ConstructedMode.Ranked) { DefaultBot.ilog_0.ErrorFormat("[TournamentScene_DeckPicker] Unprocessed ConstructedMode: {0}.", DefaultBotSettings.Instance.ConstructedMode); BotManager.Stop(); taskAwaiter = Coroutine.Yield().GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); return; } if (!bool2) { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now changing to \"Ranked\" constructed.", Array.Empty<object>()); Client.LeftClickAt(deckPickerTrayDisplay.m_rankedPlayButtons.m_rankedButton.Transform.Position); taskAwaiter = Coroutine.Sleep(1500).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); return; } } DefaultBotSettings.Instance.ClientBackAttempts = 0; TransitionPopup transitionPopup = GameMgr.Get().m_transitionPopup; if (transitionPopup != null && transitionPopup.IsShown()) { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] The \"Matching\" popup is showing.", Array.Empty<object>()); taskAwaiter = Coroutine.Sleep(1000).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } else { PlayButton playButton = deckPickerTrayDisplay.m_playButton; UberText newPlayButtonText = playButton.m_newPlayButtonText; if (!playButton.IsEnabled()) { DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] The \"{0}\" is not enabled.", newPlayButtonText.Text); } else { UberText newPlayButtonText2 = playButton.m_newPlayButtonText; Vector3 center = newPlayButtonText2.m_TextMeshGameObject.Renderer.Bounds.m_Center; DefaultBot.ilog_0.InfoFormat("[TournamentScene_DeckPicker] Now clicking the \"{0}\" button.", newPlayButtonText2.Text); Client.LeftClickAt(center); taskAwaiter = Coroutine.Sleep(3000).GetAwaiter(); if (!taskAwaiter.IsCompleted) { await taskAwaiter; taskAwaiter = taskAwaiter2; taskAwaiter2 = default(TaskAwaiter); } taskAwaiter.GetResult(); taskAwaiter = default(TaskAwaiter); } } } }
最終定位,發現問題出在bool @bool = Options.Get().GetBool(Option.IN_WILD_MODE);上
Assembly-CSharp中的Option枚舉,已經擴展了。原來的順序被打亂了。
enum在c#中,默認從0開始。
將Assembly-CSharp中的Option和兄弟里的Option復制出來,然后打印in_wild_mode的值。
新版本是0xC0,也就是192
舊版本是0xAE,也就是174
嘗試直接替換兄弟里面的Option,然后發現保存的代碼上面的代碼變成了很奇怪的模式。
bool @bool = Options.Get().GetBool(Option.HAS_STARTED_A_DECK);
嘗試打印之前代碼中的in_wild_mode的數值,映射到新版本的枚舉,很尷尬,發現映射出來的是HAS_STARTED_A_DECK。
Option option = (Option)Enum.ToObject(typeof(Option), 0xAE); Console.WriteLine(option);
最好的解決方案,應該是通過字符串去解析一個枚舉出來。
Option option2 = (Option) Enum.Parse(typeof(Option), "IN_WILD_MODE"); Console.WriteLine(option2);
另外一個映射也出問題了,
bool bool2 = Options.Get().GetBool(Option.IN_RANKED_PLAY_MODE);
修改為
bool bool2 = Options.Get().GetBool(Option.HAS_SEEN_FORGE_2LOSS);
新版0x99對應153
舊版0x87對應135
使用ILSpy配合 reflexil
https://www.cnblogs.com/chucklu/p/11334424.html
https://github.com/ChuckHearthstone/SilverFish/blob/master/MonoTest/EnumTest/OptionTest.cs
1.ILSpy取消反編譯async methods,
2.然后找到method_49,
3.轉到struct88的定義。
[AsyncStateMachine(typeof(Struct88))] private Task method_49(TournamentScene tournamentScene_0) { AsyncTaskMethodBuilder asyncTaskMethodBuilder_0 = AsyncTaskMethodBuilder.Create(); int int_0 = -1; AsyncTaskMethodBuilder asyncTaskMethodBuilder = asyncTaskMethodBuilder_0; Struct88 stateMachine = default(Struct88); asyncTaskMethodBuilder.Start(ref stateMachine); return asyncTaskMethodBuilder_0.Task; }
找到struct88的move next方法,然后按照如下方式修改
找到Options.Get和GetBool,然后把中間的174換成新的192
135換成153
2020年03月18日更新
Option option2 = (Option)Enum.Parse(typeof(Option), "IN_WILD_MODE");
Console.WriteLine((int)option2);//199
Option option2 = (Option)Enum.Parse(typeof(Option), "IN_RANKED_PLAY_MODE");
Console.WriteLine((int)option2);//160