• Welcome to Smashboards, the world's largest Super Smash Brothers community! Over 250,000 Smash Bros. fans from around the world have come to discuss these great games in over 19 million posts!

    You are currently viewing our boards as a visitor. Click here to sign up right now and start on your path in the Smash community!

Official Melee Code Manager (v4.4.1) - Easily Add Mods to Your Game!

Capt. Tin

Smash Apprentice
Joined
Jul 25, 2014
Messages
105
Location
Chicago, IL
NNID
Capt.Tin
I don't know the details of what you're doing, so it's kind of hard to say. What version of MCM and Dolphin are you using?

Try using the latest version of MCM if you're not already (3.2 at this time), and/or another version of Dolphin, like 5.0+ (or set your Dolphin's settings back to defaults in case there's some possibility of conflicting settings). I just tried that code by itself on a vanilla 1.02 disc via MCM 3.2 on Dolphin 5.0-5491 and it worked fine.
I forgot to reply to this, but I'm still having this issue.

Using MCM 4.0 (Was using 3.2 when I posted my earlier message) and Dolphin 5.0. I reset Dolphin to default settings and it still occurred. Was using a Vanilla 1.02 disc with only the debug menu code enabled and still didn't work. This was the only error that popped up before Dolphin crashed:
 

Attachments

All Things Gaming 6

Smash Apprentice
Joined
Jul 2, 2016
Messages
88
Location
The middle of Knowhere
I have converted some codes to work with the PAL version of Melee:

Bowser - Flame Cancel
Restores his Flame Cancel ability to as it was in v1.00.
[Achilles]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x80135684 ---- 38800155 -> 38800156
PAL 1.00 ---- 0x80135E28 ---- 38800155 -> 38800156

Captain Falcon - Raptor Boost Enters "Fall" Action!?
For aerial hit and miss, and grounded Raptor Boost that travels offstage.
FallSpecial is the "helpless" fall state.s
[Achilles]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x800E39D0 ---- 4BFB2F31 -> 4BFE8D61
------------- 0x800E3CD0 ---- 4BFB2C31 -> 4BFE8A61
PAL 1.00 ---- 0x800E4184 ---- 4BFB2E35 -> 4BFE8D61
------------- 0x800E4484 ---- 4BFB2B35 -> 4BFE8A61



Captain Falcon - No Rapid Jabs
[Achilles]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x800D6B8C ---- 7C0802A6 -> Branch
81DE0064 2C0E0002
40820008 4E800020
7C0802A6 00000000
PAL 1.00 ---- 0x800D7340 ---- 7C0802A6 -> Branch
81DE0064 2C0E0002
40820008 4E800020
7C0802A6 00000000

DK - Always Full Giant Punch
[Achilles]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x8010D98C ---- 40820010 -> 90A4002C
PAL 1.00 ---- 0x8010E140 ---- 40820010 -> 90A4002C

Falco/Fox - Hold Z While *Aerial* Laser Emits to Fire at Half Speed
[Achilles]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x800E6908 ---- 80BF001C -> Branch
80BD065C 54A506F7
41820014 3CA04000
90A1FFF8 C1E1FFF8
FC427824 80BF001C
60000000 48000000
PAL 1.00 ---- 0x800E70BC ---- 80BF001C -> Branch
80BD065C 54A506F7
41820014 3CA04000
90A1FFF8 C1E1FFF8
FC427824 80BF001C
60000000 48000000


Giga Bowser Can Be Grabbed
[Achilles]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x8014F704 ---- 981F222A -> 60000000
PAL 1.00 ---- 0x8014FEA8 ---- 981F222A -> 60000000

ICies - Solo Popo Up-B Gives Increased Vertical Velocity
[Achilles]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x80121E7C ---- C00400A4 -> C004013C
PAL 1.00 ---- 0x80122630 ---- C00400A4 -> C004013C

Mewtwo - Always Full Shadow Ball
[Achilles]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x80144F90 ---- FC01000040820010 -> 89E2E42391E32234
PAL 1.00 ---- 0x80145734 ---- FC01000040820010 -> 89E2E42391E32234

Mr. Game and Watch - Always Specific Hammer Value
Default is 9.
[Wooggle]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x8014C760 ---- 7FC3002E -> 3BC00008
# To change the above code to give a different number (N), use '3BC0000X', where X = N - 1.
PAL 1.00 ---- 0x8014CF04 ---- 7FC3002E -> 3BC00008
# To change the above code to give a different number (N), use '3BC0000X', where X = N - 1.

Ness - PK Thunder Does Not Disappear on Hit or Death
This is an SSBM v1.00 game mechanic that was changed in v1.02.
[_glook]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x802ABCB0 ---- 4BFFFC5D38600001 -> 4bfc748160000000
PAL 1.00 ---- 0x802AC380 ---- 4BFFFC5D38600001 -> 4bfc748160000000

Ness - PK Thunder and PK Flash Last Forever
PK Thunder is still stopped when it hits something (either the ground or a character).
[_glook]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.02 --- 0x80269528 ---- 7C0802A6 -> 4E800020
PAL 1.00 ---- 0x80269BF8 ---- 7C0802A6 -> 4E800020

Peach - Always Pull Specific Turnip
The default for this code is Stitch Face, but it can be changed to any of the turnips.
Check the text files in the library for notes on how to change it.
[??]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.00 --- 0x802BBDA0 ---- 38C60001 -> 39000007
------------- 0x8011FE74 ---- 7FE3FB78 -> 48000010
# To change the turnip for the mod above, change the
# 7 in "39000007" to one of the following numbers:
# 0: Smile
# 1: T Eyes
# 2: Line Eyes
# 3: Circle Eyes
# 4: Upward Curve Eyes
# 5: Wink
# 6: Dot Eyes
# 7: Stitch Face
PAL 1.00 ---- 0x802BD9D4 ---- 7CC83378 -> 39000000
------------- 0x80120CB4 ---- 7FE3FB78 -> 48000010

NTSC 1.01 --- 0x802BC988 ---- 7CC83378 -> 39000007
------------- 0x8011CE04 ---- 40820010 -> 48000010
NTSC 1.02 --- 0x802BD410 ---- 7CC83378 -> 39000007
------------- 0x8011D090 ---- 40820010 -> 48000010

PM me If you have any problems.
 
Last edited:

rockandroll805

Smash Rookie
Joined
Mar 14, 2017
Messages
7
I forgot to reply to this, but I'm still having this issue.

Using MCM 4.0 (Was using 3.2 when I posted my earlier message) and Dolphin 5.0. I reset Dolphin to default settings and it still occurred. Was using a Vanilla 1.02 disc with only the debug menu code enabled and still didn't work. This was the only error that popped up before Dolphin crashed:
I am also having this issue whenever I try to enter the debug menu whether through "Debug menu replaces Tournament Mode" or by setting the AR code in dolphin. It happens any time I enable any code using MCM and will continue to happen even if I disable the code with MCM and have no other codes enabled. For example if I copy my 1.02 iso of melee with nothing on it, go into debug mode it works fine but if I enable anything on the copy and disable it I can't go into debug anymore because of that error.
 

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,179
Location
Sacramento, CA
I forgot to reply to this, but I'm still having this issue.

Using MCM 4.0 (Was using 3.2 when I posted my earlier message) and Dolphin 5.0. I reset Dolphin to default settings and it still occurred. Was using a Vanilla 1.02 disc with only the debug menu code enabled and still didn't work. This was the only error that popped up before Dolphin crashed:
I am also having this issue whenever I try to enter the debug menu whether through "Debug menu replaces Tournament Mode" or by setting the AR code in dolphin. It happens any time I enable any code using MCM and will continue to happen even if I disable the code with MCM and have no other codes enabled. For example if I copy my 1.02 iso of melee with nothing on it, go into debug mode it works fine but if I enable anything on the copy and disable it I can't go into debug anymore because of that error.
You most likely have the Debug Mode Region selected for use for custom code. You can check/change that by clicking on the Code-Space Options button:
upload_2018-2-21_19-26-41.png

All regions that are selected in that options window will have the vanilla code at those areas erased, in order to reserve the area for custom code. So just deselect that region if you want to use the game's vanilla Debug Mode. Then use the "Restore" button to the right of that region to restore the original game code there, or you could manually copy a new DOL file, or use the button labeled "Restore Original DOL", which restores the whole DOL to vanilla. If I remember for the next version, I'll change that region so it's disabled by default.
 

rockandroll805

Smash Rookie
Joined
Mar 14, 2017
Messages
7
You most likely have the Debug Mode Region selected for use for custom code. You can check/change that by clicking on the Code-Space Options button:

All regions that are selected in that options window will have the vanilla code at those areas erased, in order to reserve the area for custom code. So just deselect that region if you want to use the game's vanilla Debug Mode. Then use the "Restore" button to the right of that region to restore the original game code there, or you could manually copy a new DOL file, or use the button labeled "Restore Original DOL", which restores the whole DOL to vanilla. If I remember for the next version, I'll change that region so it's disabled by default.
Wow, I feel silly, I remember looking through that menu too. Anyways, thanks for the fast reply, all this stuff is super helpful me getting into modding. I got everything working normally again.
 

DraGon72097

Smash Rookie
Joined
Oct 25, 2016
Messages
18
So I need some help with this:

I'm trying to import some gecko codes, specifically the UCF mod, into the 20XX 4.07++ DOL, however it doesn't seem to work. I'm using Melee Code Manager v4.0, and I've tried every combination of reserved regions. Whenever I try to run the iso (testing in dolphin 5.0-321 with no gecko codes/AR codes enabled), it freezes on the black screen before I'm prompted that there is no memory card. The regular DOL works just fine, so I'm certain it's the imported codes.

Is there some hidden setting I'm not adjusting? I've left all the preinstalled codes alone, and only adjusted the reserved regions and added the UCF mod. Help would be greatly appreciated.
 

Rachman

be water my friend
Joined
Mar 22, 2015
Messages
229
Location
FL
So I need some help with this:

I'm trying to import some gecko codes, specifically the UCF mod, into the 20XX 4.07++ DOL, however it doesn't seem to work. I'm using Melee Code Manager v4.0, and I've tried every combination of reserved regions. Whenever I try to run the iso (testing in dolphin 5.0-321 with no gecko codes/AR codes enabled), it freezes on the black screen before I'm prompted that there is no memory card. The regular DOL works just fine, so I'm certain it's the imported codes.

Is there some hidden setting I'm not adjusting? I've left all the preinstalled codes alone, and only adjusted the reserved regions and added the UCF mod. Help would be greatly appreciated.
try using mcm 2.0, fixed my issues
 

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,179
Location
Sacramento, CA
So I need some help with this:

I'm trying to import some gecko codes, specifically the UCF mod, into the 20XX 4.07++ DOL, however it doesn't seem to work. I'm using Melee Code Manager v4.0, and I've tried every combination of reserved regions. Whenever I try to run the iso (testing in dolphin 5.0-321 with no gecko codes/AR codes enabled), it freezes on the black screen before I'm prompted that there is no memory card. The regular DOL works just fine, so I'm certain it's the imported codes.

Is there some hidden setting I'm not adjusting? I've left all the preinstalled codes alone, and only adjusted the reserved regions and added the UCF mod. Help would be greatly appreciated.
try using mcm 2.0, fixed my issues

Did you guys notice/follow this from the last update?:

**Use the "20XX 4.07++ Codes.txt" file from the GitHub, but rename the Sheik/Zelda CPU Disable Transformations mods so that they're not seen as duplicates. You don't need to use the settings.py file from there; just use (only) the 20XX Regions that comes with this new MCM version.
This still has the downside (that will be true for any 20XX/MCM version, ATM) that not all codes in 20XX will populate in the program. MCM didn't exist when Achilles first started 20XX, so the main problem is that a lot of 20XX's changes are not included in any MCM library, and are just manually edited into the DOL independently. That's why you can only use the regions Achilles has defined in the settings file on the github (or in the region specified for it in the latest version of MCM), and why it's difficult to add codes, because there's a good chance you'll overwrite some other important custom code.

Basically, the library file on the current 20XX GitHub just loosely utilizes MCM's ability to dynamically assign codespace for Achilles' code injections. So even mods that do show up in MCM may have other bits of custom code that they interact with, that do not show up in the library. Meaning that disabling a code may only uninstall part of it, resulting in a crash when the game reaches some other bit of code. Ideally, all code relating to a specific mod should really be consolidated into a single MCM module, so that it can safely be added/removed at any time.

