Language…
10 users online: AjaTheVampire, crocodileman94, DasFueller, drkrdnk, Eduard, Nciktendo, SethOsDotEXE, ShUriK KiD, WhiteYoshiEgg, Zavok - Guests: 53 - Bots: 164
Users: 55,661 (2,419 active)
Latest user: valentarising

SM64 Custom Gravity Implementation

  • Pages:
  • 1
  • 2

I have a very complex question, so I gave it its own thread. Here it is:

I want to implement gravity towards a point (planetary gravity), but in order to do that, I would need to know where the code to implement gravity is (so I can edit it). If anyone knows where the code is, please let me know.
 
Originally posted by Yoshimaster96
I have a very complex question, so I gave it its own thread. Here it is:

I want to implement gravity towards a point (planetary gravity), but in order to do that, I would need to know where the code to implement gravity is (so I can edit it). If anyone knows where the code is, please let me know.


First off, are you familiar with N64's Assembler (MIPS R4300i) and know in general how SM64 works, how code is even processed, etc.?

It's not like in Super Mario World, the ASM Syntax is different (for some it's even harder to learn) and the way how the code is processed is also different.

There are also no tools or anything similar which automatically hijacks gravity and replaces it.

I give an example with loading and saving to accumulator in SNES:
Loading a value into the accumulator, then saving it to an example address:
Code
LDA #$01 ; Loads the value $01 into the accumulator.
STA $7E0019 ; Stores the value $01 from accumulator into Address 7E:0019 which basically is the power-up for Mario in SMW.


And in MIPS:
Code
LUI T0, $8132
LUI T1, $0001
LUI T2, $0002
ADD T2, T1, T2 ; T2 := T1 + T2 -> $0003
SUB T2, T2, T1 ; T2 := T2 - T1 -> $0003 - $0001 = $0002
SW T2, $DC89(T0) ; This stores the result($0002) into register T2 to memory location of T0, which is $8132DC89.


LUI loads $81320000 into T0, then our two values $0001 and $0002 are loaded in T1 and the other one in T2. Then we add T1 + T2 ($0001 + $0002 = $0003) and store the result in T2. Then we subtract T2 - T1 and store it again in T2. Result is $0002. Then the result $0002 is stored into register T2 in the memory location of T0 ($8132DC89)

As you see, it's quite different and maybe more complicated. To make a more comfortable example:
Code
LUI T0, $8132 ; Load upper address $81320000
LUI T2, $0002 ; Load value $00020000
SW T2, $2000(t0) ; Store $00030000 into T2, in memory location of T0($81322000)


This is basically the same like the SNES ASM code up there, just that it doesn't allow direct addressing and all this stuff, so you load the "upper" address part and later store it together with the lower address part in SW(Store Word). MIPS doesn't have that luxury like 65C816 as far as I know, unfortunately.

My Mail | My Posts | PM Me | My YT Channel | My Blog

Originally posted by Tarek701
Originally posted by Yoshimaster96
I have a very complex question, so I gave it its own thread. Here it is:

I want to implement gravity towards a point (planetary gravity), but in order to do that, I would need to know where the code to implement gravity is (so I can edit it). If anyone knows where the code is, please let me know.


First off, are you familiar with N64's Assembler (MIPS R4300i) and know in general how SM64 works, how code is even processed, etc.?

It's not like in Super Mario World, the ASM Syntax is different (for some it's even harder to learn) and the way how the code is processed is also different.

There are also no tools or anything similar which automatically hijacks gravity and replaces it.

I give an example with loading and saving to accumulator in SNES:
Loading a value into the accumulator, then saving it to an example address:
Code
LDA #$01 ; Loads the value $01 into the accumulator.
STA $7E0019 ; Stores the value $01 from accumulator into Address 7E:0019 which basically is the power-up for Mario in SMW.


