Compare commits

...

17 Commits

Author SHA1 Message Date
Connor Olding 8e78d08c07 mention debug_saves 2019-08-03 07:40:44 -07:00
Connor Olding edc739ea98 move files 2019-08-03 07:39:15 -07:00
Connor Olding 1240ecd266 Merge remote-tracking branch 'debug_saves/master' 2019-08-03 07:39:15 -07:00
Connor Olding 46970df021 move files 2019-08-03 07:37:40 -07:00
Connor Olding b372392aa3 mention rng64 2019-08-03 07:34:29 -07:00
Connor Olding f463e58706 Merge remote-tracking branch 'rng64/master' 2019-08-03 07:33:13 -07:00
Connor Olding 9debd3f5ce mention coin_or_build 2019-08-03 07:31:00 -07:00
Connor Olding 9d99af3745 Merge remote-tracking branch 'coin_or_build/master' 2019-08-03 07:28:47 -07:00
Connor Olding 94d9de15a4 remove psnip_clock
i use something much shorter albeit less portable now
2019-08-03 07:17:44 -07:00
Connor Olding d3f05daf6d remove explicit_globals 2019-08-03 07:14:21 -07:00
Connor c1497d802b 2019-03-26 14:01:39 -07:00
Connor 273abe1ee4 2017-07-03 20:16:09 -07:00
Connor 89a434c5e8 2017-07-03 20:03:50 -07:00
Connor f8fbea1e92 2017-07-03 19:56:44 -07:00
Connor 44a3945bf2 2017-04-25 11:57:05 -07:00
Connor 8093266ec7 2017-04-25 11:52:21 -07:00
Connor caf9a2aab7 2017-04-25 11:44:45 -07:00
6 changed files with 314 additions and 515 deletions

View File

