Monday 4 November 2024

Daily Driving Linux for Gaming - My experience

 It's been so long since I had a tech thing I thought worth of documenting, maybe I should do a tik tok about it, would make me feel less old doing so, but while many might TikTok this journey, I prefer the depth of a written post for now, so here we are.

Intro - why? (you can probably skip this part)

So Windows has been pissing me off for the last checks notes 10 years, Windows 7 was perfect I'd gladly lived in a world where Win 7 got updated for ever instead of of the debacle 8 was. Win 10 started the trend of trying to prove that my computer wasn't indeed mine, it belongs to Microsoft, I just paid for the privilege of using it. Ads enabled by default, which you can disable, but then a windows update will "accidentally" re-enable; the constant harvesting of my usage statistics/data; trying constantly to force Onedrive down my throat; installing apps without my knowledge or permission; the list goes on.

Windows even nagged me with full-screen ads for Win 11—only to tell me my rig was ‘not compatible.

And don't even get me started on the whole copilot and AI powered spyware win 11 comes with, that wasn't the feather that broke the camel's back, that was the artillery strike that left a smoking crater where the camel was.

With all these things combined, I've decided to give gaming on Linux another try, after all I've been keeping my eye on r/linux_gaming so things have been looking up

The Plan


  1. Install Linux on the "Spare Parts PC" I have in my office.
  2. Try to play my current games on it
  3. use it for a while until the next World of Warcraft expansion drops to see if I have any issue (yes, this was the most important step ๐Ÿ˜)
  4. Purge the main rig from windows and install Linux on it (dual boot is for cowards).