And in MIPS:
Code
LUI T0, $8132
LUI T1, $0001
LUI T2, $0002
ADD T2, T1, T2 ; T2 := T1 + T2 -> $0003
SUB T2, T2, T1 ; T2 := T2 - T1 -> $0003 - $0001 = $0002
SW T2, $DC89(T0) ; This stores the result($0002) into register T2 to memory location of T0, which is $8132DC89.


LUI loads $81320000 into T0, then our two values $0001 and $0002 are loaded in T1 and the other one in T2. Then we add T1 + T2 ($0001 + $0002 = $0003) and store the result in T2. Then we subtract T2 - T1 and store it again in T2. Result is $0002. Then the result $0002 is stored into register T2 in the memory location of T0 ($8132DC89)

As you see, it's quite different and maybe more complicated. To make a more comfortable example:
Code
LUI T0, $8132 ; Load upper address $81320000
LUI T2, $0002 ; Load value $00020000
SW T2, $2000(t0) ; Store $00030000 into T2, in memory location of T0($81322000)


This is basically the same like the SNES ASM code up there, just that it doesn't allow direct addressing and all this stuff, so you load the "upper" address part and later store it together with the lower address part in SW(Store Word). MIPS doesn't have that luxury as far as I know, unfortunately.
Yes, I know that. But as for the implementation code, do you know where I can find it? I'm not looking for a tool (I know there's none), but rather where in the ROM I can find the subroutine.
 
Originally posted by Yoshimaster96
Yes, I know that. But as for the implementation code, do you know where I can find it? I'm not looking for a tool (I know there's none), but rather where in the ROM I can find the subroutine.


I never made any research to "gravity" or to the "jumping" subroutine. But as you implied that you know this kind of stuff, you might use Nemu64 0.8 for some debugging and find the subroutine yourself. Then just convert the RAM offset into a ROM offset (if you actually want to patch the asm mod into your ROM) and assemble it directly to the ROM. Use LemASM for assembling code into SM64 ROM.

Greetings,
Tarek701.

My Mail | My Posts | PM Me | My YT Channel | My Blog

