In den nächsten Tagen werde ich nicht zum posten kommen, daher hier noch ein kleiner Artikel. Es handelt sich um ein relativ simples, aber dennoch extremst cooles Feature. Der Bone-ESP!
Der Bone-ESP zeigt uns einfach jeden der 20 Knochen an. In diesem Gesamtbild ergibt sie die Entfernung, sowie die Positionierung (liegen, stehend) des Spielers. Dadurch können wir auf eine Box um den Spieler oder so einfach verzichten und das ganze sieht echt gut aus (wenn man es in Bewegung sieht )
Für den Bone-ESP sind im Grunde genommen “nur” drei Schritte nötig:
- Wir registrieren jeden einzelnen Bone und speichern das “Handle” in Tag XXX
- Wir fordern in jedem Frame über eine EngineFunktion die Position dieses Bones mit dem Tag XXX an.
- Wir wenden für jeden Bone die WorldToScreen Funkion drauf an!
Quelle : http://easysurfer.back2hack.cc/wordpress/?p=139
[spoiler]
Das Registrieren erfolgt über C# Code, welcher schnell erklärt ist:
public delegate ushort RegisterTagDelegate(Byte[] BoneName); // Das Delegate public static RegisterTagDelegate RegisterTagFunc; // Die Funktion aus dem Delegate // Alle Bone-Tags public static String[] arBoneNames = new String[] {"j_helmet" , "j_head" , "j_neck" , "j_shoulder_le", "j_shoulder_ri" , "j_elbow_le" , "j_elbow_ri", "j_wrist_le", "j_wrist_ri", "j_gun" , "j_mainroot" , "j_spineupper" , "j_spinelower" , "j_spine4" , "j_hip_ri" , "j_hip_le" , "j_knee_le" , "j_knee_ri" , "j_ankle_ri", "j_ankle_le"};
Wir legen also ein Array von Tags an, welche im folgenden Schritt dann registriert werden. Dabei wird ein Array vom Type “Bone” gefüllt!
// Im Konstruktor RegisteredBones = new Bone[20]; for (int i = 0; i < RegisteredBones.Length; i++) { RegisteredBones[i] = new Bone(); RegisteredBones[i].sBoneName = PlayerManager.arBoneNames[i]; RegisteredBones[i].iBoneID = PlayerManager.RegisterTagFunc(Encoding.ASCII.GetBytes(PlayerManager.arBoneNames[i])); }
Die Namen sollten soweit selbsterklärend sein…
Das interessante ist nun die BonePosition zu holen. Und dieses geht nur über InlineASM in C++, da sonst der Stackpointer außer Kontrolle gerät…
Also übergeben wir der C++-Wrapper Funktion die registrierte BoneID, sowie einen Zeiger der aktuellen PlayerKlasse. Dabei wird ein weiterer Zeiger übergeben. In diesem Zeiger wird dann die aktuelle Bone Position reingeschrieben. Ziemlich cool, oder?
public delegate int GetTagPosDelegate(int iBoneTag, IntPtr PtrToEntityStruct, IntPtr PtrToResult); public static GetTagPosDelegate GetTagPosFunc; private static IntPtr FreeTagPosSpace; // In Konstruktor FreeTagPosSpace = Marshal.AllocHGlobal(12); // Der Zeiger braucht ja noch Platz, wo er hinzeigen kann ^^
Unsere Funktion sieht dann also so aus:
public static Vector3 GetTagPosWrapped(MW2Player Player, int iBoneID) { PlayerManager.GetTagPosFunc(iBoneID, Player.Entity.pStructOffset, FreeTagPosSpace); // FreeTagPosSpace ist der Zeiger, in den das Resultat gespeichert wird return MemoryHelper.GetClassFromAddress(FreeTagPosSpace); // aus dem Zeiger wird wieder ein Vector3 }
Natürlich darf der C++-Code der entsprechenden Funktion auch nicht fehlen, da das Tutorial ja nicht nur total auf C# ausgelegt sein sollte…
static int GetPlayerTag (unsigned short Tag, int centity, int original) { __asm { movzx edi, Tag // Unser Tag kommt in EDI push original // Der Return-Pointer kommt auf den Stack mov esi, centity // Der Zeiger zur Player-Klasse kommt in ESI mov eax, 0x570720; // Die eigentliche Funktion (bzw Einsprungspunkt der Teilfunktion) kommt in EAX call eax // EAX wird angesprungen add esp, 0x4 // Der Stack wird gefixxt } }
Nun wird dieses auf jeden Bone angewendet, das Resultat wird in WorldToScreen in Bildschrimkoordinaten umgewandelt und wir haben unseren Bone-ESP, welcher sich mit den Figuren mitbewegt.
Und zum Abschluss noch ein LOL: In COD 7 (Black Ops) wird genau das selbe Tag-Prinzip verwendet. Doch dort gibt es noch 2 neue Tags: j_ball_le und j_ball_ri, welche die Eier des Spielers repräsentieren. Kein Witz!
Greez Easy
[/spoiler]