[CollectionManagerScene_COLLECTION] An exception occurred when calling CacheCustomDecks: System.MissingMethodException: Method 'CollectionDeckBoxVisual.string_4 = IsValid, enum20_0 = null' not found.
at Triton.Game.Mono.MonoClass.method_7(String string_4, Enum20[] enum20_0, Object[] object_0)
at Triton.Game.Mono.MonoClass.method_10[T](String string_4, Enum20[] enum20_0, Object[] object_0)
at Triton.Game.Mono.MonoClass.method_11[T](String string_4, Object[] object_0)
at Triton.Game.Mapping.CollectionDeckBoxVisual.IsValid()
at Triton.Bot.Utility.smethod_4()
at Triton.Bot.Logic.Bots.DefaultBot.DefaultBot.Struct57.MoveNext().

internal static void smethod_4()
{
try
{
CollectionDeckTray collectionDeckTray = CollectionDeckTray.Get();
if (collectionDeckTray != null)
{
foreach (TraySection traySection in collectionDeckTray.m_decksContent.m_traySections)
{
CollectionDeckBoxVisual deckBox = traySection.m_deckBox;
long deckID = deckBox.GetDeckID();
string text = deckBox.m_deckName.Text;
bool isWild = deckBox.m_isWild;
if (deckID != -1L && deckBox.IsValid())
{
CustomDeckCache customDeckCache = null;
bool flag = true;
foreach (CustomDeckCache customDeckCache2 in MainSettings.Instance.CustomDecks)
{
if (customDeckCache2.DeckId == deckID)
{
customDeckCache = customDeckCache2;
customDeckCache.Name = text;
customDeckCache.IsWild = isWild;
customDeckCache.Save();
flag = false;
break;
}
}
if (customDeckCache == null)
{
customDeckCache = new CustomDeckCache(deckID)
{
DeckId = deckID,
HeroCardId = deckBox.m_heroCardID,
Name = deckBox.GetDeckNameText().Text,
IsWild = isWild
};
}
CollectionDeck deck = CollectionManager.Get().GetDeck(deckID);
if (!deck.m_netContentsLoaded)
{
if (customDeckCache.CardIds.Count == && flag)
{
MainSettings.Instance.CustomDecks.Add(customDeckCache);
}
}
else
{
customDeckCache.CardIds.Clear();
foreach (CollectionDeckSlot collectionDeckSlot in deck.m_slots)
{
for (int i = ; i < collectionDeckSlot.Count; i++)
{
customDeckCache.CardIds.Add(collectionDeckSlot.CardID);
}
}
customDeckCache.Save();
if (flag)
{
MainSettings.Instance.CustomDecks.Add(customDeckCache);
MainSettings.Instance.Save();
}
}
}
}
}
}
catch (Exception)
{
MainSettings.Instance.CustomDecks.Clear();
MainSettings.Instance.Save();
throw;
}
}
public bool IsValid()
{
return base.method_11<bool>("IsValid", Array.Empty<object>());
}

public class CollectionDeckBoxVisual自己在调用

public long GetDeckID()
{
return base.method_11<long>("GetDeckID", Array.Empty<object>());
}
internal T method_11<T>(string string_4, params object[] object_0) where T : struct
{
return this.method_10<T>(string_4, null, object_0);
}
internal T method_10<T>(string string_4, Class276.Enum20[] enum20_0, params object[] object_0) where T : struct
{
IntPtr intPtr = this.method_7(string_4, enum20_0, object_0);
if (intPtr == IntPtr.Zero)
{
return default(T);
}
if (typeof(T) == typeof(bool))
{
IntPtr addr = MonoClass.Class276_0.method_26(intPtr);
return (T)((object)(MonoClass.ExternalProcessMemory_0.Read<byte>(addr) > ));
}
return MonoClass.ExternalProcessMemory_0.Read<T>(MonoClass.Class276_0.method_26(intPtr));
}
internal IntPtr method_7(string string_4, Class276.Enum20[] enum20_0, params object[] object_0)
{
IntPtr classInstance = this.GetClassInstance();
if (classInstance == IntPtr.Zero)
{
throw new Exception("Cannot call a method on an object instance that has no address!");
}
IntPtr intPtr = this.method_0(string_4, enum20_0);
if (intPtr == IntPtr.Zero)
{
string text = string.Empty;
if (enum20_0 != null)
{
for (int i = ; i < enum20_0.Length; i++)
{
text += enum20_0[i];
}
}
else
{
text = "null";
}
throw new MissingMethodException(this.ClassName, "string_4 = " + string_4 + ", enum20_0 = " + text);
}
return MonoClass.Class276_0.method_43(intPtr, classInstance, object_0);
}
internal IntPtr method_0(string string_4, Class276.Enum20[] enum20_0)
{
if (this.IntPtr_0 == IntPtr.Zero)
{
throw new InvalidOperationException("Cannot get a method pointer on an object that has no MonoClass pointer.");
}
return MonoClass.smethod_4(this.IntPtr_0, string_4, enum20_0);
}

