This looks cool. Would you be able to do that code for say characters? Samus and Zamus are characters that have notoriously strict memory limits and I think it would be amazing if there was a way to allocate at least 50 more kb than what Brawl has allocated for them.
Memory heaps are allocated by player as opposed to character. Each player has 4 memory heaps allocated to them. For player 1, they are:
Judging from the sizes, I would say Fighter1Resource is used for the model and Fighter1Resource2 is used for movesets and effects. Fighter1Instance is used specifically for the runtime character instance and I know that OverlayFighter1 is used for storing and executing the character's module.
As a side note, because there are only 4 fighter slots, alloys are stored collectively inside the Fighter3 and Fighter4 heaps - they can get away with this because they are smaller.
As far as increasing the size of these goes, we only have 510kb to work with - so if we were to distribute them over the 4 Resource2 heaps, it would only be an increase of about 128kb each.
I will try to see if it are any more articles we can port to other one. I bet all articles thats used by the Special B can be ported like luigis fireball, samus Charge Beam ect
The hardest part is finding the article ctor and dtor functions as well as the instantiation function. If you can find those 3 functions and the proper parameters to pass in when calling them, then porting them shouldn't be a problem.
okay, I have looks everywhere of how you did wanna port it to pal but I cant find how you did!
could you pm me of how you did and where you changed? cause it is just simply amazing!
if you have time and want that ofcourse!
The main areas I changed - in broad terms - are as follows:
0x5C20: Removed all but one call to Create_wnMarioFireball_holder_and_article 0x7B60: Changed Create_wnMarioFireball_holder_and_article to call wnRobotBeam.ctor instead of wnMarioFireball.ctor. 0x7BB4: Changed wnInstanceHolder<wnMarioFireball>.Method[0][0] to call wnRobotBeam.dtor instead of wnMarioFireball.dtor 0x7C10: Removed all but the first call to soInstanceHolder<wnMarioFireball>.Method[0][0] 0xAEA4: Changed wnArticleMediator.Method[0][1] to only check the first instance holder when creating an instance of wnRobotBeam 0xAFB0: Changed wnArticleMediator.Method[0][1] to call wnRobotBeam.instantiate instead of wnMarioFireball.instantiate 0xB3D0: Changed wnArticleMediator.Method[1][3] to only try to clear 1 wnRobotBeam instance. 0xB6E8: Changed wnArticleMediator.Method[1][4] to only check 1 wnRobotBeam instance holder. 0xB950: Changed wnArticleMediator.Method[1][5] to return an instance cap of 1 for wnRobotBeam 0xBD80: Changed wnArticleMediator.Method[1][2] to only clear 1 wnRobotBeam instance.
Just for reference, the method listing for wnArticleMediator is as follows:
It seems like a lot, but the actual number of instructions I changed is probably no more than 20. If you compare the modified module to the original Mario module, you should be able to get a good idea of what needs to be changed in the PAL version.
Concerning the file size limits: I think I may have stumbled upon a code that can be used to increase the amount of memory allocated towards stage icons. Unfortunately Brawl makes almost full use of the Wii's memory, so there's not a lot of room for expansion. However, it seems that you can safely increase the limit by approximately 510kb without causing the game to run out of memory.
Anyone care to test this for me? You'll need a sc_selmap.pac file that exceeds the normal size limit.
I would imagine something like this would help with the bizarre Plug&Play .rels behavior in regards to costume slots. In case you weren't aware, I've found that if you port a character to another who has a FitChar## that the original does not, that costume can't be selected.
For me, I've got Roy over ROB and Mewtwo over Jiggs. Roy can't access FitRobot06, it loads FitRobot00 instead. Mewtwo can't get FitPurin03.
The Plug&Play modules cover color restrictions as well to prevent crashing in case one of the original's colors aren't covered by the new character's. If you want to remove the color restrictions on Marth's module, just change the flags at 0xE6 in Section[8] of Marth's module.
The flags are documented here under Costume Flags.
Just remember that you need to make sure that all interface elements including CSPs and battle portraits exist for the additional colors.
Well, Rob's laser has been successfully ported over to Mario. It turns out I forgot to change the calls for wnMarioFireball.dtor to wnRobotLaser.dtor. There's also an oddity in the instantiation function which seems to use Mario's FLUDD charge time (viewable in BrawlBox) as a bone index for where the laser should be generated. As Mario's model doesn't contain a Bone 90, the game was crashing whenever it tried to create one.
Aside from that, Mario's Article1 parameters are now used as parameters for Rob's laser. The laser functions as it should including its ricochet behavior - however I still haven't found a way to allow Mario to aim it when shooting it. There is also a problem in that the laser uses Rob's laser effect meaning that if Rob isn't in the match, it will only appear a white polygon trail - I think BrawlBox's latest REFT editor should be able to fix that though.
I've learned a lot about articles and their constructors from this experiment. For the most part, articles are constructed almost identically aside from a few minor tweaks to the resulting object. Another interesting thing to note is that articles are also constructed nearly identically to actual characters - meaning it may be possible sometime in the future to use a character as an article.
I've also been experimenting a little bit with using menu_selchar.rel and menu_selchar_access.rel to implement the custom CSS code and include localized (and extendable) character color and icon options (think Brawl Masquerade) - but I think it would be better if I found a way to load a custom extension module file instead which all main game modifications can be pooled inside.
Anyways, here's the Laser Mario files. Right now you can only shoot one laser at a time because I only made one instance holder for it. Adding multiple instance holders - while possible - would take a substantial amount of manual hex editing that's not really necessary for the sake of this experiment.
I've also made a couple of cosmetic changes to the laser's behavior - that was mostly just for fun.
PW, can you comment more on the AI controllers you referred to here? I have made a lot of progress on AI and that may be what I need to finish things off
I don't know a whole lot about them myself. They are stored in the middle of a vtable at 0x80B27A34. More specifically, they're stored at m1b[5] 0x48B94[/i] and happen to be positioned right beside a reference to the string "aiInput". Each one corresponds to a character id and gets called constantly during a match. Back with some of my earlier attempts at creating clone modules, they caused the game to crash for certain CPU clones when they were left unchanged. However, it also crashed when I was working with the Plug&Play modules and accidentally set the ptr to 0 even though I was a player at the time - so it seems they aren't exclusively called just for CPUs.
okay! you just smash my head with a hammer! stop being so awesome and tell me what you did
well, dont stop being awesome and share some information of how you did! that might help alot!
Well, the whole process was rather lengthily, but I'll try to break it down the best I can.
It all starts in your target character's ctor function. For my case, I used ftMario.ctor. ftMario.ctor is located at file offset 0x13C. In one of my earlier posts I discussed how ftCharacter.ctor is responsible for creating the whole character memory object as well as all the module objects associated with it. In particular, we are interested in soGenerateArticleManageModuleImpl which is responsible for generating and manipulating character articles (characters without any articles will not implement this modules). Most ftCharacter.ctor functions generally take the same shape. This means that for most module files, the part of ftCharacter.ctor that calls soGenerateArticleManageModuleImpl.ctor is usually around file offset 0x850. As it turns out, the constructor call for Mario's article module is located at file offset 0x838. Following this call we find out that the soGenerateArticleManageModuleImpl.ctor function is located at file offset 0x5A74 inside ft_mario.rel
Before I go into the soGenerateArticleManageModuleImpl.ctor function, I want to explain how the soGenerateArticleManageModuleImpl object is stored in memory. It is difficult to describe it using memory offsets, so I'll describe it as a basic C++ definition.
Code:
struct soGenerateArticleManageModuleImpl { soArrayVector<wnArticle *, N> (size: 0xC + N * 0x4) soArrayVector<wnArticleEventObserver, N> (size: 0xC + N * 0x10)
Notice that the offsets 0x20 and 0x7C are equal to the summed sizes of the previous elements. That is:
0xC + 5 * 0x4 = 0x20 0xC + 5 * 0x10 = 0x5C
0x20 + 0x5C = 0x7C
This is important as you must make sure all you objects are not overlapping with other objects in memory when it comes to adding your own articles.
After these 3 base actions have been performed, there's two ways the function can go about creating articles. The first is the most basic; the constructor function does this starting at 0x5AC4:
That's probably a lot of information to take in there, but suffice it to say, those 7 primary instructions are responsible for creating the wnMarioHugeFlame object - Mario's Final Smash. Whenever you want to create an article that only appears as a single instance onscreen, then this is the structure that gets used. Besides the offsets and function references, the structure mostly stays the same.
The second method for generating articles is used for articles that appear as multiple instances onscreen - such as Mario's fireballs. They get created starting at 0x5BBC:
// update the soInstancePool declaration with a new one containing the articles we're going to add. 0x5BC4 [this + 0x84] = soInstancePool<...>.declaration 0x5AC0 var temp = this + 0x20000 // [this + 0x84] == [soArticleMediator_ptr + 0x8] // temp is used due to limitations in PowerPC's adding capabilities
0x5BD4 [temp - 0x5600] = soInstancePoolSub<wnMarioFireball, ...>.declaration 0x5BD8 var soInstancePools_ptr = temp - 0x5FFC 0x5BE4 [temp - 0x5FFC] = soInstancePoolSub<wnMarioFireball, ...>.declaration 0x5BF0 [temp - 0x5FF8] = soInstancePoolSub<wnMarioFireball, ...>.declaration 0x5C00 [temp - 0x5FF4] = soInstancePoolSub<wnMarioFireball, ...>.declaration 0x5C0C [temp - 0x5FF0] = soInstancePoolSub<wnMarioFireball, ...>.declaration // These are written immediately following the previously created article.
0x5C18 Create_wnMarioFireball_holder_and_article(soInstancePools + 0xC, ...) 0x5C24 Create_wnMarioFireball_holder_and_article(soInstancePools + 0x1F54, ...) 0x5C30 Create_wnMarioFireball_holder_and_article(soInstancePools + 0x3EA4, ...) 0x5C3C Create_wnMarioFireball_holder_and_article(soInstancePools + 0x5DEC, ...) 0x5C48 Create_wnMarioFireball_holder_and_article(temp + 0x2738, ...) // Once again, these offsets are immediately following the soInstancePoolSubs we just created.
The Create_wnMarioFireball_holder_and_article is another function inside ft_mario.rel - it can be found at file offset 0x7AF4. The function does exactly what it says.
So to summarize, the first method for creating articles has you updating the instance pool; creating the instance pool sub and instance holder; obtaining the .pac data; and creating the article all in the main function. The second method involves updating the instance pool, creating the instance pool subs and then calling the helper function to actually create the instance holder, obtain the .pac data, and create the article.
When it came to me adding ROB's laser, I replaced Create_wnMarioFireball_holder_and_article'swnMarioFireball.ctor and ftDataProvider.get_wnMarioFireball_.pac_data calls with calls to wnRobotBeam.ctor and ftDataProvider.get_wnRobotBeam_.pac_data. This wasn't a problem because both articles are Kirby-Copy articles meaning these functions were stored in sora_melee. When replacing the get .pac data function, it is also necessary to change the id being passed to it (or you can leave Mario's get .pac data function and end up with a weird mixture of both of them like I mentioned above).
I should also mention that the actual wnInstanceHolder and soInstancePoolSub declarations don't need to be changed as they are just primitive data structures that all have exactly the same shape and functionality.
Additionally, I removed all but the first call to Create_wnMarioFireball_holder_and_article as wnRobotBeam is actually larger in size than wnMarioFireball and - like I said ealier - you can't have objects overlapping in memory (you can find the size of wnMarioFireball by subtracting the offsets that are passed to Create_wnMarioFireball_holder_and_article).
Finally, I had to change the article count references and the call to ftMarioTransactor.instantiate_wnMarioFireball located inside soArticleMediatorImpl. If these count values weren't changed, then the game will crash by trying to access the other 4 article instances which I removed.
I've listed the basic details on that in one of my earlier posts, but to find everything you'll need to know the function listing of soArticleMediatorImpl:
A lot of this was trial and error and there isn't really a consistent way of finding everything. Even after doing all that, there were still a couple of bugs which I had to resolve using WiiRD - and I'm not even sure what exactly was causing it.
Anyways, make of it what you will. Hopefully you'll be able to work something out with it. Like I said before: it's pretty complicated.
Well it looks like porting Snake was a lot harder than I thought it would be. In the end, I updated the Plug&Play model to v1.2 to cover a certain oddity in sora_melee that made it difficult to patch entry data. There's not too many changes except for a new _prolog function that gets called before the v1.1 function. If anyone's had any problems porting characters over Fox, Falco, Peach, Wario, Metaknight or Snake, then this would be the cause for it.
While cloning characters to completely new slots is technically possible using the Plug&Play modules, you still need to have interface elements, CSPs, and CSS icons for the new character slot. You also need to add a new .rel and .pac file paths to sora_melee so they get loaded according to the new character Id. Because the .rel can't actually patch it's own file string, you'll have to use codes. Perhaps a creative individual could come up with a patch function that executes on sora_menu_selchar_access.rel or some other modules which makes the appropriate changes when it is loaded.
One other thing to note, while CPUs no longer exhibit behavior dictated by the A.I. controller functions (such as Olimar's constant Neutral B usage) they do still seem to exhibit some behavior of the original characters such as when they use their FS. The only A.I. related data I know of are the A.I. controllers and the A.I. files inside the MotionEtc files so I'm not sure what needs to be patched to fixed this.
I think I'm going to take a break from hacking after this. I've done a pretty hefty hacking marathon this week and have neglected a lot of important things thanks to that. But we have made a lot of progress here.
Now before the hype bandwagon gets kicked into high gear, there's a couple of things to note:
This is a very unstable test - a lot of what you see in the screenshot is the result of heavy modification of the game while it was running. The game also crashes when you exit the match.
Rob must be in the match to have the laser effect.
It is possible to load up Mario's fireball effect in place of the laser effect; this results in an odd merge between both articles. Mario shoots out a projectile that travels horizontally like a laser, but has the speed, hit effect, and damage of a fireball.
The laser was easy to copy into Mario's article bank because wnRobotLaser.ctor and ftRobotTransactor.instantiate_robot_laser are both stored as global functions in sora_melee due to Rob's laser being copyable by Kirby. Other articles are harder to replicate as their primary functions are stored inside the owner character's module file.
However, progress is progress, so I thought I'd report on it here. Here's hoping we can use this to generate more sophisticated custom characters.
Most of the fields are pretty self explanatory except id_step which simply offsets the destination address by character_id * id_step. The data_tag is 0xD8A for all entries except for the last one.
The last entry has a data_tag of 0x1D8A. This entry patches the character_id into the addresses stored at the source ptr. Writes are done in halfwords, so all addresses need to be shifted by 2 if you are writing to assembly addresses.
The first 9 copy entries are usually dedicated for patching known character parameters in sora_melee. The one's that will probably be the most useful are entries 7 and 8 which patch the character's soundbank and constants. Following the first 9 entries are the entries used for patching sora_melee functions.
Finding the functions in sora_melee is no easy feat. The main places where cloned characters will encounter errors in sora_melee are the places where the game reuses code for other characters. This is primarily to do with places involving Kirby's copy abilities, but there are other places like in the case of Link's Final Smash which has code shared with ToonLink's Final Smash.
For Snake, there shouldn't be too many problems because the grenades are of type wnSimple (I think...) which means that there shouldn't be any special code sharing to allow Kirby to use them.
As for the remaining articles, as long as you patch all the constant character Id values in ft_snake.rel, they shouldn't exhibit any problems.
You don't need any codes for entries as those are also covered by the modules.
I've tested Lucario over Yoshi and it works with no problems. I haven't tested Mewtwo yet though. I suggest that you first get Lucario working over Yoshi, and then replace Lucario's files with Mewtwo's like usual.
(Credit to Dantarion for his documentation of the modules on OpenSA.com)
I've also made a new revision to the Plug&Play model. Most of it was just to make the modules a bit easier to deal with on my end, but the new modules also now cover any bugs related to entry and result screen files as well as a few other character related flags. I've also disabled Kirby Hats for all cloned characters to avoid possible complications involving character resources (They can still be enabled, but you get the original character's hat).
As far as I've tested, all 5 of these modules work perfectly in game (Including Lucario, who's Aura Sphere now properly shows up). However, the bugs concerning when graphical and sound files get loaded and unloaded still remains. Also, while the modules do patch the soundbanks, the soundbanks actually get read before the module is loaded - so the first time you load them, they won't have the proper soundbank loaded.
I've also added a small tweak to the Module Editor 3 to make it easier to change the modules between characters.
To change a module, simply open it up in the editor and make the following changes:
- Change the module Id of the file to the target module Id. - Open Section[8] in the memory viewer and change the first value to the target character Id.
Character Ids: 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)
As far as how these modules work: simply put, they are just doing the same thing that codes do, but they make things a whole lot simpler by exploiting the powerful nature of relocations as well as the fact that modules are programs that can be run when they're loaded up.
For each module, I've added a simple program in Section[7] that gets called first during the module's _prolog function. Section[7] is identical across all of the Plug&Play modules. The actual changes and associated data are stored in Section[8] of the module. These are hex strings that are used to patch the game files when the module is loaded; this includes things like constants and color flags as well as any changes that need to be made to sora_melee. One final block in Section[8] is responsible for identifying what changes need to be made inside the module itself in order for it to function properly.
It's really quite a simple, but elegant solution to the whole mess of dealing with modules and how they integrate with sora_melee along with other global data. Making them isn't that hard - it's just tedious given the tools currently available to edit modules. The hardest part is finding the areas in sora_melee that actually need to be patched to have the cloned characters run properly.
Alright, it looks like the research on modules that began all those years ago has finally yielded some results.
This new line of modules which I've dubbed Plug&Play modules requires no codes for constants, no codes for A.I. controllers and no changes to sora_melee. These modules will work with or without the original character in the match. Moreover, customizing the module for each character slot is a matter of changing 3 values inside the file. Of course, you still need the actual moveset and motion files to go along with the module, but those files can be used as-is without any changes.
Right now, I've only created one of this kind of module: ft_Lucario.rel which me and SonicBrawler were working on - feel free to try it out. The changes needed turn turn it into a Lucario clone over any other character are documented in the .txt that's with the file.
I should note that the original bug where Lucario's Aura Sphere is not visible is still there. Also, if you load two Lucario characters and then unload one of them, it will unload Lucario's aura graphic effects along with it leaving the remaining one without any effects. Both of these bugs seem to be beyond the scope of the modules and are directly related to effect files and how they're indexed.
The module has been tested over Mario, Pit, Marth and Rob and performed consistently across the four of them, but it hasn't been tested on the entire roster.
One final note: while there was mention of using the Project M codes to aid in the development of a working Lucario clone, I have not taken the time to examine or reverse engineer the Project M codes. This module was a product of my own work.
Yeah, sorry about the Module Editor 2.2. Unfortunately, I programmed it really poorly, so adding a function to view the whole assembly block is really more trouble than it's worth. Instead, I've been using the first version of the module editor whenever it comes to viewing standalone functions (I actually use all 3 versions for different purposes XD). Now that BlackJax has started to implement the assembly viewer in BrawlBox, I don't think continuing to work on the Module Viewer is really worth it anymore.
Anyways, here's the v1 download in case you need it:
I've posted some info over in the module file thread which may be useful when it comes to cloning modules.
Just remember that while it does add a lot of clarity into the cloning process, most of the points I mentioned are ones that you guys are already changing when porting modules - so it may not be able to help much in terms of progress.
So what is the significance of all this? Well, I'll try to explain it the best I can.
All interfacing with the character modules are primarily done through the ftClassInfoImpl objects. In particular, whenever the game needs an instance of Lucario, it calls ftClassInfoImpl<33, ftLucario>.Method[0][2]. This function simply calls ftLucario.ctor.
ftLucario.ctor calls Fighter.base_ctor, ftFighterBuildData.base_ctor, soInstanceManagerFixedSimple.base_ctor, soModuleAccessor.base_ctor and each of the module constructors. Most character modules will usually create derived versions of the modules so they will implement their own constructors which will generate part of the object and then call the sora_melee version of the constructor. Sometimes though the character module will instead just opt to call the base constructor on its own as all it needs is the base functionality of the sora_melee version. Other times, a null placeholder will be loaded up in place of the module instead.
I haven't mapped all the functions that ftLucario.ctor calls yet, but that much on its own is pretty interesting.
Of particular interest is the soGenerateArticleManageModuleImpl.ctor function. Characters who don't use articles will fill the soGenerateArticleManageModuleImpl spot with a null placeholder, but characters who do use articles will have this function implemented. In addition to creating the base soGenerateArticleManageModuleImpl object, the implemented constructor will also create create soInstancePool, soInstancePoolSub and wnInstanceHolder objects inside of the soGenerateArticleManageModuleImpl object. Additionally, it will also call the constructor functions for the articles (in Lucario's case, it calls wnLucarioQigong.ctor and wnLucarioAuraBall.ctor). Essentially, this function sets up all of Lucario's articles for use. Later on when we want to create instances of the articles, we call soArticleMediatorImpl.Method[0][1] which in turn calls either create_wnLucarioQigong_instance or create_wnLucarioAuraBall_instance.
On a side note, the reason the wnLucarioAuraBall constructor and instance generator functions are in sora_melee is because Kirby can copy Lucario's AuraBall.
There are other points of interest to this information too. When cloning modules, the places that cause difficulties in the cloning process are mainly the article constructors. Both wnLucarioQigong.ctor and wnLucarioAuraBall.ctor require a .pac_resource pointer. Cloned modules will usually try to retrieve the original's .pac_resource pointer which causes a crash if the original isn't loaded. Lucario's create_wnAuraBall_instance function also references a .pac_resource pointer. The ftLucarioExtendParamAccessor.ctor and ftClassInfoImpl<33, ftLucario>.ctor functions both statically reference the module id - both need to be changed when cloning. Fighter.base_ctor and ftFighterBuildData.base_ctor also reference the module id - when they are called in ftLucario.ctor, the passed id needs to be changed.
Finally, there some spots here and there which needs to gain access to the ftClassInfoImpl object. this is usually done by calling a specific sora_melee function and passing in the module id. One of the places that needs to call this function is near the end of ftLucario.ctor (this is the same for all characters). For Lucario's module, there are two other places which does this: ftLucario.Method[17][16] and ftLucario.Method[0][3]. I'm not sure the significance of these two functions, but their use doesn't seem to be universal.
Anyways, I think this information will prove useful not just for cloning characters, but for adding additional functionality to existing characters as well. Unfortunately, there seems to be a lot of syntax to follow in order to ensure things run nicely - but hopefully that will come with time.