<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Gaming on Tom Webster</title><link>https://www.samurailink3.com/tags/gaming/</link><description>Recent content in Gaming on Tom Webster</description><generator>Hugo</generator><language>en-us</language><copyright>CC-BY-4.0</copyright><lastBuildDate>Tue, 02 Sep 2025 00:00:00 -0500</lastBuildDate><atom:link href="https://www.samurailink3.com/tags/gaming/index.xml" rel="self" type="application/rss+xml"/><item><title>The Best Game Clipping Setup</title><link>https://www.samurailink3.com/blog-posts/2025-09-02-the-best-game-clipping-setup/</link><pubDate>Tue, 02 Sep 2025 00:00:00 -0500</pubDate><guid>https://www.samurailink3.com/blog-posts/2025-09-02-the-best-game-clipping-setup/</guid><description>&lt;p&gt;I’m gonna try some YouTube stuff for a while. A lot of my projects are kinda cool and I want to talk about them and maybe inspire people to build stuff for themselves too.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=ewral02JWVg"&gt;YouTube - Tom Webster - The Best Game Clipping Setup (with only OBS!)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Download this Video (Right-Click, Save-Link As): &lt;a href="https://s3.samurailink3.com/tom-webster-videos/TomWebster-TheBestClippingSetup.mp4"&gt;https://s3.samurailink3.com/tom-webster-videos/TomWebster-TheBestClippingSetup.mp4&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Rom Browser</title><link>https://www.samurailink3.com/blog-posts/2024-10-24-rom-browser/</link><pubDate>Thu, 24 Oct 2024 00:00:00 -0500</pubDate><guid>https://www.samurailink3.com/blog-posts/2024-10-24-rom-browser/</guid><description>&lt;p&gt;aka: TAHMS RAHMS&lt;/p&gt;
&lt;p&gt;I finished a project over the weekend: Rom Browser - A simple web app designed to let my friends easily browse rom collections.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.samurailink3.com/img/content/2024-10-24-Rom-Browser_01.png"&gt;&lt;img src="https://www.samurailink3.com/img/content/2024-10-24-Rom-Browser_01.png" alt="A screenshot of a web browser showing a simple webpage with a list of fake video game titles to browse and download."&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="why-what-where-can-i-get-it"&gt;Why? What? Where can I get it?&lt;/h1&gt;
&lt;p&gt;I &lt;em&gt;fucking love&lt;/em&gt; classic games. Whatever “classic gaming” means to you, love it, hell yeah, 10/10, can’t get enough. I love the idea of shared and open culture, freedom of information, and a more limited copyright system. I love roms, emulation, and game preservation. Now that you know where I’m coming from, let’s talk about the &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A lot of people I know spent a very long time collecting and organizing rom packs for a wide variety of systems. Conveniently, I recently purchased a storage server for my homelab:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.samurailink3.com/img/content/2024-10-24-Rom-Browser_02.png"&gt;&lt;img src="https://www.samurailink3.com/img/content/2024-10-24-Rom-Browser_02.png" alt="Two servers mounted in a server rack. A 1U Dell PowerEdge R630 and a 2U PowerEdge R730."&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So now my friends had a place to back up their collections. But we wanted more than just backups, we wanted an easy way to share these collections. At first, I tried issuing everyone &lt;del&gt;S3&lt;/del&gt; &lt;del&gt;MinIO&lt;/del&gt; &lt;a href="https://silo.pigsty.io/"&gt;Silo&lt;/a&gt; keys, but, believe it or not, most people don’t use the AWS CLI on a daily basis. They wanted something easier to browse.&lt;/p&gt;
&lt;p&gt;Thus, &lt;em&gt;Rom Browser&lt;/em&gt;. I’ve needed to get deeper into frontend development for a while, and this project was just complicated enough to get really hands-on with something.&lt;/p&gt;
&lt;p&gt;So… where can you get it? You &lt;em&gt;can’t.&lt;/em&gt; This project is &lt;em&gt;extremely specific&lt;/em&gt; to my particular hosting setup. From networking to the folder structures, its just not generic enough to be easily hosted. There are a few useful things to share that I’ll post below, but right now there isn’t any linked GitLab project. So this isn’t a &lt;em&gt;project announcement&lt;/em&gt;, its just a &lt;em&gt;blog post&lt;/em&gt;.&lt;/p&gt;
&lt;h1 id="the-requirements"&gt;The Requirements&lt;/h1&gt;
&lt;h2 id="private-access"&gt;Private Access&lt;/h2&gt;
&lt;p&gt;I’m not &lt;em&gt;trying&lt;/em&gt; to get in trouble, and hosting a roms site on the open internet is an easy way to do that. This needs to be Wireguard-only, completely private network.&lt;/p&gt;
&lt;h2 id="simple-backend-learn-frontend"&gt;Simple Backend, Learn Frontend&lt;/h2&gt;
&lt;p&gt;This project shouldn’t be overly-complex on the backend. I have plenty of experience there, what I need to concentrate on is building the site itself. The backend can be dumb and shortcut-filled in an effort to prioritize frontend-learning.&lt;/p&gt;
&lt;h2 id="provide-a-good-user-experience"&gt;Provide a Good User Experience&lt;/h2&gt;
&lt;p&gt;The entire point of this project is to be more usable than the AWS CLI. The site should be intuitive and make users happy. Use domain names, not IPs. Use HTTPS to avoid scary browser warnings.&lt;/p&gt;
&lt;h2 id="make-minio-transparent"&gt;Make MinIO Transparent&lt;/h2&gt;
&lt;p&gt;The user should never be aware that they’re interacting with MinIO. I won’t use pre-signed URLs or bucket rules to provide direct access. This will run through a pass-through downloader.&lt;/p&gt;
&lt;h1 id="the-tech"&gt;The Tech&lt;/h1&gt;
&lt;p&gt;Rom Browser is broken up into three components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data Exporter - This just lists every object in the bucket, marshals the folder structure into struct variables, then exports this big-ass list of games as a JSON file.&lt;/li&gt;
&lt;li&gt;File Server - This handles distributing that JSON cache file and serving rom downloads to users.&lt;/li&gt;
&lt;li&gt;Frontend - This takes in that games cache file, then provides several useful views into the games data complete with download links.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of the benefits of this design are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No MinIO keys in the frontend, no chance of leaks.
&lt;ul&gt;
&lt;li&gt;While the risk here is low, especially with per-key policies, I don’t want to introduce bad habits here.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Users that have MinIO access can independently add new roms to the collection and this will be reflected on the site automatically when Data Exporter runs.&lt;/li&gt;
&lt;li&gt;No need for a complicated backend database scheme or anything. Its just a 5MB JSON blob. Not ideal, but good enough for casual use.
&lt;ul&gt;
&lt;li&gt;I &lt;em&gt;could&lt;/em&gt; do things like more aggressive caching/lazy loading/data sharding/etc, but this is a very small private site, its fine.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Keeps me focused on the frontend and user experience, not on backend optimization.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the frontend, I decided to try out &lt;a href="https://vuejs.org/"&gt;https://vuejs.org/&lt;/a&gt;. I didn’t need the complexity of React, but wanted something a bit opinionated because I just don’t know enough about frontend development to have strong opinions yet.&lt;/p&gt;
&lt;h1 id="networking-certificates-and-architecture"&gt;Networking, Certificates, and Architecture&lt;/h1&gt;
&lt;p&gt;This site would be hosted on Wireguard at a private &lt;code&gt;10.x.x.x&lt;/code&gt; address. To support my “Good UX” goal, I bound this &lt;code&gt;10.&lt;/code&gt; address to a DNS name. Then, there was a new problem: HTTP-only sites give scary warnings in modern browsers. If I really want to provide the best user experience, I need HTTPS. I love &lt;a href="https://letsencrypt.org/"&gt;Let’s Encrypt&lt;/a&gt;, but had only ever used it for internet-accessible sites. Never for anything internal.&lt;/p&gt;
&lt;p&gt;After some poking around, I found &lt;a href="https://go-acme.github.io/lego/"&gt;LEGO&lt;/a&gt;, a Let’s Encrypt client that supports ACME DNS challenges. I plugged in my DNS-provider’s API key and it was able to issue a cert for my internal site without a problem. I then wrote a simple bash script to automate the renewal process and move the certs into the correct location.&lt;/p&gt;
&lt;p&gt;The Data Exporter would be cron’d out to run once per hour. Doing the full list command, even on the local network, takes a bit over a minute. That’s &lt;em&gt;far too long&lt;/em&gt; to make a user wait. So we need to run this ahead of time and cache the result. To avoid needing to write any sync-scripts to keep the cache file consistent across container volumes, I just &lt;a href="https://www.redhat.com/en/blog/hard-links-linux"&gt;hard-linked&lt;/a&gt; it.&lt;/p&gt;
&lt;p&gt;The File Server is pretty simple. It listens for any requests to &lt;code&gt;/download&lt;/code&gt;, then calls the appropriate handler. If the client asks for &lt;code&gt;/download/games.json&lt;/code&gt;, the File Server reads the cache file into memory and provides it to the user. For anything else, it checks the path against a filename map to ensure it is in the dataset, downloads the object into memory, then hands it to the user. This helps obfuscate-away MinIO.&lt;/p&gt;
&lt;p&gt;The frontend is just a simple &lt;a href="https://vuejs.org/"&gt;https://vuejs.org/&lt;/a&gt; site and uses &lt;a href="https://get.foundation/index.html"&gt;Foundation&lt;/a&gt; for the styling. All of this is served from a single domain and backed by a Let’s Encrypt cert.&lt;/p&gt;
&lt;h1 id="cool-stuff"&gt;Cool Stuff&lt;/h1&gt;
&lt;h2 id="use-caddy-to-bind-multiple-containers-under-same-domain"&gt;Use Caddy to bind multiple containers under same domain&lt;/h2&gt;
&lt;p&gt;I discovered that you can use Caddy to bind multiple servers together under one domain, then just switch who gets the request based on the path. In the example below, I’m serving the site through the frontend container, but any calls to &lt;code&gt;emulation.example.com/download/&lt;/code&gt; is passed through to the File Server container.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;https://emulation.example.com {
 tls /etc/caddy/certificates/emulation.example.com.crt /etc/caddy/certificates/emulation.example.com.key
 reverse_proxy 10.1.2.3:3000
 reverse_proxy /download/* 10.1.2.3:8080
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="use-dockerfile-to-compile-and-containerize-your-software"&gt;Use Dockerfile to compile and containerize your software&lt;/h2&gt;
&lt;p&gt;I wanted to just &lt;code&gt;git push&lt;/code&gt; from my local machine and actually build the software on my server, but I didn’t want to clutter it up with a bunch of NodeJS stuff. Luckily, Docker makes this process pretty clean and easy. You can actually use a multi-step Dockerfile to build &lt;em&gt;and then&lt;/em&gt; containerize your software. Here’s an example for a simple Go program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-docker" data-lang="docker"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;golang:1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;builder&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;WORKDIR&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/opt/builder&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COPY&lt;/span&gt; . ./&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;RUN&lt;/span&gt; CGO_ENABLED&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; GOOS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;linux go build&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;alpine:latest&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;EXPOSE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;8080&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COPY&lt;/span&gt; --from&lt;span style="color:#f92672"&gt;=&lt;/span&gt;builder /opt/builder/fileserver /bin/fileserver&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CMD&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#34;/bin/fileserver&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;-config&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;/data/config.toml&amp;#34;&lt;/span&gt;]&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here’s what I used for the frontend:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-docker" data-lang="docker"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;node:23&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;AS&lt;/span&gt; &lt;span style="color:#e6db74"&gt;builder&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;WORKDIR&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/opt/builder&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COPY&lt;/span&gt; . ./&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;RUN&lt;/span&gt; npm install&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;RUN&lt;/span&gt; npm run build&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; &lt;span style="color:#e6db74"&gt;nginx:latest&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;EXPOSE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;80&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;COPY&lt;/span&gt; --from&lt;span style="color:#f92672"&gt;=&lt;/span&gt;builder /opt/builder/dist/ /usr/share/nginx/html/&lt;span style="color:#960050;background-color:#1e0010"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I then wrote a bash file to build all components in a single command.&lt;/p&gt;
&lt;h1 id="so-did-it-work-was-this-better-than-the-aws-cli"&gt;So… did it work? Was this better than the AWS CLI?&lt;/h1&gt;
&lt;p&gt;My friends absolutely loved it. The site is easy to use, fast, and provided me with a perfect opportunity to jump into frontend development. I’m extremely happy with VueJS, Foundation, &lt;a href="https://www.truenas.com/"&gt;TrueNAS&lt;/a&gt;, MinIO, and the work I put into gluing all these together.&lt;/p&gt;
&lt;p&gt;Until next time, thanks for reading!&lt;/p&gt;</description></item><item><title>Armored Core 6 Affinity Launcher</title><link>https://www.samurailink3.com/projects/2024-10-08-armored-core-6-affinity-launcher/</link><pubDate>Tue, 08 Oct 2024 00:00:00 -0500</pubDate><guid>https://www.samurailink3.com/projects/2024-10-08-armored-core-6-affinity-launcher/</guid><description>&lt;p&gt;The AC6Launcher is a small project that launches Armored Core 6 (or the AC6 Coop Launcher) without the stutters. The launcher sets the CPU affinity of &lt;code&gt;armoredcore6.exe&lt;/code&gt; and bans the use of CPU0. This is a common solution to stop AC6 from severe stuttering.&lt;/p&gt;
&lt;h1 id="where-to-get-it"&gt;Where to get it&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://gitlab.com/samurailink3/ac6launcher"&gt;https://gitlab.com/samurailink3/ac6launcher&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Instructions are on the Readme on that page.&lt;/p&gt;
&lt;h1 id="how-it-works"&gt;How it works&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Launches AC6, either through the standard &lt;code&gt;armoredcore6.exe&lt;/code&gt; or the Coop Launcher &lt;code&gt;ac6_for_coop_launcher.exe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Watches for &lt;code&gt;armoredcore6.exe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;After it finds the process, wait 15 seconds then…&lt;/li&gt;
&lt;li&gt;Sets CPU affinity to block only the first processor&lt;/li&gt;
&lt;li&gt;No more stutters 🙂&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="background-aka-story-time"&gt;Background (aka story time)&lt;/h1&gt;
&lt;p&gt;Armored Core 6 has a &lt;a href="https://steamcommunity.com/app/1888160/discussions/0/3820795131605305341/?ctp=11"&gt;well&lt;/a&gt; &lt;a href="https://www.reddit.com/r/armoredcore/comments/1cz32wl/how_do_i_make_my_ac6_stop_stuttering_so_hard/"&gt;documented&lt;/a&gt; &lt;a href="https://steamcommunity.com/app/1888160/discussions/0/3820795131610074167/"&gt;problem&lt;/a&gt; with stuttering on some systems. Stuttering was so bad that pre-rendered cutscene FMVs would continue playing for a full minute after the audio completed. It was &lt;em&gt;bad&lt;/em&gt;. Originally, this stuttering led me to just outright refund the game on Steam, but recently I decided to give it another shot.&lt;/p&gt;
&lt;p&gt;One very strange suggestion led me to setting core affinity on the &lt;code&gt;armoredcore6.exe&lt;/code&gt; process to ban the use of &lt;code&gt;CPU0&lt;/code&gt;, the first CPU core. Suddenly, no more stutters. It was magical. So the workflow was now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Launch AC6, either through &lt;a href="https://www.nexusmods.com/armoredcore6firesofrubicon/mods/3"&gt;the excellent Armored Core Coop Mod&lt;/a&gt; or regularly through Steam&lt;/li&gt;
&lt;li&gt;Open Task Manager&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;em&gt;Details&lt;/em&gt; tab&lt;/li&gt;
&lt;li&gt;Right click &lt;code&gt;armoredcore6.exe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Set affinity&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Unchcked &lt;code&gt;CPU 0&lt;/code&gt; and press &lt;em&gt;OK&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The main issue with this is that you need to do this &lt;em&gt;every time you launch the game&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I would regularly load into a mission, spend a few minutes wondering why it felt so bad to play, then remembering that I needed to do the &lt;em&gt;Task Manager Dance&lt;/em&gt; to get a good gameplay experience.&lt;/p&gt;
&lt;p&gt;Several other posters who had encountered this problem suggested using &lt;a href="https://bitsum.com/"&gt;Process Lasso&lt;/a&gt; to force AC6 away from CPU0. I didn’t want yet another piece of software running just to manage a different piece of software that was being buggy, so I tried to make my own solution. First step: Simple batch file.&lt;/p&gt;
&lt;p&gt;Stack Overflow led me to this result:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://superuser.com/questions/908848/how-do-i-permanently-set-the-affinity-of-a-process"&gt;https://superuser.com/questions/908848/how-do-i-permanently-set-the-affinity-of-a-process&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So I should be able to launch the game with something similar to: &lt;code&gt;X:\Windows\System32\cmd.exe /C start /affinity Y game.exe&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;But this didn’t work…&lt;/p&gt;
&lt;p&gt;I’m running AC6 through the Coop mod, which has its own launcher executable. If I launched the multiplayer launcher with custom affinity set, it would instantly crash. Furthermore, setting &lt;em&gt;any&lt;/em&gt; affinity on the multiplayer launcher didn’t pass that affinity to &lt;code&gt;armoredcore6.exe&lt;/code&gt; (you’d need to specifically launch sub-processes with affinity inherited from the parent process). Dead end.&lt;/p&gt;
&lt;p&gt;I needed to create my own &lt;em&gt;launcher launcher&lt;/em&gt;. A launcher to launch the launcher that launches the game. Here’s the rough steps for my application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Launch &lt;code&gt;ac6_for_coop_launcher.exe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Grab the process table and look for &lt;code&gt;armoredcore6.exe&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Once you have the AC6 PID, wait and…&lt;/li&gt;
&lt;li&gt;Set the process affinity to use all cores &lt;strong&gt;except CPU 0&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://www.samurailink3.com/img/content/2024-10-08-Armored-Core-6-Affinity-Launcher_01.gif" alt="Meme: Oh yeah. It&amp;rsquo;s all coming together."&gt;&lt;/p&gt;
&lt;p&gt;This project was relatively simple to put together, but did require me to dig into using Windows syscalls, which I don’t have a ton of experience with. I ended up testing out Notion’s AI here and it did a pretty acceptable job! I gave it a page with my current research and had it take a crack at solving the problem.&lt;/p&gt;
&lt;p&gt;Initially the AI did a great job at building the boilerplate of the application, &lt;a href="https://codeberg.org/SamuraiLink3/ac6launcher/src/branch/main/main.go#L65-L88"&gt;including this findProcess function&lt;/a&gt;, but struggled in some other areas. Initially it wanted me to use some deprecated syscall functions. Then it often suggested using &lt;code&gt;windows.SetProcessAffinityMask&lt;/code&gt;, &lt;a href="https://pkg.go.dev/golang.org/x/sys@v0.26.0/windows"&gt;which doesn’t exist&lt;/a&gt;. Then it caught a bug it had introduced which was setting an invalid number of processors in the affinity mask. In the end, it suggested this bit of code that solved that particular issue:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#75715e"&gt;// Set affinity mask&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;mask&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; ^uintptr(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;numCPU&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;runtime&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NumCPU&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;numCPU&lt;/span&gt; &amp;lt; &lt;span style="color:#ae81ff"&gt;64&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;mask&lt;/span&gt; = (&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;numCPU&lt;/span&gt;) &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As a disclaimer, I hate bit-math. So I did a bunch of manual testing and it seems like it did the trick.&lt;/p&gt;
&lt;p&gt;I’m still experimenting with using AI in programming and GameDev tasks. I have a lot of opinions on AI (room-temperature takes, mostly), but was mostly pleasantly surprised with how it saved me time with this micro-project.&lt;/p&gt;
&lt;p&gt;In the end, I ended up &lt;em&gt;very lightly cleaning up&lt;/em&gt; the code and writing some docs. I released the code as Public Domain software via &lt;a href="https://unlicense.org/"&gt;The Unlicense&lt;/a&gt;. If you’d like to contribute in any way, send a PR on GitLab.&lt;/p&gt;
&lt;p&gt;In the meantime, I’ll be playing Armored Core 6 - without the stutters.&lt;/p&gt;</description></item></channel></rss>