HearthBuddy的狂野和休闲模式来回切换
表现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 >= )
{
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.<>.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().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();
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().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().GetAwaiter();
if (!taskAwaiter.IsCompleted)
{
await taskAwaiter;
taskAwaiter = taskAwaiter2;
taskAwaiter2 = default(TaskAwaiter);
}
taskAwaiter.GetResult();
taskAwaiter = default(TaskAwaiter);
return;
}
}
DefaultBotSettings.Instance.ClientBackAttempts = ;
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().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().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 = -;
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 != )
{
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().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().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();
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().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().GetAwaiter();
if (!taskAwaiter.IsCompleted)
{
await taskAwaiter;
taskAwaiter = taskAwaiter2;
taskAwaiter2 = default(TaskAwaiter);
}
taskAwaiter.GetResult();
taskAwaiter = default(TaskAwaiter);
return;
}
}
DefaultBotSettings.Instance.ClientBackAttempts = ;
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().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().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
ILSpy取消反编译async methods,然后找到method_49,转到struct88的定义。
找到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
HearthBuddy的狂野和休闲模式来回切换的更多相关文章
- Fragment碎片频繁来回切换的时候报java.lang.IllegalStateException: No activity
出现这个问题的原因是因为使用的transcation.replace(fragmentTwo);的方式进行碎片切换的. 解决方案是使用add和show.hide方法组合实现碎片的切换(应该是显示.隐藏 ...
- CentOS下命令行和桌面模式的切换方法(转载)
桌面模式和命令行模式的切换方法 用编辑器打开 /etc/inittab 文件(这里用的是vi,你可以选择你喜欢的): #vi /etc/inittab 打开效果图如下: 桌面模式 : 把光标所在 ...
- 如何进行fragment中的来回切换?
本文选自StackOverflow(简称:SOF)精选问答汇总系列文章之一,本系列文章将为读者分享国外最优质的精彩问与答,供读者学习和了解国外最新技术,本文为大家讲解如何进行fragment中的来回切 ...
- 关于含RecyclerView的fragment来回切换时页面自动滑动到底部的解决方法
原因: 在fragment中来回切换时RecyclerView获得了焦点,而RecyclerView的 focusableOnTouchMode属性默认是true,所以在切换时RecyclerView ...
- (17/24) webpack实战技巧:生产环境和开发环境并行设置,实现来回切换
1. 概述 生产环境和开发环境所需依赖是不同: --开发依赖:就是开发中用到而发布时用不到的.在package.json里面对应的就是devDependencies下面相关配置. --生产依赖: 就是 ...
- CoreAudio实现录音播音和扬声器听筒模式的切换
本例子使用Core Audio实现类似于微信的音频对讲功能,可以录音和播放并且实现了听筒模式和扬声器模式的切换.录音主要使用AVAudioRecorder类来实现录音功能,播放则使用AVAudioPl ...
- WPF两个按钮来回切换样式
<!-- 两个按钮来回切换样式 --> <Style x:Key="SwicthFunctionMetroToggleButton" TargetType=&qu ...
- jquery点击来回切换
做个笔记偶尔用有时记不住 方法一: <div id="test"> test </div> $('#test').mouseover(function () ...
- RENIX板卡V2-100G系列工作模式速率切换——网络测试仪实操
本文主要介绍了RENIX板卡V2-100G系列工作模式速率切换相关操作.全文分为五部分内容.文章开头对V2-100G系列板卡进行了概述,之后分别详细介绍了100G工作模式.40G工作模式.25G工作模 ...
随机推荐
- 上述代码在JavaScript事件处理中
上述代码在JavaScript事件处理中很常见,主要设置为与旧版本的Internet Explorer(主要在IE9之前)兼容,因为旧版本的IE不支持标准的W3C事件处理规范. 此代码中的e表示事件对 ...
- IPC之mq_sysctl.c源码解读
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2007 IBM Corporation * * Author: Cedric ...
- zencart分类页每页显示产品数量自定义选择的方法
zencart默认分类页每页显示产品数量是固定的,如何让顾客可以选择每页显示的产品的数量呢?效果图 方式一:全部展示 方式二:下拉菜单 修改方法 1.导入sql INSERT INTO configu ...
- golang-vue实现微信小程序分享到朋友圈
最近涉及到微信小程序分享到朋友圈,不知道微信为什么不直接接口分享,咱也不敢佛,咱也不敢问,只能百度问度娘,看官方文档,网上的一些分享五花八门,每一个重点的,所以整理了一下到底怎样生成二维码分享图片才是 ...
- 异步IO框架:asyncio 中篇
上一节我们首先介绍了,如何创建一个协程对象.主要有两种方法 通过async关键字, 通过@asyncio.coroutine 装饰函数. 然后有了协程对象,就需要一个事件循环容器来运行我们的协程.其主 ...
- Tampermonkey油猴脚本管理插件-最强浏览器插件的安装使用全攻略
对于接触过谷歌浏览器插件的“玩家”们来说,应该没有人没听说过Tampermonkey用户脚本管理器,也就是中文所说的“油猴”这个chrome插件了. 油猴号称全商店最强的浏览器插件绝非浪得虚名,一 ...
- BZOJ2144 跳跳棋[建模+LCA]
思维题,思路比较神仙. 个人思路过程:个人只想到了只要中间棋子开始向外跳了,以后就不应该向内跳了,这样很蠢.所以应该要么先向内跳一会,要么直接开始中间的向外跳.不知道怎么处理,就卡住了. 20pts: ...
- zeromq实践
zeromq简介 zeroMQ不是TCP,不是socket,也不是消息队列,而是这些的综合体. ZeroMQ以嵌入式网络编程库的形式实现了一个并行开发框架(concurrency framework) ...
- Linux配置python环境2,安装python
安装锁需要的依赖包 sudo apt-get -y install gcc-5 g++-5 libc6-dev make build-essential libssl-dev zlib1g-dev l ...
- countif函数
EXCEL单元格内数据主要有以下几类:数值型,文本型,逻辑型,错误值型.其中时间类型也是一种特殊的数值.文本类型的数字是文本型. 空单元格:指什么内容也没有的单元格,姑且称之为真空. 假空单元格:指0 ...