Quote:
Originally Posted by ZeonNETWORK
exactly they are created dynamically but the id is static, so where to determine that ID if i created more GUI elements?
already tried different IDs on the CIFFlorian0Guide in GInterface.txt which off course crashes eventually
|
You choose the IDs by yourself. They can be any number, starting from about 5 (lower numbers are reserved for closebtn, titletext and drag handle). IDs have to be unique inside a window e.g. every ID should only appear once in CIFflorian0.txt, but can still be used in other GUIs. Same applies for ginterface.txt. Every entry needs to have it's own, unique ID.
Duplicate IDs do not ultimately lead to crashing. Mostly only weird behaviour. What leads to crashing is the fact that almost no code in Silkroad checks if GUI-Elements are actually existing. If you change the ID of CIFflorian0Guide and some code still uses that old ID, it might crash. These crashes usually happen because GetResObj will return 0 if the GUI Element/Window could not be found and the game doesn't check for that.
Code:
// This is fine, as long as 32001 is an existing ID, but will lead to an unavoidable crash if not
g_CGInterface->m_IRM.GetResObj(32001, 1)->SetVisibile(true);
Code:
// Failsafe, but also longer
CIFWnd* obj = g_CGInterface->m_IRM.GetResObj(32001, 1);
if (obj)
obj->SetVisibile(true);
Quote:
Originally Posted by ZeonNETWORK
i got it, and back to the main post you said the current available controls are the button and static
so if i want more controls how can i get the class members at the first place?
are there any ida plugins which manage to do that?
|
Button and Static are the ones that have their own classes. Other controls work aswell, but have some limitations. Visually, probably all controls can be used. You can place fancy headers, fake scrollbars and such. The problem is the interaction. Some, like the textbox, don't require their own class to be accessed. You can just treat them as CIFWnd and call GetText to get the content.
So in theory, creating classes for all the different UI Elements is not necessary unless you need some special feature.
But If you're still up to create one: In general, a "working" silkroad class consists of four main parts: A constructor, a destructor, a virtual function table and their runtimeclass stuff. Most of the time, just having the virtual function table is enough since you are not going to construct the object.
I've used ClassInformer for IDA and now Ghidra to find the virtual function tables via RTTI in the sro_client.
Start by figuring out if there are any virtual functions aside from the ones in the base class. Since the game is heavily based on virtuals, you may find interesting stuff there. You don't need to reconstruct the functions you have found. Simply adding the declaration is enough to call it.
Then do the runtimeclass stuff. The RuntimeClass of the object is referenced in the very first entry of the virtual function table (GetRuntimeClass). My code has macros for generating these functions.
You can also figure out the size of the object pretty easy. For example if you want to know the size of CIFButton, you just make a string-search for "CIFButton". Once found, check the references to that string.
[Only registered and activated users can see links. Click Here To Register...]
There may be multiple, the one with the PUSH is usually the correct one. If there is more than one, just look at all of them.
If it looks like this, you found the right one. Look slightly above and you see the total size of CIFButton: 0x3D4
[Only registered and activated users can see links. Click Here To Register...]
(Applies to all objects used in the UI)
Everything is kinda cross-referenced at this point. You can see the address of the RuntimeClass of CIFButton in the screenshot aswell (0x00ee9828). So having either the RuntimeClass address or the typename will lead you to the object size and the virtual function table (Through GetRuntimeClass) and the typename. The screenshot also shows the RuntimeClass of the base-class (0x00ee9720 - CIFStatic).
Constructors and destructors are usually not needed and can be very complex to reverse engineer. I can't give any specific hint on that. It's just bare assembly to c++ conversion using your own (or someone elses) brain.
If you need special behaviour, e.g. like I said before, scrolling, you need to figure out how it works by reverse engineering existing (simple) windows that implement scroll.