Skip to content

Commit

Permalink
In-game menu (#2)
Browse files Browse the repository at this point in the history
Added an in-game menu with the following options:
  - timer (continuous timer, star grab and xcam),
  - lag counter,
  - non-stop toggle,
  - special triple jump toggle,
  - rudimentary level warping (level select, level reset, not star select).
  • Loading branch information
joeydumont authored May 28, 2019
1 parent bc8e7e9 commit 87cb0d6
Show file tree
Hide file tree
Showing 25 changed files with 1,646 additions and 15,545 deletions.
1 change: 1 addition & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[submodule "gz"]
path = gz
url = [email protected]:valandil/gz.git

17 changes: 12 additions & 5 deletions GenerateHooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@
print(args.version)

# -- Names of the functions which we want to hook into SM64.
hooks = ["_start", "display_hook", "gfx_flush", "uss64_ready", "gfx_disp", "gfx_disp_w"]
HookNames = ["USS64_Start", "USS64_DisplayAddr", "USS64_gfx_flush", "USS64_Ready", "USS64_gfx_disp", "USS64_gfx_disp_w"]
hooks = ["_start", "display_hook", "interaction_star_hook1", "interaction_star_hook2", "gfx_flush", "uss64", "gfx_disp", "gfx_disp_w"]
HookNames = ["USS64_Start", "USS64_DisplayAddr", "USS64_interaction_star_hook1", "USS64_interaction_star_hook2", "USS64_gfx_flush", "USS64_Ready", "USS64_gfx_disp", "USS64_gfx_disp_w"]
addrs = []

# -- Use nm to output the symbol table of uss64.
Expand All @@ -81,6 +81,8 @@
addrs.append("0x"+match.group(0))
break

if (args.verbose == 2):
print(dict(zip(hooks,addrs)))
# -- Determine the SM64 addresses that we hook on by
# -- preprocessing the sm64.h header by specifing the proper
# -- macro definition for the SM64 version we are currently using.
Expand All @@ -92,16 +94,21 @@
"SM64_CleanUpDisplayListHook", \
"SM64_DMACopy", \
"SM64_SoundInitHook", \
"osInvalDCache_addr"
"osInvalDCache_addr", \
"SM64_interaction_star_hook1", \
"SM64_interaction_star_hook2" \
]
addrs_to_replace = []

# -- For each hook, determine the address that the preprocessor outputs, and
# -- write it in addrs_to_replace.
for i in range(len(strings_to_replace)):
sub_cmd = "printf \"#include \\\"src/sm64.h\\\"\\n{}\"".format(strings_to_replace[i])+" | {} -E -DSM64_{} -xc - | tail -n 1".format(args.mips64_gcc,args.version)
sub_cmd = "printf \"#include \\\"src/sm64.h\\\"\\n{}\"".format(strings_to_replace[i])+" | {} -E -DSM64_{} -I/opt/n64/mips64/n64-sysroot/usr/include/ -xc - | tail -n 1".format(args.mips64_gcc,args.version)
addrs_to_replace.append(subprocess.check_output(sub_cmd, shell=True).strip().decode("utf-8"))

if (args.verbose ==2):
print(dict(zip(strings_to_replace,addrs_to_replace)))

# -- Version strings, and file paths.
FileNames = ["USS64_BIN", \
"SM64_ROM", \
Expand All @@ -114,7 +121,7 @@
bin_name = os.path.splitext(subprocess.check_output(sub_cmd, shell=True).strip().decode("utf-8"))[0]+".bin"

# -- Determine if we're on mingw python.
if (sys.platform == "win32"):
if (sys.platform == "msys"):
bin_name = r"c:\\msys64\\"+bin_name

# -- Final names of the output files.
Expand Down
47 changes: 38 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ XDELTA := xdelta3
# Compiler/linker flags (verify that -mabi=32 is necessary).
N64_SYSROOT ?= /opt/n64/mips64/n64-sysroot/usr/
CFLAGS = -std=gnu11 -Wall -O1 -mtune=vr4300 -march=vr4300 -mabi=32 \
-DF3D_GBI \
-mno-check-zero-division -mdivide-breaks \
$(GRUCODE) \
-DZ64_VERSION=Z64_OOT10 \
-I ${N64_SYSROOT}/include \
-DSETTINGS_HEADER=../../../src/settings.h \
-I ${N64_SYSROOT}/include/ \
-I $(CURDIR) \
-I $(CURDIR) \
$(SM64_VERSION_FLAG)
CXXFLAGS = -std=gnu++14 -Wall -O1 -mtune=vr4300 -march=vr4300 -mabi=32\
-DF3D_GBI
$(GRUCODE)
LDSCRIPT = $(N64_SYSROOT)/lib/gl-n64.ld
LDFLAGS = -T $(LDSCRIPT) -nostartfiles -specs=nosys.specs \
-Wl,--gc-sections \
Expand All @@ -48,18 +51,24 @@ DEBUG_SCRIPTS_OUT = debug_scripts_out
EMU_SCRIPTDIR = c/Users/Joey/Documents/VGs/Emulation/Project64d/Scripts

# Source file lists.
USS64FILES = $(SRCDIR)/uss64.c $(SRCDIR)/sm64.c
USS64FILES = $(SRCDIR)/uss64_commands.c $(SRCDIR)/uss64.c \
$(SRCDIR)/sm64.c $(SRCDIR)/gz_api.c \
$(SRCDIR)/settings.c $(SRCDIR)/uss64_settings.c \
$(SRCDIR)/uss64_warps.c $(SRCDIR)/uss64_timer.c
STDFILES = $(N64_SYSROOT)/include/grc.c \
$(N64_SYSROOT)/include/vector/vector.c \
$(N64_SYSROOT)/include/startup.c
$(N64_SYSROOT)/include/startup.c \
$(N64_SYSROOT)/include/list/list.c
STDHEADERS := $(patsubst %.c, %.h, $(STDFILES))
STDHEADERS += $(N64_SYSROOT)/include/n64.h
GZFILES = gz/src/gz/gfx.c \
gz/src/gz/input.c \
gz/src/gz/resource.c \
gz/src/gz/gu.c \
gz/src/gz/zu.c
gz/src/gz/zu.c \
gz/src/gz/menu*.c
GZHEADERS = $(wildcard gz/res/gz/*.h)
RESFILES = gz/res/gz/fipps.png gz/res/gz/button_icons.png
RESFILES = gz/res/gz/*.png
HEADERS = $(SRCDIR)/sm64.h

# Source files variables.
Expand All @@ -71,7 +80,7 @@ RESSRC := $(foreach s, $(RESFILES), $(wildcard $(s)))
OBJECTS = $(USS64_OBJECTS) $(STD_OBJECTS) $(GZ_OBJECTS) $(RES_OBJECTS)

# Versions of SM64 to inject into.
USS64_VERSIONS = SM64_U SM64_J SM64_S #SM64_Q SM64_E
USS64_VERSIONS = SM64_U SM64_J SM64_S #SM64_Q SM64_E SM64_D

# Default targets.
USS64 = $(foreach v,$(USS64_VERSIONS),uss64-$(v))
Expand Down Expand Up @@ -152,21 +161,41 @@ $$(USS64_OBJECTS-$(1)): $$(OBJDIR-$(1))/%.o : % | $$$$(dir $$$$@)
$$(CC) $$(CFLAGS) -c $$< -o $$@

$$(USS64_OBJECTS-$(1)): SM64_VERSION_FLAG = -D$(3)
$$(USS64_OBJECTS-$(1)): GRUCODE = -DF3D_GBI

ifneq ($(3),SM64_S)
$$(USS64_OBJECTS-$(1)) : GRUCODE += -DF3D_BETA
endif

$$(STD_OBJECTS-$(1)) : $$(OBJDIR-$(1))/%.o : % | $$$$(dir $$$$@)
$$(CC) $$(CFLAGS) -c $$< -o $$@

$$(STD_OBJECTS-$(1)): SM64_VERSION_FLAG = -D$(3)
$$(STD_OBJECTS-$(1)): GRUCODE = -DF3D_GBI

ifneq ($(3),SM64_S)
$$(STD_OBJECTS-$(1)) : GRUCODE += -DF3D_BETA
endif

$$(GZ_OBJECTS-$(1)) : $$(OBJDIR-$(1))/%.o : % | $$$$(dir $$$$@)
$$(CC) $$(CFLAGS) -c $$< -o $$@

$$(GZ_OBJECTS-$(1)): SM64_VERSION_FLAG = -D$(3)
$$(GZ_OBJECTS-$(1)): GRUCODE = -DF3D_GBI

ifneq ($(3),SM64_S)
$$(GZ_OBJECTS-$(1)) : GRUCODE += -DF3D_BETA
endif

$$(RES_OBJECTS-$(1)) : $$(OBJDIR-$(1))/%.o : % | $$$$(dir $$$$@)
$$(GRC) -d $$(RESDESC) $$^ -o $$@
$$(GRC) $$< -d $$(RESDESC) -o $$@

$$(RES_OBJECTS-$(1)): SM64_VERSION_FLAG = -D$(3)
$$(RES_OBJECTS-$(1)): GRUCODE = -DF3D_GBI

ifneq ($(3),SM64_S)
$$(RES_OBJECTS-$(1)) : GRUCODE += -DF3D_BETA
endif

GenerateHooks-$(1) : $$(ELF-$(1)) | $$(DEBUG_SCRIPTS_OUT)/ $$(PATCHDIR)/
$$(PYTHON) $$(GENERATEHOOKS) -vv $$(ELF-$(1)) $$(VERSION-$(1)) --mips64-nm=$$(CROSS)nm --mips64-gcc=$$(CROSS)gcc
Expand Down
28 changes: 10 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
## About

Skeleton of a SM64 practice ROM. While the (provisional) title ostensibly refers to
a practice ROM to be used for speedrun practice, I don't think I have (yet) the
skills and free time necessary to provide a very polished product. Indeed, I plan
to use this project more as a way to learn more about low-level programming
Skeleton of a SM64 practice ROM. While the (provisional) title ostensibly refers
to a practice ROM to be used for speedrun practice, I don't think I have (yet)
the skills and free time necessary to provide a very polished product. Indeed, I
plan to use this project more as a way to learn more about low-level programming
(at least, lower level than I'm used to), and assembly.

## Building

To compile this C hack and patch the ROM, you will need [glank](https://github.com/glankk)'s
N64 [toolchain](https://github.com/glankk/n64). If you're on Arch Linux, simply use
```
yaourt -S mips64-gcc-n64
```
and that should install all the proper dependencies. Otherwise, follow
the instructions on the glank's repo. For now, I assume that
you have installed the toolchain in `/opt/n64-dev`. Sorry about that, I'll fix
this later.

To compile the practice hack, simply run `bash patch.sh` in the `patch`
subdirectory.
To compile this C hack and patch the ROM, you will need
[glank](https://github.com/glankk)'s N64
[toolchain](https://github.com/glankk/n64).

## Thanks

Thanks to [@kdjmonaghan](https://github.com/kdjmonaghan) for getting me started,
[@queueRAM](https://github.com/queueRAM) and for the general help and their immensely useful tools,
and of course [@glankk](https://github.com/glankk) for making gz in the first place.
[@queueRAM](https://github.com/queueRAM) and for the general help and their
immensely useful tools, and of course [@glankk](https://github.com/glankk) for
making gz in the first place.
115 changes: 64 additions & 51 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,24 @@
Development:
- [X] Check the textures that SM64 understands (fipps is ia4, for instance).
- [ ] Add support for SM64 Europe.
- [ ] Write a sane build pipeline (Makefile).
- [ ] Give $(BINDIR), $(ASMDIR) and $(PATCHDIR) as an argument to GenerateHooks in Makefile.
- [X] Create a loop for all supported versions.
- [X] Simplify directory structure of Makefile output, specifically the patch part.
- [ ] Generate patches in different formats (xdelta, bps, ...).
- [X] Capture input
- First try through Mario's object, but not sure that's active all the time.
- Otherwise, capture the raw input data from the console.
- [ ] Spawn a simple menu. Just a return option.
- [X] Code input display.
- [ ] Find more intelligent way to hook. Mario's behaviour is not run at every frame.
- Finish Fast3D support in `gbi.h`:
- [X] `G_MW_FORCEMTX` and related macros.
- [X] Fix `g{,s}SPMatrix`.
- [X] Fix `g{,s}SPVertex`.
- [X] Fix `g{,s}SPViewport`.
- [X] Fix `g{,s}MoveWd`.
- [X] Add `g{,s}SPInsertMatrix` (low priority).
- [X] Check `g{,s}SPModifyVertex`.
- [X] Check whether the `__gsSP1{Triangle,Line3D}_w1` have any use for us,
since the 2Triangles and Quadrangle stuff doesn't seem to be defined
in Fast3D. Make sure that they aren't used in gz.
- [X] Fix `g{,s}SPCullDisplayList`.
- [X] Fix the `g{,s}SPBranch` macros, and `gSPLoadUCode` related macros.
They aren't defined in Fast3D, so we should make sure that they aren't
used in gz.
- [X] Fix `g{,s}SPNumLights`.
- [X] Fix `gSPLight`.
- [X] Fix `g{,s}SPLookAt{X,Y}`.
- [X] Fix `g{,s}SPopMatrix{,N}`. The N variant doesn't exist in Fast3D, so make
sure it isn't used in gz.
- [X] ~~Fix `g{,s}SPGeometryMode`~~. Check whether gsSPLoadGeometryMode has an equivalent in F3D.
- [X] Fix `g{,s}SPSetOtherMode`.
- [X] ~~Read RAM entry point from the ROM itself instead of hard-coding it in the Python script.~~ Actually we never parse the ROM for other data, so might as well hard-code it.
- [X] Check the address at which `SM64_gDisplayListHead` points before and after the
`gfx_flush()` call to make sure that the DL is inserted.
- [X] ~~Research the behaviour of the RDP for invalid DLs.~~
There isn't much in the official docs. Maybe try to inject a known DL with
deliberately wrong data and see what happens. Choose a second level DL
to mess with a single layer (or try to).


Ideas for a future release:
- [ ] Add support for SM64 Europe.
- [ ] Add support for SM64 iQue.
- [ ] Add support for SM64 DD.
- [ ] Include a built-in patcher.
- Practice
- [ ] Infinite lives
- [ ] Level reset (with camerafix)
- [X] Reset level
- [ ] Coins don't respawn, and I suspect enemies do not return to their original positions.
- [ ] When resetting in castle, does not take into account last exit. Should
map all warp nodes correctly.
- [ ] Star Select (toggle between Tiny and Huge THI)
- [ ] This doesn't work. Trying to initiate a warp to PSS and then immediately after
another warp doesn't work. Must include some kind of delay, or figure out a way
to instantly trigger star select.
- [ ] Savestates
- [ ] Double savestates (asm)
- [ ] Something similar to memfiles in gz, with SD card writes
- [ ] Level Select (similar to warps in gz)
- [X] Level Select (similar to warps in gz)
- [ ] Not super stable. And some warps won't work depending on the current level. Should work out warp nodes.
- [ ] Pre-made practice files (customizable)
- [ ] 120 Star
- [ ] Up RTA 74 star
Expand All @@ -66,12 +33,13 @@ Ideas for a future release:
- [ ] Show timer in castle
- [ ] Centiseconds (toggle)
- [ ] Show timer always, star grab, x-cam (toggle).
- [ ] Stop timer star grab, x-cam (toggle).
- [ ] Stop timer star grab, x-cam (show both).
- HUD elements
- [ ] Lag counter, reset at level reset/star select/with L.
- [X] Lag counter, reset at level reset/star select/with L.
- [ ] Lag as lives
- [ ] Speed display
- [ ] Speed as stars
- [ ] Number of inputs per second
- Cosmetic
- [ ] No music (toggle)
- [ ] All Stars coloured (toggle, select color).
Expand All @@ -84,6 +52,51 @@ Ideas for a future release:
- [ ] Spawn fat penguin (toggle).
- [ ] TTC clock speed.
- [ ] WDW water level.
- [ ] Non-stop (toggle).
- [ ] Save best times (with and without 100c star) to SD card (or EEPROM).
- [ ] Detect if there is extra lag?
- [X] Non-stop (toggle).
- [X] Special triple jump toggle.
- [ ] Save best times (with and without 100c star) to SD card ~~(or EEPROM)~~.
- [ ] Detect if there is extra lag? (Not really possible unless you send the
same DLs (+ uss64) and check the difference in lag).

Development:
- [X] Check the textures that SM64 understands (fipps is ia4, for instance).
- [X] Write a sane build pipeline (Makefile).
- [X] Give $(BINDIR), $(ASMDIR) and $(PATCHDIR) as an argument to GenerateHooks in Makefile.
- [X] Create a loop for all supported versions.
- [X] Simplify directory structure of Makefile output, specifically the patch part.
- [ ] Generate patches in different formats (~~xdelta~~, bps, ...).
- [X] Capture input
- ~~First try through Mario's object, but not sure that's active all the time.~~
- Otherwise, capture the raw input data from the console.
- [X] Spawn a simple menu. Just a return option.
- [X] Code input display.
- [X] Find more intelligent way to hook. Mario's behaviour is not run at every frame.
- Finish Fast3D support in `gbi.h`:
- [X] `G_MW_FORCEMTX` and related macros.
- [X] Fix `g{,s}SPMatrix`.
- [X] Fix `g{,s}SPVertex`.
- [X] Fix `g{,s}SPViewport`.
- [X] Fix `g{,s}MoveWd`.
- [X] Add `g{,s}SPInsertMatrix` (low priority).
- [X] Check `g{,s}SPModifyVertex`.
- [X] Check whether the `__gsSP1{Triangle,Line3D}_w1` have any use for us,
since the 2Triangles and Quadrangle stuff doesn't seem to be defined
in Fast3D. Make sure that they aren't used in gz.
- [X] Fix `g{,s}SPCullDisplayList`.
- [X] Fix the `g{,s}SPBranch` macros, and `gSPLoadUCode` related macros.
They aren't defined in Fast3D, so we should make sure that they aren't
used in gz.
- [X] Fix `g{,s}SPNumLights`.
- [X] Fix `gSPLight`.
- [X] Fix `g{,s}SPLookAt{X,Y}`.
- [X] Fix `g{,s}SPopMatrix{,N}`. The N variant doesn't exist in Fast3D, so make
sure it isn't used in gz.
- [X] ~~Fix `g{,s}SPGeometryMode`~~. Check whether gsSPLoadGeometryMode has an equivalent in F3D.
- [X] Fix `g{,s}SPSetOtherMode`.
- [X] ~~Read RAM entry point from the ROM itself instead of hard-coding it in the Python script.~~ Actually we never parse the ROM for other data, so might as well hard-code it.
- [X] Check the address at which `SM64_gDisplayListHead` points before and after the
`gfx_flush()` call to make sure that the DL is inserted.
- [X] ~~Research the behaviour of the RDP for invalid DLs.~~
There isn't much in the official docs. Maybe try to inject a known DL with
deliberately wrong data and see what happens. Choose a second level DL
to mess with a single layer (or try to).
11 changes: 0 additions & 11 deletions Toolchain-mips64-linux-x86_64.cmake

This file was deleted.

Loading

0 comments on commit 87cb0d6

Please sign in to comment.