I use the Office PC a little bit every day, so any long term degradation and issues with updates would have been noted in the months leading to the expansion prepatch day (for those who don't know, the prepatch is when the game goes up on Major version and so any incompatibility issues will arise then).
This plan had a flaw however, the Office PC has a very old AMD GPU while my main gaming rig has some flavour of a RTX 2070 (which is Nvidia), a risk I was willing to take.

Execution

It's been a while since I had Linux as main driver, my last attempt at gaming in Linux was in 2018 and at work I've been using Macbooks since 2013 and deeming them "Unixlike enough" to bother replacing the OS on them, so I found a bit distressing trying to figure out which distro I should be using, so I went to the "old reliable" of Ubuntu and installed 22.04.
The installation was pretty smooth, followed by installing Steam and Discord which I did from the app manager. 
I had read that the best way to get Blizzard games installed was installing the B.net app via Lutris, so I went to install that but I stumbled on a comment saying Lutris on the app manager was several versions out of date, so I went to their site and grabbed the installer there, no issue.
While I was fetching things I also got ZSH for the terminal and my favourite theme to make it easier to use, but that's a tangent.
After installing Lutris, installing Bnet had a small hiccup on the installation steps which took me like 2 tries to realise I hadn't read the instructions on screen (remember the most important rule in IT: read the fucking screen), but after that I was amazed on how seamlessly everything went. Installing games directly from B.net and everything just worked. Back in 2018 I had been unable to get Overwatch working and it was a major issue since my wife loves that game and I love playing games with her, now OW2 just worked.
I even added the bnet app the the startup applications, I was happy that Lutris allowed us to start the apps without starting Lutris itself first (which was my expectation).
Then I installed the games I had been playing at the time on Steam, a few notable entries:
  • Hades II because it was an early access game I was expecting issues, but none were found.
  • Manor Lords had came out the day before and I got it in a spur of the moment buy, it just worked, was not expecting.
  • Helldivers 2 didn't work it threw a GPU error so bad it crashed the whole PC! ๐Ÿ˜ฑ
To be honest I hadn't been playing Helldivers 2 for a while as the game stopped being fun with the constant nerfs, I searched my issue for a while and concluded it was an AMD specific issue that people on Windows were also experiencing with that I decided to move and hope they patch the game and try it later or try it on the other GPU, but I gonna be honest, I never got around it I had stopped enjoying the game before I set myself on this path so I just can't bother.

I found a really weird bug though, the office pc connects to the same monitor I use for work, I discovered if I had wow+bnet running on office pc, but then on the monitor, swapped the input (in the input select, I do not mean swap cables) so I could see what laptop was doing, when I swapped back, the game would have closed ๐Ÿคจ.  I discovered this by accident as my use cases don't involve swapping monitor input that often, but it's really odd.

For weeks I was pretty satisfied with this, I would play games for a bit on the office pc and everything was great, I even did a twitch stream and everything worked fine (except for HD2, I found the issue on stream ๐Ÿ˜…).

Until one day...

One day the Bnet app just stopped launching. No error, just nothing. I found the logs from Lutris app, searching for that error didn't turn up much, people with similar issues years ago, some solutions included swapping the wine version to a newer one at the time which is now older than what I was using, all in that vein of not applicable.
I set B.net to be launched from Steam with Proton instead, that worked great, "small price to pay" I thought and moved on with my life, the office pc has been like that since.

Eventually I found an issue with Bluetooth headsets, I could not for the life of me pair one of my Airpods to the office pc - even when I used a USB dongle that I had used to pair the same ones to my (still) windows pc. Another BT headset I had laying around (PCX 550) had a bit of a hard time connecting, it would pair, often connect but not register as a sound device, requiring several bluetooth service restarts via the command line for it to work.
Googling around the issue I found some comments saying that 22.04 didn't have support for the faster/newer BT protocol my Airpods used, it came pre installed with 23.x though. It had instructions to install said dependencies, but I followed them to the same result. With this information in mind I decided I was going to try a newer version of Ubuntu on the main rig when time came.
And time came.

Going all in

By the time the prepatch came out and I verified absolutely no issues with it ❤️ Ubuntu 24.04 LTS was out, so I burned that into a bootable thumb drive and set to turn my main gaming rig into a Linux machine.
Before installing I did the try it thing  and checked that I could in fact pair my Airpods and they worked flawlessly on 24.04 - the next obvious step was to purge all of my drives and install it, what could go wrong?

I understand that I don't understand several things about the Linux ecosystem, things like Appimages, flatpacks and Snaps are new to me as they didn't exist last I daily drove Linux; there are things I don't know if I should complain about Ubuntu or Gnome; while going Ubuntu on my main rig went pretty much as I expected given the Office PC's experience, I have some critiques:
  • On 24.04 you cannot install a .deb file from the GUI by double clicking on it like you could before, I had to install another installer for that. Why? 
  • They changed the way the icons for the Dock are fetch, so most of my apps now have this default cogwheel icon, while I understand I can make a .desktop file for them and point for the icon, it's just fucking stupid, it is working fine on 22.04 why make it worse? If there was a change needed there to make it better why not use the old way as fallback?  This is a "we hate our users" kind of change.
  • Why do all the Appimages [that I use] need the "--no-sandbox" argument or they fail silently? 
    • Also, why so many things silently fail?
  • What's the deal with permissions and Snaps? I have some comics I read occasionally on a different drive (not an extarnal drive, just a slow high capacity one to store media), and I couldn't open anything with OpenComic or YACReader when installed via Snaps, this looks like a design decision, it's the kind of thing that steers people away from Linux.

Unexpected issues

On 24.04 I'm having a few fun little issues with World of Warcraft which still don't manifest on 22.04, such as the Dock and the taskbar on top deciding they should be over the game 

Note the dock on top of the game, and the annoying cogwheel icons.

Sometimes the place where the cursor is and the place the game registers it will differ by a several vertical pixels, you can tell this is happening when you're trying to click something and you click what's above it instead, both these problems however have the same solution, which is going into the graphical settings of the game, changing the resolution to "default" and pressing apply.

There's a constant focus issue where I launch the game and try to click stuff on it, but it instead brings to focus the apps bellow it on that position, I just started throwing the game to a different desktop and minimising the bnet launcher.

I got this ROG Mouse with a joystick on the thumb, I have it configured to be the arrow keys and I use it in a variety of games as such. However when I use it on WoW I get massive frame drop for a second, usually only the first time I do it. Can't figure out why, but I also can't change the joystick functions because the ROG software to change it doesn't work on Linux obviously, and Wine doesn't forward USB connections which is annoying, the only solution would be to run windows on a VM just to use this particular software, CBA.

If I close discord "to taskbar" meaning that it's still running, I have the icon the taskbar saying it's running, then I click the discord icon on the dock (which will have the little dot telling me about a notification), then I'll get a second discord instance instead of opening the one still running ๐Ÿคก

I did not expect the Nvidia drivers to be so behind on Ubuntu, which led me to manually downloading more recent one from Nvidia and installing them - which is fine. However, every time there's a big update my drivers get fucked and I loose graphics on restart, forcing me into terminal mode where I'll go in and reinstall the drivers from my downloads folder, I guess I'm glad for that terminal only installer.


Speaking of breaking the GUI, I tried to install a fancy video editor and it told me I was missing some sound related libs, so I go into terminal and start installing them, one in particular said it was satisfied by two packages and I had to pick one, so I did the smart thing and picked the one on the top of the list without any research on the matter obviously.  Halfway through the installation my screen goes black and stays that way. Restarting didn't help. I had to press F2 to force it into command line mode and after trying many things (and yes purging those packages was the fist thing I did), the only way I got my GUI back was doing `sudo apt-get install --reinstall ubuntu-desktop`, which also removed most of my apps. Luckily after reinstalling the apps they got their configs back from $home and even their icons were placed correctly in the Dock. This little side-quest highlights something I love and hate about Linux - your system is yours and you can do whatever you want, including fuck it up. However it can be so easy to fuck it up.

Final weird issue, for the longest time I couldn't use "´~รง^" and other characters from my native language, this was resolved this week or so by some update I didn't notice.

Conclusion

I'm likely not quitting Linux, these issues I faced have been annoying but not game breaking, in fact I didn't go into detail how pretty much every other game I threw at it just worked. Either through Heroic Launcher or through "Adding Non-Steam game" to steam I was even able to try some weird indie stuff from itch.io and it was rare that it took me more than one try to get stuff running. For example, in Darkest Dungeon 2 I had to restart the game after setting it to window mode.
But seeing me deal with these annoying little issues makes my wife not very keen in abandoning windows with me once win10 runs out of security updates next year.
Next I'm gonna give Bazzite a go, maybe I can get good results there.

Wednesday 20 December 2017

ObjectifyHash Gem - My favorite over engineered solution for a stupid problem

Years after the initial development, I was finally allowed to bring this little gem to the public as part of my employer's effort to bring forth more open source code - hopefully more of these will come out soon.
Objectifyhash a very over-engineered solution for a stupid problem: dealing with nested objects on JSON responses from REST services. I find this specially painful when you need to navigate these representations, search for things in them and be able to do actions, one always ends up with code that looks like 

def find_thing_on_x things
  things.detect do |t| t['identification']['name'] == 'thing'; end
end
....
res = get 'https://my-service.com/stuff'

my_thing = find_thing_on_x res['data']['stuff']['things']

Not only is this ugly to look at, but very functional looking feels very un-Ruby like, not mentioning that on non-english keyboards like mine, brackets are hidden behind an awkward Alt Gr + numbers combo.
So, what I wanted to do in this case would be that either get the Stuff JSON mapped to a Stuff class on my Namespace so I can access handy Stuff related methods, or, if that doesn't exists, to get a generic object that allows me to handle Stuff more easily  AND (this is the fun part that other gems at the time didn't cover) repeat recursively for all nested objects inside.
That means, on the example above, it would create a Data class, a Data::Stuff and da Data::Stuff::Thing - since "things" is an array, it leaves it as an array, but each member becomes a Thing! 