@ -44,6 +44,11 @@ i recently repurposed this script
to render characters to bitmaps for use as textures in games,
but i haven't uploaded that version yet.
### coin\_or\_build
a shell script that builds Bonmin and its many, *many* dependencies
on other coin\_or projects.
### danbooru\_atomizer
a Python script that scrapes atom feeds on [danbooru (nsfw)](https://danbooru.donmai.us/)
@ -57,6 +62,14 @@ for a given search query. requires zsh and xml2.
i don't think this version works anymore,
so i'll have to update it with my local changes sometime.
### debug\_saves
for Majora's Mask:
these gameshark cheats will override the default save file
with the debug save file. create a new file on the file select screen
and it should create a debug save.
*note:* this is probably the same as using map select.
### desmos
[stuff i've plotted in desmos.](/desmos/desmos.md)
@ -102,10 +115,6 @@ with all the appropriate character mappings.
the code is Unlicensed, and i believe the font itself is public domain.
### explicit\_globals
hmm, this probably shouldn't be here...
### filter\_tutorial
a single Python file that walks you through
@ -197,15 +206,10 @@ since the resulting format cannot be deserialized,
this is primarily intended for debugging purposes,
and i'd like to think it excels at that.
### psnip\_clock
### rng64
a fork of the clock utility header file
from [Portable Snippets](https://github.com/nemequ/portable-snippets)
by Evan Nemerson.
this fork removes the dependency on `windows.h` for the Windows backend
by using some gross hacks,
albeit not as gross as actually having to include `windows.h`.
this is licensed under [CC0 1.0.](https://creativecommons.org/publicdomain/zero/1.0/)
some notes on the random number generator that Ocarina of Time
and Majora's Mask use. don't get your hopes up about the manipulation stuff.
### speedrun\_comparison

151
coin_or_build/everything Normal file
View File

@ -0,0 +1,151 @@
#!/usr/bin/env bash
set -e
prefix="/opt/coin-or"
# get json2 for helping with github APIs later:
if [ ! -s "json2" ]; then
curl -LsS https://github.com/vi/json2/raw/master/json2 -o json2
fi
chmod +x json2
# ensure we can actually run it:
./json2 <<< '{}' >/dev/null
# prepare paths:
mkdir -p $prefix/lib/pkgconfig
PATH="$prefix/bin:$PATH"
PKG_CONFIG_PATH="$prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
# prepare a mapping of coin-or project names to their tar.gz's:
declare -A tgzs
note() {
echo -e "\e[1m$@\e[0m" >&2
}
stfu() {
"$@" > .stdout 2> .stderr || fail=$?
if [[ "$fail" -ne 0 ]]; then
echo "command failed with exit status $fail:" >&2
echo -E "$@" >&2
echo >&2
note '$ tail .stdout'
tail .stdout >&2
echo >&2
note '$ tail .stderr'
tail .stderr >&2
return 1
fi
}
get_autotool() {
if [ -s "$1.tar.gz" ]; then
note "skipping downloading $1"
return 0
fi
note "downloading $1"
curl -LsS "http://ftp.gnu.org/gnu/${1%-*}/$1.tar.gz" -o "$1.tar.gz"
}
make_autotool() {
if [[ $(command -v "${1%-*}") == "$prefix/bin"* ]]; then
note "skipping building $1"
return 0
fi
note "building $1"
# always extract in case configs/caches got messed up (as they do):
tar -xzf "$1.tar.gz"
pushd "$1" >/dev/null
stfu ./configure --prefix=$prefix
stfu make
stfu make install
popd >/dev/null
}
get_coin() {
organ="coin-or"
if [ "$1" == "BuildTools" ] || [[ "$1" == "ThirdParty-"* ]]; then
organ="coin-or-tools"
fi
curl -LsS "https://api.github.com/repos/$organ/$1/tags" | ./json2 > temp
for i in {0..9}; do # check first few tags for a release
grep -Eq "^/$i/name=releases" temp || continue
url="$(grep -E "^/$i/tarball_url=" temp)"
url="${url#*=}"
sha="$(grep -E "^/$i/commit/sha=" temp)"
sha="${sha#*=}"
tgz="$organ-$1-${sha::7}.tar.gz"
tgzs["$1"]="$tgz"
if [ -s "$tgz" ]; then
note "skipping downloading $1"
else
note "downloading $1"
curl -LsS "$url" -o "$tgz"
fi
return 0
done
echo "failed to find the latest release of $1" >&2
return 1
}
with() {
withs=()
for name in "$@"; do
withs+=("--with-$name")
if [ "$name" == "asl" ]; then
withs+=("--with-$name-lib=$(pkg-config --libs coin$name)")
withs+=("--with-$name-incdir=$prefix/include/coin/ThirdParty/")
else
withs+=("--with-$name-lib=$(pkg-config --libs $name)")
withs+=("--with-$name-incdir=$prefix/include/coin/")
fi
done
}
make_coin() {
note "building $1"
tgz="${tgzs[$1]}"
# always extract in case configs/caches got messed up (as they do):
tar -xzf "$tgz"
dir="$(tar -tzf "$tgz" | head -1 | cut -f1 -d/)"
pushd "$dir" >/dev/null
if [[ "$1" == "ThirdParty-"* ]]; then
stfu "./get.${1##*-}"
fi
shift
stfu ./configure --prefix=$prefix "${withs[@]}" "$@"
stfu make
stfu make install
popd >/dev/null
}
for autotool in autoconf-2.59 automake-1.9.6 libtool-1.5.22; do
get_autotool "$autotool"
make_autotool "$autotool"
done
get_coin CoinUtils
get_coin Osi
get_coin Clp
get_coin Cgl
get_coin Cbc
get_coin Ipopt
get_coin Bonmin
get_coin ThirdParty-ASL
with; make_coin ThirdParty-ASL
with; make_coin CoinUtils
with coinutils; make_coin Osi
with coinutils osi; make_coin Clp
with coinutils osi clp; make_coin Cgl
with coinutils osi clp cgl asl; make_coin Cbc
with coinutils osi clp cgl asl cbc; make_coin Ipopt --with-blas="/mingw64/bin/libopenblas.dll"
with coinutils osi clp cgl asl cbc ipopt; make_coin Bonmin
# FIXME: Bonmin needs to be linked with more stuff: (g++ invoked by libtool)
# -lipoptamplinterface
# -lcoinasl

View File

@ -0,0 +1,26 @@
### how to use:
these gameshark cheats will override the default save file with the debug save file.
create a new file on the file select screen and it should create a debug save.
note: this is probably the same as using map select.
### MM (J) 1.0
```
D1142850 0C05
D1142852 053D
81142852 0573
```
### MM (J) 1.1
```
D11428B0 0C05
D11428B2 0555
811428B2 058B
```
### MM (U)
```
D1146AC8 0C05
D1146ACA 1224
81146ACA 125A
```

View File

@ -1,25 +0,0 @@
local mt = getmetatable(_G)
if mt == nil then
mt = {}
setmetatable(_G, mt)
end
mt.__declared = {}
function mt.__newindex(t, n, v)
if not mt.__declared[n] then
local info = debug.getinfo(2, "S")
if info and info.what ~= "main" and info.what ~= "C" then
error("cannot assign undeclared global '" .. tostring(n) .. "'", 2)
end
mt.__declared[n] = true
end
rawset(t, n, v)
end
function mt.__index(t, n)
if not mt.__declared[n] then
local info = debug.getinfo(2, "S")
if info and info.what ~= "main" and info.what ~= "C" then
error("cannot use undeclared global '" .. tostring(n) .. "'", 2)
end
end
end

View File

@ -1,478 +0,0 @@
/* Clocks (v1)
* Portable Snippets - https://github.com/nemequ/portable-snippets
* Created by Evan Nemerson <evan@nemerson.com>
*
* To the extent possible under law, the authors have waived all
* copyright and related or neighboring rights to this code. For
* details, see the Creative Commons Zero 1.0 Universal license at
* https://creativecommons.org/publicdomain/zero/1.0/
*
* Modified by Connor Olding, 2017
*/
#if !defined(PSNIP_CLOCK_H)
#define PSNIP_CLOCK_H
#if !defined(PSNIP_CLOCK_STATIC_INLINE)
# if defined(__GNUC__)
# define PSNIP_CLOCK__COMPILER_ATTRIBUTES __attribute__((__unused__))
# else
# define PSNIP_CLOCK__COMPILER_ATTRIBUTES
# endif
# define PSNIP_CLOCK__FUNCTION PSNIP_CLOCK__COMPILER_ATTRIBUTES static
#endif
enum PsnipClockType {
/* This clock provides the current time, in units since 1970-01-01
* 00:00:00 UTC not including leap seconds. In other words, UNIX
* time. Keep in mind that this clock doesn't account for leap
* seconds, and can go backwards (think NTP adjustments). */
PSNIP_CLOCK_TYPE_WALL = 1,
/* The CPU time is a clock which increases only when the current
* process is active (i.e., it doesn't increment while blocking on
* I/O). */
PSNIP_CLOCK_TYPE_CPU = 2,
/* Monotonic time is always running (unlike CPU time), but it only
ever moves forward unless you reboot the system. Things like NTP
adjustments have no effect on this clock. */
PSNIP_CLOCK_TYPE_MONOTONIC = 3
};
struct PsnipClockTimespec {
uint64_t seconds;
uint64_t nanoseconds;
};
/* Methods we support: */
#define PSNIP_CLOCK_METHOD_CLOCK_GETTIME 1
#define PSNIP_CLOCK_METHOD_TIME 2
#define PSNIP_CLOCK_METHOD_GETTIMEOFDAY 3
#define PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER 4
#define PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME 5
#define PSNIP_CLOCK_METHOD_CLOCK 6
#define PSNIP_CLOCK_METHOD_GETPROCESSTIMES 7
#define PSNIP_CLOCK_METHOD_GETRUSAGE 8
#define PSNIP_CLOCK_METHOD_GETSYSTEMTIMEPRECISEASFILETIME 9
#define PSNIP_CLOCK_METHOD_GETTICKCOUNT64 10
#include <assert.h>
#if defined(HEDLEY_UNREACHABLE)
# define PSNIP_CLOCK_UNREACHABLE() HEDLEY_UNREACHABLE()
#else
# define PSNIP_CLOCK_UNREACHABLE() assert(0)
#endif
/* Choose an implementation */
/* #undef PSNIP_CLOCK_WALL_METHOD */
/* #undef PSNIP_CLOCK_CPU_METHOD */
/* #undef PSNIP_CLOCK_MONOTONIC_METHOD */
/* We want to be able to detect the libc implementation, so we include
<limits.h> (<features.h> isn't available everywhere). */
#if defined(__unix__) || defined(__unix) || defined(__linux__)
# include <limits.h>
# include <unistd.h>
#endif
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
/* These are known to work without librt. If you know of others
* please let us know so we can add them. */
# if \
(defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17))) || \
(defined(__FreeBSD__))
# define PSNIP_CLOCK_HAVE_CLOCK_GETTIME
# elif !defined(PSNIP_CLOCK_NO_LIBRT)
# define PSNIP_CLOCK_HAVE_CLOCK_GETTIME
# endif
#endif
#if defined(_WIN32)
# if !defined(PSNIP_CLOCK_CPU_METHOD)
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_GETPROCESSTIMES
# endif
# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
# endif
#endif
#if defined(__MACH__)
# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
# endif
#endif
#if defined(PSNIP_CLOCK_HAVE_CLOCK_GETTIME)
# include <time.h>
# if !defined(PSNIP_CLOCK_WALL_METHOD)
# if defined(CLOCK_REALTIME_PRECISE)
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME_PRECISE
# elif !defined(__sun)
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME
# endif
# endif
# if !defined(PSNIP_CLOCK_CPU_METHOD)
# if defined(_POSIX_CPUTIME) || defined(CLOCK_PROCESS_CPUTIME_ID)
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_PROCESS_CPUTIME_ID
# elif defined(CLOCK_VIRTUAL)
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_VIRTUAL
# endif
# endif
# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
# if defined(CLOCK_MONOTONIC_RAW) && !defined(__EMSCRIPTEN__)
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC_RAW
# elif defined(CLOCK_MONOTONIC_PRECISE)
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC_PRECISE
# elif defined(_POSIX_MONOTONIC_CLOCK) || defined(CLOCK_MONOTONIC)
# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME
# define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC
# endif
# endif
#endif
#if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L)
# if !defined(PSNIP_CLOCK_WALL_METHOD)
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_GETTIMEOFDAY
# endif
#endif
#if !defined(PSNIP_CLOCK_WALL_METHOD)
# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_TIME
#endif
#if !defined(PSNIP_CLOCK_CPU_METHOD)
# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK
#endif
/* Primarily here for testing. */
#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) && defined(PSNIP_CLOCK_REQUIRE_MONOTONIC)
# error No monotonic clock found.
#endif
/* Implementations */
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_TIME)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_TIME))
# include <time.h>
#endif
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY))
# include <sys/time.h>
#endif
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64))
typedef struct _FILETIME {
uint32_t dwLowDateTime;
uint32_t dwHighDateTime;
} FILETIME;
typedef union _LARGE_INTEGER {
struct {
uint32_t LowPart;
int32_t HighPart;
};
struct {
uint32_t LowPart;
int32_t HighPart;
} u;
int64_t QuadPart;
} LARGE_INTEGER;
#ifdef __cplusplus
#define PSNIP_EXTERN extern "C"
#else
#define PSNIP_EXTERN
#endif
PSNIP_EXTERN void * __stdcall GetCurrentProcess(void);
PSNIP_EXTERN int __stdcall QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
PSNIP_EXTERN int __stdcall QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
PSNIP_EXTERN int __stdcall GetProcessTimes(
void *hProcess,
FILETIME *lpCreationTime,
FILETIME *lpExitTime,
FILETIME *lpKernelTime,
FILETIME *lpUserTime
);
#endif
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE))
# include <sys/time.h>
# include <sys/resource.h>
#endif
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME))
# include <CoreServices/CoreServices.h>
# include <mach/mach.h>
# include <mach/mach_time.h>
#endif
/*** Implementations ***/
#define PSNIP_CLOCK_NSEC_PER_SEC ((uint32_t) (1000000000ULL))
#if \
(defined(PSNIP_CLOCK_CPU_METHOD) && (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
(defined(PSNIP_CLOCK_WALL_METHOD) && (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \
(defined(PSNIP_CLOCK_MONOTONIC_METHOD) && (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME))
PSNIP_CLOCK__FUNCTION uint32_t
psnip_clock__clock_getres (clockid_t clk_id) {
struct timespec res;
int r;
r = clock_getres(clk_id, &res);
if (r != 0)
return 0;
return (uint32_t) (PSNIP_CLOCK_NSEC_PER_SEC / res.tv_nsec);
}
PSNIP_CLOCK__FUNCTION int
psnip_clock__clock_gettime (clockid_t clk_id, struct PsnipClockTimespec* res) {
struct timespec ts;
if (clock_gettime(clk_id, &ts) != 0)
return -10;
res->seconds = (uint64_t) (ts.tv_sec);
res->nanoseconds = (uint64_t) (ts.tv_nsec);
return 0;
}
#endif
PSNIP_CLOCK__FUNCTION uint32_t
psnip_clock_wall_get_precision (void) {
#if !defined(PSNIP_CLOCK_WALL_METHOD)
return 0;
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_WALL);
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY
return 1000000;
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME
return 1;
#else
return 0;
#endif
}
PSNIP_CLOCK__FUNCTION int
psnip_clock_wall_get_time (struct PsnipClockTimespec* res) {
(void) res;
#if !defined(PSNIP_CLOCK_WALL_METHOD)
return -2;
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_WALL, res);
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME
res->seconds = time(NULL);
res->nanoseconds = 0;
#elif defined(PSNIP_CLOCK_WALL_METHOD) && PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY
struct timeval tv;
if (gettimeofday(&tv, NULL) != 0)
return -6;
res->seconds = tv.tv_sec;
res->nanoseconds = tv.tv_usec * 1000;
#else
return -2;
#endif
return 0;
}
PSNIP_CLOCK__FUNCTION uint32_t
psnip_clock_cpu_get_precision (void) {
#if !defined(PSNIP_CLOCK_CPU_METHOD)
return 0;
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_CPU);
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK
return CLOCKS_PER_SEC;
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES
return PSNIP_CLOCK_NSEC_PER_SEC / 100;
#else
return 0;
#endif
}
PSNIP_CLOCK__FUNCTION int
psnip_clock_cpu_get_time (struct PsnipClockTimespec* res) {
#if !defined(PSNIP_CLOCK_CPU_METHOD)
(void) res;
return -2;
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_CPU, res);
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK
clock_t t = clock();
if (t == ((clock_t) -1))
return -5;
res->seconds = t / CLOCKS_PER_SEC;
res->nanoseconds = (t % CLOCKS_PER_SEC) * (PSNIP_CLOCK_NSEC_PER_SEC / CLOCKS_PER_SEC);
#elif defined(PSNIP_CLOCK_CPU_METHOD) && PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES
FILETIME CreationTime, ExitTime, KernelTime, UserTime;
LARGE_INTEGER date, adjust;
if (!GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime))
return -7;
/* http://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ */
date.HighPart = UserTime.dwHighDateTime;
date.LowPart = UserTime.dwLowDateTime;
adjust.QuadPart = 11644473600000 * 10000;
date.QuadPart -= adjust.QuadPart;
res->seconds = date.QuadPart / 10000000;
res->nanoseconds = (date.QuadPart % 10000000) * (PSNIP_CLOCK_NSEC_PER_SEC / 100);
#elif PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE
struct rusage usage;
if (getrusage(RUSAGE_SELF, &usage) != 0)
return -8;
res->seconds = usage.ru_utime.tv_sec;
res->nanoseconds = tv.tv_usec * 1000;
#else
(void) res;
return -2;
#endif
return 0;
}
PSNIP_CLOCK__FUNCTION uint32_t
psnip_clock_monotonic_get_precision (void) {
#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
return 0;
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC);
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
static mach_timebase_info_data_t tbi = { 0, };
if (tbi.denom == 0)
mach_timebase_info(&tbi);
return (uint32_t) (tbi.numer / tbi.denom);
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64
return 1000;
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
LARGE_INTEGER Frequency;
QueryPerformanceFrequency(&Frequency);
return (uint32_t) ((Frequency.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC) ? PSNIP_CLOCK_NSEC_PER_SEC : Frequency.QuadPart);
#else
return 0;
#endif
}
PSNIP_CLOCK__FUNCTION int
psnip_clock_monotonic_get_time (struct PsnipClockTimespec* res) {
#if !defined(PSNIP_CLOCK_MONOTONIC_METHOD)
(void) res;
return -2;
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME
return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC, res);
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME
uint64_t nsec = mach_absolute_time();
static mach_timebase_info_data_t tbi = { 0, };
if (tbi.denom == 0)
mach_timebase_info(&tbi);
nsec *= ((uint64_t) tbi.numer) / ((uint64_t) tbi.denom);
res->seconds = nsec / PSNIP_CLOCK_NSEC_PER_SEC;
res->nanoseconds = nsec % PSNIP_CLOCK_NSEC_PER_SEC;
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER
LARGE_INTEGER t, f;
if (QueryPerformanceCounter(&t) == 0)
return -12;
QueryPerformanceFrequency(&f);
res->seconds = t.QuadPart / f.QuadPart;
res->nanoseconds = t.QuadPart % f.QuadPart;
if (f.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC)
res->nanoseconds /= f.QuadPart / PSNIP_CLOCK_NSEC_PER_SEC;
else
res->nanoseconds *= PSNIP_CLOCK_NSEC_PER_SEC / f.QuadPart;
#elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64
const ULONGLONG msec = GetTickCount64();
res->seconds = msec / 1000;
res->nanoseconds = sec % 1000;
#else
return -2;
#endif
return 0;
}
/* Returns the number of ticks per second for the specified clock.
* For example, a clock with millisecond precision would return 1000,
* and a clock with 1 second (such as the time() function) would
* return 1.
*
* If the requested clock isn't available, it will return 0.
* Hopefully this will be rare, but if it happens to you please let us
* know so we can work on finding a way to support your system.
*
* Note that different clocks on the same system often have a
* different precisions.
*/
PSNIP_CLOCK__FUNCTION uint32_t
psnip_clock_get_precision (enum PsnipClockType clock_type) {
switch (clock_type) {
case PSNIP_CLOCK_TYPE_MONOTONIC:
return psnip_clock_monotonic_get_precision ();
case PSNIP_CLOCK_TYPE_CPU:
return psnip_clock_cpu_get_precision ();
case PSNIP_CLOCK_TYPE_WALL:
return psnip_clock_wall_get_precision ();
}
PSNIP_CLOCK_UNREACHABLE();
return 0;
}
/* Set the provided timespec to the requested time. Returns 0 on
* success, or a negative value on failure. */
PSNIP_CLOCK__FUNCTION int
psnip_clock_get_time (enum PsnipClockType clock_type, struct PsnipClockTimespec* res) {
assert(res != NULL);
switch (clock_type) {
case PSNIP_CLOCK_TYPE_MONOTONIC:
return psnip_clock_monotonic_get_time (res);
case PSNIP_CLOCK_TYPE_CPU:
return psnip_clock_cpu_get_time (res);
case PSNIP_CLOCK_TYPE_WALL:
return psnip_clock_wall_get_time (res);
}
return -1;
}
#endif /* !defined(PSNIP_CLOCK_H) */

