Compare commits

...

34 Commits

Author SHA1 Message Date
Cadey Ratio 630860a636 input display
Signed-off-by: Christine Dodrill <me@christine.website>
2021-07-26 21:35:49 -04:00
Cadey Ratio 188d91a9ec docker build 2020-10-21 23:10:45 -04:00
Cadey Ratio a49c44a017 gamebridge hacks 2020-10-21 20:27:12 -04:00
Cadey Ratio c30ec9e5c1 Merge pull request 'gamebridge: Twitch Control' (#2) from gamebridge into master 2020-05-11 22:40:03 +00:00
Cadey Ratio eb90d5dcf8 Add 'doc/inputguide.txt' 2020-05-09 21:18:50 +00:00
Cadey Ratio 3e3be0dc1e start on longjump macro 2020-05-09 11:20:58 -04:00
Cadey Ratio 902c98451b gamebridge: multiple commands per line 2020-05-09 11:00:46 -04:00
Cadey Ratio 09f51531cc Merge branch 'tasing' into gamebridge 2020-05-09 11:00:24 -04:00
Cadey Ratio 80cfdd2a11 patch out dying 2020-05-09 10:53:02 -04:00
Cadey Ratio d05b467578 lerp it good 2020-05-09 10:12:13 -04:00
Cadey Ratio 298942850e shell.nix: cargo-watch 2020-05-09 10:12:06 -04:00
Cadey Ratio e1a0d912fe Revert "Revert "integrate puppycam patch""
This reverts commit b9fd048aad.
2020-05-09 09:43:14 -04:00
Cadey Ratio a88fd9aa82 lerp all inputs with a lerper 2020-05-09 09:16:29 -04:00
Cadey Ratio b9fd048aad Revert "integrate puppycam patch"
This reverts commit c52fdb27f8.
2020-05-09 06:39:38 -04:00
Cadey Ratio 74862e92a4 330 frames to lerp down, i guess 2020-05-09 06:30:23 -04:00
Cadey Ratio bf3e531d20 fix lerping 2020-05-08 23:50:23 -04:00
Cadey Ratio cafe38aae6 lerp debugging 2020-05-08 23:44:03 -04:00
Cadey Ratio 2f5d5a1659 gamebridge: remove killcmd 2020-05-08 21:25:25 -04:00
Cadey Ratio 42e09e7189 twitch control 2020-05-08 20:47:36 -04:00
Cadey Ratio afd84937a1 gamebridge: clear the controller every input frame 2020-05-08 19:23:56 -04:00
Cadey Ratio 26b6c1dfd3 gamebridge: press a and start forever (a long time!) 2020-05-08 19:17:41 -04:00
Cadey Ratio f477907e1e controller: newline before exit message 2020-05-08 18:35:15 -04:00
Cadey Ratio 70338a9b47 gamebridge: use a match here 2020-05-08 18:32:29 -04:00
Cadey Ratio 4357cd0494 proof of concept: pipe a demo into the game 2020-05-08 18:18:45 -04:00
Cadey Ratio 1fd397d89c Update 'gamebridge/Cargo.toml' 2020-05-08 22:03:57 +00:00
Cadey Ratio 1d0da2661f Update 'doc/gamebridge.org' 2020-05-08 22:03:34 +00:00
Cadey Ratio 0f3a72ac78 remove gamebridge tag 2020-05-08 18:00:20 -04:00
Cadey Ratio a8ecacd2ca gamebridge: implement simple protocol 2020-05-08 17:56:55 -04:00
Cadey Ratio 7be9a1aef6 implement gamebridge in the game code 2020-05-08 16:59:08 -04:00
Cadey Ratio cc11d483cb start game bridge code 2020-05-08 16:30:43 -04:00
Cadey Ratio a08fffa9a4 pin nixpkgs 2020-05-08 16:10:51 -04:00
Cadey Ratio cf7c89e31f let tas playback and input coexist 2020-05-08 08:47:25 -04:00
Cadey Ratio 0a4f693fdc tas recorder is functional 2020-05-08 06:48:52 -04:00
Cadey Ratio 5e138304d8 investigate TAS-ing this 2020-05-07 23:30:33 -04:00
28 changed files with 1982 additions and 21 deletions

9
.gitignore vendored
View File

@ -71,3 +71,12 @@ sm64config.txt
!/sound/**/*custom*/**/*.aiff
!/assets/**/*custom*.bin
!/assets/**/*custom*/**/*.bin
/target
vblank
input
*.m64
.env
# Nix
/result

867
Cargo.lock generated Normal file
View File

@ -0,0 +1,867 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff"
[[package]]
name = "arc-swap"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b585a98a234c46fc563103e9278c9391fde1f4e6850334da895d27edb9580f62"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi 0.3.8",
]
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bytes"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1"
[[package]]
name = "cc"
version = "1.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "core-foundation"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
dependencies = [
"bitflags",
"fuchsia-zircon-sys",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "futures"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399"
[[package]]
name = "futures-io"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
[[package]]
name = "futures-sink"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc"
[[package]]
name = "futures-task"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626"
[[package]]
name = "futures-util"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6"
dependencies = [
"futures-core",
"futures-sink",
"futures-task",
"pin-project",
"pin-utils",
]
[[package]]
name = "gamebridge"
version = "0.1.0"
dependencies = [
"anyhow",
"bitflags",
"kankyo",
"log",
"pretty_env_logger",
"tokio",
"twitchchat",
]
[[package]]
name = "getrandom"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hermit-abi"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
]
[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
dependencies = [
"libc",
]
[[package]]
name = "kankyo"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "325a11231fa70c1d1b562655db757cefb6022876d62f173831f35bd670ae0c40"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
dependencies = [
"winapi 0.2.8",
"winapi-build",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
[[package]]
name = "lock_api"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
[[package]]
name = "mio"
version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
dependencies = [
"cfg-if",
"fuchsia-zircon",
"fuchsia-zircon-sys",
"iovec",
"kernel32-sys",
"libc",
"log",
"miow 0.2.1",
"net2",
"slab",
"winapi 0.2.8",
]
[[package]]
name = "mio-named-pipes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3"
dependencies = [
"log",
"mio",
"miow 0.3.3",
"winapi 0.3.8",
]
[[package]]
name = "mio-uds"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
dependencies = [
"iovec",
"libc",
"mio",
]
[[package]]
name = "miow"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
dependencies = [
"kernel32-sys",
"net2",
"winapi 0.2.8",
"ws2_32-sys",
]
[[package]]
name = "miow"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
dependencies = [
"socket2",
"winapi 0.3.8",
]
[[package]]
name = "native-tls"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "net2"
version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
dependencies = [
"cfg-if",
"libc",
"winapi 0.3.8",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "openssl"
version = "0.10.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"lazy_static",
"libc",
"openssl-sys",
]
[[package]]
name = "openssl-probe"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
[[package]]
name = "openssl-sys"
version = "0.9.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f02309a7f127000ed50594f0b50ecc69e7c654e16d41b4e8156d1b3df8e0b52e"
dependencies = [
"autocfg",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "parking_lot"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
dependencies = [
"cfg-if",
"cloudabi",
"libc",
"redox_syscall",
"smallvec",
"winapi 0.3.8",
]
[[package]]
name = "pin-project"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82c3bfbfb5bb42f99498c7234bbd768c220eb0cea6818259d0d18a1aa3d2595d"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccbf6449dcfb18562c015526b085b8df1aa3cdab180af8ec2ebd300a3bd28f63"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pin-project-lite"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7505eeebd78492e0f6108f7171c4948dbb120ee8119d9d77d0afa5469bef67f"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
[[package]]
name = "ppv-lite86"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
[[package]]
name = "pretty_env_logger"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
dependencies = [
"env_logger",
"log",
]
[[package]]
name = "proc-macro2"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c1f4b0efa5fc5e8ceb705136bfee52cfdb6a4e3509f770b478cd6ed434232a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "redox_syscall"
version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
[[package]]
name = "regex"
version = "1.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
[[package]]
name = "remove_dir_all"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
dependencies = [
"winapi 0.3.8",
]
[[package]]
name = "schannel"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "039c25b130bd8c1321ee2d7de7fde2659fa9c2744e4bb29711cfc852ea53cd19"
dependencies = [
"lazy_static",
"winapi 0.3.8",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "security-framework"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "signal-hook-registry"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41"
dependencies = [
"arc-swap",
"libc",
]
[[package]]
name = "slab"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "smallvec"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
[[package]]
name = "socket2"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"winapi 0.3.8",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8e5aa70697bb26ee62214ae3288465ecec0000f05182f039b477001f08f5ae7"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tempfile"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
dependencies = [
"cfg-if",
"libc",
"rand",
"redox_syscall",
"remove_dir_all",
"winapi 0.3.8",
]
[[package]]
name = "termcolor"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
dependencies = [
"winapi-util",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
dependencies = [
"lazy_static",
]
[[package]]
name = "tokio"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05c1d570eb1a36f0345a5ce9c6c6e665b70b73d11236912c0b477616aeec47b1"
dependencies = [
"bytes",
"fnv",
"futures-core",
"iovec",
"lazy_static",
"libc",
"memchr",
"mio",
"mio-named-pipes",
"mio-uds",
"num_cpus",
"pin-project-lite",
"signal-hook-registry",
"slab",
"tokio-macros",
"winapi 0.3.8",
]
[[package]]
name = "tokio-macros"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tokio-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "twitchchat"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "905384e7e60a8bb3a1a4528a62c97d4d39c6522bd6c2885b52e01acb710dd276"
dependencies = [
"futures",
"log",
"native-tls",
"parking_lot",
"static_assertions",
"tokio",
"tokio-tls",
]
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "vcpkg"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi 0.3.8",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
dependencies = [
"winapi 0.2.8",
"winapi-build",
]

2
Cargo.toml Normal file
View File

@ -0,0 +1,2 @@
[workspace]
members = [ "./gamebridge" ]

44
default.nix Normal file
View File

@ -0,0 +1,44 @@
{ pkgs ? import <nixpkgs> { } }:
with pkgs;
stdenv.mkDerivation rec {
pname = "sm64pc";
version = "latest";
buildInputs = [
gnumake
python3
audiofile
pkg-config
SDL2
libusb1
glfw3
libgcc
xorg.libX11
xorg.libXrandr
libpulseaudio
alsaLib
glfw
libGL
unixtools.hexdump
clang_10
];
src = ./.;
buildPhase = ''
chmod +x ./extract_assets.py
make -j
'';
installPhase = ''
mkdir -p $out/bin
cp ./build/us_pc/sm64.us.f3dex2e $out/bin/sm64pc
'';
meta = with stdenv.lib; {
description = "Super Mario 64 PC port, requires rom :)";
license = licenses.unfree;
};
}

54
doc/gamebridge.org Normal file
View File

@ -0,0 +1,54 @@
#+TITLE: gamebridge
An interface between Super Mario 64 and just about anything else your heart
desires.
* High level ideas
the rust program has two threads, one is getting the inputs from $SOMEWHERE and
the other is doing the file I/O to the game
the game bridge thread has two file descriptors open, a fifo for feeding inputs
to the game and a fifo opened by the game for signaling vblanks
the game will then write a readiness signal to the rust program and read the
button data fifo
then things will progress normally
the getting the input thread of the rust program will have some logic for
telling how long ago it got liveness of the input source (explicitly vaguely
defined to allow a controller to sit there and do nothing as long as it still
exists), and then "sticking" it until, say, 10 frames have passed and then it
will block infinitely, freezing the game in place
* Goals
+ Blocking, synchronous rust as much as possible
+ unix fifos are great, let's use them
* Protocol
The protocol between the game and the bridge will be as follows (based on the
[[http://tasvideos.org/EmulatorResources/Mupen/M64.html][Mupen64 demo format]]). Two unix fifos will be created by the bridge.
The game and the bridge will both need to take care that the files are opened in
*unbuffered I/O modes*. This can be done with
=setvbuf(f, (char *)NULL, _IONBF, 0);= in C and is the default in Rust.
The first one will be called =vblank= and will then be opened by the game in
write mode when it starts. The bridge will open this fifo in read mode.
The second one will be called =input= and will be opened by the game in read
mode. The bridge will open this fifo in write mode.
On every frame, the game *MUST* write the text ="OK\n"= to the vblank fifo. This
will signal the bridge that it *MUST* write four bytes of data to the input
fifo, conforming to the [[http://tasvideos.org/EmulatorResources/Mupen/M64.html#ControllerData][Controller Data]] specification of the Mupen64 format.
This data will be interpreted by the game as actions for Mario to take.
The bridge *MUST* block on waiting for the vblank fifo to be written to by the
game and the game *MUST* block on the input fifo being written to by the bridge.
When the game is exiting, the game *SHOULD* write ="BYE"= to the vblank fifo.
When the bridge recieves a ="BYE"= message, it *MUST* exit.

51
doc/inputguide.txt Normal file
View File

@ -0,0 +1,51 @@
SUPER MARIO 64 CONTROL GUIDE
N64 BUTTON INPUT = KEYBOARD INPUT (KEYBOARD SCAN CODES)
A Button = L (38)
B Button = , (51)
Start Button = Spacebar (57)
R Button = Right Shift (54)
Z Button = K (37)
C Stick Up = Up Arrow (?)
C stick Down = Down Arrow (?)
C Stick Left = Left Arrow (?)
C Stick Right = Right Arrow (?)
Stick Up = W (17)
Stick Down = S (31)
Stick Left = A (30)
Stick Right = D (32)
KEYBOARD SCAN CODES:
Key Code ¦ Key Code ¦ Key Code
¦ ¦
Esc 1 ¦ A 30 ¦ Caps Lock 58
! or 1 2 ¦ S 31 ¦ F1 59
@ or 2 3 ¦ D 32 ¦ F2 60
# or 3 4 ¦ F 33 ¦ F3 61
$ or 4 5 ¦ G 34 ¦ F4 62
% or 5 6 ¦ H 35 ¦ F5 63
^ or 6 7 ¦ J 36 ¦ F6 64
& or 7 8 ¦ K 37 ¦ F7 65
* or 8 9 ¦ L 38 ¦ F8 66
( or 9 10 ¦ : or ; 39 ¦ F9 67
) or 0 11 ¦ " or ' 40 ¦ F10 68
_ or - 12 ¦ ~ or ` 41 ¦ F11 133
+ or = 13 ¦ Left Shift 42 ¦ F12 134
Bksp 14 ¦ | or \ 43 ¦ NumLock 69
Tab 15 ¦ Z 44 ¦ Scroll Lock 70
Q 16 ¦ X 45 ¦ Home or 7 71
W 17 ¦ C 46 ¦ Up or 8 72
E 18 ¦ V 47 ¦ PgUp or 9 73
R 19 ¦ B 48 ¦ Gray - 74
T 20 ¦ N 49 ¦ Left or 4 75
Y 21 ¦ M 50 ¦ Center or 5 76
U 22 ¦ < or , 51 ¦ Right or 6 77
I 23 ¦ > or . 52 ¦ Gray + 78
O 24 ¦ ? or / 53 ¦ End or 1 79
P 25 ¦ Right Shift 54 ¦ Down or 2 80
{ or [ 26 ¦ Prt Sc or * 55 ¦ PgDn or 3 81
} or ] 27 ¦ Alt 56 ¦ Ins or 0 82
Enter 28 ¦ Spacebar 57 ¦ Del or . 83
Ctrl 29 ¦

22
docker.nix Normal file
View File

@ -0,0 +1,22 @@
{ pkgs ? import <nixpkgs> { } }:
with pkgs;
let
site = callPackage ./default.nix { };
dockerImage = pkg:
pkgs.dockerTools.buildLayeredImage {
name = "ghcr.io/xe/sm64pc";
tag = "latest";
contents = [ pkg mesa mesa.drivers mesa_glu mesa_noglu libGL_driver ];
config = {
Cmd = [ "${strace}/bin/strace" "${pkg}/bin/sm64pc" ];
Env = [ "LD_LIBRARY_PATH=/lib" "LIBGL_DRIVERS_PATH=/lib/dri" ];
WorkingDir = "/";
};
};
in dockerImage site

1
gamebridge/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

16
gamebridge/Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[package]
name = "gamebridge"
version = "0.1.0"
authors = ["Cadey Ratio <cadey@firemail.cc>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0"
bitflags = "1.2"
kankyo = "0.3"
log = "0.4"
pretty_env_logger = "0.4"
tokio = { version = "0.2", features = ["full", "macros"] }
twitchchat = "0.10"

99
gamebridge/src/au.rs Normal file
View File

@ -0,0 +1,99 @@
#[derive(Copy, Clone)]
pub(crate) struct Lerper {
extended_tick: u64,
lerp_time: f64,
goal: i64,
pub(crate) scalar: i64,
max: i64,
min: i64,
}
impl Lerper {
pub(crate) fn init(lerp_time: f64, max: i64, min: i64, goal: i64) -> Lerper {
Lerper {
extended_tick: 0,
lerp_time: lerp_time,
goal: goal,
scalar: 0, // I hope to GOD that 0 is the resting point
max: max,
min: min,
}
}
pub(crate) fn add(&mut self, new_scalar: i64) {
self.scalar += new_scalar;
}
pub(crate) fn update(&mut self, new_scalar: i64) {
self.scalar = new_scalar;
}
pub(crate) fn apply(&mut self, now: u64) -> i64 {
let scalar = self.scalar;
self.scalar = match scalar {
_ if scalar == self.goal => self.goal,
_ if scalar >= self.max => {
self.extended_tick = now;
scalar - 1
}
_ if scalar <= self.min => {
self.extended_tick = now;
scalar + 1
}
_ => {
let t = (now - self.extended_tick) as f64 / self.lerp_time;
lerp(self.scalar, 0, t)
}
};
if self.scalar >= self.max {
return self.max;
}
if self.scalar <= self.min {
return self.min;
}
self.scalar
}
pub(crate) fn pressed(&mut self, threshold: i64) -> bool {
if self.scalar <= threshold {
self.scalar = 0;
}
self.scalar >= threshold
}
}
fn lerp(start: i64, end: i64, t: f64) -> i64 {
(start as f64 * (1.0 - t) + (end as f64) * t) as i64
}
#[cfg(test)]
mod test {
#[test]
fn lerp_scale() {
for case in [(0.1, 10), (0.5, 31)].iter() {
let t = case.0;
let start = 127.0 * t;
assert_eq!(super::lerp(start as i64, 0, t), case.1);
}
}
#[test]
fn lerper() {
use super::Lerper;
let mut lerper = Lerper::init(15.0, 127, -128, 0);
for case in [(127, 3, 126), (100, 8, 66), (-124, 8, -82)].iter() {
let scalar = case.0;
let now = case.1;
let want = case.2;
lerper.update(scalar);
let result = lerper.apply(now);
assert_eq!(result, want);
}
}
}

View File

@ -0,0 +1,41 @@
bitflags! {
// 0x0100 Digital Pad Right
// 0x0200 Digital Pad Left
// 0x0400 Digital Pad Down
// 0x0800 Digital Pad Up
// 0x1000 Start
// 0x2000 Z
// 0x4000 B
// 0x8000 A
pub(crate) struct HiButtons: u8 {
const NONE = 0x00;
const DPAD_RIGHT = 0x01;
const DPAD_LEFT = 0x02;
const DPAD_DOWN = 0x04;
const DPAD_UP = 0x08;
const START = 0x10;
const Z_BUTTON = 0x20;
const B_BUTTON = 0x40;
const A_BUTTON = 0x80;
}
}
bitflags! {
// 0x0001 C-Right
// 0x0002 C-Left
// 0x0004 C-Down
// 0x0008 C-Up
// 0x0010 R
// 0x0020 L
// 0x0040 (reserved)
// 0x0080 (reserved)
pub(crate) struct LoButtons: u8 {
const NONE = 0x00;
const C_RIGHT = 0x01;
const C_LEFT = 0x02;
const C_DOWN = 0x04;
const C_UP = 0x08;
const R_BUTTON = 0x10;
const L_BUTTON = 0x20;
}
}

203
gamebridge/src/main.rs Normal file
View File

@ -0,0 +1,203 @@
#[macro_use]
extern crate bitflags;
pub(crate) mod au;
pub(crate) mod controller;
pub(crate) mod twitch;
use crate::au::Lerper;
use anyhow::{anyhow, Result};
use log::{debug, error, info, warn};
use std::{
fs::{File, OpenOptions},
io::{Read, Write},
str::from_utf8,
sync::{Arc, RwLock},
thread::spawn,
};
pub(crate) struct State {
frame: u64,
stickx: Lerper,
sticky: Lerper,
a_button: Lerper,
b_button: Lerper,
z_button: Lerper,
r_button: Lerper,
start: Lerper,
c_left: Lerper,
c_right: Lerper,
c_up: Lerper,
c_down: Lerper,
}
pub(crate) type MTState = Arc<RwLock<State>>;
fn main() -> Result<()> {
pretty_env_logger::try_init()?;
kankyo::init()?;
let mut vblank = File::open("vblank")?;
let mut input = OpenOptions::new().write(true).open("input")?;
const STICK_LERP_TIME: f64 = 500.0; // 450 frames to lerp stick positions down to 0
const BUTTON_LERP_TIME: f64 = 20.0; // 20 frames to lerp button inputs down to 0
let st = {
let st = State {
frame: 0,
stickx: Lerper::init(STICK_LERP_TIME, 127, -128, 0),
sticky: Lerper::init(STICK_LERP_TIME, 127, -128, 0),
a_button: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
b_button: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
z_button: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
r_button: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
start: Lerper::init(BUTTON_LERP_TIME / 4.0, 64, -1, 0), // z button is special
c_left: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
c_right: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
c_up: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
c_down: Lerper::init(BUTTON_LERP_TIME, 64, -1, 0),
};
Arc::new(RwLock::new(st))
};
info!("ready");
{
let st = st.clone();
spawn(move || twitch::run(st));
}
loop {
let mut data = [0; 3];
debug!("waiting for vblank");
vblank.read(&mut data)?;
let str = from_utf8(&data)?;
debug!("got data: {}", str);
let mut controller = [0; 4];
match str {
"OK\n" => {
{
let mut data = st.write().unwrap();
data.frame += 1;
}
let mut data = st.write().unwrap();
let frame = data.frame + 1;
//data.stickx.update(data.controller[2] as i64);
//data.sticky.update(data.controller[3] as i64);
debug!("x before: {}", data.stickx.scalar);
let mut stickx_scalar = data.stickx.apply(frame) as i8;
debug!("x after: {}", data.stickx.scalar);
debug!("y before: {}", data.sticky.scalar);
let mut sticky_scalar = data.sticky.apply(frame) as i8;
debug!("y after: {}", data.sticky.scalar);
let dist = stick_distance(stickx_scalar, sticky_scalar);
if dist <= 10 {
stickx_scalar = 0;
sticky_scalar = 0;
}
use controller::{HiButtons, LoButtons};
let mut hi = HiButtons::NONE;
let mut lo = LoButtons::NONE;
const BUTTON_PUSH_THRESHOLD: i64 = 2;
// high buttons
data.a_button.apply(frame);
if data.a_button.pressed(BUTTON_PUSH_THRESHOLD) {
hi = hi | HiButtons::A_BUTTON;
}
data.b_button.apply(frame);
if data.b_button.pressed(BUTTON_PUSH_THRESHOLD) {
hi = hi | HiButtons::B_BUTTON;
}
data.z_button.apply(frame);
if data.z_button.pressed(BUTTON_PUSH_THRESHOLD) {
hi = hi | HiButtons::Z_BUTTON;
}
data.start.apply(frame);
if data.start.pressed(BUTTON_PUSH_THRESHOLD) {
hi = hi | HiButtons::START;
}
data.r_button.apply(frame);
if data.r_button.pressed(BUTTON_PUSH_THRESHOLD) {
lo = lo | LoButtons::R_BUTTON;
}
data.c_up.apply(frame);
if data.c_up.pressed(BUTTON_PUSH_THRESHOLD) {
lo = lo | LoButtons::C_UP;
}
data.c_down.apply(frame);
if data.c_down.pressed(BUTTON_PUSH_THRESHOLD) {
lo = lo | LoButtons::C_DOWN;
}
data.c_left.apply(frame);
if data.c_left.pressed(BUTTON_PUSH_THRESHOLD) {
lo = lo | LoButtons::C_LEFT;
}
data.c_right.apply(frame);
if data.c_right.pressed(BUTTON_PUSH_THRESHOLD) {
lo = lo | LoButtons::C_RIGHT;
}
debug!(
"[ rust] {:02x}{:02x} {:02x}{:02x}",
hi.bits(),
lo.bits(),
stickx_scalar as u8,
sticky_scalar as u8
);
controller[0] = hi.bits() as u8;
controller[1] = lo.bits() as u8;
controller[2] = stickx_scalar as u8;
controller[3] = sticky_scalar as u8;
input.write(&controller)?;
}
"BYE" => {
warn!("asked to exit by the game");
return Ok(());
}
_ => {
error!("got unknown FIFO data {}", str);
return Err(anyhow!("unknown FIFO data received"));
}
};
}
}
fn stick_distance(x: i8, y: i8) -> i8 {
let x = (x as f64).powi(2);
let y = (y as f64).powi(2);
(x + y).sqrt() as i8
}
#[cfg(test)]
mod test {
#[test]
fn stick_distance() {
for case in [
(0, 0, 0),
(127, 0, 127),
(64, 64, 90),
(-64, 64, 90),
(-64, -64, 90),
]
.iter()
{
let x = case.0;
let y = case.1;
assert_eq!(crate::stick_distance(x, y), case.2);
}
}
}

121
gamebridge/src/twitch.rs Normal file
View File

@ -0,0 +1,121 @@
use crate::MTState;
use tokio::stream::StreamExt as _;
use twitchchat::{events, Control, Dispatcher, Runner, Status};
pub(crate) fn run(st: MTState) {
use tokio::runtime::Runtime;
Runtime::new()
.expect("Failed to create Tokio runtime")
.block_on(handle(st));
}
async fn handle(st: MTState) {
let (nick, pass) = (
// twitch name
std::env::var("TWITCH_NICK").expect("bot nickname to be in the environment"),
// oauth token for twitch name
std::env::var("TWITCH_PASS").expect("bot password to be in the environment"),
);
// putting this in the env so people don't join my channel when running this
let channels = &[std::env::var("TWITCH_CHANNEL").unwrap()];
let dispatcher = Dispatcher::new();
let (runner, control) = Runner::new(dispatcher.clone(), twitchchat::RateLimit::default());
let fut = run_loop(control.clone(), dispatcher, channels, st);
let conn = twitchchat::connect_easy_tls(&nick, &pass).await.unwrap();
tokio::select! {
_ = fut => { control.stop() }
status = runner.run(conn) => {
match status {
Ok(Status::Eof) => {}
Ok(Status::Canceled) => {}
Ok(Status::Timeout) => {}
Err(err) => panic!(err),
}
}
}
}
async fn run_loop(
mut control: Control,
mut dispatcher: Dispatcher,
channels: &[String],
st: MTState,
) {
let mut join = dispatcher.subscribe::<events::Join>();
let mut part = dispatcher.subscribe::<events::Part>();
let mut pmsg = dispatcher.subscribe::<events::Privmsg>();
async fn wait_and_join(
control: &mut Control,
dispatcher: &mut Dispatcher,
channels: &[String],
) {
let ready = dispatcher.wait_for::<events::IrcReady>().await.unwrap();
eprintln!("our name: {}", ready.nickname);
let w = control.writer();
for channel in channels {
eprintln!("joining: {}", channel);
let _ = w.join(channel).await;
eprintln!("joined");
}
eprintln!("joined all channels")
}
wait_and_join(&mut control, &mut dispatcher, channels).await;
loop {
tokio::select! {
Some(msg) = join.next() => {
eprintln!("{} joined {}", msg.name, msg.channel);
}
Some(msg) = part.next() => {
eprintln!("{} left {}", msg.name, msg.channel);
}
Some(msg) = pmsg.next() => {
let chatline = msg.data.to_string();
let chatline = chatline.to_ascii_lowercase();
let mut data = st.write().unwrap();
const BUTTON_ADD_AMT: i64 = 64;
for cmd in chatline.to_string().split(" ").collect::<Vec<&str>>().iter() {
match *cmd {
"a" => data.a_button.add(BUTTON_ADD_AMT),
"b" => data.b_button.add(BUTTON_ADD_AMT),
"z" => data.z_button.add(BUTTON_ADD_AMT),
"cam" | "camera" => data.r_button.add(BUTTON_ADD_AMT),
"cup" => data.c_up.add(BUTTON_ADD_AMT),
"cdown" => data.c_down.add(BUTTON_ADD_AMT),
"cleft" => data.c_left.add(BUTTON_ADD_AMT),
"cright" => data.c_right.add(BUTTON_ADD_AMT),
"start" => data.start.add(BUTTON_ADD_AMT),
"up" | "u" => data.sticky.add(127),
"down" | "d" => data.sticky.add(-128),
"left" | "l" => data.stickx.add(-128),
"right" | "r" => data.stickx.add(127),
"stop" => {data.stickx.update(0); data.sticky.update(0);},
"unstuck" => {
data.a_button.update(0);
data.b_button.update(0);
data.z_button.update(0);
data.r_button.update(0);
data.c_up.update(0);
data.c_down.update(0);
data.c_left.update(0);
data.c_right.update(0);
}
_ => {},
}
}
eprintln!("[{}] {}: {}", msg.channel, msg.name, msg.data);
}
else => { break }
}
}
}

46
longjump.inputs Normal file
View File

@ -0,0 +1,46 @@
0000f97f
0000f97f
0000f97f
0000f97f
0000f97f
2000fa7f
2000fa7f
2000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000fa7f
a000ff7f
a000177f
a000347f
a0005479
a0005a74
a0005a73
a0006269
a0006664
a0006b5f
a0006b5e
20006b5e
20006b5e
20006b5e
2000576b
20003e6f
20002765
20002042
20001e24
20000000
20000000
20000000
20000000
20000000
20000000

26
nix/sources.json Normal file
View File

@ -0,0 +1,26 @@
{
"niv": {
"branch": "master",
"description": "Easy dependency management for Nix projects",
"homepage": "https://github.com/nmattia/niv",
"owner": "nmattia",
"repo": "niv",
"rev": "e0ca65c81a2d7a4d82a189f1e23a48d59ad42070",
"sha256": "1pq9nh1d8nn3xvbdny8fafzw87mj7gsmp6pxkdl65w2g18rmcmzx",
"type": "tarball",
"url": "https://github.com/nmattia/niv/archive/e0ca65c81a2d7a4d82a189f1e23a48d59ad42070.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs": {
"branch": "nixpkgs-unstable",
"description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to",
"homepage": "https://github.com/NixOS/nixpkgs",
"owner": "NixOS",
"repo": "nixpkgs-channels",
"rev": "502845c3e31ef3de0e424f3fcb09217df2ce6df6",
"sha256": "0fcqpsy6y7dgn0y0wgpa56gsg0b0p8avlpjrd79fp4mp9bl18nda",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs-channels/archive/502845c3e31ef3de0e424f3fcb09217df2ce6df6.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
}

134
nix/sources.nix Normal file
View File

@ -0,0 +1,134 @@
# This file has been generated by Niv.
let
#
# The fetchers. fetch_<type> fetches specs of type <type>.
#
fetch_file = pkgs: spec:
if spec.builtin or true then
builtins_fetchurl { inherit (spec) url sha256; }
else
pkgs.fetchurl { inherit (spec) url sha256; };
fetch_tarball = pkgs: spec:
if spec.builtin or true then
builtins_fetchTarball { inherit (spec) url sha256; }
else
pkgs.fetchzip { inherit (spec) url sha256; };
fetch_git = spec:
builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; };
fetch_builtin-tarball = spec:
builtins.trace
''
WARNING:
The niv type "builtin-tarball" will soon be deprecated. You should
instead use `builtin = true`.
$ niv modify <package> -a type=tarball -a builtin=true
''
builtins_fetchTarball { inherit (spec) url sha256; };
fetch_builtin-url = spec:
builtins.trace
''
WARNING:
The niv type "builtin-url" will soon be deprecated. You should
instead use `builtin = true`.
$ niv modify <package> -a type=file -a builtin=true
''
(builtins_fetchurl { inherit (spec) url sha256; });
#
# Various helpers
#
# The set of packages used when specs are fetched using non-builtins.
mkPkgs = sources:
let
sourcesNixpkgs =
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {};
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
in
if builtins.hasAttr "nixpkgs" sources
then sourcesNixpkgs
else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
import <nixpkgs> {}
else
abort
''
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
add a package called "nixpkgs" to your sources.json.
'';
# The actual fetching function.
fetch = pkgs: name: spec:
if ! builtins.hasAttr "type" spec then
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
else if spec.type == "file" then fetch_file pkgs spec
else if spec.type == "tarball" then fetch_tarball pkgs spec
else if spec.type == "git" then fetch_git spec
else if spec.type == "builtin-tarball" then fetch_builtin-tarball spec
else if spec.type == "builtin-url" then fetch_builtin-url spec
else
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
# Ports of functions for older nix versions
# a Nix version of mapAttrs if the built-in doesn't exist
mapAttrs = builtins.mapAttrs or (
f: set: with builtins;
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
);
# fetchTarball version that is compatible between all the versions of Nix
builtins_fetchTarball = { url, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchTarball;
in
if lessThan nixVersion "1.12" then
fetchTarball { inherit url; }
else
fetchTarball attrs;
# fetchurl version that is compatible between all the versions of Nix
builtins_fetchurl = { url, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchurl;
in
if lessThan nixVersion "1.12" then
fetchurl { inherit url; }
else
fetchurl attrs;
# Create the final "sources" from the config
mkSources = config:
mapAttrs (
name: spec:
if builtins.hasAttr "outPath" spec
then abort
"The values in sources.json should not have an 'outPath' attribute"
else
spec // { outPath = fetch config.pkgs name spec; }
) config.sources;
# The "config" used by the fetchers
mkConfig =
{ sourcesFile ? ./sources.json
, sources ? builtins.fromJSON (builtins.readFile sourcesFile)
, pkgs ? mkPkgs sources
}: rec {
# The sources, i.e. the attribute set of spec name to spec
inherit sources;
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
inherit pkgs;
};
in
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }

View File

@ -1,7 +1,9 @@
let pkgs = import <nixpkgs> { };
let
sources = import ./nix/sources.nix;
pkgs = import <nixpkgs> { };
in pkgs.mkShell {
buildInputs = with pkgs; [
gnumake
# Mario 64
python3
audiofile
pkg-config
@ -15,6 +17,18 @@ in pkgs.mkShell {
alsaLib
glfw
libGL
openssl
# build tools
gnumake
clang_10
gdb
# gamebridge
rustc
cargo
cargo-watch
rls
rustfmt
];
}

View File

@ -1258,10 +1258,24 @@ void debug_print_speed_action_normal(struct MarioState *m) {
void update_mario_button_inputs(struct MarioState *m) {
if (m->controller->buttonPressed & A_BUTTON) {
m->input |= INPUT_A_PRESSED;
print_text(210, 32, "A");
}
if (m->controller->buttonDown & A_BUTTON) {
m->input |= INPUT_A_DOWN;
print_text(210, 32, "A");
}
if (m->controller->buttonDown & B_BUTTON) {
print_text(226, 32, "B");
}
if (m->controller->buttonDown & R_TRIG) {
print_text(226, 48, "R");
}
if (m->controller->buttonDown & Z_TRIG) {
print_text(210, 48, "2");
}
// Don't update for these buttons if squished.
@ -1457,6 +1471,7 @@ void set_submerged_cam_preset_and_spawn_bubbles(struct MarioState *m) {
* Both increments and decrements Mario's HP.
*/
void update_mario_health(struct MarioState *m) {
return;
s32 terrainIsSnow;
if (m->health >= 0x100) {
@ -1865,7 +1880,7 @@ void init_mario_from_save_file(void) {
save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1);
gMarioState->numKeys = 0;
gMarioState->numLives = 4;
gMarioState->numLives = 99;
gMarioState->health = 0x880;
gMarioState->unkB8 = gMarioState->numStars;

View File

@ -1183,7 +1183,7 @@ s32 act_death_exit(struct MarioState *m) {
#else
play_sound(SOUND_MARIO_OOOF2, m->marioObj->header.gfx.cameraToObject);
#endif
m->numLives--;
//m->numLives--;
// restore 7.75 units of health
m->healCounter = 31;
}
@ -1199,7 +1199,7 @@ s32 act_unused_death_exit(struct MarioState *m) {
#else
play_sound(SOUND_MARIO_OOOF2, m->marioObj->header.gfx.cameraToObject);
#endif
m->numLives--;
//m->numLives--;
// restore 7.75 units of health
m->healCounter = 31;
}
@ -1215,7 +1215,7 @@ s32 act_falling_death_exit(struct MarioState *m) {
#else
play_sound(SOUND_MARIO_OOOF2, m->marioObj->header.gfx.cameraToObject);
#endif
m->numLives--;
//m->numLives--;
// restore 7.75 units of health
m->healCounter = 31;
}
@ -1259,7 +1259,7 @@ s32 act_special_death_exit(struct MarioState *m) {
}
if (launch_mario_until_land(m, ACT_HARD_BACKWARD_GROUND_KB, MARIO_ANIM_BACKWARD_AIR_KB, -24.0f)) {
m->numLives--;
//m->numLives--;
m->healCounter = 31;
}
// show mario

View File

@ -29,6 +29,7 @@ struct ConfigOption {
/*
*Config options and default values
*/
bool configGameBridge = false;
bool configFullscreen = false;
// Keyboard mappings (scancode values)
unsigned int configKeyA = 0x26;
@ -47,6 +48,7 @@ unsigned int configKeyStickRight = 0x20;
static const struct ConfigOption options[] = {
{.name = "gamebridge", .type = CONFIG_TYPE_BOOL, .boolValue = &configGameBridge},
{.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configFullscreen},
{.name = "key_a", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyA},
{.name = "key_b", .type = CONFIG_TYPE_UINT, .uintValue = &configKeyB},

View File

@ -1,6 +1,7 @@
#ifndef CONFIGFILE_H
#define CONFIGFILE_H
extern bool configGameBridge;
extern bool configFullscreen;
extern unsigned int configKeyA;
extern unsigned int configKeyB;

View File

@ -3,13 +3,16 @@
#include "controller_recorded_tas.h"
#include "controller_keyboard.h"
#include "controller_sdl.h"
#include "controller_gamebridge.h"
#include "controller_tas_recorder.h"
static struct ControllerAPI *controller_implementations[] = {
&controller_recorded_tas,
//&controller_gamebridge,
&controller_sdl,
&controller_keyboard,
//&controller_tas_recorder,
};
s32 osContInit(OSMesgQueue *mq, u8 *controllerBits, OSContStatus *status) {

View File

@ -0,0 +1,95 @@
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ultra64.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "controller_api.h"
#include "../configfile.h"
static FILE *vblank;
static FILE *input;
#define vblank_fname "vblank"
#define input_fname "input"
#define ok "OK\n"
#define bye "BYE"
static void gamebridge_close(void) {
if (!configGameBridge) {
return;
}
printf("\n[gamebridge] exiting\n");
fwrite(bye, 1, strlen(bye), vblank);
fclose(vblank);
fclose(input);
unlink(vblank_fname);
unlink(input_fname);
}
static void gamebridge_init(void) {
if (!configGameBridge) {
return;
}
printf("[gamebridge] starting...\n");
fflush(stdout);
unlink(vblank_fname);
unlink(input_fname);
int result;
result = mkfifo(vblank_fname, S_IRUSR|S_IWUSR);
if (result < 0) {
perror("mkfifo "vblank_fname);
assert(result < 0);
}
result = mkfifo(input_fname, S_IRUSR| S_IWUSR);
if (result < 0) {
perror("mkfifo "input_fname);
assert(result < 0);
}
vblank = fopen(vblank_fname, "w+");
input = fopen(input_fname, "rb+");
assert(vblank);
assert(input);
setvbuf(vblank, NULL, _IONBF, 0);
setvbuf(input, NULL, _IONBF, 0);
printf("[gamebridge] starting rust daemon\n");
fflush(stdout);
system("./target/release/gamebridge &");
atexit(gamebridge_close);
}
static void gamebridge_read(OSContPad *pad) {
if (!configGameBridge) {
return;
}
//printf("[gamebridge] waiting for input\n");
fwrite(ok, 1, strlen(ok), vblank);
uint8_t bytes[4] = {0};
fread(bytes, 1, 4, input);
pad->button = (bytes[0] << 8) | bytes[1];
pad->stick_x = bytes[2];
pad->stick_y = bytes[3];
//printf("[gamebridge] %02x%02x %02x%02x\n", bytes[0], bytes[1], bytes[2], bytes[3]);
fflush(stdout);
}
struct ControllerAPI controller_gamebridge = {
gamebridge_init,
gamebridge_read
};

View File

@ -0,0 +1,8 @@
#ifndef CONTROLLER_GAMEBRIDGE_H
#define CONTROLLER_GAMEBRIDGE_H
#include "controller_api.h"
extern struct ControllerAPI controller_gamebridge;
#endif

View File

@ -1,26 +1,48 @@
#include <stdio.h>
#include <ultra64.h>
#include <assert.h>
#include <fcntl.h>
#include "controller_api.h"
static FILE *fp;
static FILE *fin;
static int counter;
#define OFFSET 0x400
#define fname "cont.m64"
static void tas_init(void) {
fp = fopen("cont.m64", "rb");
if (fp != NULL) {
uint8_t buf[0x400];
fread(buf, 1, sizeof(buf), fp);
fin = fopen(fname, "rb");
if (fin == NULL) {
return;
}
printf("[tas_playback] loading %s\n", fname);
uint8_t buf[OFFSET];
fread(buf, 1, sizeof(buf), fin);
counter = 0;
}
static void tas_read(OSContPad *pad) {
if (fp != NULL) {
uint8_t bytes[4] = {0};
fread(bytes, 1, 4, fp);
pad->button = (bytes[0] << 8) | bytes[1];
pad->stick_x = bytes[2];
pad->stick_y = bytes[3];
if (fin == NULL) {
return;
}
uint8_t bytes[4] = {0};
int result = fread(bytes, 1, 4, fin);
if (feof(fin)) {
printf("[tas_playback] end of tas input\n");
fclose(fin);
fin = NULL;
return;
}
pad->button = (bytes[0] << 8) | bytes[1];
pad->stick_x = bytes[2];
pad->stick_y = bytes[3];
counter+=4;
printf("[tas_playback] %08x called %04x %02x%02x\n", (counter + OFFSET), pad->button, bytes[2], bytes[3]);
fflush(stdout);
}
struct ControllerAPI controller_recorded_tas = {

View File

@ -0,0 +1,57 @@
#include <stdio.h>
#include <ultra64.h>
#include <assert.h>
#include <fcntl.h>
#include "controller_api.h"
static FILE *fout;
static int counter;
#define OFFSET 0x400
#define fname "rec.m64"
static void tas_recorder_close(void) {
fclose(fout);
printf("[tas_recorder] saving tas data to %s\n", fname);
}
static void tas_recorder_init(void) {
if (fname == NULL) {
fout = NULL;
return;
}
unlink(fname);
printf("[tas_recorder] writing output to %s\n", fname);
fout = fopen(fname, "wb");
assert(fout != NULL);
uint8_t buf[OFFSET];
memset(buf, 0, sizeof(buf));
fwrite(buf, 1, sizeof(buf), fout);
atexit(tas_recorder_close);
counter = 0;
}
static void tas_recorder_read(OSContPad *pad) {
if (fout == NULL) {
return;
}
counter += 4;
uint8_t bytes[4] = {0};
int button1 = pad->button;
int button2 = pad->button;
bytes[0] = button1 >> 8;
bytes[1] = button2 & 0x00FF;
bytes[2] = pad->stick_x;
bytes[3] = pad->stick_y;
fwrite(bytes, 1, 4, fout);
printf("[tas_recorder] %08x: %04x %02x%02x\n", (counter + OFFSET), pad->button, bytes[2], bytes[3]);
}
struct ControllerAPI controller_tas_recorder = {
tas_recorder_init,
tas_recorder_read
};

View File

@ -0,0 +1,8 @@
#ifndef CONTROLLER_TAS_RECORDER_H
#define CONTROLLER_TAS_RECORDER_H
#include "controller_api.h"
extern struct ControllerAPI controller_tas_recorder;
#endif

View File

@ -1,7 +1,7 @@
#ifndef GFX_SCREEN_CONFIG_H
#define GFX_SCREEN_CONFIG_H
#define DESIRED_SCREEN_WIDTH 640
#define DESIRED_SCREEN_HEIGHT 480
#define DESIRED_SCREEN_WIDTH 1366
#define DESIRED_SCREEN_HEIGHT 768
#endif