The above example becomes much more beautiful with:

stuff = get('https://my-service.com/stuff').to_obj
my_thing = stuff.find_thing
OR
my_thing = stuff.data.stuff.find_things

I usually go with the second example here, as finding things is an action of Stuff and not from Data, but whatever.

So, all JSON objects become ruby objects of the class named after their key within the namespace of the previous key - easy, right?
It also has an exception handling, where you can specify several keys to map to specific existing classes on your code, this is how you inject your own methods such as the "find_things" above.

But this isn't even the part which makes it over-engineered, I opted to dynamically assigning methods to the instances with the values they should return, this means there's no setter methods and has brought some pains into the our work, the funnest of them all are when we have conflicts in Namespace or inherited methods from basic object, the supreme ofender: {"file": {"id": 123}} in which creating a File with an id method didn't work as aspected, so there's a few gotchas here , in this situation expect File_ and _id_ to happen, but overall I've enjoyed working with this tool.

Checkout the github page with more details and I hope there's more equally crazy people like me to enjoy this gem.

Wednesday 3 August 2016

Things Developers say - But it works for this case

I love my developers, some of the smartest people I've worked with, but every once in a while they say something odd about why a problem isn't a problem.
(I really need to start writing these down when they happen for better posts.)

There's a feature on Skystore, where if you rent a movie but don't play it for 28 days, we'll send you an e-mail reminding you there's only two days left to watch. The subject of the e-mail is something like: "Only 2 days left to watch [movie name]".
As you can imagine waiting 30 days to test something like this is not feasible, especially for an automation enthusiast such as myself.
Luckily we have ways to trigger this e-mails before the time runs out, which leads to an e-mail with the following subject: "Only 0.0416666666666667 days left to watch".
I didn't bother to see the code on how two days turn into less than half a day if you force the service to run, but got some reassuring that this only happened if you force to service to run earlier. It's fine, we log a bug on the issue tracker the same, just not a "fix it now" kind of bug.