I was working on a new MCM library that should have nearly everything, which would make adding new codes to 20XX much easier. (Partly because the program will tell you if any mods conflict with one another.) However it still needs some work, and I haven't had time for a while lately. It's very high on my Melee related to-do list though.

As for Gecko codes, you can't add them unless you modify where the Gecko codehandler and codelist are stored. You'll probably also need more space for them since 20XX uses most of the current free DOL space. See this post for a file that has extra space added to it. Make sure to read the spoiler it mentions on configuring MCM.
 
Last edited:

tauKhan

Smash Lord
Joined
Feb 9, 2014
Messages
1,349
DraGon72097 DraGon72097

Adding to what DRGN answered:
1) Did you try adding UCF as an injection mod? I attached a properly converted (NTSC 1.02) UCF 0.73 injection mod text file to this message. You may add the file to the Mods Library folder.
2) Remove (or exclude) the default mcm library mods from the Mods Library when editing 20xx to avoid conflicting codes interfering.
 

Attachments

Last edited:

tufferugli

Smash Rookie
Joined
Oct 14, 2018
Messages
15
hi all!
first time posting on smashboards :)

so, i was trying to "transalte" this code from ntsc 1.02 to pal
Code:
Dpad up/down toggles rumble on CSS
NTSC 1.02

C22608D8 00000019
887F0007 2C030000
40820070 7C972378
57800739 40820010
5780077B 40820034
4800009C 7EE3BB78
38800000 38A0000E
38C00000 38ED9950
3D808037 618C8430
7D8903A6 4E800421
38800001 48000008
38800000 7EE3BB78
3D808015 618CED4C
7D8903A6 4E800421
38800001 989F0007
3C80C040 909F0014
C03F0014 C0428E0C
C01F000C EC01002A
D01F000C FC600850
FC030840 41810008
EC6300B2 D07F0014
4180001C C0828258
FC032040 41810010
38800000 909F0014
989F0007 889F0004
60000000 00000000

i've converted the first ram address in pal (C22608D8 to C226103C) like i did for some other codes, but it's not enough.
can someone help me?
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
hi all!
first time posting on smashboards :)

so, i was trying to "transalte" this code from ntsc 1.02 to pal
Code:
Dpad up/down toggles rumble on CSS
NTSC 1.02

C22608D8 00000019
887F0007 2C030000
40820070 7C972378
57800739 40820010
5780077B 40820034
4800009C 7EE3BB78
38800000 38A0000E
38C00000 38ED9950
3D808037 618C8430
7D8903A6 4E800421
38800001 48000008
38800000 7EE3BB78
3D808015 618CED4C
7D8903A6 4E800421
38800001 989F0007
3C80C040 909F0014
C03F0014 C0428E0C
C01F000C EC01002A
D01F000C FC600850
FC030840 41810008
EC6300B2 D07F0014
4180001C C0828258
FC032040 41810010
38800000 909F0014
989F0007 889F0004
60000000 00000000

i've converted the first ram address in pal (C22608D8 to C226103C) like i did for some other codes, but it's not enough.
can someone help me?
Welcome! There appear to be 2 problems here. I don’t have a PAL version to test this on atm, so let me know if these fixes don't work correctly.

First, from the looks of things -- it appears that you’ve copied the C2 address and translated it as a DOL offset rather than a RAM address, giving you the incorrect C2 input. To translate a C2 code you need to convert the RAM address; which is the C2 input with "80" replacing the "C2" part:


(Edit: Thanks T tauKhan for explaining this simpler method)

After the tool finds a matching RAM address for other versions, you can take the last 6 digits of the PAL address and use it for your new C2 input. So in this case, C2261078 is the "translation" you’re looking for. It represents the RAM address 80261078.


Second, there are a couple of function calls in that code. Gecko codes need to load the addresses for these in halves in order to call them, so they usually take the form of 2 instructions. In this code, there are 2 cases of this that I can see in the instructions: “3D808037 618C8430” and “3D808015 618CED4C”. These create the addresses 80378430 and 8015ED4C when put together.

To get this code working on a PAL version of Melee, you would need to convert these addresses just like you would the C2 input.


Here's the code with all of the above conversions applied:
Dpad up/down toggles rumble on CSS
PAL 1.00

C2261078 00000019
887F0007 2C030000
40820070 7C972378
57800739 40820010
5780077B 40820034
4800009C 7EE3BB78
38800000 38A0000E
38C00000 38ED9950
3D808037 618C8334
7D8903A6 4E800421
38800001 48000008
38800000 7EE3BB78
3D808015 618CF4F0
7D8903A6 4E800421
38800001 989F0007
3C80C040 909F0014
C03F0014 C0428E0C
C01F000C EC01002A
D01F000C FC600850
FC030840 41810008
EC6300B2 D07F0014
4180001C C0828258
FC032040 41810010
38800000 909F0014
989F0007 889F0004
60000000 00000000
 
Last edited:

tufferugli

Smash Rookie
Joined
Oct 14, 2018
Messages
15
Welcome! There appear to be 2 problems here. I don’t have a PAL version to test this on atm, so let me know if these fixes don't work correctly.

First, from the looks of things -- it appears that you’ve copied the C2 address and translated it as a DOL offset rather than a RAM address, giving you the incorrect C2 input. To translate a C2 code, you need to first translate the RAM address into a DOL offset, and then copy the offset into the conversion tool:


After the tool finds a matching DOL offset, copy it back into the RAM address conversion tool in the PAL field to generate a corrected RAM address. You can take the last 6 digits of the address and use it for your new C2 input:


So in this case, C2261078 is the "translation" you’re looking for.
It represents the RAM address 80261078.


Second, there are a couple of function calls in that code. Gecko codes need to load the addresses for these in halves in order to call them, so they usually take the form of 2 instructions. In this code, there are 2 cases of this that I can see in the instructions: “3D808037 618C8430” and “3D808015 618CED4C”. These create the addresses 80378430 and 8015ED4C when put together.

To get this code working on a PAL version of Melee, you would need to convert these addresses just like you would the C2 input.


Here's the code with all of the above conversions applied:
Dpad up/down toggles rumble on CSS
PAL 1.00

C2261078 00000019
887F0007 2C030000
40820070 7C972378
57800739 40820010
5780077B 40820034
4800009C 7EE3BB78
38800000 38A0000E
38C00000 38ED9950
3D808037 618C8334
7D8903A6 4E800421
38800001 48000008
38800000 7EE3BB78
3D808015 618CF4F0
7D8903A6 4E800421
38800001 989F0007
3C80C040 909F0014
C03F0014 C0428E0C
C01F000C EC01002A
D01F000C FC600850
FC030840 41810008
EC6300B2 D07F0014
4180001C C0828258
FC032040 41810010
38800000 909F0014
989F0007 889F0004
60000000 00000000
it works :D
the animation of the hand is a little bizzare (in ntsc it goes form left to right in springy way, while with this code it insta flash to the left and then stop the animation), but the code works :)

i messed up big time on the address search :c
beside that, how did you know that those were address halves?
3D80 and 618C are commonly used in gecko?

i know that i'm asking a lot (so feel free to say no), but could you explain me how this code function?
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
Well, basically C2 codes are like 2 pieces of bread in a code sandwich. They wrap around the real code in order to give it an injection location and a return branch.

The top piece is the C2XXXXXX YYYYYYYY part -- which describes X, the injection hook address and Y, the size of the encapsulated machine code. The bottom piece is the “60000000 00000000” or “00000000” part at the end of each code.

C2 codes need to be aligned by 64 bits (2 lines) so “60000000” (which is a “no operation” instruction) only appears when there are an even number of instructions. The last “00000000” part is a placeholder for a return branch, which gets calculated and written only after the game starts.

C2XXXXXX YYYYYYYY
(code)
60000000 00000000

The middle (code) part is the raw machine code that makes the code behave the way it does. You can use the ASM <-> Hex Converter tool from the Mod Construction Tab in MCM to convert this into a more human-readable format, which can then be interpreted like this:

https://i.imgur.com/zrxV8uC.png


The big giveaways are the bctrl instructions. Other variations to look out for are blrl and bctr. Each function call takes 4 instructions for a gecko code, but you can see in the above screenshot that they are declared using 2 instructions, and called using the other 2. They do not necessarily have to be clumped together like this, and can be harder to find in other codes.

The “lis” instruction declares the first half of the address, and the “ori” instruction appends the second half to the first half. “mtctr” puts the address in the ctr register, and “bctrl” calls the address currently in the ctr register; running the instructions at its location.

---

could you explain me how this code function?
It looks like this injects code into a function that monitors for controller inputs on the CSS. The added instructions conditionally make calls to the mentioned functions 80378430 (HSD_PadRumbleActiveID) and 8015ed4c (Rumble_StoreRumbleFlag). I would assume these can be used to activate rumble on a given controller ID, and the conditions check for button press logic.

If you’d like to know more about details, I highly recommend checking out Dan’s Intro to Wii/Gamecube Game Modding tutorial, and the Community Symbol Map.
 

tauKhan

Smash Lord
Joined
Feb 9, 2014
Messages
1,349
Chiming in to note that with newer versions of MCM, converting RAM addresses between versions can be done a bit simpler than what Punkline described.

You can now just plug a RAM address into one of the "Code Offset Conversion" fields, and the program prints out the corresponding RAM addresses into rest of the fields.
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
Chiming in to note that with newer versions of MCM, converting RAM addresses between versions can be done a bit simpler than what Punkline described.

You can now just plug a RAM address into one of the "Code Offset Conversion" fields, and the program prints out the corresponding RAM addresses into rest of the fields.
Oh, didn’t realize this! Thanks, I’ve edited my post to reflect this for anyone else who comes across it.


Edit: Also, a few afterthoughts about other cues to look out for in cases of codes that won’t port correctly:
The combination of “lis” and “ori” is a very practical way to build addresses, and is probably what you’ll find in most codes -- but another way to do it is to use “addi” or “subi” in place of “ori”. This is what the game uses, so it may sometimes pop up in codes that need to be ported.

The cases for “subi” will require you to actually subtract the value to find the address, and can’t be read as plainly from the instructions as “ori” and “addi”:
Code:
lis r3,     0x8015     # r3 = 0x80150000
ori r3, r3, 0xED4C     # r3 = 0x8015ED4C

lis r4,      0x8016    # r4 = 0x80160000
subi r4, r4, 0x12B4    # r4 = 0x8015ED4C
Gecko codes basically use this method of address building as a workaround for not being able to calculate their relative offset to a branch destination. This method of address building can also be used to reference data tables that are static, or create pointer addresses to things like callback functions. These will also need to be ported if they are included in codes.

This is trickier to look out for because there is no giveaway bctlr, blrl, or bctr instruction. The easiest way to spot these is by looking out for an instruction that looks like this:
Code:
lis rA, 0x80XX         # rA = 0x80XX0000
-- where “rA” can be any register. The “80” is what you’re looking for, specifically. Finding this used in “lis” instructions is not a guarantee that you’ve found a global base address, but it is a good indication. To confirm, you need to find where rA ORed, added to, or subtracted from:

Code:
ori  rB, rA, 0xYYYY    # rB = 80XX0000 | 0x0000YYYY
addi rB, rA, 0xYYYY    # rB = 80XX0000 + 0x0000YYYY
subi rB, rA, 0xYYYY    # rB = 80XX0000 - 0x0000YYYY
-- where “rB” can be any register. The use of “rA” from the previous lis instruction is what you’re looking to confirm.

From this point, rB might be used as a base address for loading/storing data, passed as an argument to a function, stored as a pointer address value, etc.
Registers r13 and r2 are are dedicated to storing a base address to a list of static variables and constants. These variables can be useful, or might even be necessary for some codes -- and they will need to be ported in codes that use them.

Rather than an address; these are offsets that need to be ported. Each is a negative offset from a static address stored in r2 or r13, and so the destination is a static reference.

In the current version of MCM (v4.0) attempting to reference these offsets as absolute addresses triggers an OOB error in the conversion tool. A workaround that I’ve used in the past is to find an example of an instruction that uses the offset you need to port, and to convert the address of that instruction instead. Then, read the offset used by the ported instruction to find the ported offset.
DRGN DRGN -- this last scenario seems to run into a limitation of the offset conversion tool, at least when attempting to use the equivalent RAM addresses.
tufferugli tufferugli -- this last scenario might explain the odd hand behavior in the ported code you were describing. After taking another look at the code, I spotted a use of r13 before one of the function calls. I’ll look into this a bit later to see if I can make another correction to the ported code.
 