这个里面的this,应该某一个class的IntPtr_0

internal IntPtr IntPtr_0
{
get
{
IntPtr? intPtr = this.nullable_0;
if (intPtr == null)
{
IntPtr? intPtr2 = this.nullable_0 = new IntPtr?(this.vmethod_0(this.AssemblyPath, this.ClassNamespace, this.ClassName));
return intPtr2.Value;
}
return intPtr.GetValueOrDefault();
}
}
private static IntPtr smethod_4(IntPtr intptr_1, string string_4, Class276.Enum20[] enum20_0)
{
MonoClass.Class274 @class = new MonoClass.Class274();
@class.string_0 = string_4;
@class.enum20_0 = enum20_0;
Dictionary<string, List<MonoClass.Class273>> dictionary;
if (!MonoClass.dictionary_3.TryGetValue(intptr_1, out dictionary))
{
MonoClass.dictionary_3.Add(intptr_1, new Dictionary<string, List<MonoClass.Class273>>());
dictionary = MonoClass.dictionary_3[intptr_1];
}
List<MonoClass.Class273> list;
if (!dictionary.TryGetValue(@class.string_0, out list))
{
dictionary.Add(@class.string_0, new List<MonoClass.Class273>());
list = dictionary[@class.string_0];
}
MonoClass.Class273 class2 = list.FirstOrDefault(new Func<MonoClass.Class273, bool>(@class.method_0));
if (class2 == null)
{
IntPtr intPtr = MonoClass.Class276_0.method_33(intptr_1, @class.string_0, @class.enum20_0);
if (intPtr != IntPtr.Zero)
{
class2 = new MonoClass.Class273(@class.string_0, intPtr, @class.enum20_0);
list.Add(class2);
}
}
if (class2 == null)
{
return IntPtr.Zero;
}
return class2.IntPtr_0;
}

这里的intptr_1是上面的类的

下面有一个很奇怪的写法,赋值之后,还可以直接做比较

 int a = ;
if ((a = ) > )
{
Console.WriteLine(a);
}
internal IntPtr method_33(IntPtr intptr_37, string string_0, params Class276.Enum20[] enum20_0)
{
while (intptr_37 != IntPtr.Zero)
{
using (AllocatedMemory allocatedMemory = this.externalProcessMemory_0.CreateAllocatedMemory())
{
allocatedMemory.AllocateOfChunk<IntPtr>("Itr");
IntPtr intPtr;
while ((intPtr = this.method_35(intptr_37, allocatedMemory["Itr"])) != IntPtr.Zero)
{
IntPtr address = this.method_37(intPtr);
if (this.externalProcessMemory_0.ReadStringA(address) == string_0)
{
if (enum20_0 != null)
{
Class276.Enum20[] array = this.method_31(intPtr);
if (array.Length != enum20_0.Length || !array.SequenceEqual(enum20_0))
{
continue;
}
}
return intPtr;
}
}
intptr_37 = this.method_25(intptr_37);
}
}
return IntPtr.Zero;
}

有2个while循环

第一个循环,是传入的intptr_37不为IntPtr.Zero【这里的intptr_37就是类开始的地址】

     基于externalProcessMemory_0分配256的内存

     256的内存里面,分配一个内存chunk

     intPtr = method_35(intptr_37,新分配的内存chunk)