A couple days go by, a dev comes back to me:
- You know, that has to do with the time left calculation, if we wait 28 days the e-mail will look well.
- So you're telling me it's fine because for the current business requirement that calculation happens to give a whole number?
- Yes.
- This value is configurable, so if someone decides it's supposed to be 3 days instead of 2, we change the config value and our customers start receiving mails telling them they have 2.333333333 days to watch?
*blank stare* - Ok we'll take care of it next sprint.
Yes I did say "3" that many times out loud.
 

Wednesday 29 June 2016

Watir Webdriver / Selenium HTTP Authentication - if it's stupid and it works, it ain't stupid

I've taken some time to write a small sanity test pack to run on the web app that uses the platform my team develops.
Although we have a very good and thorough automated test coverage, I'm very paranoid and want to make sure we didn't miss anything that breaks basic functionality, not that it happens often, or in recent memory, I'm just paranoid - it's a good quality for QA person, right?
So I went about the correct way of doing things, Page Object Model; I have a basic page object that has functionalities that are relevant through the whole app, like knowing when page is fully loaded, how to login, etc. Everything else inherits from this class.
First problem, http authentication, selenium and watir still (!!!) don't have a proper way of dealing with this well, so I went with the normal "https://username:password@url." method, which by the way, nobody else tells you this: use URI encoding on the username and password.
But then I got to the playback page on our app (which is kinda an important page if you're online movie retailer), for reasons not important for this post, on this page there's a https -> http redirect, this redirects cause our username:password deal to be lost and I got stuck with the authentication popup.
Googling how to get around this today still gives me about the same answers as a few years ago, which include this lovely (yet old) Watirmelon post that suggest using AutoAuth plugin for Firefox, usually I'd be against this, since it binds my tests to Firefox, but since for my particular sanity-for-other-team kind of work, I don't really mind, however AutoAuth no longer works with recent versions of Firefox, it stopped working on v39, currently we're on v47.
After much dive into documentation and stackoverflow questions, I gave up, I was ready to ask them to turn off HTTP Authentication for that page, until a co-worker casually mentioned:
Try opening the http version with username and password on the url first, at the start of your test, then go to the normal https start page and do the normal test, the browser will remember when you get redirected.
That a stupid solution... but it works, so it ain't stupid.
Here's how my code changed:

      [...]
      browser.goto inject_auth( url ) if url
      wait_for_load
      [...]

to:

    if url
      browser.goto inject_auth(url)
      wait_for_load
      browser.goto inject_auth(url).sub( 'https', 'http')+ 'playback/fcf7ce62-5695-4d80-be85-662798c9ac7c?token=undefined'
      wait_for_load
      browser.goto inject_auth(url)
    end

Hacky, I know, I have to load the normal page first, because I set up the http load purposely to hit a 404 so this wouldn't cause any unintentional side effect, but it also gives me another redirect, only after this little dance I get to go to the initial page I intended.
Hope this helps other people trying to automate apps with redirects.

The Watirmelon post I mentioned before resolves the problem with NTLM  auth, which could be applied to everything, however my solution doesn't solve that particular problem, if you find out how, please let me know.

Monday 18 April 2016

The importance of using proper naming in your tests

The Skystore project, which I'm the lead tester for, still has a lot of unreleased features, while the reason for this are beyond the scope of what I intend to talk here, one particular feature brought down an important, albeit obvious lesson: Naming matters.

One feature that has been worked a while ago, but is still unavailable, is called "playnext"; it's a simple feature: when giving out video playback information to the client, the server will include some information about what to suggest the user to watch next, some time before the end of the video, the client will display a little box showing that information with an easily accessible play button.
This feature has several tests along with it as what should be suggested varies in accordance with different conditions which have all to be tested and made sure the server is giving out the correct info and structure.
As an automation evangelist I've automated the shit out of this feature, every normal, erroneous, corner and edge case was covered and everything was saved into GIT, available to everyone and runs everyday on every integration environment - good times.

After client applications implemented their side of this feature and found it lacking, it was decided that a new feature would be implemented server side, it would behave just like playnext, but with a different structure that would better satisfy the needs of the clients giving more complete and extendable information a "playnext 2.0". Since different teams have different priorities and implementation times, it was decided that the two features would run side-by-side for a while, to preserve those who had already implemented the first version.
When deciding which tests would be needed, I've said to my minion responsible for it: "Look at the playnext tests, copy them, adapt to the new structure, see if there's anything missing or need to be removed and you should be done quickly".

Later the feature was developed and tested, approved and delivered upon the client teams. Then they noticed that there were several missing parts and it was mostly unusable.
How did this pass the tests? It was obviously broken! My minion told me "I did what you told me, I've copied all the tests I found, there weren't many though"

I've looked for playnext in the feature files, found only a couple of tests, but I know I wrote a bunch of them, what happened? I looked into one file I knew had a few of the tests and found the problem:

play next... play next play next....

There it was, in the tests I named the feature "play next" instead of "playnext", when searching for the correct name, only a couple tests had it.
This explains why he thought there weren't many tests.

So, when naming and describing your tests and features remember:

  • Describe your tests using the correct feature name.
  • Make sure to use the name consistently (ie: don't change the name mid way).
That's it. After this event the tests were corrected, the missing testes added, the feature was patched and integrated with and everybody is happy, hopping it's well received when available to a wider audience.

Saturday 15 August 2015

Using Dropbox to sync saved games (and more) across multiple computers

Over three years ago I made a post on Reddit explaining how to do this, since then Steam introduced cloud saving, so all saved games were sync'd without a second thought, I kinda grew used to it. Long passed is the time when I'd backup my saved games on CD's and DVD's with fear of losing all those game hours to a computer failure.
However I got hit with this problem recently when I bought Banished on GOG, while it's great that they sell all the games DRM free, it's a shame they don't have cloud saving yet, so I went back to the old technique and decided to share it on a more permanent place than reddit.
Please note that instructions cover Windows 7, Linux and OSX, now Win 8 or 10, honestly I don't know if shell link extension works there, if there's an alternative and as of now, I don't care.
The original post:


I started using this technique to sync saved games so I can continue my massive Civilization games when my gf is sleeping at her house. It's the same I've used for years to sync my pidgin settings and .vimrc across my linux machines, but yeah using it for gaming:
First of all you need [...] Dropbox (why on earth are you not using this yet anyway?) make and account and stuff. If you're on Ubunto it's available on the software center thinggy.
Windows 7 only: Get Shell Link Extension 
(my pictures examples are with wow addons and settings on windows 7)
Now find what you want to sync and MOVE it to a folder on dropbox:
In this case I'm moving the Addons folder
On windows, drag the folder back to where it was with the right button and select Drop Here -> Symbolic Link, it will pop up an authorization thinggy, but it's ok.
On Mac and Linux pop open a console and use the "ln -s /path/to/drobox/place/where/you/put/your/stuff /original/path/thing" command
And you're done! Yey
Bonus, you can share folders with your friends so you all can use each other's computers to play or whatever, for instance, next I'm making sure me and my gf can play WoW on any of our computers with the same addons and addons preferences.

Not that I condone this kind of thing, but if you got you pc games at the special Bay shop and thus don't have steam, you can use this technique.

Thursday 26 February 2015

Things Developers say

As a QA person I've been told by developers a myriad of rather amusing things or funny conversations caused by failed tests and the all too often "works on my machine".
I've been meaning to compile them, but I'll just start making posts as they happen/I remember.

All names and locations have been removed for privacy of those involved.


$Dev: On $ticket you mention that the $behaviour happens when it shouldn't. However on the requirements it says $behaviour is expected.
$Me: Oh, I must have missed that, where does it say so on requirements?
$Dev: Well, something things are common knowledge and shouldn't need to be written anywhere.

$QA2: This doesn't work
$Dev: Of course it works, look *press button on his laptop* it works, you're testing it wrong.
$QA2: But that's your machine.
$Dev: So? It works.
$QA2: "Works on my machine"
$Dev: It works!
$Me: Great, $Dev we should tell $Boss to arrange $Ops to have your laptop sent to $location.
$Dev: Why?
$Me: Your machine will be the new prod server obviously, since it only works on your machine.

At this point $Dev helped $QA2 to find the root cause of the problem, things were indeed broken.

$Me: This doesn't work when you use $resource_type.
$Dev: Can't reproduce, did what arguments did you use? Can you retest please in the RC and master branch please?
$Me: I used the arguments of a $resource_type, here's the error stack trace on both branches.
$Dev: I used $other_resource_type and it works, are you putting the arguments correctly? Or are you using dummy/broken data?
$Me: I used $resource_type, if I had used bad data I'd have said so in the first place. Just try $resource_type.
*couple minutes go by*
$Dev: Ok this doesn't work, I'll fix it.