From 91652510dc72bf2cd8a13a4d9852409df9301879 Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Sat, 9 May 2020 17:33:50 -0400 Subject: [PATCH] blog: add gamebridge post (#143) * blog: add gamebridge post * blog/gamebridge: convert org mode to markdown * blog/gamebridge: make title more amusing * blog/gamebridge: add note about theoretical nintendo 64 emulator support in the future --- blog/gamebridge-2020-05-09.markdown | 275 ++++++++++++++++++++++++++++ static/blog/gamebridge.dot | 38 ++++ static/blog/gamebridge.png | Bin 0 -> 34176 bytes 3 files changed, 313 insertions(+) create mode 100644 blog/gamebridge-2020-05-09.markdown create mode 100644 static/blog/gamebridge.dot create mode 100644 static/blog/gamebridge.png diff --git a/blog/gamebridge-2020-05-09.markdown b/blog/gamebridge-2020-05-09.markdown new file mode 100644 index 0000000..b3f3638 --- /dev/null +++ b/blog/gamebridge-2020-05-09.markdown @@ -0,0 +1,275 @@ +--- +title: "Gamebridge: Fitting Square Pegs into Round Holes since 2020" +date: 2020-05-09 +series: howto +tags: + - witchcraft + - sm64 + - twitch +--- + +# Gamebridge: Fitting Square Pegs into Round Holes since 2020 + +Recently I did a stream called [Twitch Plays Super Mario 64][tpsm64]. During +that stream I both demonstrated and hacked on a tool I'm calling +[gamebridge][gamebridge]. Gamebridge is a tool that lets you allow games to +interoperate with programs they really shouldn't be able to interoperate with. + +[tpsm64]: https://www.twitch.tv/videos/615780185 +[gamebridge]: https://github.com/Xe/gamebridge + +Gamebridge works by aggressively hooking into a game's input logic (through a +custom controller driver) and uses a pair of [Unix fifos][ufifo] to communicate +between it and the game it is controlling. Overall the flow of data between the +two programs looks like this: + +[ufifo]: http://man7.org/linux/man-pages/man7/fifo.7.html + +![A diagram explaining how control/state/data flows between components of the +gamebridge stack](/static/blog/gamebridge.png) + +You can view the [source code of this diagram in GraphViz dot format +here](/static/blog/gamebridge.dot). + +The main magic that keeps this glued together is the use of _non-blocking_ I/O. +This means that the bridge input thread will be blocked _at the kernel level_ +for the vblank signal to be written, and the game will also be blocked at the +kernel level for the bridge input thread to write the desired input. This +effectively uses the Linux kernel to pass around a scheduling quantum like you +would in the L4 microkernel. This design consideration also means that +gamebridge has to perform _as fast as possible as much as possible_, because it +realistically only has a few hundred microseconds at best to respond with the +input data to avoid humans noticing any stutter. As such, gamebridge is written +in Rust. + +## Implementation + +When implementing gamebridge, I had a few goals in mind: + +- Use blocking I/O to have the kernel help with this +- Use threads to their fullest potential +- Unix fifos are great, let's use them +- Understand linear interpolation better +- Create a surreal demo on Twitch +- Only have one binary to start, the game itself + +As a first step of implementing this, I went through the source code of the +Mario 64 PC port (but in theory this could also work for other emulators or even +Nintendo 64 emulators with enough work) and began to look for anything that +might be useful to understand how parts of the game work. I stumbled across +`src/pc/controller` and then found two gems that really stood out. I found the +interface for adding new input methods to the game and an example input method +that read from tool-assisted speedrun recordings. The controller input interface +itself is a thing of beauty, I've included a copy of it below: + +```c +// controller_api.h +#ifndef CONTROLLER_API +#define CONTROLLER_API + +#include + +struct ControllerAPI { + void (*init)(void); + void (*read)(OSContPad *pad); +}; + +#endif +``` + +All you need to implement your own input method is an init function and a read +function. The init function is used to set things up and the read function is +called every frame to get inputs. The tool-assisted speedrunning input method +seemed to conform to the [Mupen64 demo file spec as described on +tasvideos.org][mupendemo], and I ended up using this to help test and verify +ideas. + +[mupendemo]: http://tasvideos.org/EmulatorResources/Mupen/M64.html + +The thing that struck me was how _simple_ the format was. Every frame of input +uses its own four-byte sequence. The constants in the demo file spec also helped +greatly as I figured out ways to bridge into the game from Rust. I ended up +creating two [bitflag][bitflag] structs to help with the button data, which +ended up almost being a 1:1 copy of the Mupen64 demo file spec: + +[bitflag]: https://docs.rs/bitflags/1.2.1/bitflags/ + +```rust +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; + } +} +``` + +### Input + +This is where things get interesting. One of the more interesting side effects +of getting inputs over chat for a game like Mario 64 is that you need to [hold +buttons or even the analog stick][apress] in order to do things like jumping +into paintings or on ledges. When you get inputs over chat, you only have them +for one frame. Therefore you need some kind of analog input (or an emulation of +that) that decays over time. One approach you can use for this is [linear +interpolation][lerp] (or lerp). + +[apress]: https://youtu.be/kpk2tdsPh0A?list=PLmBeAOWc3Gf7IHDihv-QSzS8Y_361b_YO&t=13 +[lerp]: https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/a-brief-introduction-to-lerp-r4954/ + +I implemented support for both button and analog stick lerping using a struct I +call a [Lerper][lerper] (the file it is in is named `au.rs` because [.au.][au] is +the lojban emotion-particle for "to desire", the name was inspired from it +seeming to fake what the desired inputs were). + +[lerper]: https://github.com/Xe/gamebridge/blob/b2e7ba21aa14b556e34d7a99dd02e22f9a1365aa/src/au.rs +[au]: http://jbovlaste.lojban.org/dict/au + +At its core, a Lerper stores a few basic things: + +- the current scalar of where the analog input is resting +- the frame number when the analog input was set to the max (or + above) +- the maximum number of frames that the lerp should run for +- the goal (or where the end of the linear interpolation is, for most cases in + this codebase the goal is 0, or neutral) +- the maximum possible output to return on `apply()` +- the minimum possible output to return on `apply()` + +Every frame, the lerpers for every single input to the game will get applied +down closer to zero. Mario 64 uses two signed bytes to represent the controller +input. The maximum/minimum clamps make sure that the lerped result stays in that +range. + +### Twitch Integration + +This is one of the first times I have ever used asynchronous Rust in conjunction +with synchronous rust. I was shocked at how easy it was to just spin up another +thread and have that thread take care of the Tokio runtime, leaving the main +thread to focus on input. This is the block of code that handles [running the +asynchronous twitch bot in parallel to the main thread][twitchrs]: + +[twitchrs]: https://github.com/Xe/gamebridge/blob/b2e7ba21aa14b556e34d7a99dd02e22f9a1365aa/src/twitch.rs#L12 + +```rust +pub(crate) fn run(st: MTState) { + use tokio::runtime::Runtime; + Runtime::new() + .expect("Failed to create Tokio runtime") + .block_on(handle(st)); +} +``` + +Then the rest of the Twitch integration is boilerplate until we get to the +command parser. At its core, it just splits each chat line up into words and +looks for keywords: + +```rust +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::>().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);}, + _ => {}, + } +} +``` + +This implements the following commands: + +| Command | Meaning | +|----------|----------------------------------| +| `a` | Press the A button | +| `b` | Press the B button | +| `z` | Press the Z button | +| `r` | Press the R button | +| `cup` | Press the C-up button | +| `cdown` | Press the C-down button | +| `cleft` | Press the C-left button | +| `cright` | Press the C-right button | +| `start` | Press the start button | +| `up` | Press up on the analog stick | +| `down` | Press down on the analog stick | +| `left` | Press left on the analog stick | +| `stop` | Reset the analog stick to center | + +Currently analog stick inputs will stick for about 270 frames and button inputs +will stick for about 20 frames before drifting back to neutral. The start button +is special, inputs to the start button will stick for 5 frames at most. + +### Debugging + +Debugging two programs running together is surprisingly hard. I had to resort to +the tried-and-true method of using `gdb` for the main game code and excessive +amounts of printf debugging in Rust. The [pretty\_env\_logger][pel] crate (which +internally uses the [env_logger][el] crate, and its environment variable +configures pretty\_env\_logger) helped a lot. One of the biggest problems I +encountered in developing it was fixed by this patch, which I will paste inline: + +[pel]: https://docs.rs/pretty_env_logger/0.4.0/pretty_env_logger/ +[el]: https://docs.rs/env_logger/0.7.1/env_logger/ + +```diff +diff --git a/gamebridge/src/main.rs b/gamebridge/src/main.rs +index 426cd3e..6bc3f59 100644 +@@ -93,7 +93,7 @@ fn main() -> Result<()> { + }, + }; + +- sticky = match stickx { ++ sticky = match sticky { + 0 => sticky, + 127 => { + ymax_frame = data.frame; +``` + +Somehow I had been trying to adjust the y axis position of the stick by +comparing the x axis position of the stick. Finding and fixing this bug is what +made me write the Lerper type. + +--- + +Altogether, this has been a very fun project. I've learned a lot about 3d game +design, historical source code analysis and inter-process communication. I also +learned a lot about asynchronous Rust and how it can work together with +synchronous Rust. I also got to make a fairly surreal demo for Twitch. I hope +this can be useful to others, even if it just serves as an example of how to +integrate things into strange other things from unixy first principles. + +You can find out slightly more about [gamebridge][gamebridge] on its GitHub +page. Its repo also includes patches for the Mario 64 PC port source code, +including one that disables the ability for Mario to lose lives. This could +prove useful for Twitch plays attempts, the 5 life cap by default became rather +limiting in testing. + +Be well. diff --git a/static/blog/gamebridge.dot b/static/blog/gamebridge.dot new file mode 100644 index 0000000..dea8085 --- /dev/null +++ b/static/blog/gamebridge.dot @@ -0,0 +1,38 @@ +digraph G { + rankdir=LR; + + subgraph cluster_0 { + style=filled; + color=lightgrey; + node [style=filled,color=white]; + controller_driver [label="controller\ndriver"]; + label = "game"; + } + + subgraph cluster_2 { + style=filled; + color=lightgrey; + node [style=filled,color=white]; + vblank; + input; + label = "OS"; + } + + subgraph cluster_1 { + style=filled; + color=lightgrey; + node [style=filled,color=white]; + input_thread [label="input"]; + internet_thread [label="internet"]; + state; + input_thread -> state [label="apply\nlerp"]; + internet_thread -> state; + label = "bridge"; + } + + controller_driver -> vblank [label="on each\nframe"]; + input -> controller_driver [label="when input\nis available"]; + vblank -> input_thread [label="when game signals\nvblank"]; + state -> input_thread [label="querying state"]; + input_thread -> input [label="send input to game"]; +} diff --git a/static/blog/gamebridge.png b/static/blog/gamebridge.png new file mode 100644 index 0000000000000000000000000000000000000000..af50c55cbdfb551abfa0126a536c622d322ca7cb GIT binary patch literal 34176 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 L8l+tIdFcNEqHX6M literal 0 HcmV?d00001