Skip to content

Blog

Warcraft III on Arch Linux

Download ElAmigos Repack: https://1337x.to/torrent/3130265/Warcraft-III-Complete-Edition-MULTi6/

unrar x Warcraft.III.Complete.Edition.MULTi6.rar
cd Warcraft.III.Complete.Edition.MULTi6
sudo mount -o loop IGG-Warcraft.III.Complete.Edition.MULTi6.iso /mnt

Now paste this lutris script somewhere. It was adapted from here: https://lutris.net/games/warcraft-iii-reign-of-chaos/,https://lutris.net/games/install/19676/view

war3.yml
name: Warcraft III - Reign of Chaos
game_slug: warcraft-iii-reign-of-chaos
runner: wine
version: ElAmigos Repack
slug: warcraft-iii-reign-of-chaos-elamigos
script:
  files:
  - mod: https://github.com/legluondunet/MyLittleLutrisScripts/raw/master/Warcraft%20III%20-%20Reign%20of%20Chaos/RenderEdge_Widescreen.mix
  - script: https://github.com/legluondunet/MyLittleLutrisScripts/raw/master/Warcraft%20III%20-%20Reign%20of%20Chaos/resolution.sh
  - reg_file: https://github.com/legluondunet/MyLittleLutrisScripts/raw/master/Warcraft%20III%20-%20Reign%20of%20Chaos/warcraft_iii_cd_utf8.reg
  game:
    args: -opengl -window
    exe: drive_c/Games/WarCraft III/Warcraft III.exe
    prefix: $GAMEDIR
  installer:
  - task:
      arch: win64
      name: create_prefix
      prefix: $GAMEDIR
  - task:
      app: baekmuk arial lavfilters
      name: winetricks
      prefix: $GAMEDIR
  - insert-disc:
      requires: reign.ico
  - task:
      description: Installing Warcraft III (ElAmigos Repack)...
      executable: $DISC/setup.exe
      name: wineexec
  - merge:
      dst: $GAMEDIR/drive_c/Program Files (x86)/Warcraft III
      src: reg_file
  - chmodx: script
  - execute:
      args: $RESOLUTION_WIDTH $RESOLUTION_HEIGHT
      file: script
  - task:
      filename: $GAMEDIR/drive_c/Games/WarCraft III/warcraft_iii_cd_utf8.reg
      name: set_regedit_file
  - copy:
      dst: $GAMEDIR/drive_c/Games/WarCraft III
      src: mod
  system:
    env:
      MESA_LOADER_DRIVER_OVERRIDE: zink
    gamescope: false
    gamescope_fps_limiter: '60'
    gamescope_game_res: 1920x1080
    gamescope_output_res: 1920x1080
  wine:
    dxvk: false

Now in lutris: Add > Install from a local script and point it to that lutris script file.

Rest just follow the installation wizard.

GTA San Andreas on Arch Linux

Get the iso

Find the latest best place to torrent from here: https://www.reddit.com/r/Piracy/wiki/megathread/all_purpose/

I can confirm GTA-San-Andreas-HOODLUM-Plus-SAMP-Multiplayer from https://1337x.to works.

Install Lutris

Info

Enable multilib in /etc/pacman.conf first by uncommenting:

[multilib]
Include = /etc/pacman.d/mirrorlist

How to install lutris instructions were clearly laid out by İbrahim Korucuoğlu at https://www.siberoloji.com/how-to-install-and-use-lutris-on-arch-linux. I'm just reproducing the steps here:

sudo pacman -S mesa lib32-mesa vulkan-radeon lib32-vulkan-radeon
# For Nvidia
# sudo pacman -S nvidia nvidia-utils lib32-nvidia-utils
# For Intel
# sudo pacman -S mesa lib32-mesa vulkan-intel lib32-vulkan-intel
# For AMD
sudo pacman -S mesa lib32-mesa vulkan-radeon lib32-vulkan-radeon
sudo pacman -S vulkan-tools
vulkaninfo | less
sudo pacman -S lutris
sudo pacman -S wine wine-gecko wine-mono
sudo pacman -S lib32-gnutls lib32-libldap lib32-mpg123 lib32-openal lib32-v4l-utils lib32-libpulse lib32-alsa-plugins lib32-libxcomposite lib32-libxinerama lib32-ncurses lib32-libxml2 lib32-freetype2 lib32-libpng lib32-sdl2
sudo pacman -S winetricks
paru -S dxvk-bin

Install proton-ce-custom from aur

paru -S proton-ge-custom

Configure Lutris

Update 2025-05-25

I went with proton-ge-custom because of the recommendation that appeared in lutris. But system wine had better performance and significantly faster startup time. You can skip this section if you go with.

1750839104.png

1750709603.png

Preferences > Runners > Wine

Select proton-ge-custom.

1750709643.png

Mount the downloaded iso

sudo mount -o loop Grand\ Theft\ Auto\ \(GTA\)\ San\ Andreas-HOODLUM/hlm-gtasa.iso /mnt

Visit https://lutris.net/games/grand-theft-auto-san-andreas/ and press the Install button. This will open some dialog in Lutris. Go through the steps and point to the /mnt/setup.exe file.

Hit yes and proceed through the install. It will take a while. You'll know when its done, the red Abort button will go away and it will show Success.

Chromium Flags

If you're on wayland you might want to configure chrome to use xorg/xwayland. There seems to be some issue switching between Lutris (that uses xorg backend) and chrome on wayland.

> chrome://flags/
    > Preferred Ozone Platform
        > X11

Transcribe videos with google colab and openai whisper

Google colab provides powerful GPUs with 12G of VRAM even at free tier. I foud this very useful to first generate srt files of chinese youtube videos and then translate the chinese srt files into english srt files.

Sample yt-dlp command to download video

# proxy, cookies, format and output name are not compulsory.
yt-dlp --proxy socks5://localhost:1080/ --cookies /tmp/cookies.txt -f "bestvideo[height=720]+bestaudio" 'https://www.youtube.com/watch?v=XlmWtg4ksaw' -o '藏南的诅咒:困死在喜马拉雅南坡的印度'

Sample ffmpeg command to extract audio from video

ffmpeg -i input.webm -vn -acodec libmp3lame -ab 192k output.mp3

First visit https://colab.research.google.com/

File
    > New notebook in Drive

Set the runtime type

Runtime
    > Change runtime type

Select python3 as interpreter and t4 gpu as hardware accelator

1749154186.png

Each code bock below is inserted by pressing the +Code button in the UI first and then entering the text. Lines that beings with ! is run in the os shell environment, while the rest are run in the selected interpreter (here python3). After typing in each code blocks, press the run button:

1749139785.png

The codeblocks (run in sequence)

!pip install openai-whisper
from google.colab import files
uploaded = files.upload() # (1)
  1. Click on Choose Files, navigate to and select file.
filename = list(uploaded.keys())[0]
print(f"Uploaded file: {filename}")
import os
os.environ['FNAME'] = filename
!whisper "$FNAME" --output_format srt --language zh --model turbo

Note

Replace zh with the spoken language in the uploaded audio file

filename_without_ext = os.path.splitext(os.environ['FNAME'])[0]
files.download(f"{filename_without_ext}.srt")

Note

  1. The generated srt file has the same name but different srt as extension.

Translate with google translate

At https://translate.google.com, in Documents tab you see that google only supports .docx, .pdf, .pptx, .xlsx.

1749152901.png

To work around this limitation, use libreoffice.

libreoffice --convert-to "docx:MS Word 2007 XML" output.srt

This creates output.docx. Get it translated at google translate and download the resulting docx. Convert it back with

libreoffice --convert-to "txt:Text" output-eng.docx

Rename this file to your "video name.srt" and you're good to go!