I debugged a bit, and found 13 possible subroutine locations (some addresses are very close and could be part of the same subroutine:

Code
RAM:     ROM:
80380E24 FDBA4
80380E5C FDBDC
80253ABC EABC
80253BB0 EBB0
80253C90 EC90
80253CC0 ECC0
80253D08 ED08
8026FA2C 14FF4
8026A034 25034
80256B78 11B78
80378818 F5598
80256A18 11A18
8029C890 57890
 
Originally posted by Yoshimaster96
I debugged a bit, and found 13 possible subroutine locations (some addresses are very close and could be part of the same subroutine:

Code
RAM:     ROM:
80380E24 FDBA4
80380E5C FDBDC
80253ABC EABC
80253BB0 EBB0
80253C90 EC90
80253CC0 ECC0
80253D08 ED08
8026FA2C 14FF4
8026A034 25034
80256B78 11B78
80378818 F5598
80256A18 11A18
8029C890 57890


As I said, I made no research in gravity/jump subroutine. But conversion(RAM->ROM) was correct. (Subtracting 0x245000 from RAM offset) So you're maybe on the right path.

Keep continuing. As said earlier, if you have the knowledge about the MIPS R4300i Assembly (syntax, know how to assemble, etc.) this shouldn't be really hard to you. Of course, it's getting a bit more "complex" if you want to do it like in Super Mario Galaxy.

Good luck!

EDIT:
Also, subtracting 0x245000 only works in a RAM offset range from 0x80246000 to about 0x80333000.

Greetings,
Tarek701.

My Mail | My Posts | PM Me | My YT Channel | My Blog

Hello once again! I've been debugging a bit more, and I think I've found the approximate location of the routine.

Code
RAM:     ROM:  ACCESS:
80380E24 FDBA4 R
80380E5C FDBDC   W
80253ABC EABC  R
80253BB0 EBB0  R
80253C90 EC90  R
80253CC0 ECC0  R
80253D08 ED08  R
80378818 F5598 R
8029C890 57890 R
80263798 1E798 R
80378810 F5590 R
80255AAC 10AAC   W


As you can see, only the first two are close enough to be in the same function and read and write Mario's Y position. Though I'm not certain if this affects all objects, and I don't know the range of the function, it is at least a start.
 
Yes, it does. Its like you have to actually recreate the whole SM64 engine. As Tarek said, subtracting 0x245000 to get the position in RAM, be careful of what you do from there, I thought you'd look for some free space, make a JAL command that'd jump there and execute mario's new gravity which you will write from there, say the address were 0x4AAA.

Code
4AAA+245000=249AAA
JAL $80249AAA
this will make the code jump to the address 249AAA and continue from there, do this if you don't want screw up mario's gravity, also this code comes after this "Begin Code"(within the checksum)
Code
ADDIU SP, SP, $FFE8
SW RA, $0014 (SP)
this just Adds an immediate un assigned word, which if I remember tells the game the code is going to start.

Originally posted by Cackletta
Yes, it does. Its like you have to actually recreate the whole SM64 engine. As Tarek said, subtracting 0x245000 to get the position in RAM, be careful of what you do from there, I thought you'd look for some free space, make a JAL command that'd jump there and execute mario's new gravity which you will write from there, say the address were 0x4AAA.

Code
4AAA+245000=249AAA
JAL $80249AAA
this will make the code jump to the address 249AAA and continue from there, do this if you don't want screw up mario's gravity, also this code comes after this "Begin Code"(within the checksum)
Code
ADDIU SP, SP, $FFE8
SW RA, $0014 (SP)
this just Adds an immediate un assigned word, which if I remember tells the game the code is going to start.
You wouldn't happen to know where the beginning and the end of the subroutine is, would you?
 
Originally posted by Yoshimaster96
Originally posted by Cackletta
Yes, it does. Its like you have to actually recreate the whole SM64 engine. As Tarek said, subtracting 0x245000 to get the position in RAM, be careful of what you do from there, I thought you'd look for some free space, make a JAL command that'd jump there and execute mario's new gravity which you will write from there, say the address were 0x4AAA.

Code
4AAA+245000=249AAA
JAL $80249AAA
this will make the code jump to the address 249AAA and continue from there, do this if you don't want screw up mario's gravity, also this code comes after this "Begin Code"(within the checksum)
Code
ADDIU SP, SP, $FFE8
SW RA, $0014 (SP)
this just Adds an immediate un assigned word, which if I remember tells the game the code is going to start.
You wouldn't happen to know where the beginning and the end of the subroutine is, would you?

I don't have my pc with me now, use NEMU64 to RAM/Memory watch to get it.

I found the entry point at RAM 80380DE8, ROM FDB68.

I can't figure it out, and the function is way too long to post here. If anyone wants to go ahead, be my guest.
 
Originally posted by Cackletta
Yes, it does. Its like you have to actually recreate the whole SM64 engine. As Tarek said, subtracting 0x245000 to get the position in RAM, be careful of what you do from there, I thought you'd look for some free space, make a JAL command that'd jump there and execute mario's new gravity which you will write from there, say the address were 0x4AAA.

Code
4AAA+245000=249AAA
JAL $80249AAA
this will make the code jump to the address 249AAA and continue from there, do this if you don't want screw up mario's gravity, also this code comes after this "Begin Code"(within the checksum)
Code
ADDIU SP, SP, $FFE8
SW RA, $0014 (SP)
this just Adds an immediate un assigned word, which if I remember tells the game the code is going to start.


Actually, this code just ensures, that our return address is safely stored and not lost/overwritten while we code and it won't write into the stack by prior functions. However, this is only used if we're calling another subroutine in a subroutine. Obviously the old return address would be lost(replaced by the newer one) if we would call another subroutine. That's why this code is so important.

If we're done with our main subroutine, we have to get the old return address back again by putting the end part to it:

Code
LW RA, $0014 (SP)
JR RA
ADDIU SP, SP, $0018


So, example(not real addresses here):
Let's say we jumped from 802156C9 -> So that would be our return address.

Code
8026902C: (our subroutine)
ADDIU SP, SP, $FFE8 ; Subtracts 0x18 from stack pointer to prevent mess up.
SW RA, $0014 (SP)   ; Store our return address onto the stack.
JAL $8023695C       ; Let's say this is some pre-defined function thing.
NOP                 ; Our delay slot. Gets executed before JAL, then JAL! So always look out what you put in there. Otherwise NOP it. 
LW RA, $0014 (SP)   ; Take off the return address from the stack again and put it (obviously) into RA register.
JR RA               ; Return to return address. (In ex.: 802156C9)
ADDIU SP, SP, $0018 ; Adds back the 0x18 to stack pointer.


My Mail | My Posts | PM Me | My YT Channel | My Blog

Turns out my previous find was incorrect. The function is located (I think) between 8025661C and 802569F0 (pointed to at 80256C78).
 

Why doesn't this code work?

Code
LUI T0, $0033
ORI T0, T0, $B1AC
LUI T3, $4080
ORI T3, T3, $0000
SW T3, $0000 (R0)
LWC1 F9, $0000 (R0)
LW T1, $0000 (T0)
BGTZ T1, $0001165C
BLTZ T1, $00011668
LW T1, $0004 (T0)	;$00256640
BGTZ T1, $00011674
BLTZ T1, $00011680
LW T1, $0008 (T0)	;$0025664C
BGTZ T1, $0001168C
BLTZ T1, $00011698
NOP
LWC1 F6, $000C (T0)	;$0001165C
SUB.S F6, F6, F9
J $00256640
LWC1 F6, $000C (T0)	;$00011668
ADD.S F6, F6, F9
J $00256640
LWC1 F6, $0010 (T0)	;$00011674
SUB.S F6, F6, F9
J $0025664C
LWC1 F6, $0010 (T0)	;$00011680
ADD.S F6, F6, F9
J $0025664C
LWC1 F6, $0014 (T0)	;$0001168C
SUB.S F6, F6, F9
J $002566A4
LWC1 F6, $0014 (T0)	;$00011698
ADD.S F6, F6, F9
J $002566A4
NOP			;$002566A4
 
Did you do what I and Tarek told you to?
Code
//START
ADDIU SP, SP, $FFE8
SW RA, $0014 (SP)

//ACTUAL CODE

//END
LW RA, $0014 (SP)   
JR RA              
ADDIU SP, SP, $0018 

That's the template.

Also, convert
Code
J

To
Code
JAL

Once you are done.

Originally posted by Cackletta
Did you do what I and Tarek told you to?
Code
//START
ADDIU SP, SP, $FFE8
SW RA, $0014 (SP)

//ACTUAL CODE

//END
LW RA, $0014 (SP)   
JR RA              
ADDIU SP, SP, $0018 

That's the template.

Also, convert
Code
J

To
Code
JAL

Once you are done.
Tried that and the game still crashes.

[EDIT]
The error I get is:

I need to add more code in GeneralSectionLinkage cause this is going
to cause an exception
 
Use PJ64 2.1 then.

Originally posted by Cackletta
Use PJ64 2.1 then.

I get this error:

Fatal Error: Stopping emulation
 
Originally posted by Yoshimaster96

The error I get is:

I need to add more code in GeneralSectionLinkage cause this is going
to cause an exception

Originally posted by Yoshimaster96

BGTZ T1, $0001165C
BLTZ T1, $00011668

That error is caused by having two jumps overlapping like this. N64's MIPS executes one line of code following any jump, so you have created some kind of incalculable operation here.

Originally posted by Skelux
Originally posted by Yoshimaster96

The error I get is:

I need to add more code in GeneralSectionLinkage cause this is going
to cause an exception

Originally posted by Yoshimaster96

BGTZ T1, $0001165C
BLTZ T1, $00011668

That error is caused by having two jumps overlapping like this. N64's MIPS executes one line of code following any jump, so you have created some kind of incalculable operation here.
I fixed that, but now the game crashes!
 
  • Pages:
  • 1
  • 2