Beyond All Reason launcher

No idea if anyone here is interested in this, or whether this is even the right place to post, but I had some fun last weekend :robot:

I recently discovered Beyond All Reason, a modern RTS game build on the popular open-source Spring game engine.

They do offer Linux versions of the launcher in form of AppImage and Flatpak, which would probably have worked. (I did not try)
But I wanted to know if I could write a nix derivation myself. So i did.

This is just the launcher, not the engine. (Although, Spring is already in nixpkgs, so that might not be much harder.)

All necessary resources are on GitHub under the beyond-all-reason organization.

Ingame lobby: GitHub - beyond-all-reason/BYAR-Chobby
Launcher: GitHub - beyond-all-reason/spring-launcher: Launcher for SpringRTS games
Downloader: GitHub - beyond-all-reason/pr-downloader: console downloader for spring maps/games written in c++

The launcher will download the engine and the game to ~/Beyond All Reason/.
I wrapped the result in steam-run, so that the game starts without further patching. The launcher itself is just an Electron app and does not require it.

{ lib
, stdenv
, fetchFromGitHub
, buildNpmPackage
, runCommand
, nodejs
, electron
, butler
, steam-run
, jq
, xorg
, libcxx

  # dependencies for pr-downloader
, gcc
, cmake
, curl
, pkg-config
, jsoncpp
, boost
, minizip
}:

# This builds the launcher for Beyond All Reason.
# Which can then download the engine, the lobby, and the game.
# Starts the launcher with steam-run, so that the game starts without further
# patching.

