Echo_
2011-05-14 23:30:17
The SMART Hooks Tutorial
by Echo_
by Echo_
The reflection library is almost completely based off of hooks returning the values of fields from the RuneScape client. In order to be able to make your own reflection functions, you need to first understand how to retrieve field data and use it in your script. This tutorial will cover that, and hopefully make it easier for some to understand reflection.
The Hooks
If you go to your reflection includes folder and open up Core, you should see hooks.simba. You should find something similar to this:
const
ClientVersion = 646;
HookRev = 3;
{Static Hooks}
hook_static_LoginIndex = 'ta.j';
hook_static_getChatLines = 'tb.c';
hook_static_CameraYaw = 'wo.h';
hook_static_MyPlayer = 'lja.s';
hook_static_BaseX = 'sf.j';
hook_static_BaseY = 'iba.S';
hook_static_NPCIndexArray = 'cga.Q';
hook_static_LoopCycle = 'ct.c';
hook_static_getNPCNC = 'lo.d';
hook_static_getItemDefLoader = 'lha.N';
hook_static_getObjectDefLoader = 'ob.t';
hook_static_NPCNodes = 'cm.m';
hook_static_NPCCount = 'eka.k';
hook_static_GroundSettingsArray = 'ct.e';
hook_static_LoadedPlane = 'im.g';
hook_static_PlaneArray = 'jt.g';
hook_static_Toolkit = 'sm.W';
hook_static_getCollapsedMenuItems = 'ir.x';
hook_static_MenuOptionCount = 'gi.l';
hook_static_MenuCollapsedOptionsCount = 'kh.M';
hook_static_MenuX = 'vp.k';
hook_static_MenuY = 'bb.sb';
hook_static_MenuWidth = 'jk.g';
hook_static_MenuHeight = 'ed.f';
hook_static_MenuX2 = 'lm.p';
hook_static_MenuY2 = 'fu.L';
hook_static_MenuWidth2 = 'kn.f';
hook_static_MenuHeight2 = 'qv.gb';
hook_static_MenuNodeList = 'baa.i';
hook_static_MenuOpen = 'jj.s';
hook_static_IsMenuTabbed = 'hia.U';
hook_static_GetInterfaces = 'dn.l';
hook_static_ValidInterfaces = 'vp.f';
hook_static_GetSettings = 'wfa.g';
hook_static_GroundItemCache = 'bba.L';
hook_static_GetSkillExperiences = 'ig.d';
hook_static_GetSkillLevels = 'paa.x';
hook_static_MapAngle = 'hu.w';
hook_static_DestX = 'tfa.d';
hook_static_DestY = 'ri.f';
hook_static_PlayerCount = 'qf.h';
hook_static_PlayerIndexArray = 'ch.s';
hook_static_GetPlayers = 'aka.g';
hook_static_CamPosX = 'ap.B';
hook_static_CamPosY = 'sj.T';
hook_static_GroundTiles = 'pba.h';
hook_static_GetCrossHairColor = 'vo.g';
{Class SDModel}
class_SDModel = 'or';
hook_sdmodel_getIndices1 = 'A';
hook_sdmodel_getIndices2 = 'Sb';
hook_sdmodel_getIndices3 = 'G';
hook_sdmodel_getPointsX = 'Eb';
hook_sdmodel_getPointsY = 'mb';
hook_sdmodel_getPointsZ = 'Yb';
{Class ChatLine}
class_ChatLine = 'pu';
hook_chatline_getName = 'a';
hook_chatline_getMessage = 'b';
{Class Animable}
class_Animable = 'oq';
hook_animable_PixelX = 'E';
hook_animable_PixelY = 'u';
hook_animable_Plane = 'B';
{Class Player}
class_Player = 'ib';
hook_player_GetLevel = 'td';
hook_player_GetName = 'ed';
hook_player_GetTeam = 'pd';
hook_player_PlayerDef = 'Gd';
{Class Character}
class_Character = 'ns';
hook_character_GetHitDamges = '';
hook_character_Animation = 'Hb';
hook_character_Motion = 'Uc';
hook_character_WalkQueueX = 'Yc';
hook_character_WalkQueueY = 'Tc';
hook_character_GetHeight = 'ob';
hook_character_LoopCycleStatus = 'jb';
hook_character_HPRatio = 'Jb';
hook_character_GetInteracting = 'ub';
hook_character_Orientation = 'cc';
{Class AnimableNode}
class_AnimableNode = 'dja';
hook_AnimableNode_GetAnimable = 'b';
hook_AnimableNode_GetNext = 'c';
{Class AnimableEntity}
class_AnimableEntity = 'aaa';
hook_animableentity_getAreaX1 = 'K';
hook_animableentity_getAreaX2 = 'T';
hook_animableentity_getAreaY1 = 'X';
hook_animableentity_getAreaY2 = 'U';
{Class PlayerDef}
class_PlayerDef = 'pfa';
hook_playerdef_GetEquipment = 'o';
{Class NodeCache}
class_NodeCache = 'lk';
hook_nodecache_GetNodes = 'd';
{Class Item}
class_Item = 'ai';
hook_item_GetID = 'l';
hook_item_GetStack = 'n';
{Class ItemDefLoader}
class_ItemDefLoader = 'gia';
hook_itemdefloader_getMRUNodes = 'o';
{Class ItemDef}
class_ItemDef = 'lv';
hook_itemdef_getLoader = 'w';
hook_itemdef_getGroundActions = 'K';
hook_itemdef_getActions = 'S';
{Class MRUNodes}
class_MRUNodes = 'af';
hook_mrunodes_getNodeCache = 'n';
hook_mrunodes_getList = 'e';
hook_mrunodes_getInitialCount = 'c';
hook_mrunodes_getSpaceLeft = 'g';
{Class ObjectDefLoader}
class_ObjectDefLoader = 'ek';
hook_objectdefloader_getMRUNodes = 'h';
{Class NPC}
class_NPC = 'kf';
hook_npc_NPCDef = 'qd';
hook_npc_getLevel = 'sd';
{Class NPCDef}
class_NPCDef = 'em';
hook_npcdef_GetActions = 'n';
hook_npcdef_GetName = 'I';
hook_npcdef_GetLevel = 'z';
hook_npcdef_GetID = 'pb';
{Class NPCDefLoader}
class_NPCDefLoader = 'kd';
hook_npcdefloader_ModelRef = 'n';
{Class NPCNode}
class_NPCNode = 'pe';
hook_npcnode_GetNPC = 'm';
{Class SDViewport}
class_SDViewport = 'oda';
hook_sdviewport_xOff = 'o';
hook_sdviewport_xX = 'p';
hook_sdviewport_xY = 'n';
hook_sdviewport_xZ = 'j';
hook_sdviewport_yOff = 'E';
hook_sdviewport_yX = 't';
hook_sdviewport_yY = 'D';
hook_sdviewport_yZ = 'z';
hook_sdviewport_zOff = 's';
hook_sdviewport_zX = 'g';
hook_sdviewport_zY = 'm';
hook_sdviewport_zZ = 'k';
{Class SDToolkit}
class_SDToolkit = 'nia';
hook_sdtoolkit_Viewport = 'J';
hook_sdtoolkit_xMin = 'K';
hook_sdtoolkit_xMax = 'ib';
hook_sdtoolkit_yMin = 'X';
hook_sdtoolkit_yMax = 'cb';
hook_sdtoolkit_zMin = 'I';
hook_sdtoolkit_zMax = 'S';
hook_sdtoolkit_xScale = 'F';
hook_sdtoolkit_yScale = 'db';
{Class SDPlane}
class_SDPlane = 's';
hook_sdplane_TileHeights = 'h';
{Class NodeListCache}
class_NodeListCache = 'tga';
hook_nodelistcache_GetNodeList = 'k';
{Class NodeList}
class_NodeList = 'v';
hook_nodelist_Current = 'o';
hook_nodelist_Head = 'e';
{Class Node}
class_Node = 'sja';
hook_node_Next = 'h';
hook_node_GetID = 'c';
hook_node_Previous = 'a';
{Class MenuGroupNode}
class_MenuGroupNode = 'laa';
hook_MenuGroupNode_getNodeSubListItems = 'x';
{Class NodeSubList}
class_NodeSubList = 'wd';
hook_nodesublist_getHead = 'i';
{Class NodeSub}
class_NodeSub = 'lm';
hook_nodesub_Next = 't';
{Class Menu}
class_Menu = 'pja';
hook_menu_Option = 'w';
hook_menu_Action = 'H';
{Class ObjectInterface}
class_ObjectInterface = 'sha';
hook_interface_GetActions = 'I';
hook_interface_GetX = 'v';
hook_interface_GetY = 'mc';
hook_interface_GetWidth = 'rd';
hook_interface_GetHeight = 'Ac';
hook_interface_GetText = 'dd';
hook_interface_GetTextureID = 'x';
hook_interface_GetTextColor = 'fd';
hook_interface_GetModelID = 'r';
hook_interface_GetModelZoom = 'Tc';
hook_interface_GetName = 'nc';
hook_interface_GetChildren = 'h';
hook_interface_GetID = 'tb';
hook_interface_GetStack = 'W';
hook_interface_GetParentID = 'X';
hook_interface_IsHidden = 'Yb';
{Class SettingArray}
class_SettingArray = 'vaa';
hook_settingarray_GetData = 'b';
{Class SoftReference}
class_SoftReference = 'kl';
hook_softreference_getReference = 'z';
{Class HardReference}
class_HardReference = 'kr';
hook_hardreference_getObject = 'C';
{Class Ground}
class_Ground = 'ug';
hook_ground_AnimableList = 'r';
hook_ground_WallObject1 = 'k';
hook_ground_WallObject2 = 'o';
hook_ground_WallDecoration1 = 'h';
hook_ground_WallDecoration2 = 'i';
hook_ground_FloorDecoration = 'g';
{Class WallObjectData}
class_WallObjectData = 'ad';
hook_WallObjectData_GetID = 'ib';
hook_WallObjectData_GetModel = 'tb';
hook_WallObjectData_GetOrientation = 'fb';
{Class WallDecorationData}
class_WallDecorationData = 'sm';
hook_WallDecorationData_GetID = 'vb';
hook_WallDecorationData_GetModel = 'nb';
hook_WallDecorationData_GetOrientation = 'db';
{Class FloorDecorationData}
class_FloorDecorationData = 'bb';
hook_FloorDecorationData_GetID = 'hb';
hook_FloorDecorationData_GetModel = 'xb';
hook_FloorDecorationData_GetOrientation = 'cb';
{Class InteractiveObject}
class_InteractiveObject = 'ur';
hook_interactiveobject_GetID = 'hb';
hook_interactiveobject_GetModel = 'Hb';
hook_interactiveobject_GetOrientation = 'Bb';
{Class InteractiveObject2}
class_InteractiveObject2 = 'gr';
hook_interactiveobject2_GetObjectData = 'mb';
{Class SecondLevelObject}
class_SecondLevelObject = 'wm';
hook_secondlevelobject_GetID = 'i';
hook_secondlevelobject_GetModel = 'u';
hook_secondlevelobject_GetOrientation = 'q';
{Class WallObjectSub2}
class_WallObjectSub2 = 'ec';
hook_wallobjectsub2_getComposite = 'cb';
{Class WallDecorationSub2}
class_WallDecorationSub2 = 'jc';
hook_walldecorationsub2_getComposite = 'W';
{Class FloorDecorationSub2}
class_FloorDecorationSub2 = 'iba';
hook_floordecorationsub2_getComposite = 'fb';
{Class GrandExchange}
class_GrandExchange = 'dn';
hook_grandexchange_getStatus = 'e';
hook_grandexchange_getID = 'c';
hook_grandexchange_getPrice = 'i';
hook_grandexchange_getTotal = 'j';
hook_grandexchange_getTransferred = 'd';
hook_grandexchange_getSpent = 'f';So, what are they? Every one of these PascalScript constants represents a field or method in the RuneScape client. The string of letters you see them assigned to are the obfusicated names of the fields. Jagex obfusicates their client so that bots are a pain in the ass to create and maintain, but that is why we have hook updaters. I won't go further into what fields are in this tutorial, if you want to know more you can read my Introduction to Client Hacking for the Java Impaired.
These hooks aren't of much use to you if you don't know what java data type they represent, so you will have to find out :) The RuneScape client has data types that we don't commonly use in scripting, so here's a quick summary of each data type from the Java Tutorials.
byte: The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive). The byte data type can be useful for saving memory in large arrays, where the memory savings actually matters. They can also be used in place of int where their limits help to clarify your code; the fact that a variable's range is limited can serve as a form of documentation.
short: The short data type is a 16-bit signed two's complement integer. It has a minimum value of -32,768 and a maximum value of 32,767 (inclusive). As with byte, the same guidelines apply: you can use a short to save memory in large arrays, in situations where the memory savings actually matters.
int: The int data type is a 32-bit signed two's complement integer. It has a minimum value of -2,147,483,648 and a maximum value of 2,147,483,647 (inclusive). For integral values, this data type is generally the default choice unless there is a reason (like the above) to choose something else. This data type will most likely be large enough for the numbers your program will use, but if you need a wider range of values, use long instead.
long: The long data type is a 64-bit signed two's complement integer. It has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807 (inclusive). Use this data type when you need a range of values wider than those provided by int.
float: The float data type is a single-precision 32-bit IEEE 754 floating point. Its range of values is beyond the scope of this discussion, but is specified in section 4.2.3 of the Java Language Specification. As with the recommendations for byte and short, use a float (instead of double) if you need to save memory in large arrays of floating point numbers. This data type should never be used for precise values, such as currency. For that, you will need to use the java.math.BigDecimal class instead. Numbers and Strings covers BigDecimal and other useful classes provided by the Java platform.
double: The double data type is a double-precision 64-bit IEEE 754 floating point. Its range of values is beyond the scope of this discussion, but is specified in section 4.2.3 of the Java Language Specification. For decimal values, this data type is generally the default choice. As mentioned above, this data type should never be used for precise values, such as currency.
boolean: The boolean data type has only two possible values: true and false. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its "size" isn't something that's precisely defined.
char: The char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive).
Now that we have that out of the way, we need to find that field! Here's a step by step process on finding the variable you need and its data type.
Step 1: Download the runescape client jar from here. You also need a java decompiler, you can get one here.
Step 2: Look in hooks.simba and find the class of the field you are looking for. I will be looking for the hook "GetX".
{Class ObjectInterface}
class_ObjectInterface = 'sha'; // The class containing my hook
hook_interface_GetActions = 'I';
hook_interface_GetX = 'v'; // My hook
hook_interface_GetY = 'mc';
hook_interface_GetWidth = 'rd';
hook_interface_GetHeight = 'Ac';
hook_interface_GetText = 'dd';
hook_interface_GetTextureID = 'x';
hook_interface_GetTextColor = 'fd';
hook_interface_GetModelID = 'r';
hook_interface_GetModelZoom = 'Tc';
hook_interface_GetName = 'nc';
hook_interface_GetChildren = 'h';
hook_interface_GetID = 'tb';
hook_interface_GetStack = 'W';
hook_interface_GetParentID = 'X';
hook_interface_IsHidden = 'Yb';If your hook was static, then the letters preceding the dot are the class name, and the letters after are the field name.Step 3: Now open up the java decompiler you downloaded. Click File -> OpenFile, and find where you saved the client (runescape.jar). Open that up.
Step 4: Scroll down the left panel until you see the class containing your field, then click it to open it.
Step 5: Now that you have your class open, find the field associated with your hook. Here's mine:

Step 6: The variable assigned to your field is right before the variable name. In this case, mine is an int.
Using Your Hooks
Now that you've gone through all the trouble of finding out what kind of variable your hook is, you want to be able to use it in your script! You can assign the value of the field in the RuneScape client to a Simba variable using some fun little functions I like to call "SmartGetField" functions :p Here's a list of all of them.
SmartGetFieldByte(parent: Integer; path: string): Integer;
SmartGetFieldShort(parent: Integer; path: string): Integer;
SmartGetFieldInt(parent: Integer; path: string): Integer;
SmartGetFieldLongH(parent: Integer; path: string): Integer;
SmartGetFieldLongL(parent: Integer; path: string): Integer;
SmartGetFieldFloat(parent: Integer; path: string): Extended;
SmartGetFieldDouble(parent: Integer; path: string): Extended;
SmartGetFieldBoolean(parent: Integer; path: string): Boolean;
SmartGetFieldObject(parent: Integer; path: string): Integer;
SmartGetFieldArrayByte(parent: Integer; path: string; index: Integer): Integer;
SmartGetFieldArrayShort(parent: Integer; path: string; index: Integer): Integer;
SmartGetFieldArrayInt(parent: Integer; path: string; index: Integer): Integer;
SmartGetFieldArrayLongH(parent: Integer; path: string; index: Integer): Integer;
SmartGetFieldArrayLongL(parent: Integer; path: string; index: Integer): Integer;
SmartGetFieldArrayFloat(parent: Integer; path: string; index: Integer): Extended;
SmartGetFieldArrayDouble(parent: Integer; path: string; index: Integer): Extended;
SmartGetFieldArrayBoolean(parent: Integer; path: string; index: Integer): Boolean;
SmartGetFieldArrayChar(parent: Integer; path: string; index: Integer): Integer;
SmartGetFieldArrayObject(parent: Integer; path: string; index: Integer): Integer;
SmartGetFieldArray2DByte(parent: Integer; path: string; x, y: Integer): Integer;
SmartGetFieldArray2DShort(parent: Integer; path: string; x, y: Integer): Integer;
SmartGetFieldArray2DInt(parent: Integer; path: string; x, y: Integer): Integer;
SmartGetFieldArray2DLongH(parent: Integer; path: string; x, y: Integer): Integer;
SmartGetFieldArray2DLongL(parent: Integer; path: string; x, y: Integer): Integer;
SmartGetFieldArray2DFloat(parent: Integer; path: string; x, y: Integer): Extended;
SmartGetFieldArray2DDouble(parent: Integer; path: string; x, y: Integer): Extended;
SmartGetFieldArray2DBoolean(parent: Integer; path: string; x, y: Integer): Boolean;
SmartGetFieldArray2DChar(parent: Integer; path: string; x, y: Integer): Integer;
SmartGetFieldArray2DObject(parent: Integer; path: string; x, y: Integer): Integer;
SmartGetFieldArray3DByte(parent: Integer; path: string; x, y, z: Integer): Integer;
SmartGetFieldArray3DShort(parent: Integer; path: string; x, y, z: Integer): Integer;
SmartGetFieldArray3DInt(parent: Integer; path: string; x, y, z: Integer): Integer;
SmartGetFieldArray3DLongH(parent: Integer; path: string; x, y, z: Integer): Integer;
SmartGetFieldArray3DLongL(parent: Integer; path: string; x, y, z: Integer): Integer;
SmartGetFieldArray3DFloat(parent: Integer; path: string; x, y, z: Integer): Extended;
SmartGetFieldArray3DDouble(parent: Integer; path: string; x, y, z: Integer): Extended;
SmartGetFieldArray3DBoolean(parent: Integer; path: string; x, y, z: Integer): Boolean;
SmartGetFieldArray3DChar(parent: Integer; path: string; x, y, z: Integer): Integer;
SmartGetFieldArray3DObject(parent: Integer; path: string; x, y, z: Integer): Integer;Now, according to the data type of your hook, you will have to use the function that matches up with it. Since "GetX" was an int, I will have to use SmartGetFieldInt. If your variable had a another class' name as its type, then you will use SmartGetFieldObject. There are also functions for arrays and multidimensional arrays up to 3D, so every variable type is covered.
So let's say I want to write a function that will return an interface's X coordinate using reflection. I have the hook from earlier, so here is what I would do.
function GetInterfaceX(parentIndex, childIndex): Integer;
var
i: Integer;
begin
i := GetInterface(parentIndex, childIndex);
Result := SmartGetFieldInt(i, hook_interface_GetX);
SmartFreeObject(i);
end;Don't pay attention to the parentIndex and childIndex I'm using to grab the interface, the point I am trying to demonstrate with this snippet is the meaning of the parameters of the "SmartGetField" functions. The parent in this case is the interface ID, the parent is what you are trying to grab the data from. Also take note of the "SmartFreeObject" I have at the end of the function. If you don't include this, you will have created a memory leak and SMART will crash.
Conclusion
Now that you know how to take full advantage of our hooks, you can write some reflection snippets of your own :) If you have any questions or comments, feel free to post them on this topic. I will reply to them as quickly as I can.