HearthstoneCalc – Injecting
Der Werdegang von HearthstoneCalc hat einen eigenen Post verdient, in welchem dann weitere Ansätze (Monte Carlo Tree Search) vorgestellt werden. In diesem Blogeintrag geht es allerdings um das Injecten und Daten abrufen aus Hearthstone. Denn ohne Daten aus dem Spiel müssen wir HearthstoneCalc garnicht mehr weiterentwickeln.
Uns wird es zum Glück leicht gemacht. Hearthstone ist mit der Engine Unity3D geschrieben. Für Blizzard hat das den großen Vorteil, das Spiel einfach auf mobile Geräte (Tables und Smartphones, Android und iOS) portieren zu können. Für uns hat es den großen Vorteil, dass Unity .NET (genauer gesagt: Mono) verwendet. Und da die Binaries noch nicht einmal obfuscated vorliegen, haben wir ein relativ einfaches Spiel.
Der für Unity relevante Code wird in der Assembly-CSharp.dll gespeichert. Die Anzahl der Klassen überschreitet alles, was ich bisher gesehen habe. Dementsprechend fällt es am Anfang schwer, uns zurecht zu finden. Auch muss man sich zunächst an die Unity-Eigenarten gewöhnen: Jedes Objekt ist eine Entity, die wiederrum mehrere Unterentities haben kann. Oftmals haben Klassen Unterklassen, enthalten viel zu viel Renderlogik oder scheinen nie erzeugt zu werden.
Daher gilt zu klären: Welche Daten müssen wir alle Abrufen? Die Daten aus dem Spiel müssen in die Strukturen von HearthstoneCalc gebracht werden. Die wichtigste und größte Struktur ist hierbei die GameState-Klasse (Links). Sie enthält das Spielfeld mit den Monstern, die Karten des Spielers und die Infos über die jeweiligen Helden. Natürlich haben die Helden weitere Unterklassen, wie z.B. die ausgerüstete Waffe oder die gesetzen Geheimnisse. Auch Monster sind inzwischen komplexer geworden, denn sie können verschiedene Buffs besitzen und auf andere umliegende Minions Einfluss ausüben.
Die Klassen aus Hearthstone können wir nicht einfach übernehmen, denn sie enthalten viel zu viele Informationen. Diese Klassen sind nicht dafür ausgelegt, Millionen möglicher Boardzustände zu speichern. Zu diesem Problem werde ich nächsten Post über HearthstoneCalc noch mehr sagen.
Der große Vorteil von Mono ist natürlich, dass wir realtiv einfach .NET Code ausführen können. .NET Code in einem Programm ausführen? Klingt doch sehr nach CLR-Hosting!? Leider ist das nicht so einfach, denn die Unity-Klassen mögen es nicht, wenn sie außerhalb von mscorlib.dll Thread aufgrufen werden. Versucht man eine Unity-Funktion direkt aufzurufen, so erhält man folgende Fehlermeldung zu gesicht: