Building Zelda Ocarina of Time with Nix!

I saw a Modern Vintage Gamer video yesterday where he talked about a project that was able to reverse engineer the machine code for Zelda Ocarina of Time. They are able to produce a 1 for 1 identical ROM from source code written in C.

I wanted to be able to build this and potentially play around with the game code. Being on NixOS I had to patch some pre-compiled binaries that were in the repository. It looks like they have a precompiled assembler and possibly a C compiler, likely to be able to produce the same binary output each time.

I was able to get into a “pure” nix shell and build the project with the following:

# NOTE: you'll need to enter the shell with this
#       environment variable set:
#       NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1
#
let
  nixpkgs = builtins.fetchTarball {
    # nixpkgs-unstable (2021-10-28)
    url = "https://github.com/NixOS/nixpkgs/archive/22a500a3f87bbce73bd8d777ef920b43a636f018.tar.gz";
    sha256 = "1rqp9nf45m03mfh4x972whw2gsaz5x44l3dy6p639ib565g24rmh";
  };
in
{
  pkgsNative ? import nixpkgs { }
  ,pkgsCross ? import nixpkgs {
    crossSystem = {
      config = "mips-linux-gnu";
    };
  }
}:

pkgsCross.mkShell {
  buildInputs = [
    pkgsCross.gcc
    pkgsNative.libpng
  ];
  nativeBuildInputs = [
    pkgsNative.git
    pkgsNative.gcc
    pkgsNative.python3
  ];
}

The combination of packages inside buildInputs an nativeBuidlInputs is odd, but it’s the result of trying different permuations until I was able to find something that works. For example, the project expects “gcc” to be the native compiler and “mips-linux-gnu-gcc” to be the cross-compiler, but if you put pkgsCross.gcc in nativeBuildInputs, then “gcc” points to the cross compiler. If anyone is able to simplify or make this code better let me know.

I also don’t like that I need to specify NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM. Is there a way to avoid the need for this in the nix expression?

For those interested in building this themselves, you’ll also need to patch the interpreter on the pre-compiled binaries, which you can do that with this script:

#!/usr/bin/env sh
set -ex

interp=$(patchelf --print-interpreter $(which env))
for version in 5.3 7.1; do
    for tool in cc cfe uopt ugen as1; do
        patchelf --set-interpreter $interp ./tools/ido_recomp/linux/$version/$tool
    done
done

I can build the project in about 40 seconds with this:

NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix-shell --pure ~/nix-shells/zelda.nix
time make setup -j24
time make -j24

Also note that to build the project, you’ll need to get ahold of a base rom image that the build can extract the assets from. I believe it needs to be a debug, USA, Master Quest version of the ROM. You’ll know your build worked if you produced a rom that is binary identical to the base rom file (with the baserom headers stripped, the build will do this for you).

I would love to be able to add a derivation for this in nixpkgs, but I’m not sure that’s possible with the need for assets that Nintendo would not make publicly available outside of purchasing them with a physical game cartridge.

10 Likes

I would love to be able to add a derivation for this in nixpkgs

@Yvar created the derivation for a similar project - the PC port of Super Mario 64, you can use it as an example on how to handle copyrighted assets: nixpkgs/pkgs/games/sm64ex/default.nix at bc5d68306b40b8522ffb69ba6cff91898c2fbbff · NixOS/nixpkgs · GitHub

1 Like

We have the requireFile function for similar cases, but such derivations tend to be harder to get into nixpkgs, I think. You can’t get CI on Hydra, and the set of human testers gets also necessarily restricted a lot, so such packages tend to rot. Maybe better publish a flake style package somewhere.

3 Likes

Hi, I wanted to add that I’ve packaged shipwright, an Ocarina of Time PC port, together with PaulGrandperrin. That uses requireFile as @vcunat said and has an unfree license set as well so hydra won’t build it. I do personally think this would be fine to have in nixpkgs, seeing how it already has two maintainers who are willing to review/update it.

Paul has written a few patches to move some runtime configuration files to XDG dirs instead of attempting to write to the nix store / the users PWD, which is much appreciated.

As soon as his PR to my nixpkgs fork is merged I will PR the derivation to nixpkgs. For now you can take a look at the code here: shipwright: patch for asset, data and conf locations by PaulGrandperrin · Pull Request #1 · IvarWithoutBones/nixpkgs · GitHub. I’ve already played through the game a little bit, noticed a few crashes here and there but it’s very playable :slight_smile:

Is there still interest in building the N64 rom itself? If yes, I could look into that as well.

1 Like