let
  version = "1.1861.0";
  srcs = {
    # Contains the configuration for the launcher.
    byar-chobby = fetchFromGitHub {
      owner = "beyond-all-reason";
      repo = "BYAR-Chobby";
      rev = "v${version}";
      sha256 = "sha256-YnOW63Z8A/W89TeeMDJcVKjA1ErATvPHzm26wQdWH2I=";
    };
    spring-launcher = fetchFromGitHub {
      owner = "beyond-all-reason";
      repo = "spring-launcher";
      rev = "439a9b7b7d835691267ad13586d0efc763d39b60";
      sha256 = "sha256-26bDjlbh2lppMC6+6pyqdaSNbVrwKPj4ckMK0LZleQY=";
    };
  };

  # From: https://github.com/beyond-all-reason/BYAR-Chobby/blob/1ee341043b6bb1f488ed5aab5d02c85018c572ed/.github/workflows/launcher.yml
  src = runCommand "byar-launcher-src-${version}"
    {
      buildInputs = [ nodejs jq ];
    } ''
    cp -r ${srcs.byar-chobby} BYAR-Chobby
    cp -r ${srcs.spring-launcher} launcher
    chmod -R +w *

    echo --- Patch launcher with dist_cfg
    cp -r BYAR-Chobby/dist_cfg/* launcher/src/
    for dir in bin files build; do
      mkdir -p launcher/$dir
      if [ -d launcher/src/$dir/ ]; then
        mv launcher/src/$dir/* launcher/$dir/
        rm -rf launcher/src/$dir
      fi
    done

    echo --- Make package.json
    GITHUB_REPOSITORY=beyond-all-reason/BYAR-Chobby
    cd BYAR-Chobby
    export PACKAGE_VERSION=${version}
    echo "Making build for version: $PACKAGE_VERSION"
    node build/make_package_json.js ../launcher/package.json dist_cfg/config.json $GITHUB_REPOSITORY $PACKAGE_VERSION
    cd ..

    echo --- Patching package.json
    # Rebuilding electron would fail: It tries to access github.com.
    # And we do not need it anyway.
    jq 'del(.devDependencies.electron)' launcher/package.json > temp
    mv temp launcher/package.json
    jq 'del(.packages."".devDependencies.electron)' launcher/package-lock.json \
      | jq 'del(.packages."node_modules/electron")' > temp
    mv temp launcher/package-lock.json

    echo --- Force dev mode to prevent launcher-update
    sed -i 's/const isDev = .*\;/const isDev = true\;/' launcher/src/launcher_wizard.js

    mv launcher $out
  '';

  nodeModules = buildNpmPackage {
    inherit src version;
    pname = "byar-launcher-package";
    npmDepsHash = "sha256-cCUtkycZ0bpLwcCfBjf+rTeoMHN7jIxcYCtyrB4rC8A=";
    npmFlags = [ "--legacy-peer-deps" ];
    dontNpmBuild = true;
    passthru = {
      buildInputs = [
        nodejs
        libcxx
        xorg.libX11
      ];
    };
    installPhase = ''
      mv node_modules $out
    '';
  };

  pr-downloader = stdenv.mkDerivation rec {
    pname = "pr-downloader";
    version = "master";
    src = fetchFromGitHub {
      owner = "beyond-all-reason";
      repo = "pr-downloader";
      rev = "79b605d013a0c5a92090b3892e8e0c0aeccac2a8";
      sha256 = "sha256-noroFiv2wAUCgI1ne2sP0PVBxIf20D+m5oa5+pk2OXQ=";
      fetchSubmodules = true;
    };
    buildInputs = [
      gcc
      cmake
      curl
      pkg-config
      jsoncpp
      boost
      minizip
    ];
    postInstall = ''
      mkdir $out/bin
      mv $out/pr-downloader $out/bin
    '';
  };
in
stdenv.mkDerivation {
  inherit src version;
  pname = "byar-launcher";
  phases = [ "buildPhase" ];
  buildPhase = ''
    mkdir -p $out/lib/dist
    cp -r $src/* $out/lib/dist
    chmod -R +w $out/lib/dist

    cp -r ${nodeModules} $out/lib/dist/node_modules

    rm $out/lib/dist/bin/butler/linux/butler
    ln -s ${butler}/bin/butler $out/lib/dist/bin/butler/linux/butler

    rm $out/lib/dist/bin/pr-downloader
    ln -s ${pr-downloader}/bin/pr-downloader $out/lib/dist/bin/pr-downloader

    mkdir -p $out/bin
    echo '#!/bin/sh' > $out/bin/byar-launcher
    echo "${steam-run}/bin/steam-run ${electron}/bin/electron $out/lib/dist" >> $out/bin/byar-launcher
    chmod +x $out/bin/byar-launcher
  '';
}

At some point in the future it could be nice to have the launcher as part of nixpkgs, but currently there is still a lot of development (and most importantly renaming) happening, so that would probably be wasted effort.
Anyway, a Steam release is planned

(I did not test multiplayer, but I see no reason why it would not work.)

4 Likes

Hello, I’ve tried appimage, flatpack, none of them are worked… The only reason I have windows is this game. I’ve recently switched from arch to nixos.

pretty late, but there is this jcdickinson/barnix: A Nix build of Beyond All Reason - Codeberg.org

1 Like

The reason the AppImage does not work out of the box (for me) is that the binaries are linked against OpenAL, but the required libraries are not included in the AppImage.

Unfortunately, both source-based approached (OP from this thread and jcdickinson’s) no longer work for me on 24.11/unstable and with recent BYAR. However, if you are fine to go the binary-based path and just use the provided AppImage, then the following should work (at least it does for me):

{
  pkgs ? import <nixpkgs> { },
}:

let
  version = "1.2988.0";
  pname = "byar";
in
pkgs.appimageTools.wrapType2 {
  name = "${pname}-${version}";

  src = pkgs.fetchurl {
    url = "https://github.com/beyond-all-reason/BYAR-Chobby/releases/download/v${version}/Beyond-All-Reason-${version}.AppImage";
    hash = "sha256-ZJW5BdxxqyrM2TJTO0SBp4BXt3ILyi77EZx73X8hqJE=";
  };

  extraPkgs = pkgs: [ pkgs.openal ];

  meta = {
    description = "Beyond All Reason RTS";
    homepage = "https://www.beyondallreason.info";
    downloadPage = "https://www.beyondallreason.info/download";
    platforms = [ "x86_64-linux" ];
  };
}
1 Like