Last edited:

tufferugli

Smash Rookie
Joined
Oct 14, 2018
Messages
15
Oh, didn’t realize this! Thanks, I’ve edited my post to reflect this for anyone else who comes across it.


Edit: Also, a few afterthoughts about other cues to look out for in cases of codes that won’t port correctly:
The combination of “lis” and “ori” is a very practical way to build addresses, and is probably what you’ll find in most codes -- but another way to do it is to use “addi” or “subi” in place of “ori”. This is what the game uses, so it may sometimes pop up in codes that need to be ported.

The cases for “subi” will require you to actually subtract the value to find the address, and can’t be read as plainly from the instructions as “ori” and “addi”:
Code:
lis r3,     0x8015     # r3 = 0x80150000
ori r3, r3, 0xED4C     # r3 = 0x8015ED4C

lis r4,      0x8016    # r4 = 0x80160000
subi r4, r4, 0x12B4    # r4 = 0x8015ED4C
Gecko codes basically use this method of address building as a workaround for not being able to calculate their relative offset to a branch destination. This method of address building can also be used to reference data tables that are static, or create pointer addresses to things like callback functions. These will also need to be ported if they are included in codes.

This is trickier to look out for because there is no giveaway bctlr, blrl, or bctr instruction. The easiest way to spot these is by looking out for an instruction that looks like this:
Code:
lis rA, 0x80XX         # rA = 0x80XX0000
-- where “rA” can be any register. The “80” is what you’re looking for, specifically. Finding this used in “lis” instructions is not a guarantee that you’ve found a global base address, but it is a good indication. To confirm, you need to find where rA ORed, added to, or subtracted from:

Code:
ori  rB, rA, 0xYYYY    # rB = 80XX0000 | 0x0000YYYY
addi rB, rA, 0xYYYY    # rB = 80XX0000 + 0x0000YYYY
subi rB, rA, 0xYYYY    # rB = 80XX0000 - 0x0000YYYY
-- where “rB” can be any register. The use of “rA” from the previous lis instruction is what you’re looking to confirm.

From this point, rB might be used as a base address for loading/storing data, passed as an argument to a function, stored as a pointer address value, etc.
Registers r13 and r2 are are dedicated to storing a base address to a list of static variables and constants. These variables can be useful, or might even be necessary for some codes -- and they will need to be ported in codes that use them.

Rather than an address; these are offsets that need to be ported. Each is a negative offset from a static address stored in r2 or r13, and so the destination is a static reference.

In the current version of MCM (v4.0) attempting to reference these offsets as absolute addresses triggers an OOB error in the conversion tool. A workaround that I’ve used in the past is to find an example of an instruction that uses the offset you need to port, and to convert the address of that instruction instead. Then, read the offset used by the ported instruction to find the ported offset.
DRGN DRGN -- this last scenario seems to run into a limitation of the offset conversion tool, at least when attempting to use the equivalent RAM addresses.
tufferugli tufferugli -- this last scenario might explain the odd hand behavior in the ported code you were describing. After taking another look at the code, I spotted a use of r13 before one of the function calls. I’ll look into this a bit later to see if I can make another correction to the ported code.
thanks a lot :D
 
Last edited:

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
tufferugli tufferugli - I fully reversed the dpad rumble toggle code and posted some ports in Dan’s old thread for it. If you’re interested in learning exactly how the code works, I’ve also commented the source ASM and formatted it with descriptive labels and symbols. In addition to a PAL gecko code, I’ve made them available for all versions as DOL mods. These can be written more efficiently than gecko codes, and are installed to an ISO or DOL with Melee Code Manager.

I still don’t have any other Melee versions to test with right now, so let me know if anything else isn’t working as intended.

Also, to explain the weird hand behavior -- Dan had used the floats 0.8 and 0.015625 from r2 (aka “rtoc”) to control the distance of the shake translation for the effect on the hand cursor. This is one of the 2 registers dedicated to pointing to a table of static variables and constants. Since these offsets were not ported, random data was being interpreted as these floats instead -- which would likely have translated the X position of the cursor to some arbitrary value with a ridiculous exponent.

---

rtoc holds constants instead of variables; so its values are read-only, and do not change. Instead of porting the references to rtoc made in Dan’s code, I rebuilt the values manually -- eliminating the need for porting them at the cost of adding a couple of extra lines of code.

One offset I did port however, was -0x66B0(r13). This appears to be used to create some kind of pointer that’s important to the process of enabling rumble for a controller. I wanted to be more conservative with it, as I didn't know the extent of how it was used.

DRGN DRGN -- for 1.02 Melee, r13 = 804DB6A0. So, the equivalent RAM address for this offset would be 804D4FF0 (804DB6A0 - 66B0). Default r13 and rtoc data values are defined within the DOL, so wouldn’t it be possible for the offset conversion tool to reach these offsets when referenced as absolute RAM addresses? Currently, attempting to reference an offset like the above triggers this error:

-- yet, using the same address as a hook or overwrite location yields no errors:

If the conversion tool were able to see this region, it would be much easier to deal with these scenarios when porting codes that use values we don’t know the origin of.

For now, to work around this; I found where the game enables rumble from functions used in the options menu, and found the r13 offset being used by the instruction at 802477E0. I then converted THAT address, and used MCM’s static overwrite tool to inquire about the contents of each ported instruction, and used the hard-coded offsets for my port.
 
Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,179
Location
Sacramento, CA
Update! Big addition to the "Menu Text to Hex" tool. If you don't know and are curious what that's for, see this thread.
Plus other improvements, mostly for mod developers.

To 4.1:

- Updated the "Menu Text to Hex" tool, to include all Hiragana, Katagana, and Kanji characters​
- Greatly improved assembly performance (no longer using pyiiasmh to interface with EABI libraries)​
- Trying out disabling the linker during assembly (ba = 00000000); discuss. Might later re-enable​
- Added a new special syntax that can be used when writing codes, 'RAM symbols' (described in spoiler below)​
- Added a warning if any mods appear to be installed to disabled regions, with a prompt to enable them​
- Added a "Mod Search" button to the Mod Construction tab (same function as pressing CTRL-F) *​
- Comments on lines containing special branch syntaxes are now preserved​
- Fixed a performance regression regarding assembling unconditional branches that don't set any flags​
- Fixed a small GUI/highlighting related bug on the Item Switch window's "Item Frequency" dropdown​
- Improvements/additions to the Summary tab:​
- Added a context menu option to toggle whether it's sorting by offset (Advanced/Simple View) **​
- Added a context-menu option to toggle showing DOL Offsets or RAM Addresses​
- Added standalone function names to the Mods Summary tree when switched to Advanced View​
- 'View in...' features on a child item in the Mods Summary tree (in Simple View) now refers to parent item​
- 'View in...' features added to Standalone Functions tree when selecting a mod listing​
- Audio output simplified (moved from pygame to pyaudio)​
- Removed warning of audio problems if no audio driver/device is available​

* Used to search for Mods in your Mods Library by name. It was already previously available by pressing CTRL-F (since v4.0), but I figure it was mostly only known to those who noticed its introduction in the change logs, or by word of mouth.
** Switches between Simple View and Advanced View (Sorting by Offset) modes. Again, this feature previously existed (by clicking on the DOL Offset/RAM Address header), but was probably not widely known-about.

This feature takes further advantage of Standalone Functions. There's a more detailed description of these in the second post of this thread, but in short, standalone functions are blocks of code of any length (such as a function, or a table of some kind of data) that you can define with your mods, which can then be accessed by any number of other mods. Each standalone function is added to the DOL only once, so they're great for saving space or preventing the need to make changes to something in multiple places.

Standalone Functions are assigned to addresses in RAM which are dynamically determined (i.e. they can change) when MCM installs mods and saves ASM/Hex to the DOL. (You can also always look at the Summary tab, if you'd like to know where a particular piece of data was placed.) So this pointer symbol syntax allows you to use a symbol (basically a variable name), in this case a standalone function's name, in place of that dynamic RAM address.

So, for example, you could write:

.long <<functionName>>​
lis r0, <<functionName>>@h​
ori r31, r0, <<functionName>>@l​

which would become (assuming a function located at 0x80123456):

.long 0x80123456​
lis r0, 0x80123456@h​
ori r31, r0, 0x80123456@l​

And would then assemble as usual to:

80123456 3C008012​
601F3456​

As you may or may not know, you can store codes in the Mods Library in hex or assembly form (with comments, using #). Particularly useful for developing or debugging. Previously, the compiling process would slow down opening the program (since it was necessary to assemble each mod to calculate their code lengths), so I previously recommended only having the mods you're currently working on saved as assembly, and then compiling it yourself when you're done or for release. However, assembling in this version is ~10x faster, so you don't need to worry about that much anymore.
 
Last edited:

TheStupidGamer

Smash Rookie
Joined
Mar 2, 2019
Messages
1
Do you like awesome custom codes? Do you like Melee? Do you like awesome custom codes in your Melee? Then this is the program for you!​

This is the best way to view, add, and/or remove all of your code based mods in Melee, and set up your game’s default gameplay settings (game mode, stock count, etc., so they all finally stay remembered after restarting the game!). Supports DOL mods (including injection mods) as well as Gecko codes. Everything is done in a very easy-to-use interface, which simply presents you with a list of available mods, and allows you to install or uninstall them from your game with just a single click.

Cool stuff for average users:
  • Easiest and fastest way to add code-based mods to your game
  • Use DOL mods instead of Gecko codes, to make your game run more efficiently
  • No need to understand hex editing or ASM coding
  • Easily adjust your game’s default settings (stock mode, items/stages, etc.)
  • Provides visual ‘fill-meters’ to show how much space is available for custom code
  • No need to extract/import the DOL from your game to update it
  • Eliminates the old problem of mods' custom code overlapping one another
  • Mod conflict detection feature identifies mods that may be incompatible with one another
  • Avoid dealing with Nintendont/DIOS MIOS Gecko/.GCT code loader problems
Cool stuff for developers:
  • Easily create and add injection mods without needing to calculate branches
  • Easily create and add static overwrites of any length
  • Large game projects can be much more modular and manageable
  • Automatic, efficient usage of available [user-defined] ‘free space’ used for custom code
  • Relocates all custom code after editing if it uses more or less space
  • Troubleshoot problems easier by quickly swapping out suspected mods
  • Can use RAM addresses for DOL mods instead of searching for DOL offsets
  • Easily convert Gecko codes to DOL mods using the above functionality
  • New "Custom Branch Syntaxes" for easily making function calls (info below)
  • Use "Standalone Functions" to reduce redundant code usage in the DOL
  • Automatically looks up DOL ‘original’ code when adding a new mod via the GUI
  • ASM to Hex converter and RAM Address to-from DOL Offset converter built-in
  • Plus more converters and other useful tools in the Tools tab

Take a look!

View attachment 134970

Dark green are mods that are currently installed, while light green are mods selected to be installed once you hit ‘Save’, and those in red are mods that will be uninstalled upon saving.

The ASM of injection mods is automatically aligned directly after one-another to optimize the DOL’s free space. If updates or changes are made to the mods, the locations in the DOL of their custom code will be adjusted accordingly the next time you save.

You can give this program a DOL file, or an entire ISO (disc image file).

View attachment 134972

View attachment 134971

Before getting to the download, if this is your first time using this, please read the important info below first.

This will typically work best if you start using it with a fresh, unmodified DOL or ISO. If you already have codes installed in your game, that’s OK, it will automatically detect those too as long as they’re included in the “Mods Library”, which is the folder of text files that contains all of the mods. The Mods Library included in the download comes with many mods by default. And I will add more over time. However, if mods that you'd like to use are not included (of if you'd like to create new ones), you can easily add them using the interface in the Mod Construction tab. More info and details on this can be found in the post below this one.

Codes in your game that are not added to the library may be overwritten when you use this program to modify your ISO. There are two simple solutions to this: 1) Add the code to the library as mentioned above, or 2) edit the “settings.py” file to ignore the DOL sections where those other, non-library codes reside (notes can be found in that file that go into more depth on how to do this). In any case, I recommend backing up your game just in case, or more specifically, your DOL file (the file that holds these codes), before using this program. There's a clearly visible button labeled "Export DOL", which you can use to do this easily. Also, if you need one, the download comes with copies of the original DOLs for each game version.

