Awesome find you've got there. It sounds like you're getting pretty good at editing modules.
I'm not much of a Skype or MSN person, but if I get the chance, we can try to meet up on IRC.
Anyways, you spiked my curiosity with what you found in the st_tbreak constructor. Here's what I've found out so far:
First off, a few things to note: -Almost all object methods have r3 pointing to the calling object. (sort of like the "this" keyword in C++) -Objects that inherit from the "Ground" object have a node like behavior in that they can point to eachother.
So I started off with that method you were looking at - Method[23]: the stage constructor or initializer.
It starts off doing a bit of housecleaning such as storing various variables onto the stack, but there's a few importing things it does to start off: -Set r27 to r3 ("this") -Set r29 to Section[4] (Constants) -Set r30 to Section[5] (Object Declarations)
These registers (as far as I've gotten) remain the same for the whole constructor function.
Next it calls a routine from st_melee at Section[1] 0x223140 and passes in "this". Other stages do this too, so I'm guessing its the most basic form the stage constructor.
A bit later you'll see an instruction bl 0x1884 that isn't bound to a relocation instruction (you'll also see similar calls later on, but they're all calling the same subroutine). This small subroutine is used frequently throughout the constructor - it takes 3 parameters: r3 an integer r4 an unknown pointer r5 a string pointer
This subroutine does a few things: -Immediately discard r4 (oddly enough...) -Call malloc (at 0x8000C8B8) with a size of 0x1A4 -Call the Ground Object constructor passing in the new malloc'd ptr and the string pointer. -Call the new Ground Object's Method[0][26]. -Call the new Ground Object's Method[0][42] passing in the integer argument -Call two more unknown st_melee functions on the new Ground Object.
I'm not sure if the string pointer is directly used or if it's just used for naming the node, but strings passed to it are things like grTargetBreakGround, grTargetBreakGroundIce and BeltConveyorNode%02dS.
After creating the node, it usually stores it in some arbitrary place in the stage object. After that it does a few other things, but it seems that it always calls the node's Method[0][37] and Method[0][39] after it is done.
That's about everything I've got so far, I'm still in the middle of analyzing things, so I don't know exactly what's what yet. There's one more interesting function that should be useful if anyone has a debugger:
dbgprintf (r3=format, r4=param) 0x801D8600
I'm not entirely sure if it is truly a debug printout function, but it seems to be used to describe in plaintext activities that are in the middle of taking place. Placing a breakpoint there might prove to be useful.
The Stage Roster Expansion code doesn't change your stage select screen on it's own. After applying the Stage Roster Expansion code, you'll need to add the stages to your stage select screen using the Custom Stage Select Screen code
This one's already filled out - it should add the additional ten stages to the end of the Melee stage select screen. They'll be alternating between FD and Battlefield icons.
If you're looking for more details on stage hitboxes, I think there was some research done on the boards here a while ago concerning the cars on Onnett among other things. I think someone ended up discovering a certain pattern to the function calls inside the module files of the stages that allowed them to customize the hitboxes. They couldn't add or remove them though because there wasn't a way to effectively modify modules at the time.
Anyways, I imagine there'd be a lot of useful information in that thread if you can find it. I can't do a whole lot of research these days, but I just thought I'd drop by to see if I could help out at all.
Ahem, it turns out that you can modify sound banks (along with a bunch of other things) inside the sora_melee module (found in common2.pac). Most of this stuff was already documented by Dantarion on the OpenSA website, but it was all in ingame address form. The main points of interest are stored in Section[4], but there's a few interesting things in Section[5] too.
Code:
Section[4] 0x10C0 .pac List 0x119C Kirby Hat .pac List 0x1278 Kirby Hat File Types 0x12B0 Entry File Types 0x12E8 Result File Types 0x1320 .rel list 0x13FC Color Flags 0x14D8 Character Sets 0x18F0 Internal Fighter Name List 0x1B84 Entry Article Data 0x1C60 Sound Banks 0x1E18 MotionEtc File Data
Section[5] 0x2C3A0 IC Constant Sets 0x48B94 Ai Controllers
Each field holds about 55 entries corresponding to each character's internal id. The .rel list and .pac lists are pointers to the strings representing files for a particular character. More info on these can be found on Dant's website here. Of particular interest is the Character Sets(at 0x14D8), which sets which characters are preloaded in the case of Zelda/Sheik or Pokemon Trainer - if there's been any problems with porting those characters, that'd be one of the places to look.
In section[5] I've listed the Ai Controller functions which (if I recall correctly) were one of the things I had issues with back when I was working on the Clone Engine - those need to be adjusted when doing module ports to and from certain characters.
If you want to make modifications to the sora_melee module, you'll need to use the Module Editor 3 - but the last version had a bug in the relocation calculations that corrupted the file, so I've updated it to 3.1 here.
Oh, as a bonus, I think there's a spot in Main.dol at 0x4512E0 (ingame address 0x804551E8) which determines which colors are available for each character in the CSS - but I'm just working off of a vague memory of something long ago and a memory dump of Brawl, so I could be completely wrong. Anyways, if anyone's interested in working on the Masquerade project, you'd need to look for something like that.
Anyways, just thought I'd drop by for the dying days of the Wii era. There's not too many of us left these days - I hear that even BlackJax is gone or has at least gone on reduced activity like me.
Nice job Dant. I'm not really much of a python guy so I'm not sure how valuable my input would be, but it's cool to know that you're still working on the modules.
If you're looking to parse the object data, then you'll probably need to use these wrappers. There's not much organization to the object data otherwise.
Code:
Virtual Function Table: 0x00 (ptr) Declaration 0x04 (int) Scope Level 0x08 (ptr[]) Functions (no termination)
Declaration: 0x00 (string*) Name 0x04 (Inheritance[]*) Inheritance (0x00000000 terminated)
Just remember that it's possible for an object to have more than one Virtual Function Table depending on how many unique scope levels there are in it's inheritance hierarchy. I should note also, that while I call them Scope Levels for the time being, I don't really know exactly what their values represent - all I know is that for every unique value, there's usually an additional Virtual Function Table.
So it looks like I've found out where the raw assembly of each of the PSA commands are stored. Moreover, I've also found where inside the character module files the 0C series commands are stored.
A long time ago, I mentioned that I'd found out that the first byte of each PSA command represented one or more module inside Brawl. This was the list that I posted at the time:
I'm not sure why, but I never took this bit of information any further at the time. Anyways, it turns out that these modules are stored inside the the Common2 module (module id 1B). Moreover, each of these modules implement a specific interface soAnimCmdEventObserver. This interface is what allows the module to communicate with the instruction set used by PSA.
In order to find the methods used by the soAnimCmdEventObserver interface I needed to update the old Module Viewer 2. As it turns out, a small quirk in the method table which I was previously ignoring actually corresponded to which interfaces they belong to. It was just a dirty fix, so it's not anything fancy, but you'll need it if you want to find any of the PSA assembly code.
I guess I should warn everyone ahead of time, that in order to find the assembly of a specific PSA action, you'll need a really good understanding of assembly and a lot of patience - it also helps if you decide on what you're looking for beforehand.
For this example, I'll be looking for the Basic Variable Increment command - given by the PSA id 12030100.
Using the list up above, the first byte of this command (0x12) corresponds to soWorkManageModuleImpl. Start by opening up the common2 module in the new Module Viewer 2. Navigating through the object list to the soWorkManageModuleImpl object and opening up it's inheritance hierarchy, you'll spot the soAnimCmdEventObserver as well as its base; the soEventObserver<soAnimCmdEventObserver>. Observe that the Unknown value of both of them are 16. I'm not sure exactly what this value means, but what's important right now is that it seems to indicate the objects position in the inheritance hierarchy.
The method list has been reorganized so that the first index sorts the methods by inheritance and the second index distinguishes the individual methods. The higher the Unknown value of the inherited object, the higher the first index is for its corresponding methods. In this case, the soAnimCmdEventOberver's events are Method[1][0] to Method[1][5] (just remember that it will likely be different for each module).
The soAnimCmdEventObserver methods usually have a pretty consistent layout. soAnimCmdEventObserver.Method[0] (Method[1][0] in this case) seems to be some sort of initializer or hook function, but it isn't really all that interesting - the interesting ones are the two after it. soAnimCmdEventObserver.Method[1] is an identifier function which returns a boolean value depending on whether the first byte of the PSA command passed to it is equal to 12. If that function returns true, then the soAnimCmdEventObserver.Method[2] is called. This is the function that handles the rest of the PSA command.
As it turns out, Method[1] and Method[2] actually call Method[3] and Method[4] in this case so to get at the actual assembly, you'll have to look at those two instead. Just remember that it isn't always this way as things will vary wildly depending on what module you are looking at.
Anyways, if you open up Method[4] (Method[1][4]) - the main handler for the PSA commands starting with 0x12 - you'll be confronted with a ton of assembly you'll need to wade through. You're pretty much on your own here. However, it may help to know that the lines:
lwz r12,16(r12) mtspr ctr,r12 bctr extsb r0,r3
will put the second byte of the PSA command into r0. From here, you can follow the code through until you find the handler you're looking for - in this case we would be looking for a branch when r0 = 0x03.
Hey, I didn't say it was simple, and I can't really say it's all that useable for most people either. But this sort of knowledge could lead to a lot of potential. Mainly that using this could allow custom assembly scripts to be ran during gameplay whenever a certain PSA command is triggered.
A few other notes:
Some command set series draw upon multiple modules - such as the 06 series commands (hitboxes and such). In particular, the 0C series draws upon not only the ft<character>.rel, but also a bunch of other unidentified modules.
When it comes to finding the character specific 0C series commands, you'll need to open the character's .rel file and navigate to the ft<FighterName> object. The main handlers there are actually Method[3][14] and Method[3][15].
Inside the Common2 module there's an object call soAnimCommandInterpreter or something. If I had to venture a guess, I'd say that's what is responsible for parsing PSA commands during gameplay.
That's about it for now. I haven't done any testing on it, so it's all pretty much theory until someone decides to try something with it and proves it - but for now, it seems pretty sound.
wow! I am amazed, you actually answer my question and now I am happy and that information will be excellent help! I understand more about Epilog, Prolog, Bssoffsets and more about Relocation section thanks to you :3 I appreciate your help! x3
but there is one thing that still bugs me, about nameOffset. often when it is a Offset, it's most of the time 4-8 hex big and often ends on either 0-4-8-C but the nameOffset ends on almost every single hex that are known (0-F), mostly 6 and 1 are they stored/load/created at the same way the Bss Memory are created in runtime?
planing to write completely a whole new Module file from scratch to understand more about it's struckture not this time :3
The name offset and size seems to be only used for debug purposes as it doesn't have any use during runtime (The revolution SDK makes reference to it though). As for why the offset isn't aligned to 0x4; that's because strings are stored in memory back to back without any alignment. Therefore, string pointers can end in any values from 0x0 to 0xF.
and awesome with Module editor 3 >w< also, I need to ask you! do you know something about how the Relocation are linked to Objects and Assembly?
and do you possible know exactly how NameOffset, PrologOffset, EpilogOffset and Unresolved Offset are linked? I just dont find it out how D:
A huge thanks for the gift
Hmm, a lot of questions here. I guess I'll start from the beginning.
When the module is first loaded into memory, the first thing the game does is call a function on it that links the module to each of the other modules loaded into memory. In the Revolution SDK, this function is called OSLink. When called on a module, it resolves all relocations inside the module and checks all existing modules for dependencies on it resolving them in the process.
I won't go into too much detail on how the relocations are stored as you can find that in the Module Viewer 3 Source code, but one important thing to know is the relocation types:
Code:
Value = SectionOffset + Addend
0x00 nop 0x01 Write Word ( target u32 = Value ) 0x02 Set Long Branch Offset ( target u32 = (target u32 & ~0x03FFFFFC) | (Addend & 0x03FFFFFC) ) 0x03 Write Lower Half ( target u16 = Value & 0xFFFF ) 0x04 == 0x03 0x05 Write Upper Half ( target u16 = (Value >> 16) & 0xFFFF ) 0x06 == 0x05 0x07 Set Short Branch Offset ( target u32 = (target u32 & ~0xFFFC) | (Addend & 0xFFFC) ) 0x08 == 0x07 0x09 == 0x07 0x0A Set Long Branch Destination ( target long branch destination = Addend ) 0x0B Set Short Branch Destination ( target short branch destination = Addend ) 0x0C == 0x0B 0x0D == 0x0B
Once the module is linked, the _prolog function may be optionally called. In Brawl, the _prolog function is always called. The assembly code for the _prolog function can be found by going to the PrologOffset inside the section specified by PrologSection (the PrologSection is almost always the Section[1]). When called, it invokes the constructor for each of the top level objects inside the module. The pointers to these constructor functions are usually found in Section[2] of the module.
Objects exist in multiple parts. All object declarations, inheritance values and virtual function tables are usually stored in Section[5]. There isn't a whole lot of organization to the data, but there are a few basic structures that can be found if you know what to look for:
Code:
(because all pointers only exist once the module has been linked, you won't be able to see these values inside a regular hex viewer. They can be found using the Module Viewer 3's memory viewer though)
Declaration (8 bytes) 0x00 Name ptr 0x04 Inheritance[] ptr
Because everything is so unorganized, the only way you can really parse this section is if you use a code crawler like the Module Viewer 2 used. For the time being, Module Viewer 3 supports simple tagging, but hopefully there'll be a way to automate the process soon.
As for the actual objects themselves; they are created by the constructor functions into the Bss Memory which in turn is created at runtime. The Bss Memory is accessed like the rest of the module sections and is usually found at Section[6] - while you can open it in the memory viewer, the actual section doesn't exist in the module and is only created at runtime.
Beyond that, the _epilog function does the opposite of the _prolog function and is called right before the module is unlinked (The destructor function pointers are found in Section[3]). As for the _unresolved function; all external functions calls in the module are initially directed towards this function. That way, if a function doesn't get linked, the _unresolved function is called instead. For the most part, it does something along the lines of throwing an exception while reporting the module's source file (e.g. mo_fighter.cpp)
That's about as much as I know about the module files - the rest of it you already posted in the link in the opening post.
I'll be around, so if you have any other questions, go ahead and ask away.
Hi everyone, Phantom Wings here. I haven't been by for a while now so I figured I'd drop by and pay my regards to the Brawl Hacking community. I notice that there's been a little bit of interest in the workings of .rels in this here thread so:
I had this one on the backburner before I left the last time. It's not as intuitive as the Module Editor 2, but it does support editing blocks and relocations as well as saving - hope it helps.
The app itself isn't that well put together, but the module library should be easy enough to salvage for use in BrawlBox - but as usual, don't expect any commenting in my source code.
I was going through my notes the other day when something caught my attention that I'd meant to expand on a little more. It's not really anything useable at the moment, but hey, I figure someone should be able to get something out of it.
You may have seen these classes before if you've ever taken the time to look inside any stage module. For the sake of the analysis, I used the Wifi Waiting Room stage(st_otrain.rel) - I will refer to it whenever necessary.
For now we'll look at stClassInfoImpl<55, stOnlineTrainning>, a derived class of the stClassInfo class. (you could argue that it's actually an implementation of the abstract interface stClassInfo, but let's not complicate the terminology) This is a lightweight class that Brawl uses whenever it needs to generate the Wifi Waiting Room stage for you to fight on. (Incidentally, the Results Screen stage's stClassInfo is always loaded into memory, so it can be loaded at any time)
The method in question that loads the stage is stClassInfoImpl<55, stOnlinetrainning>.Method[1]. I won't go into details, but it does 3 main things:
1. Allocate a block of memory on the StageInstance heap the size of the stOnlineTrainning class. 2. Call the stMelee constructor. (the base class of the stOnlineTrainning class) 3. Construct the remaining parts unique to the stOnlineTrainning class.
After the constructor returns, the address of the stOnlineTrainning class gets stored at 80B8A428. (Somewhere inside module 1B) When the match actually starts, stOnlineTrainning gets accessed from 80B8A428 and it's initializer gets called.
For all instances of the Stage class, method[23] is the initalizer. This is the function that is responsible for loading up all the assets from STGONLINETRAINING.pac. It is also responsible for creating any other instances that exist on the stage as separate objects. (The blocks from Mushroomy Kingdom, say)
And unfortunately, that's really as far as I got with this. I might venture a guess as to say that the method at 80015DDC is responsible for loading specific archives out of the .pac with r4 being the type and r5 being the FileIndex, but the rest of it is uncharted territory.
In case that all went by a little bit too fast for you, I whipped up a quick diagram for you to reference at your leisure. (The diagram says that Method[22] is the Stage initializer - ignore that, it's really Method[23])
Just a few more miscellaneous notes:
As mentioned above, the current existing stage instance can be accessed at any time from the pointer at 80B8A428.
All methods in a class that don't reference assembly inside it's own module are methods that have not been overridden from it's base class.
Method[127] is the main loop of the stage. It is constantly called and is used for things like the Sandbag in WWR or rebuilding the mansion in Luigi's Mansion.
Just as there are constructors and initializers, there are also destructors and finalizers. stClassInfo.Method[0] is used for removing the stClassInfo from memory and Stage.Method[22] is the destructor for the actual stage
The memory allocation function can be found at 8000C8B8, it may be a good idea to see what else calls it if you wish to find out where other classes get constructed. (8000C8C8 is the memory free function if anyone was wondering) Also, here's a list of the types of memory heaps.
Well Bah, and here I was hoping that the modules handled all of this. >.<
Anyways, it looks like there's a lot more that needs to be changed in order to get everything to line up correctly. From what I can gather using WiiRD, one of those things seems to point to two separate methods between Ike and Rob. Quite frankly, I have absolutely no idea what it is, but changing repointing Rob's method to Ike's allows Ike to go over Rob.
Here's the code
Code:
Rob has Ike's ...Something: 4A000000 80B27AC0 14000000 80914B5C E0000000 80008000
I'll look into this some more, but it's going to be a while until I have as much free time as I had today.
This module will allow you to clone Ike over any character in the roster and - when I finish the actual Engine part of the Clone Engine - clone him into any empty space in the roster.
In order to clone a character you need to put all of their resources (moveset, models, motion and final smash) into the target character's folder named according to the target character's name. Then adjust the generic module to match the character (Read the Change.txt) and rename it to the target character's module name.
If you want to go the extra mile and add sound whenever the host character isn't present, then you can adjust the sound banks to your liking with the following code:
Code:
Sound Bank Modifier:[Phantom Wings] 4A000000 80AD89E0 1400ZZZZ 0000000YY E0000000 80008000
ZZZZ = XX * 0x04
Characters [XX]: 00 Mario 01 Donkey Kong 02 Link 03 Samus 04 Yoshi 05 Kirby 06 Fox 07 Pikachu 08 Luigi 09 Captain Falcon 0A Ness 0B Bowser 0C Peach 0D Zelda 0E Sheik 0F Popo 10 (Nana) 11 Marth 12 Mr. Game & Watch 13 Falco 14 Ganondorf 15 Wario 16 Metaknight 17 Pit 18 Zero Suit Samus 19 Olimar 1A Lucas 1B Diddy Kong 1C Pokemon Trainer 1D Charizard 1E Squirtle 1F Ivysaur 20 Dedede 21 Lucario 22 Ike 23 Robot 24 (Pra-mai) 25 Jigglypuff 26 (Mewtwo) 27 (Roy) 28 (Dr. Mario) 29 Toon Link 2A (Toon Zelda) 2B (Toon Sheik) 2C Wolf 2D (Dixie) 2E Snake 2F Sonic 30 Giga Bowser 31 Warioman 32 Red Alloy 33 Blue Alloy 34 Yellow Alloy 35 Green Alloy 36 (Mario D)
Sound Bank Values [YY]: 01 Mario 02 Link 03 Pit 04 Metaknight 05 Dedede 06 Donkey Kong 07 Samus/Zero Suit Samus 08 Yoshi 09 Kirby 0A Fox 0B Pikachu 0C Luigi 0D Captain Falcon 0E Ness 0F Bowser 10 Peach 11 Zelda/Sheik 12 Popo/Nana 13 Marth 14 Mr. Game & Watch 15 Falco 16 Ganondorf 17 Wario 18 Olimar 19 Lucas 1A Diddy Kong 1B Pokemon Trainer 1C Charizard 1D Squirtle 1E Ivysaur 1F Lucario 20 Ike 21 Rob 22 Jigglypuff 23 Toon Link 24 Wolf 25 Snake 26 Sonic 27 Unknown 28 Alloy 29-4B Unknown
And finally, for your convenience and to prove that it works properly, here's a fully equipped clone of Ike Cloud over Mario.
Some things to note: -As noted above, unless you use the Sound Bank modifier, the clone will not have any unique sounds or voice if the host character is not in the match.
-If both the clone and the original are in the match, only one set of Graphic effects will be used. This is because the graphics are being loaded into a single set of ids that both movesets are calling whenever they create graphic effects. (To fix this, we'd need to further analyze the graphic effect files)
-The .Pac file which is usually considered optional when reskinning an existing character is required if you want to use training or SSE with the clone.
-Replacing the target character's Entry file is optional, but if you don't replace it then the original's entry Articles will still appear.
-All the Cloud outfits in the example file are the same... .
Before I go, please no requests for modules. I haven't mastered the art patching them yet so I need a little more time before I can mass produce them.
Flattery will get you everywhere, but for the time being I'm still not officially on the job. As with Dant's case, life has taken the wheel while hacking has gotten stuck with the back seat.
I'm aiming to take a little bit of time near the end of the month to try and get back into the swing of things again.