第二个循环内部

        [intPtr = method_35(intptr_37,新分配的内存chunk)]  这个在下一次循环的时候会再做一次

        address = method_37(intPtr);

用externalProcessMemory_0.ReadStringA(address)读取方法名

判断方法名是否匹配,如果匹配,就返回intPtr;否则回到第二个循环

     第二个循环结束,还没有找到符合要求的,

会执行intptr_37 = this.method_25(intptr_37);

第一个循环

1.  重新分配内存chunk

2.  第二个循环

3.  method25修改intptr_37的值

其中1和3的的修改,是为了在第二个循环中使用

internal IntPtr method_25(IntPtr intptr_37)
{
return this.method_17<IntPtr>(this.intptr_28, new object[]
{
intptr_37
});
}

+ intptr_0 0x10000000 System.IntPtr

+ intptr_28 0x100165A7 System.IntPtr   和intptr_0相比,相差0x165A7,也就是‭91559‬

这里的第二个参数,只传了intptr_37

private T method_17<T>(IntPtr intptr_37, params object[] object_0) where T : struct
{
return this.externalProcessMemory_0.CallInjected<T>(intptr_37, CallingConvention.Cdecl, object_0);
}

private readonly ExternalProcessMemory externalProcessMemory_0;

public class ExternalProcessMemory : MemoryBase  这个类在C#写的GreyMagic里面

第二个循环

1. intPtr = method_35(intptr_37,新分配的内存chunk)