121
rng64/rng.md Normal file
View File

@ -0,0 +1,121 @@
# info dump on the RNG in OoT and MM
if you find any discrepancies, please
leave a comment or tweet at [@antiformant][twitter].
[twitter]: https://twitter.com/antiformant
## the function itself
the random number generator in both games is an LCG:
https://en.wikipedia.org/wiki/Linear_congruential_generator
specifically, it uses the constants from Numerical Recipes in C.
```c
/* the C code looks something like this: */
static uint32_t rng_value = 1;
uint32_t prng() {
/* note: intentional unsigned overflow. */
rng_value = rng_value * 1664525 + 1013904223;
return rng_value;
/* note: in the game, there's some code to reinterpret the value
as a floating point number, which I've omitted here. */
}
```
if you're interested, you can find the function(s) in any version by searching
for F35F in RAM. you should see a 660D nearby, usually a bit before.
you can find the rng_value variable
by looking at the disassembly of the RNG function.
note that there are a few different variations of the function
that are not commonly invoked; you can find these the same way.
here are some known addresses:
game, version | RNG value | RNG function | variants
------------- | --------- | ------------ | --------
OoT 1.0 | 80105440 | 800CDC90 | ?
OoT 1.2 | 80105A80 | 800CE4D0 | ?
MM (J) 1.1 | 8009E890 | 8008797C | 80087940
MM (U): | 80097530 | 80086FDC | ?
## the quirks
when a new scene is loaded,
the RNG value is set directly to the CPU's cycle count.
that means, depending on all the code that has been run
up to that point, the RNG value is set to a
pseudo-unpredictable value when you enter a new area.
to clarify what a "new scene" being loaded is:
* loading the title screen
* loading a save file
* entering a new area (TODO: do rooms within a scene count?)
* **not** the N64 logo being shown
* **not** the file select screen
### other invocations
creating a new file will invoke the RNG
to determine the Bomber's Code, etc.
obviously, this does not apply to OoT.
although the GameCube versions don't have an N64 logo,
they still do similar initializations before the title screen is shown.
### emulators
as far as i know, the cycle counter in emulators
(including Virtual Console, excluding CEN64)
is very roughly approximated.
it's not a critical component to emulating most games,
so emulators can skimp on it to achieve better performance.
this means RNG should be fairly consistent, given identical inputs.
*this does not mean RNG will be consistent across emulators.*
the plugins you use might affect this as well.
## exploiting the RNG
### in Ocarina of Time
because the title screen sequence starts on Hyrule Field
with a ton of actors loaded,
the RNG value is updated many times each frame.
as far as i know, you'd have to be frame perfect to reach the file select screen
with a consistent RNG, but i haven't done a lot of testing.
maybe there's a part of the title sequence
with wider gaps between RNG invocations,
giving you a wider window to enter the inputs to reach the file select screen.
this might not be exploitable anyway due to
the reset that occurs when loading scenes, as described earlier.
### in Majora's Mask
the first title screen in this game is very simple.
only a handful of actors are loaded and executing.
as a result, the RNG is only invoked
something like every 75 frames *on average.*
this is a big window to reach the file select screen.
*in theory,* you should be able mash A and Start to reach the
file select to create a file, and that file will have the same
Bomber's code, lottery codes, and Spider House mask order.
remember that "the same" is specific to each emulator,
as described earlier.
### in practice
this needs testing.
i can somewhat consistently reach the file select screen
with the same RNG value in Project64 2.2 and Bizhawk 1.12.1.
Virtual Console and N64 have not been tested.
this might be useful for the new MM 100% ruleset
if it's found to be consistent, but don't hold your breath.