Merge pull request 'gamebridge: Twitch Control' (#2) from gamebridge into master

This commit is contained in:
Cadey Ratio 2020-05-11 22:40:03 +00:00
commit c30ec9e5c1
24 changed files with 1836 additions and 19 deletions

6
.gitignore vendored
View File

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

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" ]

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.

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 = 270.0; // 270 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);
}
}
}

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

@ -0,0 +1,111 @@
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").unwrap(),
// oauth token for twitch name
std::env::var("TWITCH_PASS").unwrap(),
);
// 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),
"r" => 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" => data.sticky.add(127),
"down" => data.sticky.add(-128),
"left" => data.stickx.add(-128),
"right" => data.stickx.add(127),
"stop" => {data.stickx.update(0); data.sticky.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": "f73bf8d584148677b01859677a63191c31911eae",
"sha256": "0jlmrx633jvqrqlyhlzpvdrnim128gc81q5psz2lpp2af8p8q9qs",
"type": "tarball",
"url": "https://github.com/nmattia/niv/archive/f73bf8d584148677b01859677a63191c31911eae.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": "5f14d99efed32721172a819b6e78a5520bab4bc6",
"sha256": "1nxqbcsc8bfmwy450pv6s12nbvzqxai5mr6v41y478pya26lb108",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs-channels/archive/5f14d99efed32721172a819b6e78a5520bab4bc6.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 sources.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

@ -1457,6 +1457,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 +1866,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_sdl,
&controller_keyboard,
&controller_gamebridge,
&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/debug/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