(intPtr = this.method_35(intptr_37, allocatedMemory["Itr"])

这里虽然2个参数没变,但是执行后的返回结果一直在变

2. address = method_37(intPtr);

3. 读取方法名,看是否匹配

this.externalProcessMemory_0.ReadStringA(address)

注意,在第二个循环里面intptr_37的不会变化的,然后是address在变 。不太清楚allocatedMemory["Itr"]是否会变化

internal IntPtr method_35(IntPtr intptr_37, IntPtr intptr_38)
{
return this.method_17<IntPtr>(this.intptr_19, new object[]
{
intptr_37,
intptr_38
});
}

第一个参数是this.intptr_19 = this.intptr_0 + 120353;    intptr_0 是mono.dll的地址

第二个参数指针数组传递了2个地址,intptr_37和intptr_38。 intptr_37是类开始的地址,intptr_38是新分配的内存chunk

这里计算的返回结果,会作为method_37的第一个参数。第二个参数指针数组传递的值一直没变,但是返回结果一直在变。

internal IntPtr method_37(IntPtr intPtr )
{
return this.method_17<IntPtr>(this.intptr_21, new object[]
{
intPtr 
});
}

这里第一个参数是this.intptr_21 = this.intptr_0 + 231261;

第二个参数,指针数组只传递了一个地址intPtr 。 这个地址是intPtr = method_35(intptr_37,新分配的内存chunk)

这个方法调用后,是为了拿到方法名的地址,根据地址读出方法名

private T method_17<T>(IntPtr intptr_37, params object[] object_0) where T : struct
{
return this.externalProcessMemory_0.CallInjected<T>(intptr_37, CallingConvention.Cdecl, object_0);
}

第二个循环,对于类的执行结果如下

+ intptr_37 0x0AD14698 System.IntPtr
+ allocatedMemory["Itr"] 0x03430000 System.IntPtr
+ intPtr 0x0AFC00A0 System.IntPtr
+ address 0x0BCC9A22 System.IntPtr
this.externalProcessMemory_0.ReadStringA(address) ".ctor" string

+ intptr_37 0x0AD14698 System.IntPtr
+ allocatedMemory["Itr"] 0x03430000 System.IntPtr
+ intPtr 0x0AFC00C0 System.IntPtr
+ address 0x0BD05E38 System.IntPtr
this.externalProcessMemory_0.ReadStringA(address) "get_SCALED_UP_LOCAL_SCALE" string

+ intptr_37 0x0AD14698 System.IntPtr
+ allocatedMemory["Itr"] 0x03430000 System.IntPtr
+ intPtr 0x0AFCE148 System.IntPtr
+ address 0x0BD05E52 System.IntPtr
this.externalProcessMemory_0.ReadStringA(address) "set_SCALED_UP_LOCAL_SCALE" string

+ intptr_37 0x0AD14698 System.IntPtr
+ allocatedMemory["Itr"] 0x03430000 System.IntPtr
+ intPtr 0x0AFBFDF8 System.IntPtr
+ address 0x0BCF8FDF System.IntPtr
this.externalProcessMemory_0.ReadStringA(address) "Awake" string

+ intptr_37 0x0AD14698 System.IntPtr
+ allocatedMemory["Itr"] 0x03430000 System.IntPtr
+ intPtr 0x0AFCE168 System.IntPtr
+ address 0x0BC6668E System.IntPtr
this.externalProcessMemory_0.ReadStringA(address) "Update" string

+ intptr_37 0x0AD14698 System.IntPtr
+ allocatedMemory["Itr"] 0x03430000 System.IntPtr
+ intPtr 0x0AFCE188 System.IntPtr
+ address 0x0BCF9174 System.IntPtr
this.externalProcessMemory_0.ReadStringA(address) "Show" string

+ intptr_37 0x0AD14698 System.IntPtr
+ allocatedMemory["Itr"] 0x03430000 System.IntPtr
+ intPtr 0x0AFCE1A8 System.IntPtr
+ address 0x0BCBE79B System.IntPtr
this.externalProcessMemory_0.ReadStringA(address) "Hide" string

+ intptr_37 0x0AD14698 System.IntPtr
+ allocatedMemory["Itr"] 0x03430000 System.IntPtr
+ intPtr 0x0AFCE1C8 System.IntPtr
+ address 0x0BCFAB02 System.IntPtr
this.externalProcessMemory_0.ReadStringA(address) "IsShown" string

smethod_4方法的某一次返回值为  + IntPtr_0 0x0AFCE2C8 System.IntPtr,对应的方法名的GetDeckID

- class2 {Triton.Game.Mono.MonoClass.Class273} Triton.Game.Mono.MonoClass.Class273
Enum20_0 null ns27.Class276.Enum20[]
+ IntPtr_0 0x0AFCE2C8 System.IntPtr
Name "GetDeckID" string
enum20_0 null ns27.Class276.Enum20[]
+ intptr_0 0x00000000 System.IntPtr
string_0 null string

method_0方法中监视this的值,

- this {Triton.Game.Mapping.CollectionDeckBoxVisual} Triton.Game.Mono.MonoClass {Triton.Game.Mapping.CollectionDeckBoxVisual}
+ Address 0x1C995690 System.IntPtr
AssemblyPath @"C:\Program Files (x86)\Hearthstone\Hearthstone_Data\Managed\Assembly-CSharp.dll" string
ClassName "CollectionDeckBoxVisual" string

处理方案

拿到C:\Program Files (x86)\Hearthstone\Hearthstone_Data\Managed\Assembly-CSharp.dll

使用ILSpy反编译,然后搜索CollectionDeckBoxVisual,发现这个类是存在的

搜索CollectionDeckBoxVisual.IsValid,这个方法已经不在了,新的方法名字是

 public bool IsValidForCurrentMode()
{
CollectionDeck collectionDeck = GetCollectionDeck();
if (collectionDeck == null)
{
return false;
}
bool @bool = Options.Get().GetBool(Option.IN_WILD_MODE);
return collectionDeck.IsValidForRuleset && collectionDeck.IsValidForFormat(@bool);
}

所以,处理思路是,把HearthBuddy里面的IsValid改为IsValidForCurrentMode【注意这里最后是mode不是model】

HearthBuddy炉石兄弟 Method 'CollectionDeckBoxVisual.IsValid' not found.的更多相关文章

  1. HearthBuddy炉石兄弟 Method 'Entity.GetRace' not found.

    解决方案 namespace Triton.Game.Mapping{// Token: 0x020004A4 RID: 1188[Attribute38("Entity")]pu ...

  2. HearthBuddy炉石兄弟 如何调试ai

    Sepefeets's update to botmaker's Silverfish AI This AI is a Custom Class for Hearthranger and Hearth ...

  3. HearthBuddy炉石兄弟 格雷迈恩

    getDecks(); 设置 private void getDecks() { Dictionary<string, int> tmpDeck = new Dictionary<s ...

  4. 炉石兄弟 修复图腾师问题 by大神beebee102, 还有阴燃电鳗

    修复图腾师问题   beebee102 修复了先摇图腾再下图腾师的问题,另外加了阴燃电鳗的sim卡.在兄弟策略的模拟程序中测试了没问题,真机没有试过,麻烦吧友测试了回复一下.链接: [有效] http ...

  5. HearthBuddy 第一次调试

    HearthBuddy https://www.jiligame.com/70639.html 解压缩包,打开hearthbuddy.exe直接运行就可以:不用替换mono.dll直接可用:不需要校验 ...

  6. 科猫网项目总结(基于SSM框架)

    1.配置文件的添加 SSM整合需要web.xml配置文件,springmvc的配置文件,spring和mybatis整合的配置文件. 1.web.xml文件的配置 1.在WEB-INF下新建web.x ...

  7. [.NET] ConfuserEx脱壳工具打包

    [.NET] ConfuserEx脱壳工具打包 ConfuserEx 1.0.0脱壳步骤        Written by 今夕何夕[W.B.L.E. TeAm] 1.先用UnconfuserEx把 ...

  8. [Java] Spring 示例

    (一)IoC/DI 功能 配置解析:将配置文件解析为BeanDefinition结构,便于BeansFactory创建对象 对象创建:BeansFactory 根据配置文件通过反射创建对象,所有类对象 ...

  9. Playfield 类方法的注释

    前言 本篇随笔的底包采用的是百度炉石兄弟吧20200109折腾版中自带的 routines 文件. 本次仅为绝大多数方法添加 xml 注释和简单解析,没有具体解析与重构. Playfield 类方法众 ...

随机推荐

  1. 机器学习-SVM-核函数

    SVM-核函数 在研究了一天的SVM核函数后,我顿悟了一个道理: 研究和使用核函数的人,从一开始的目的就是把data分开而已.高维和映射,都是原来解释操作合理性的,但根本不是进行这一操作的原因 我为什 ...

  2. Get MySQL这5个优化技巧

    一个成熟的数据库架构并不是一开始设计就具备高可用.高伸缩等特性的,它是随着用户量的增加,基础架构才逐渐完善.这篇文章主要谈谈MySQL数据库在发展周期中所面临的问题及优化方案,暂且抛开前端应用不说,大 ...

  3. 【electronjs入门教程 】electronjs 介绍

    官网地址:https://electronjs.org/ 官网文档地址:https://electronjs.org/docs/ electronjs使用 JavaScript, HTML 和 CSS ...

  4. 25 Python之模块与包

    一.模块   模块就是一个包含了python定义和申明的文件,文件名就是模块的名字加上.py的后缀/ 模块的分类:     1.使用python编写的py文件     2.已被编译位共享库或者DLL或 ...

  5. 基于bootstrap的分页插件

    之前做的分页,是自己后端写一堆代码,返回给前端页面显示,感觉比较繁重.不灵活.今天研究下基于bootstrap的做的插件,整理如下: 在使用bootstrap的插件的时候,需要导入一些css.js. ...

  6. shell awk读取文件中的指定行的指定字段

    1.awk功能和实用形式 awk指定读取文件中的某一行的某个字段 awk      可以设置条件来输出文件中m行到n行中每行的指定的k字段,使用格式如下 awk    'NR==m,NR==n {pr ...

  7. 生成大量插入语句,并将语句写入txt文件中

    import java.io.*; /** * Created by czz on 2019/9/23. */ public class TTest { /** * 生成大量插入语句,并将语句写入tx ...

  8. 「工具」三分钟了解一款思维导图工具:XMind Zen

    一款非常实用的商业思维导图软件,融合艺术与创造力.致力于高效的可视化思维,强调软件的跨平台使用,帮助用户提高生产效率. 相关信息 · 操作系统:macOS / Windows / Linux · 官方 ...

  9. xss技巧记录

    1.iframe的srcdoc属性 先演示一下 <iframe srcdoc="<script>alert(1)</script>"> 浏览器渲 ...

  10. JAVA项目中的常用的异常处理情况总结

    可能遇见的异常或错误: 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的.例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略. 运行时异常: ...