Note that because of issues mentioned above, this currently wont work for 20XX. I have 20XX, which is awesome, but I also like to play my own customized Melee, which is a bit different. So this allows me to modify that however I want, or even build it from scratch if needed, in just a couple minutes. However if you guys like the direction a program like this could take Melee, then I could probably work with @achilles1515 at some point for 20XX compatibility. Honestly, a program like this has the potential to handle something like that and much more, in terms of mod packs and simplified, personalized customization.

Gecko Codes are supported, but cannot be copy/pasted into the library text files exactly as-is, and must be slightly modified from the format commonly seen in .gct files. You can use the Mod Construction tab to input them, which will do this for you and save them to the library in the required format. Or you may convert them to DOL mods, which is a form that's more efficient for the game to run. Please see the post below this one on how to do this conversion. The Gecko codehandler used by MCM is a modified version of the one posted and discussed here.

Important note on making changes to mods: If you need to change the injection point that a mod uses or the location of a static overwrite, then you must first uninstall the mod from your game. This is necessary in order to prevent changes that are no longer used from the old version of the mod to be permanently included in your game. (Naturally, this is because if you change the places that a mod targets, the program has no reason to look at or modify code from the old areas.)

Custom debug menus can be used, but being able to use them to control other mods will depend on the method you’re using. Control that does not target the mod itself, such as setting a flag that the mod will independently use on its own, or working by only modifying the game’s code (e.g. to toggle an injection mod’s branch back to the game’s original code, as long as you save/restore the branch) will work as normal. However, targeting the mod’s custom code with a normal branch will not work because its location is variable. Instead, you can target them as you would a standalone function. Check out the second post in ’Standalone Functions and Special Branch Syntaxes’ for details.


Melee Code Manager Downloads - v4.1:
64-bit

These programs take quite a bit of time. If you'd like to give back or show how much support there is out there for these, please consider donating!
You can do so via Paypal:
Or you can follow me on Patreon to support my main Melee projects.

Version 4.1:
- Updated the "Menu Text to Hex" tool, to include all Hiragana, Katagana, and Kanji characters​
- Greatly improved assembly performance (no longer using pyiiasmh to interface with EABI libraries)​
- Trying out disabling the linker during assembly (ba = 00000000); discuss. Might later re-enable​
- Added a new special syntax that can be used when writing codes, 'RAM symbols' (described in spoiler below)​
- Added a warning if any mods appear to be installed to disabled regions, with a prompt to enable them​
- Added a "Mod Search" button to the Mod Construction tab (same function as pressing CTRL-F) *​
- Comments on lines containing special branch syntaxes are now preserved​
- Fixed a performance regression regarding assembling unconditional branches that don't set any flags​
- Fixed a small GUI/highlighting related bug on the Item Switch window's "Item Frequency" dropdown​
- Improvements/additions to the Summary tab:​
- Added a context menu option to toggle whether it's sorting by offset (Advanced/Simple View) **​
- Added a context-menu option to toggle showing DOL Offsets or RAM Addresses​
- Added standalone function names to the Mods Summary tree when switched to Advanced View​
- 'View in...' features on a child item in the Mods Summary tree (in Simple View) now refers to parent item​
- 'View in...' features added to Standalone Functions tree when selecting a mod listing​

- Audio output simplified (moved from pygame to pyaudio)​
- Removed warning of audio problems if no audio driver/device is available​

* Used to search for Mods in your Mods Library by name. It was already previously available by pressing CTRL-F (since v4.0), but I figure it was mostly only known to those who noticed its introduction in the change logs, or by word of mouth.
** Switches between Simple View and Advanced View (Sorting by Offset) modes. Again, this feature previously existed (by clicking on the DOL Offset/RAM Address header), but was probably not widely known-about.

