Compare commits
17 Commits
9babd47832
...
8e78d08c07
Author | SHA1 | Date | |
---|---|---|---|
Connor Olding | 8e78d08c07 | ||
Connor Olding | edc739ea98 | ||
Connor Olding | 1240ecd266 | ||
Connor Olding | 46970df021 | ||
Connor Olding | b372392aa3 | ||
Connor Olding | f463e58706 | ||
Connor Olding | 9debd3f5ce | ||
Connor Olding | 9d99af3745 | ||
Connor Olding | 94d9de15a4 | ||
Connor Olding | d3f05daf6d | ||
Connor | c1497d802b | ||
Connor | 273abe1ee4 | ||
Connor | 89a434c5e8 | ||
Connor | f8fbea1e92 | ||
Connor | 44a3945bf2 | ||
Connor | 8093266ec7 | ||
Connor | caf9a2aab7 |
28
README.md
28
README.md
|
@ -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
151
coin_or_build/everything
Normal 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
|
26
debug_saves/use-debug-saves.md
Normal file
26
debug_saves/use-debug-saves.md
Normal 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
|
||||
```
|
|
@ -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
|
|
@ -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
121
rng64/rng.md
Normal 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.
|
Loading…
Reference in New Issue
Block a user