Configuration management with mkdocs and pymdownx.snippets

I believe this is a better way to manage your config files than uploading them to github. With this approach all you need to do is sync your configs file into the config folder within the root of your mkdocs site. They can easily be embedded as snippets in markdown files with appropriate syntax highlighting and contents of these config files also turn up in site search.

Here's an example:

$ mkdocs new vectorspace.xyz
$ cd vectorspace.xyz
$ nvim mkdocs.yml # (1)
$ mkdir configs
$ cp ~/.zshrc configs/
$ nvim docs/index.md # (2)
  1. look down further for mkdocs.yml
  2. look down further for index.md
mkdocs.yml
1
2
3
site_name: My Docs
markdown_extensions:
  - pymdownx.snippets # (1)
  1. For pydownx extension, you need to install python-pymdown-extensions on archlinux
docs/index.md
# Welcome to MkDocs

For full documentation visit [mkdocs.org](https://www.mkdocs.org).

## Commands

* `mkdocs new [dir-name]` - Create a new project.
* `mkdocs serve` - Start the live-reloading docs server.
* `mkdocs build` - Build the documentation site.
* `mkdocs -h` - Print help message and exit.

## Project layout

    mkdocs.yml    # The configuration file.
    docs/
        index.md  # The documentation homepage.
        ...       # Other markdown pages, images and other files.

```zsh
--8<-- "configs/.zshrc"
```

Here I've just added:

```zsh
--8<-- "configs/.zshrc"
```

... to the end of the autogenerated docs/index.md file when you first create a site. Check the results of this by:

# Inside the directory that contains the mkdocs.yml file
mkdocs serve -a 127.0.0.1:9000

see the results for yourself at 127.0.0.1:9000

pydownx is just one of the many awesome extensions developed by github id facelessuser. Check out more at their site: https://facelessuser.github.io/pymdown-extensions/

How to think about flutter layouts

Let's be real specific here. Note the following specific question and the specific answer.

Question: What determines the size of a widget in flutter?
Answer: The widget can size itself however it wants but it is limited by the constraints imposed by its immediate parent widget. Widgets might also change their behavior entirely when it receives no constraints/is unconstrained. For instance, when a Column receives fixed constraints, like 0.0 <= h <= 100.3 and 0.0 <= w <= 958, it will try to assume the maximum height it can: 100.3. It chooses only enough width to fit its widest child, within the constraints ofcourse. But when the Column widget receives unbounded constraints, it no longer sets its height to the maximum it can, which is rational since the maximum would be infinity under unbounded constraints.

In a typical layout we create which starts with a Column (or Row), it receives fixed constraints and chooses to be biggest it can along its main axis. So a Column fills out the whole screen. This is what I mean by a typical layout:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: Scaffold(
        appBar: AppBar(title: Text('Layout study')),
        body: const MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Hello There'),
      ],
    );
  }
}

Our layout process for the app stars from the Column. Look at devtools to see what the layout looks like, pay attention to the constraints Column receives and what it decides its size is gonna be.

1732826833.png

You can see it choose the maximum of height from the the constraint and just enough width to fit the child Text widget.

Also note here that the child of this Column receives unconstrained height. We can exploit this fact by having one of the child widget take infinite height. As I mentioned earlier, when a Column receives unbounded height, it tries to do the rational next best thing, to be tall enough to fit its children. What happens if one those children say it wants to be too taller beyond the height of screen:

Column(
  children: [
    Container(
      width: 100,
      height: 5000,
      color: Colors.blue,
    ),
  ],
)
Now we get the classic overflow error. This is what we see in devtools:

1732829021.png

And this on the display:

1732829047.png

Look at the layout as shown in flutter inspector again and note that Column passes definite constraints width-wise to the child. So it has no problem rendering this despite the widget trying to set its width to something larger than the screen.

Column(
  children: [
    Container(
      width: 5000,
      height: 100,
      color: Colors.blue,
    ),
  ],
)