Version 4.0 ( 64-bit | 32-bit ):
- Support expanded to other GameCube and Wii games!*​
- Supports 20XXHP 4.07++**​
- The game's vanilla Debug Mode can now be used alongside Gecko codes​
- The Gecko codehandler and codelist can now be stored in user-defined regions***​
- Free-space code regions updated slightly:​
-[ Start area of Aux Code Regions changed to 0x407540 (NTSC 1.02)​
-[ Aux Code Regions end point moved to 0x4088B0​
-[ "20XXHP 4.07 Regions" added (do not use with other regions selected)​

- Conflict with CrazyHand resolved (via AuxCodeRegions end point change above)​
- Free Space indicator divided into two; one for standard codes, one for Gecko​
- Gecko codehandler and codelist wrapper excluded from free space indicators​
- Code Free Space Indicators show exact used and available free space on mouse-over​
- CMD windows no longer briefly appear during mod parsing or ASM assembly/disassembly​
- Finally completely revamped the Summary tab:​
-[ See each and every change done to the DOL, as well as their locations​
-[ See how much free space each mod or individual change uses​
-[ Left-click the DOL Offset header to sort changes in order of offset​
-[ Right-click the DOL Offset header to view locations as RAM Addresses​
-[ New features: "Create Installed Mods List", and "Install Mods List"​
-[ Convenient 'View DOL Hex' button added​

- Mod Search Feature! Press CTRL-F in Mods Library tab to search for mods by name​
- All hex inputs in the Tools tab now automatically remove spaces & line breaks​
- Mod Construction tab improvements:​
-[ The offsets shown can now be toggled between DOL Offsets or RAM Addresses​
-[ Undo/redo functionality added​
-[ Much more intelligent 'Unsaved' status detection​
-[ Fixed mods misunderstanding their installation status​
-[ Mouse-wheel scrolling over module list added​
-[ "New Hex" scroll position now preserved when switching between code change modules​
-[ GUI elements now properly fill space when expanding the window​
-[ Custom code length display added to static overwrites​

- Tools tab GUI elements now properly fill space when expanding the window​
- Code Offset Converter updated:​
-[ Now can also be used with RAM Addresses (outputs in same form as input)​
-[ Fixed an issue reducing quickSearch=False (option in settings) match effectiveness​
-[ The available input fields now based on the DOLs present in the Original DOLs folder​

- RAM Address Converter input fields now based on the DOLs in the Original DOLs folder​
- ToolTip module updated; fixes multi-monitor issues​
- Original DOL files no longer hash-checked before use (for hex restoration, etc.)​
- Code-Space Options button now brings the window to the front if it's already open​
- settings.py file changed. But GCM 4.x will still be backwards compatible with MCM 3.x files​
- Mod Library parsing features/improvements:​
-[ Folders/subfolders/files within the Mods Library that start with "!" are now ignored​
-[ Folders/subfolders/files starting with "+" are parsed exclusively (others ignored)​
-[ Pseudo-ops (assembly directives) can now be used within raw ASM code​
-[ empty lines (those with only line breaks) are now preserved in mod descriptions​
-[ Duplicate mod detection added. Previously could have caused problems when saving​

- Errors are now output to "Error Log.txt"​
- "Restore Original DOL" feature added (Reverts the currently loaded DOL to vanilla)​
- Region details tooltip added to total region size labels in Code-Space Options window​
- "Save As..." button now always available​
- Improved logic for installing SFs; should add stability for recursive SF calls​
- Fixed: Mods that share many SFs no longer need to be ordered in the Mods Library​
- Fixed cases of some injection mods not being detected as installed​
- Fixed branching to standalone functions from long static overwrites​
- Fixed an obscure case where a conflict being detected could break an installed mod​
- Other fixes and behavior improvements​
- Lots of logic improvements and code refactoring, so we'll still need some testing​
*To use GCM with other games, see the spoiler regarding that in the second post of this thread.
**Use the "20XX 4.07++ Codes.txt" file from the GitHub, but rename the Sheik/Zelda CPU Disable Transformations mods so that they're not seen as duplicates. You don't need to use the settings.py file from there; just use the 20XX Regions that comes with this new MCM version.
***Using the Tournament Mode Region for the codelist grants over 260% more space for Gecko codes!

Version 3.2 (64-bit | 32-bit[/SIZE]):
- New option: "Update Default Game Settings Only". Compatible with 20XX!​
- A new text to hex converter for Melee's unique menu texts in the Tools tab*
- Rumble options (per-player defaults) added to the Default Game Settings tab!​
- Simplified/cleaned-up default game settings code (now much easier to add more options)​
- Conflict detection feature now works between mods and the game's default game settings​
- Fixed a parsing bug for some long static overwrites created by the GUI​
- Fixed a bug stopping an automatic rescan of enabled codes after changing program options​
- Fixed installation false-positives occurring on some codes using static overwrites​
- Fixed the Code Offset Conversion input (was broken in just v3.1)​
- Improved some messages & dialog boxes to the user​
- 32-bit build also available!​

*The dictionary for this converter resides in the settings.py file, so you may modify it if you want to figure out more characters.

Version 3.1:
- Standalone function definitions can be shared across specific, or all, game versions​
- Standalone functions can now be the only thing in a mod; i.e. "Function Modules"​
- Scanning for mods is faster​
- Fixed an uncommon, odd GUI bug causing mods to render incorrectly​
- Fixed small bug on Mod Construction tab dealing with PAL code updates​
- Mods can now be filtered out from parsing by use of a '!' in first few lines (example)​
- Further mod organization, and new mods added to library (& a few duplicates removed)​
- Will now assume mods are disabled if a static overwrite occurs in reserved regions​
- Message for conflicting mod detection fixed to accurately report range ends​
- Minor aesthetic fixes (folder tab icon disappearances)​
- Fixed notes incorrectly stating that some gecko codes were unavailable​
- Tooltip message added to explain the update button in the Mod Construction tab​
- Summary tab now displays totals for how much space mods and standalone functions use​
- Pressing CTRL-s on the Mods Library or General Settings tab saves your codes to the DOL​
- Pressing CTRL-s on the Mod Construction tab saves the selected mod to your library​
- If a mod is saved to a new file, Library is rescanned to include it​
- "Open this File" button now works on empty Mods Library tabs​
- Better validation of "Offset" input field in Mod Construction tab code changes​
- The Share/Save functions will now attempt to retrieve missing Original Hex values​
- Scroll position and tab selection are now preserved when rescanning Mods Library​
- Now remembers last opened file type for the next time you want to open an ISO or DOL​
- Added a check for mods writing a static overwrite or injection point to regions used for custom code​
- much code cleanup, and testing, bringing this out of the 3.0 "beta"​

Version 3.0 (considered beta, since there are so many new changes):
- New nested tab interface for far-greater, user-customizable mod organization​
- Mods can now be stored in library as ASM rather than just hex​
- New "Mod Construction" tab, for better in-program mod editing and creation​
- Mod Construction tab supports viewing/editing ASM with notes/comments​
- Rewrote core code-saving logic to be more stable/concise/efficient​
- Catches and warns you about mods that conflict with (overwrite) one another​
- Rewrote checking for installed mods; should eliminate false-positives​
- Improved error checking when saving codes to a DOL/ISO​
- Improved support for Gecko codes (for 04 and C2 types)​
- Now remembers and defaults to the directory of the last file loaded​
- Processing/saving mods that include special branch syntaxes is much faster​
- Standalone Functions now only need to be included with one mod​
- Custom Branch Syntaxes can now be used with static overwrites​
- Fixed parsing bug where branching to 0x8 would be mistaken as a RAM address​
- Free space region ( 0x15CC, 0x1698 ) changted to ( 0x15F0, 0x1698 )​
- Regions for custom code are now defined differently in the settings.py file​
- More regions defined for injecting custom code (Tournament Mode, etc.)​
- Regions defined in settings.py now have separate toggles within the GUI​
- If new regions are added to settings.py, they will show up in GUI as well​
- Empty lines now usable in descriptions​
- Fixed (hopefully) all branch Hex -> ASM converter (disassembly) issues​
- Improved disassembly performance (speed)​
- Fixed a bug that caused ASM not aligned to 8 bytes to fail assembly​
- Now zeroes-out unused areas of the free space regions upon saving​
- New "Summary" tab, which shows mod totals and lists installed mods​
- Mods parser now picks up comments preceded with "#" in descriptions, etc.​
- "##" now used in Mods Library files to exclude comments from parser​
- "Save As..." button/functionality added​
- Progress indication added for save operations​
- Can now just hit 'Enter' in the "ISO / DOL" text field to load that file​
- Fixed 'Hitbox Displays Do Not Interpolate' (had bad formatting in library)​
- Gecko codehandler moved to the settings.py file, for user modifications​
- Better behavior on Gecko codes use (warns about overwriting required regions)​
- New option to ignore hash-check on hex restoration (vanillaDolSafetyOverride)​
- Fixed alignment for injection code saved directly after the Gecko codehandler​
- Removed Herobrine​

Version 2.1 (x64 | (x86):
- 32-bit build now available!​
- Fixed a parsing bug that would occur with mods that use several standalone functions​
- Fixed ASM compiling bug relating to using standalone functions with custom branch syntaxes​
- Added measures to prevent enabled/disabled mods with the same injection points from conflicting​
- Scrollwheel support!​
- Added 'CTRL-A' (Select All) support for text entry fields​
- Slightly improved ASM > Hex conversion efficiency​
- Number Conversion Tool: 'L' character removed from negative 32-bit floats​
- Font size now adapts to user's system's font size setting (tested on Win7)​
- Increasing/decreasing font size is now an option in the settings file​

Version 2.0 (from the original release of this program):
- Added support for standalone functions (can be shared by multiple mods)​
- New convenient calling/branching syntax for functions (e.g. "bl 0x800948a8")​
- The 'Offset' value can now optionally be given as a RAM address instead​
- Program renamed, from "DRGN's DOL Manager" to "Melee Code Manager"​
- Can now add/remove & manage Gecko codes in the DOL (thx to R&D by Dan Salvato)​
- Added the Tools tab with the following tools -​
-- Interface to easily add new codes to the library (formats them for you)​
-- Can add new codes in the form of assembly without needing to convert first​
-- ASM <-> Hex Converter (available separately from the above functionality)​
-- Number converter, RAM address converter, and code offset converter​
-- Text to Hex (ASCII) converter​

- Drag-and-drop now works with the program icon (previously only available on GUI)​
- Before overwriting/changing a game's DOL, now asks if you'd like to back it up​
- Now uses '#' rather than '*' for comments in Mods Library (the code text files)​
- Fixed an alignment problem occuring with free space in non-v1.02 game versions​
- Better error handling in case of a problem while applying a mod to a game​
- Better parsing of mods library (attempts to explain errors if encountered)​
- New, more convenient syntax for long static overwrites (and can be any length)​
- Recognizes .GCM files now rather than .GCN :p
- Fixed the audio causing a crash when no audio drivers were detected​
- Increased custom code free space by 0xF64 (thx to R&D by achilles)​
- Free space regions exposed to user via settings file (can set to ignore regions)​
- Injection Mods show how much space they use (by byte; separate from the meter)​
- Reorganized the mods in the text files by their purpose​
- Converted a lot of Gecko codes to DOL mods and added them to the library​

In the future, I don't see why a program couldn't use packs (even could be a standard zip) which include any combination of game files, textures, audio, and/or ASM. For example, the 'Debug Menu Replaces Tournament Mode' combined with the graphics for it, or a mod pack for a stage, where you might need the stage file as well as a few code changes separate from it, and perhaps music. There could be a program that could install all parts of it, as one unit, directly to your ISO in one step. Adding a custom debug menu builder to this would also likely be possible.

- - -​

Shout-outs and special thanks to @Achilles1515 and @Michael Ashby for their support!

And also thanks to @shuall, @_glook, @Jorgasms, @ SinsOfApathy SinsOfApathy , and others, who each stopped their busy hacking to answer questions or give suggestions during my initial design stages. And to Punkline Punkline , for bug reporting/documenting and other feedback.
I plan to put this on Github at some point, but feel free to PM me for the source code for now.
I have no idea how to use this, so if you can respond to this than that'd be great. Also i'm trying this with 20XX so pls & thx
 

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,179
Location
Sacramento, CA
NewUpdate.png

Version 4.2:
- The Mods Library folder you're loading from can now be changed within the program
- Added a new feature to the Mod Construction tab: "Import Gecko Code"
- Now able to create a GCT file from selected mods
- Improved error message reporting related to resolving special syntaxes
- Can now Shift-Click 'Select All'/'Deselect All' buttons to apply to entire library
- Folders starting with . (such as ".git") are now excluded from Mods Library parsing
- Last instruction of injection code no longer replaced if it ends with a special syntax
- Modules consisting of only SFs are no longer detected as installed if they're not used
- Additions to the ASM <-> HEX Converter:
- Fixed disassembly of branch values (incorrect in v4.1.1)
- Code length display
- Scrollbars
- Proper window resizing rather than a fixed size
- Disassembly of '.word' is converted to '.long' for hex input that is 4 bytes long​
- Fixed some obscure bugs that could occur when parsing <<RAM>> symbols
- Fixed resolving of multiple <<RAM>> syntaxes mixed with assembled hex code
- Fixed usage of the assembly OR operator, '|', in custom code
- Fixed 'check if writing to custom code regions' for mods written with RAM addresses
- Fixed preservation of whitespace preceding comments during mod parsing
- Drastically improved speed of folder-opening functions; e.g. 'Open Mods Library Folder'
- Added '-d' command line argument for Debug Mode, to log debug/error messages
- A good amount of refactoring, code clean-up, and small efficiency improvements​
 

TheSocialZombie

Smash Cadet
Joined
Jun 25, 2017
Messages
49
Quick question: how would I convert a gecko code into a 20XXHP region compatible DOL mod? Like, where is that option?
 
Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,179
Location
Sacramento, CA
I've created a perk for those who want to subscribe to my Patreon: early access to beta & test builds, so you can try out new features and versions of MCM while I'm still working on them. I often have a hard time finding time to work on these, so I figured this was a good way to share some useful things between ready/finished releases. It's also the perfect time to give feedback or suggestions for new features, as I can more quickly/easily make adjustments before making official releases. Test builds could even include ad hoc tweaks for specific things you might be working on, such as print statements for extra info on certain processes.

The current unreleased build for MCM only has a few small fixes/features atm. But DTW has some big changes in the works.

Quick question: how would I convert a gecko code into a 20XXHP region compatible DOL mod? Like, where is that option?
Oops; didn't see this.

Well, that's kind of tricky atm. You would need to convert the mod to the form of a standard overwrite/injection mod, which you can do with the new 'Import Gecko Code' feature in the Mod Construction tab. But in order to add that to 20XXHP, you need to use MCM v2.0, and the files found here. The tricky part is whether or not the code's components conflict with anything currently in 20XX (and that old version of MCM does not have conflict detection). These matters are explained in more detail here.
 
Last edited:

dreamsyntax

Smash Rookie
Joined
Aug 3, 2019
Messages
7
Is there a max length that the "Import Gecko" feature supports?
Most of my codes have been importing fine but this one C2 code of 0x16 line (posted below)
result in nothing. No error message, no added mod etc.

Any ideas or something I missed?


c2282514 00000016
3de0807d 61ef71a0
81ef0000 81ef0000
3e00807d 621071a8
82100000 82100000
823f0008 8231001c
c1f10000 c2110004
c2310008 c24f0000
c26f0004 c28f0008
edef9028 edef03f2
ee109828 ee100432
edef802a ee31a028
ee310472 eeb1782a
c1f10000 c2110004
c2310008 c2500000
c2700004 c2900008
edef9028 edef03f2
ee109828 ee100432
edef802a ee31a028
ee310472 edf1782a
fc0fa840 38a00001
41800008 38a00000
60000000 00000000

lis r15, 0x807D
ori r15, r15, 0x71A0
lwz r15, 0x0(r15)
lwz r15, 0x0(r15)
lis r16, 0x807D
ori r16, r16, 0x71A8
lwz r16, 0x0(r16)
lwz r16, 0x0(r16)
lwz r17, 0x8(r31)
lwz r17, 0x1C(r17)
lfs f15, 0x0(r17)
lfs f16, 0x4(r17)
lfs f17, 0x8(r17)
lfs f18, 0x0(r15)
lfs f19, 0x4(r15)
lfs f20, 0x8(r15)
fsubs f15, f15, f18
fmuls f15, f15, f15
fsubs f16, f16, f19
fmuls f16, f16, f16
fadds f15, f15, f16
fsubs f17, f17, f20
fmuls f17, f17, f17
fadds f21, f17, f15
lfs f15, 0x0(r17)
lfs f16, 0x4(r17)
lfs f17, 0x8(r17)
lfs f18, 0(r16)
lfs f19, 0x4(r16)
lfs f20, 0x8(r16)
fsubs f15, f15, f18
fmuls f15, f15, f15
fsubs f16, f16, f19
fmuls f16, f16, f16
fadds f15, f15, f16
fsubs f17, f17, f20
fmuls f17, f17, f17
fadds f15, f17, f15
fcmpo cr0, f15, f21
li r5, 1
blt 0x8
li r5, 0


EDIT: Should have guessed, MCM is case sensitive.

Dolphin defaults to lowercase code when exporting (why!? >_>)
Working great now.
Awesome work on MCM!
 
Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,179
Location
Sacramento, CA
Is there a max length that the "Import Gecko" feature supports?
Most of my codes have been importing fine but this one C2 code of 0x16 line (posted below)
result in nothing. No error message, no added mod etc.

Any ideas or something I missed?


c2282514 00000016
3de0807d 61ef71a0
81ef0000 81ef0000
3e00807d 621071a8
82100000 82100000
823f0008 8231001c
c1f10000 c2110004
c2310008 c24f0000
c26f0004 c28f0008
edef9028 edef03f2
ee109828 ee100432
edef802a ee31a028
ee310472 eeb1782a
c1f10000 c2110004
c2310008 c2500000
c2700004 c2900008
edef9028 edef03f2
ee109828 ee100432
edef802a ee31a028
ee310472 edf1782a
fc0fa840 38a00001
41800008 38a00000
60000000 00000000

lis r15, 0x807D
ori r15, r15, 0x71A0
lwz r15, 0x0(r15)
lwz r15, 0x0(r15)
lis r16, 0x807D
ori r16, r16, 0x71A8
lwz r16, 0x0(r16)
lwz r16, 0x0(r16)
lwz r17, 0x8(r31)
lwz r17, 0x1C(r17)
lfs f15, 0x0(r17)
lfs f16, 0x4(r17)
lfs f17, 0x8(r17)
lfs f18, 0x0(r15)
lfs f19, 0x4(r15)
lfs f20, 0x8(r15)
fsubs f15, f15, f18
fmuls f15, f15, f15
fsubs f16, f16, f19
fmuls f16, f16, f16
fadds f15, f15, f16
fsubs f17, f17, f20
fmuls f17, f17, f17
fadds f21, f17, f15
lfs f15, 0x0(r17)
lfs f16, 0x4(r17)
lfs f17, 0x8(r17)
lfs f18, 0(r16)
lfs f19, 0x4(r16)
lfs f20, 0x8(r16)
fsubs f15, f15, f18
fmuls f15, f15, f15
fsubs f16, f16, f19
fmuls f16, f16, f16
fadds f15, f15, f16
fsubs f17, f17, f20
fmuls f17, f17, f17
fadds f15, f17, f15
fcmpo cr0, f15, f21
li r5, 1
blt 0x8
li r5, 0


EDIT: Should have guessed, MCM is case sensitive.

Dolphin defaults to lowercase code when exporting (why!? >_>)
Working great now.
Awesome work on MCM!
Oh, I didn't even realize that feature was case sensitive, haha. No need for it to be. Whoops. I'll change that for the next version, so it's easier to use with Dolphin.
 

dreamsyntax

Smash Rookie
Joined
Aug 3, 2019
Messages
7
Oh, I didn't even realize that feature was case sensitive, haha. No need for it to be. Whoops. I'll change that for the next version, so it's easier to use with Dolphin.
Minor bug I found, in v4.2.
The refresh button (for number of bytes) does not work for standalone functions. It will stay at last counted value until the mod is saved, and MCM is restarted.

Maybe a major bug / or more likely, I do not understand proper usage of standalone functions:
I think I either lack the understanding for how to properly use standalone functions or there is an issue with the feature.
I took a look at Impossible Cancel v0.20 (library) by Punkline to understand.

My situation is I have a C2 gecko code that I was injecting at 5 different addresses, but other than the C2[address], the code was identical.
Seems like a perfect candidate for standalone function, right?

Just for transparency here is the code and asm source::

Gecko Code:
Code:
C2242B10 00000016
3DE0807D 61EF71A0
81EF0000 81EF0000
3E00807D 621071A8
82100000 82100000
823F0008 8231001C
C1F10000 C2110004
C2310008 C24F0000
C26F0004 C28F0008
EDEF9028 EDEF03F2
EE109828 EE100432
EDEF802A EE31A028
EE310472 EEB1782A
C1F10000 C2110004
C2310008 C2500000
C2700004 C2900008
EDEF9028 EDEF03F2
EE109828 EE100432
EDEF802A EE31A028
EE310472 EDF1782A
FC0FA840 38A00001
41800008 38A00000
60000000 00000000
ASM Source:
Code:
MainBoss Target Closest Player Inject @ 80242B10 || ORIGINAL: lwz  r5, 0x3148 (r13)
lis r15, 0x807D
ori r15, r15, 0x71A0
lwz r15, 0x0(r15)
lwz r15, 0x0(r15)
lis r16, 0x807D
ori r16, r16, 0x71A8
lwz r16, 0x0(r16)
lwz r16, 0x0(r16)
lwz r17, 0x8(r31)
lwz r17, 0x1C(r17)
lfs f15, 0x0(r17)
lfs f16, 0x4(r17)
lfs f17, 0x8(r17)
lfs f18, 0x0(r15)
lfs f19, 0x4(r15)
lfs f20, 0x8(r15)
fsubs f15, f15, f18
fmuls f15, f15, f15
fsubs f16, f16, f19
fmuls f16, f16, f16
fadds f15, f15, f16
fsubs f17, f17, f20
fmuls f17, f17, f17
fadds f21, f17, f15
lfs f15, 0x0(r17)
lfs f16, 0x4(r17)
lfs f17, 0x8(r17)
lfs f18, 0(r16)
lfs f19, 0x4(r16)
lfs f20, 0x8(r16)
fsubs f15, f15, f18
fmuls f15, f15, f15
fsubs f16, f16, f19
fmuls f16, f16, f16
fadds f15, f15, f16
fsubs f17, f17, f20
fmuls f17, f17, f17
fadds f15, f17, f15
fcmpo cr0, f15, f21
li r5, 1
blt 0x8
li r5, 0
Being unfamiliar with MCM this is my process:
New Mod -> Import Gecko Code -> Import
This add an Injection entry. I did the same for another of the same code just at a different injection address, via importer.
Now I have two injection entries. Opening it reveals they have the same converted code contents.
So, I cut the content, make a new Standalone function and paste.
I call it bossmagic

In my other two injection entries I put in
"bl <bossmagic>"

Here are pictures for reference:


Save, run.
Instead I'm greeted with this:

The bottom part is one of the injects, it branches directly to another b instruction returning me to then next instruction.
I do see my standalone function right above it, but it never b's to it.

Lastly here is the output / share button version of this:
Code:
    -==-


BossTesting
[dream]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.06 --- 0x802A6DA8 ---- 80AD3148 -> Branch

bl <bossmagic>

------------- 0x80242B10 ---- 80AD3148 -> Branch

bl <bossmagic>

<bossmagic> NTSC 1.06
3DE0807D 61EF71A0
81EF0000 81EF0000
3E00807D 621071A8
82100000 82100000
823F0008 8231001C
C1F10000 C2110004
C2310008 C24F0000
C26F0004 C28F0008
EDEF9028 EDEF03F2
EE109828 EE100432
EDEF802A EE31A028
EE310472 EEB1782A
C1F10000 C2110004
C2310008 C2500000
C2700004 C2900008
EDEF9028 EDEF03F2
EE109828 EE100432
EDEF802A EE31A028
EE310472 EDF1782A
FC0FA840 38A00001
41800008 38A00000
60000000 00000000
I brought this up on the discord and psiLupan has been trying to help figure out what's wrong. Any help would be appreciated !
 
Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,179
Location
Sacramento, CA
Minor bug I found, in v4.2.
The refresh button (for number of bytes) does not work for standalone functions. It will stay at last counted value until the mod is saved, and MCM is restarted.

Maybe a major bug / or more likely, I do not understand proper usage of standalone functions:
I think I either lack the understanding for how to properly use standalone functions or there is an issue with the feature.
I took a look at Impossible Cancel v0.20 (library) by Punkline to understand.

My situation is I have a C2 gecko code that I was injecting at 5 different addresses, but other than the C2[address], the code was identical.
Seems like a perfect candidate for standalone function, right?

Just for transparency here is the code and asm source::

Gecko Code:
Code:
C2242B10 00000016
3DE0807D 61EF71A0
81EF0000 81EF0000
3E00807D 621071A8
82100000 82100000
823F0008 8231001C
C1F10000 C2110004
C2310008 C24F0000
C26F0004 C28F0008
EDEF9028 EDEF03F2
EE109828 EE100432
EDEF802A EE31A028
EE310472 EEB1782A
C1F10000 C2110004
C2310008 C2500000
C2700004 C2900008
EDEF9028 EDEF03F2
EE109828 EE100432
EDEF802A EE31A028
EE310472 EDF1782A
FC0FA840 38A00001
41800008 38A00000
60000000 00000000
ASM Source:
Code:
MainBoss Target Closest Player Inject @ 80242B10 || ORIGINAL: lwz  r5, 0x3148 (r13)
lis r15, 0x807D
ori r15, r15, 0x71A0
lwz r15, 0x0(r15)
lwz r15, 0x0(r15)
lis r16, 0x807D
ori r16, r16, 0x71A8
lwz r16, 0x0(r16)
lwz r16, 0x0(r16)
lwz r17, 0x8(r31)
lwz r17, 0x1C(r17)
lfs f15, 0x0(r17)
lfs f16, 0x4(r17)
lfs f17, 0x8(r17)
lfs f18, 0x0(r15)
lfs f19, 0x4(r15)
lfs f20, 0x8(r15)
fsubs f15, f15, f18
fmuls f15, f15, f15
fsubs f16, f16, f19
fmuls f16, f16, f16
fadds f15, f15, f16
fsubs f17, f17, f20
fmuls f17, f17, f17
fadds f21, f17, f15
lfs f15, 0x0(r17)
lfs f16, 0x4(r17)
lfs f17, 0x8(r17)
lfs f18, 0(r16)
lfs f19, 0x4(r16)
lfs f20, 0x8(r16)
fsubs f15, f15, f18
fmuls f15, f15, f15
fsubs f16, f16, f19
fmuls f16, f16, f16
fadds f15, f15, f16
fsubs f17, f17, f20
fmuls f17, f17, f17
fadds f15, f17, f15
fcmpo cr0, f15, f21
li r5, 1
blt 0x8
li r5, 0
Being unfamiliar with MCM this is my process:
New Mod -> Import Gecko Code -> Import
This add an Injection entry. I did the same for another of the same code just at a different injection address, via importer.
Now I have two injection entries. Opening it reveals they have the same converted code contents.
So, I cut the content, make a new Standalone function and paste.
I call it bossmagic

In my other two injection entries I put in
"bl <bossmagic>"

Here are pictures for reference:


Save, run.
Instead I'm greeted with this:

The bottom part is one of the injects, it branches directly to another b instruction returning me to then next instruction.
I do see my standalone function right above it, but it never b's to it.

Lastly here is the output / share button version of this:
Code:
    -==-


BossTesting
[dream]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.06 --- 0x802A6DA8 ---- 80AD3148 -> Branch

bl <bossmagic>

------------- 0x80242B10 ---- 80AD3148 -> Branch

bl <bossmagic>

<bossmagic> NTSC 1.06
3DE0807D 61EF71A0
81EF0000 81EF0000
3E00807D 621071A8
82100000 82100000
823F0008 8231001C
C1F10000 C2110004
C2310008 C24F0000
C26F0004 C28F0008
EDEF9028 EDEF03F2
EE109828 EE100432
EDEF802A EE31A028
EE310472 EEB1782A
C1F10000 C2110004
C2310008 C2500000
C2700004 C2900008
EDEF9028 EDEF03F2
EE109828 EE100432
EDEF802A EE31A028
EE310472 EDF1782A
FC0FA840 38A00001
41800008 38A00000
60000000 00000000
I brought this up on the discord and psiLupan has been trying to help figure out what's wrong. Any help would be appreciated !
Code that's injected does not branch back automatically (which was an intentional design, partly for cases where it might not be desired). So in your case, those injections are being branched to, executed, and then because injection code is stored end-to-end, code execution is just going to the next block of code, which is just another branch because that's what "bl <bossmagic>" assembles to. A branch back to the injection site will be added automatically if the last instruction in the injection code (not the SF) is a standard/unconditional branch or a null word (opcodes 48/49/4A/4B/00). This is why you might notice that most injection mod code in MCM ends with a branch (even if it's just 48000000, technically a branch to nowhere) or an empty word.

However, you don't really need injections for what you're trying to do. Since your injection code and the vanilla code you're ok with replacing (the 4 bytes at the 0x80242B10 and 0x802A6DA8 offsets) are the same size, you can just outright replace the original code at those offsets with a branch using static overwrites. And because you're using a branch-link (bl) to get to the standalone function, you can just add a branch-link-return (blr) to the end of the function, and code execution will return to the injection site when it's done with the function.

What game is this for btw? Also, I'll have the update button working for SFs in the next update.

Code:
    -==-


BossTesting
[dream]
Revision ---- DOL Offset ---- Hex to Replace ---------- ASM Code -
NTSC 1.06 --- 0x802A6DA8 ---- 80AD3148 -> bl <bossmagic>
------------- 0x80242B10 ---- 80AD3148 -> bl <bossmagic>

<bossmagic> NTSC 1.06
3DE0807D 61EF71A0
81EF0000 81EF0000
3E00807D 621071A8
82100000 82100000
823F0008 8231001C
C1F10000 C2110004
C2310008 C24F0000
C26F0004 C28F0008
EDEF9028 EDEF03F2
EE109828 EE100432
EDEF802A EE31A028
EE310472 EEB1782A
C1F10000 C2110004
C2310008 C2500000
C2700004 C2900008
EDEF9028 EDEF03F2
EE109828 EE100432
EDEF802A EE31A028
EE310472 EDF1782A
FC0FA840 38A00001
41800008 38A00000
4E800020

Also, keep in mind that after you've saved, the Summary tab will show you where all of the custom code and branches were placed, which can help with debugging or figuring out what the program is doing.

SinsOfApathy SinsOfApathy
 
Last edited:

dreamsyntax

Smash Rookie
Joined
Aug 3, 2019
Messages
7
Code that's injected does not branch back automatically (which was an intentional design, partly for cases where it might not be desired). So in your case, those injections are being branched to, executed, and then because injection code is stored end-to-end, code execution is just going to the next block of code, which is just another branch because that's what "bl <bossmagic>" assembles to. A branch back to the injection site will be added automatically if the last instruction in the injection code (not the SF) is a standard/unconditional branch or a null word (opcodes 48/49/4A/4B/00). This is why you might notice that most injection mod code in MCM ends with a branch (even if it's just 48000000, technically a branch to nowhere) or an empty word.
Right, I should definitely be using static overwrites for this particular case. I had done that before (code was identical to what you posted) and it does work.

I'm just struggling to see why the inject didn't at least branch to the start of the standalone function though. Is it because it was a branch as the final instruction (per your explanation)? If I had li r3, 8 or some other junk in the Inject, e.g.:
Code:
38600008 [aka  li r3, 8]
bl <bossmagic>
38600008 [aka li r3, 8]
It would have properly branched to bossmagic (and failed to return given how bossmagic was written)?


The above would just result in it ignoring the bl to bossmagic. So only li r3,8, li r3, 8 would be left.

There are other codes I will need to port that are more complex and would require multiple calls to different standalone functions. That's the case I'm worried about atm due to the behavior I'm experiencing.

I was expecting it to at least branch to the start of the standalone function (and fail since it would not properly redirect at the end).

To be 100% clear, the injection never even attempts to bl to my standalone function.

I tested, and yep.
it works properly so long as its wrapped in other code. The example I cross out above with li r3,8 wrapping the bl has it working properly.


That said maybe having MCM throw an error or suggesting a convert to static in the case of poor usage like my original example that fails might be a good idea.
Thanks for the explanation!
 
Last edited:

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
Hey DRGN DRGN -- I was reading the other day that the -I command line option for as.exe lets you specify multiple .include paths. It made me wonder: would it be possible to use this to make the .include directive -- when used in MCM -- search for file resources in a way that prioritizes the directory that the code was installed from; followed by backup directories?

This would make it possible to include prerequisite *.s, *.asm, *.i, *.inc or other assets locally with a code without having to stuff a bunch of weird files into the MCM root directory. This might be particularly useful for building projects that can be easily updated and maintained as a set of modules.

Considering the newer Mods Library system folder mechanics introduced recently, I think it would be particularly advantageous to use a priority that went something like:
  1. Override- files in the active directory take precedence over all others, for overriding purposes
  2. Local - files in the same directory that the code (*.txt) was loaded from, in the Mods Library
  3. Mods Library - an optional default local to the currently specified Mods Library directory
  4. Default - a final default in the MCM directory, for tries that missed all other catches
Level 1 would be whatever the current MCM version is using -- which currently lets .include find files in the root MCM directory. I believe this would be useful for development purposes, as it currently is. Maybe it could be given a special folder instead of directly using the active directory directly, or a selectable folder like the Mods Library.

I figure that since folders can be hidden from the regular MCM parser with a '.' character, an optional folder called ‘.include’ could then contain any files for levels 3 and 4.


If it were possible to then preemptively inform MCM of what files will be loaded within a code as a form of redundant metadata in the code description (maybe specified as file path names somewhere around the code title/desc/authors tag) -- then the program could simply skip codes that would fail to find the stated prerequisite files. I figure they could then appear 'disabled' in the same way that codes for the wrong version of Melee are disabled; thereby hiding the errors normally caused by .include failures, and just generally provide a less messy user experience.

What do you think of these ideas?

---


On a sort of similar note: what do you think about the idea of some kind of protocol for invoking the linker when assembling specific codes?

My understanding is that this slows down the parse, and is therefor undesirable in most cases since the linker is usually not needed for most codes -- but there are a few features in ASM that can only be used with the linker enabled, and they might be helpful for assembling larger projects in MCM.

Would it be possible to allow for individual exceptions with some kind of special token or statement made as part of the code description info, or something? Or, perhaps at the very beginning of a standalone function or injection code container, for individual ASM programs within a single code?
 
Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,179
Location
Sacramento, CA
Hey DRGN DRGN -- I was reading the other day that the -I command line option for as.exe lets you specify multiple .include paths. It made me wonder: would it be possible to use this to make the .include directive -- when used in MCM -- search for file resources in a way that prioritizes the directory that the code was installed from; followed by backup directories?

This would make it possible to include prerequisite *.s, *.asm, *.i, *.inc or other assets locally with a code without having to stuff a bunch of weird files into the MCM root directory. This might be particularly useful for building projects that can be easily updated and maintained as a set of modules.

Considering the newer Mods Library system folder mechanics introduced recently, I think it would be particularly advantageous to use a priority that went something like:
  1. Override- files in the active directory take precedence over all others, for overriding purposes
  2. Local - files in the same directory that the code (*.txt) was loaded from, in the Mods Library
  3. Mods Library - an optional default local to the currently specified Mods Library directory
  4. Default - a final default in the MCM directory, for tries that missed all other catches
Level 1 would be whatever the current MCM version is using -- which currently lets .include find files in the root MCM directory. I believe this would be useful for development purposes, as it currently is. Maybe it could be given a special folder instead of directly using the active directory directly, or a selectable folder like the Mods Library.

I figure that since folders can be hidden from the regular MCM parser with a '.' character, an optional folder called ‘.include’ could then contain any files for levels 3 and 4.


If it were possible to then preemptively inform MCM of what files will be loaded within a code as a form of redundant metadata in the code description (maybe specified as file path names somewhere around the code title/desc/authors tag) -- then the program could simply skip codes that would fail to find the stated prerequisite files. I figure they could then appear 'disabled' in the same way that codes for the wrong version of Melee are disabled; thereby hiding the errors normally caused by .include failures, and just generally provide a less messy user experience.

What do you think of these ideas?

---


On a sort of similar note: what do you think about the idea of some kind of protocol for invoking the linker when assembling specific codes?

My understanding is that this slows down the parse, and is therefor undesirable in most cases since the linker is usually not needed for most codes -- but there are a few features in ASM that can only be used with the linker enabled, and they might be helpful for assembling larger projects in MCM.

Would it be possible to allow for individual exceptions with some kind of special token or statement made as part of the code description info, or something? Or, perhaps at the very beginning of a standalone function or injection code container, for individual ASM programs within a single code?
Oh, that's pretty cool. Yeah, the idea and the priority list you suggested sounds like it would work well. The '.include' folders make sense too.

Since codes need to be assembled when the library is parsed, .include dependencies could just be checked for and resolved automatically at that time, using the priority you suggested, and I don't think an additional tag/info field would be needed with the code. Or were you suggesting that explicitness for testing/convenience purposes? Or maybe it would be useful in case you want different files to use different dependencies by the same name (again, likely for testing, since that otherwise sounds like a naming fiasco to be avoided). In either case, there could be a button somewhere to check exactly what dependencies or include paths would be used. Having them appear disabled with a warning displayed on them in the case of missing files is also a good idea.

Yeah, we could use the linker for special cases. It would seem most efficient to do it per-code-block. I'll have to take a look at the parser to see what syntax should be safe for that.

And yeah, performance is why the linker is no longer used. The bulk of the slowdown was due to the creation of output files from the assembler (as far as the linker was concerned, these were necessary temp files, used for input to it). Since I figured the linker wasn't needed, I just chopped that part of the pipeline clean off, found how to get the assembler to output no files at all, and just parsed its stdout instead. But if we do need the linker for some things, I may be able to instead try piping the assembler output strait to the linker input and avoid any temp files, giving us better performance than we had when the linker was present in the past.
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
Awesome! I think this will enable some really cool things in MCM.

Since codes need to be assembled when the library is parsed, .include dependencies could just be checked for and resolved automatically at that time, using the priority you suggested, and I don't think an additional tag/info field would be needed with the code. Or were you suggesting that explicitness for testing/convenience purposes? Or maybe it would be useful in case you want different files to use different dependencies by the same name (again, likely for testing, since that otherwise sounds like a naming fiasco to be avoided). In either case, there could be a button somewhere to check exactly what dependencies or include paths would be used. Having them appear disabled with a warning displayed on them in the case of missing files is also a good idea.

The extra dependency file name definitions wouldn't be for the ASM, rather it would be a matter of informing MCM of what file names it should expect to find for a particular code for the sake of controlling errors in cases where the code hasn’t been installed correctly. I only mean stating file names that would be local to one of the possible include paths; so for example, a code that has the line .include "primlite.s" could then also place the string "primlite.s" somewhere in a place where MCM could see it, and then MCM would check the available paths for a match. It would be totally optional since the parse can just succeed normally without it -- but would afford avoiding a list of errors in cases of failure.

It might be entirely unnecessary though, now that I consider that the errors could probably just be detected automatically and hidden that way. I only suggested it as a means of assisting MCM in detecting the errors before they would be displayed; for the sake of making codes that use prerequisites less frustrating to install or include with other code setups. The idea would be that this disabling behavior helps the code still exist in the library without having to be removed or hidden if it hasn’t got the right prerequisites, which may be the case if the module can be configured for different setups.

If this could be done without the redundancy, then disregard that suggested detail.

---


I’m imagining a couple of scenarios where this might be particularly helpful.

The first is for convenient customization.

If I have a file containing a data table that defines default user settings for a code, it can serve as a module that could be easily swapped out or overridden with other configurations of user settings. It may also provide lists of pointers, or other data that could become modular in its application inside of a code that uses it. It is also not limited to emitted byte data, in that it can set up macros and symbols to create objects that help set up structures in other contexts. This becomes particularly useful when multiple paths are available, in an ordered priority.

I think symbol configurations, color schemes, string data, masks, lists, or even binary files with the .incbin directive could all be defined like this without really invoking a dependency hell when applied to specific codes -- and could potentially be very useful.

For cases where things might actually become a naming fiasco, it might be resolvable using another .include from inside the first module, like a chain. This could use a target directory that is selected after being invoked from a base module -- allowing a program that intends to use some custom set of files to explicitly state the subdirectory name it wants to use; or something like that.

---


The second is for modules that are not for specific ASM programs, but rather for general use by multiple ASM programs.

I actually held off responding here for a little bit so that I could post a WIP of a fairly radical example of this. You can see more details in the RT Stack Snacks thread. I feel like this is something that projects like 20XX could have benefited from quite a bit for centralizing the allocation of all of its static data. It's geared towards larger projects, but it has a ton of potential for being useful in a modular way if a couple of extra installation steps are taken with codes.


The code creates a novel method of allocating persistent variables that survive purges of the memory heap in a way that doesn’t require static DOL space or changes to the arena size. It uses its own set of core modules to create a useful enumeration tool that is used to define data offsets that become variable allocations, which any other ASM program can then read or write to. The macro automates calculation of the total allocation size by simply considering the number of bytes counted in a given set of offset names by the user -- so the symbol information it generates depends on how the user configures it.

The problem with this code however is that all of its variable definitions must be defined from the same place at the very beginning of the game program, and so multiple codes that want to read from or write to the allocations it makes will need to reference the same symbol information that other codes may potentially need to have configurable access to. This makes it impractical to make the symbols attached to any one code’s ASM program for distribution, unless the code is released separate from the module.

By using the enum macro to create offset names within a file, it’s possible to externalize the user definitions and .include the symbol information into any code that might need it. That way, carefully named offsets in the included file can be used like unique keywords for loading variables from arbitrarily stacked allocations from a common base address; even if the variables change locations from configuration to configuration. This allows the order of each group of variables to not matter -- only the consistency of the names of each variable.

2 or more programs can read from the same data table like this in a way that is both convenient and easy to read:

Rich (BB code):
# in file “.RTStackSnacks\Snacks.txt”  
  
enum, 4, myASIDFunction.xASID, myASIDFunction.xASTID;  
myASIDFunction.prereq = 1 
# allocate 2 variables and a prereq symbol for the function "myASIDFunction"    
Rich (BB code):
<myASIDFunction> 
.include "RTStackSnacks.s" 
enum r3, 1, rProperty, rASTID, rCount, rSnacks; xNextASTID=-0x5228 
# local symbols 
  
.ifdef myASIDFunction.prereq 
getsnacks rSnacks 
# rSnacks = base address of RT Stack Snacks 
  
stw rProperty, myASIDFunction.xASID(rSnacks)  # this is an imported symbol 
lhz rASTID, xNextASTID(r13)                   # this is a locally defined symbol 
stw rASTID, myASIDFunction.xASTID(rSnacks) 
# pack a snack into rSnacks, for later 
  
.endif 
# do not assemble instructions if missing .prereq 
  
blr 
  
  
NTSC 1.02 ----- 800693d4 ---- 7c982378 -> Branch 
# Injection applies any usage of myASIDFunction to a transformation of the next Action State 
.include "RTStackSnacks.s" 
rASID=r4; rSnacks=r12; xNextASTID=-0x5228 
  
.ifdef myASIDFunction.prereq 
getsnacks rSnacks 
lwz r0, myASIDFunction.xASTID(rSnacks) 
lhz r15, xNextASTID(r13) 
cmpw r0, r15 
bne- _return 
  lwz rASID, myFunction.xASID(rSnacks) 
  # if transition ID matches, then get your snack back 
   
_return: 
li r0, 0 
stw r0, myASIDFunction.xASTID(rSnacks) 
# destroy record 
  
.endif 
# do not assemble instructions if missing .prereq 
  
mr r24, rASID 
.long 0 


In this case, the code would basically become a benign NOP if the prerequisite assets for configuring the module correctly were missing. If the prereq symbol is found though, it attempts to use the symbols it thinks the module will contain.

An alternative to this would be to throw in a line that does something like .ifndef myASIDFunction.prereq; .error "myASIDFunction requires variables that are missing from .RTStackSnacks\\Snacks.txt"; .endif . That way, even if the correct module is detected, the things that a given code needs from the module can be individually tested for and throw more specific errors about what is missing.
 
Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,179
Location
Sacramento, CA
Awesome! I think this will enable some really cool things in MCM.




The extra dependency file name definitions wouldn't be for the ASM, rather it would be a matter of informing MCM of what file names it should expect to find for a particular code for the sake of controlling errors in cases where the code hasn’t been installed correctly. I only mean stating file names that would be local to one of the possible include paths; so for example, a code that has the line .include "primlite.s" could then also place the string "primlite.s" somewhere in a place where MCM could see it, and then MCM would check the available paths for a match. It would be totally optional since the parse can just succeed normally without it -- but would afford avoiding a list of errors in cases of failure.

It might be entirely unnecessary though, now that I consider that the errors could probably just be detected automatically and hidden that way. I only suggested it as a means of assisting MCM in detecting the errors before they would be displayed; for the sake of making codes that use prerequisites less frustrating to install or include with other code setups. The idea would be that this disabling behavior helps the code still exist in the library without having to be removed or hidden if it hasn’t got the right prerequisites, which may be the case if the module can be configured for different setups.

If this could be done without the redundancy, then disregard that suggested detail.

---


I’m imagining a couple of scenarios where this might be particularly helpful.

The first is for convenient customization.

If I have a file containing a data table that defines default user settings for a code, it can serve as a module that could be easily swapped out or overridden with other configurations of user settings. It may also provide lists of pointers, or other data that could become modular in its application inside of a code that uses it. It is also not limited to emitted byte data, in that it can set up macros and symbols to create objects that help set up structures in other contexts. This becomes particularly useful when multiple paths are available, in an ordered priority.

I think symbol configurations, color schemes, string data, masks, lists, or even binary files with the .incbin directive could all be defined like this without really invoking a dependency hell when applied to specific codes -- and could potentially be very useful.

For cases where things might actually become a naming fiasco, it might be resolvable using another .include from inside the first module, like a chain. This could use a target directory that is selected after being invoked from a base module -- allowing a program that intends to use some custom set of files to explicitly state the subdirectory name it wants to use; or something like that.

---


The second is for modules that are not for specific ASM programs, but rather for general use by multiple ASM programs.

I actually held off responding here for a little bit so that I could post a WIP of a fairly radical example of this. You can see more details in the RT Stack Snacks thread. I feel like this is something that projects like 20XX could have benefited from quite a bit for centralizing the allocation of all of its static data. It's geared towards larger projects, but it has a ton of potential for being useful in a modular way if a couple of extra installation steps are taken with codes.


The code creates a novel method of allocating persistent variables that survive purges of the memory heap in a way that doesn’t require static DOL space or changes to the arena size. It uses its own set of core modules to create a useful enumeration tool that is used to define data offsets that become variable allocations, which any other ASM program can then read or write to. The macro automates calculation of the total allocation size by simply considering the number of bytes counted in a given set of offset names by the user -- so the symbol information it generates depends on how the user configures it.

The problem with this code however is that all of its variable definitions must be defined from the same place at the very beginning of the game program, and so multiple codes that want to read from or write to the allocations it makes will need to reference the same symbol information that other codes may potentially need to have configurable access to. This makes it impractical to make the symbols attached to any one code’s ASM program for distribution, unless the code is released separate from the module.

By using the enum macro to create offset names within a file, it’s possible to externalize the user definitions and .include the symbol information into any code that might need it. That way, carefully named offsets in the included file can be used like unique keywords for loading variables from arbitrarily stacked allocations from a common base address; even if the variables change locations from configuration to configuration. This allows the order of each group of variables to not matter -- only the consistency of the names of each variable.

2 or more programs can read from the same data table like this in a way that is both convenient and easy to read:

Rich (BB code):
# in file “.RTStackSnacks\Snacks.txt”  
  
enum, 4, myASIDFunction.xASID, myASIDFunction.xASTID;  
myASIDFunction.prereq = 1 
# allocate 2 variables and a prereq symbol for the function "myASIDFunction"    
Rich (BB code):
<myASIDFunction> 
.include "RTStackSnacks.s" 
enum r3, 1, rProperty, rASTID, rCount, rSnacks; xNextASTID=-0x5228 
# local symbols 
  
.ifdef myASIDFunction.prereq 
getsnacks rSnacks 
# rSnacks = base address of RT Stack Snacks 
  
stw rProperty, myASIDFunction.xASID(rSnacks)  # this is an imported symbol 
lhz rASTID, xNextASTID(r13)                   # this is a locally defined symbol 
stw rASTID, myASIDFunction.xASTID(rSnacks) 
# pack a snack into rSnacks, for later 
  
.endif 
# do not assemble instructions if missing .prereq 
  
blr 
  
  
NTSC 1.02 ----- 800693d4 ---- 7c982378 -> Branch 
# Injection applies any usage of myASIDFunction to a transformation of the next Action State 
.include "RTStackSnacks.s" 
rASID=r4; rSnacks=r12; xNextASTID=-0x5228 
  
.ifdef myASIDFunction.prereq 
getsnacks rSnacks 
lwz r0, myASIDFunction.xASTID(rSnacks) 
lhz r15, xNextASTID(r13) 
cmpw r0, r15 
bne- _return 
  lwz rASID, myFunction.xASID(rSnacks) 
  # if transition ID matches, then get your snack back 
   
_return: 
li r0, 0 
stw r0, myASIDFunction.xASTID(rSnacks) 
# destroy record 
  
.endif 
# do not assemble instructions if missing .prereq 
  
mr r24, rASID 
.long 0 


In this case, the code would basically become a benign NOP if the prerequisite assets for configuring the module correctly were missing. If the prereq symbol is found though, it attempts to use the symbols it thinks the module will contain.

An alternative to this would be to throw in a line that does something like .ifndef myASIDFunction.prereq; .error "myASIDFunction requires variables that are missing from .RTStackSnacks\\Snacks.txt"; .endif . That way, even if the correct module is detected, the things that a given code needs from the module can be individually tested for and throw more specific errors about what is missing.
Sounds good. Though due to work, family stuff, and travel, I likely won't be able to look at it this month. I also may release a smaller update without this first, so I can then release other work. So it may be a little while. I'll let you know if I have any questions or when I have a test build, of course.
 

Kitsune91

Lone Smasher
Joined
Mar 22, 2014
Messages
129
Location
Bakersfield, California
3DS FC
4270-1611-3292
DraGon72097 DraGon72097

Adding to what DRGN answered:
1) Did you try adding UCF as an injection mod? I attached a properly converted (NTSC 1.02) UCF 0.73 injection mod text file to this message. You may add the file to the Mods Library folder.
2) Remove (or exclude) the default mcm library mods from the Mods Library when editing 20xx to avoid conflicting codes interfering.
I followed the instructions to inject this into my 20XX Training Hack Pack however where would I be able to check to make sure it was successful or that UCF is on? I assume it doesn't add a sub-menu into the Training Hack Pack options since I didn't see anything in there. Sorry for being a noob, I just started using MCM today.
 

tauKhan

Smash Lord
Joined
Feb 9, 2014
Messages
1,349
The mod includes the CSS text indicator; if you don't see that then you didn't succeed.
 

Kitsune91

Lone Smasher
Joined
Mar 22, 2014
Messages
129
Location
Bakersfield, California
3DS FC
4270-1611-3292
The mod includes the CSS text indicator; if you don't see that then you didn't succeed.
Would I be able to private message you regarding this? I'm close I think but just need help to see what I am overlooking. I'm attempting to add it to my 4.07++ Training Hack Pack. Your help would be greatly appreciated.
 

JoshuaMK

Smash Apprentice
Joined
May 19, 2019
Messages
75
Hey DRGN DRGN , please consider this for MCM! It should be compatible with the extended dol, and adds an extra ~0x40800 bytes of usable space for gecko codes. This means that Melee would have about 0x60000 bytes of free space in total, with ~0x19800 of it being for DOL mods, and ~0x40800 of it being for gecko codes patched with the code handler. I will have updates for SME-CODE in the near-ish future, so if you decide to support this in MCM, please be aware of new versions.

https://smashboards.com/threads/sme-code-v1-0-a-way-to-have-huge-space.498167/
 
Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,179
Location
Sacramento, CA
Update!

It's been quite a while, and this turned out to be a bigger one than I intended. (In fact, I almost considered this a major update, to v"5.0" instead.) I just found so much to do once I jumped back into it. There are a couple new features, several fixes, and a lot of little tweaks to improve the user experience. I still think there are a lot of improvements that could be made though.

Version 4.3:
- Added a feature for special branch syntax offsets; e.g. 'bl <GeckoCodehandler>+0xA4'​
- Fixed installation detection of mods that use a special branch syntax (broke in 4.2)​
- Mod Web Links feature added (GUI can link to a Smashboards thread and/or Git repo)​
- .imports now scan a hierarchy of directories as well as the executable root folder*​
- 'Create GCT File' renamed to 'Create INI', which is what it was actually creating​
- Added a new 'Create GCT' feature, which creates a binary gecko codelist file​
- Improved checking/handling of Gecko codes in cases where Gecko codes are disabled​
- The 'View DOL Hex' feature now shows current program data instead of saved file data​
- Improved undo/redo history states and tracking in the Mod Construction tab​
- 'Import Gecko Code' feature (specifically for C2 codes) is no longer case-sensitive​
- The update button on the Mod Construction tab now works for Standalone Functions​
- Avoids loading custom code regions that are not compatible with the current DOL​
- Button added to choose a Mods Library folder when no Mod Library is found/chosen​
- The prompt to choose a Mods Library directory now defaults to closest existing folder​
- Hovering over the button to choose a Mods Library now shows the current library​
- Improved mod detection in cases where multiple regions cover some of the same area​
- Improved tab/scroll-position re-setting when re-scanning Mods Library​
- Eliminated redundant error messages from bad Gecko code imports​
- Fixed disassembly of all unconditional branches (b, bl, ba, bla). Output normalized​
- Fixed an audio initialization error occurring when no audio driver is installed​
- Fixed an audio initialization error occurring after no Mod Library was found​
- Fixed character conversion in Menu Text to Hex feature for '耐' and '待' characters​
- Fixed a bug that could cause a Mods Library panel to temporarily appear on other tabs​
- The ASM <-> Hex Converter window's spawn position now always over the main window​
- Some dependencies for codes from Punkline and UnclePunch have been included​
- Added 4 bytes to all revisions of 'Tournament Mode Region' ends (overwrites last blr)​
- Added around 40 mods to the default mods library​
- Small improvements to assembly/disassembly performance​
- Added support for [REDACTED; TOP-SECRET]​

*The priority for .import directives is as follows:
1) The current working directory (this is usually the MCM root folder)​
2) Directory of the mod's code file (particularly useful if the mod has its own folder)​
3) The current Mods Library's ".include" directory (this is a new folder)​
4) The MCM root folder's ".include" directory (this is a new folder)​

The directories will be searched in that order, and the first directory to contain a match to the target import file will be added to the list of import directories used during assembly. Multiple directories can be added by multiple .import statements. You can check what paths are being used during the import process by loading up the mod in the Mod Construction tab (click the Edit button in the Mod Construction tab), and click on the Info button in the top-right. Also, when you're working on a mod, and you open the ASM <-> Hex Converter, it will use the same context (import paths) as the current mod that you're viewing. You'll see a note of it at the bottom of the converter.

Relative paths work similarly, using the same priority as the base paths. For example, the line .include "./stageStuff/position.s" would first look in '[CWD]/stageStuff', then '[MCM root folder]/Mods Library/[yourModFolder]/stageStuff', '[MCM root folder]/Mods Library/.include/stageStuff', and then '[MCM root folder]/.include/stageStuff'.


The Mod Web Links is a pretty cool little feature. It adds links right on the GUI (on the mod module in the Mods Library tab):
web links.png


You can include links to Smashboards threads and/or Github repos. I'm restricting to just those domains atm, just for safety/security. But I can add other domains to allow if you guys would like. Super helpful for people to quickly look up how to configure the mod, or talk about it, report bugs, etc.

You can add these by adding <urlPath> to the mod's description. Single or double quotes are optional. There's no limit to the number you can add ATM, but it might look pretty funky in the GUI if you add too many. You can see what web links are included with a mod in the Mod Construction tab. But I haven't added an interface there yet to add/remove links, so you'll just have to do it manually in the code's text file.

Whew! Glad to finally have this released! Please let me know if you find any issues.
 
Last edited:
Top Bottom