Skip to content

Instantly share code, notes, and snippets.

@lazanet
Last active January 2, 2026 21:12
Show Gist options
  • Select an option

  • Save lazanet/9698e8b38fe68f2789a3d1200145e250 to your computer and use it in GitHub Desktop.

Select an option

Save lazanet/9698e8b38fe68f2789a3d1200145e250 to your computer and use it in GitHub Desktop.
Trilogy Save Editor - Linux AppImage

Mass Effect Trilogy Save Editor - Linux AppImage

How do I use this?

$ wget https://gist.githubusercontent.com/lazanet/9698e8b38fe68f2789a3d1200145e250/raw/Trilogy_Save_Editor-x86_64.AppImage
$ chmod +x Trilogy_Save_Editor-x86_64.AppImage
$ ./Trilogy_Save_Editor-x86_64.AppImage

How do I build this?

$ git clone https://gist.github.com/9698e8b38fe68f2789a3d1200145e250.git metrilogy && cd metrilogy/
$ make

Is this better than what's on NexusMods?

Yep. This is a standard AppImage that should work reliably on various Linux distributions. Also, this doesn't weigh 400MB.

Why AppImage?

AppImage is a format that allows you to package an application with all its dependencies into a single file that can be run on any Linux distribution.

Why didn't you upstream these changes?

I have no idea how to integrate this properly upstream — and quite frankly, I don't care that much. Feel free to upstream it if you want to.

License

# Multi-stage Dockerfile for building Trilogy Save Editor as an AppImage
FROM ubuntu:22.04 AS builder
# Prevent interactive prompts during package installation
ENV DEBIAN_FRONTEND=noninteractive
# Install build dependencies
RUN apt-get update && apt-get install -y \
curl \
build-essential \
pkg-config \
libssl-dev \
libgtk-3-dev \
libwebkit2gtk-4.0-dev \
libappindicator3-dev \
librsvg2-dev \
libsoup2.4-dev \
wget \
file \
fuse \
libfuse2 \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js (v18 LTS)
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
# Install Rust (1.70.0 for compatibility with wasm-bindgen 0.2.78)
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.70.0
ENV PATH="/root/.cargo/bin:${PATH}"
# Add wasm32 target
RUN rustup target add wasm32-unknown-unknown
# Install Trunk v0.14.0 (matching CI.yml version)
RUN wget -qO- https://github.com/thedodd/trunk/releases/download/v0.14.0/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf- \
&& mv trunk /root/.cargo/bin/
# Set working directory
WORKDIR /build
# Copy project files
COPY source/ .
# Install npm dependencies
RUN npm install
# Build using the same steps as CI.yml
# Run tailwind build
RUN npm run build
# Trunk build
RUN trunk build --dist target/dist --release
# App Build
RUN cargo build -p app --release
# Stage 2: Create AppImage
FROM ubuntu:22.04 AS appimage
ENV DEBIAN_FRONTEND=noninteractive
# Install AppImage dependencies
RUN apt-get update && apt-get install -y \
wget \
file \
fuse \
libfuse2 \
desktop-file-utils \
libgtk-3-0 \
libwebkit2gtk-4.0-37 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /appimage
# Copy built application from builder stage
COPY --from=builder /build/target/release/trilogy-save-editor ./trilogy-save-editor
COPY --from=builder /build/target/dist ./dist
COPY --from=builder /build/misc/tse.png ./icon.png
COPY --from=builder /build/databases ./databases
# Download linuxdeploy and appimagetool
RUN wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage \
&& chmod +x linuxdeploy-x86_64.AppImage \
&& ./linuxdeploy-x86_64.AppImage --appimage-extract \
&& mv squashfs-root linuxdeploy-squashfs-root
RUN wget -q https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage \
&& chmod +x appimagetool-x86_64.AppImage \
&& ./appimagetool-x86_64.AppImage --appimage-extract \
&& mv squashfs-root appimagetool-squashfs-root
# Create AppDir structure
RUN mkdir -p AppDir/usr/bin AppDir/usr/share/applications AppDir/usr/share/icons/hicolor/256x256/apps
# Copy the binary
RUN cp trilogy-save-editor AppDir/usr/bin/
RUN cp icon.png AppDir/usr/share/icons/hicolor/256x256/apps/trilogy-save-editor.png
# Copy dist folder (web assets) and databases
RUN cp -r dist AppDir/usr/share/trilogy-save-editor && \
cp -r databases AppDir/usr/bin/
# Copy WebKit helpers (fix for missing child process error)
# We mimic the system path structure because the library seems to hardcode it or ignore exec path
RUN mkdir -p AppDir/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0 && \
cp -r /usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/* AppDir/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/
# Create desktop file
RUN mkdir -p AppDir/usr/share/applications && \
echo "[Desktop Entry]" > AppDir/usr/share/applications/trilogy-save-editor.desktop && \
echo "Type=Application" >> AppDir/usr/share/applications/trilogy-save-editor.desktop && \
echo "Name=Trilogy Save Editor" >> AppDir/usr/share/applications/trilogy-save-editor.desktop && \
echo "Comment=A save editor for Mass Effect Trilogy (and Legendary)" >> AppDir/usr/share/applications/trilogy-save-editor.desktop && \
echo "Exec=trilogy-save-editor" >> AppDir/usr/share/applications/trilogy-save-editor.desktop && \
echo "Icon=trilogy-save-editor" >> AppDir/usr/share/applications/trilogy-save-editor.desktop && \
echo "Categories=Game;Utility;" >> AppDir/usr/share/applications/trilogy-save-editor.desktop && \
echo "Terminal=false" >> AppDir/usr/share/applications/trilogy-save-editor.desktop
RUN desktop-file-validate AppDir/usr/share/applications/trilogy-save-editor.desktop
# Create AppRun script
RUN echo '#!/bin/bash' > AppDir/AppRun && \
echo 'SELF=$(readlink -f "$0")' >> AppDir/AppRun && \
echo 'HERE=${SELF%/*}' >> AppDir/AppRun && \
echo 'export PATH="${HERE}/usr/bin:${PATH}"' >> AppDir/AppRun && \
echo 'export LD_LIBRARY_PATH="${HERE}/usr/lib:${LD_LIBRARY_PATH}"' >> AppDir/AppRun && \
echo 'export WEBKIT_EXEC_PATH="${HERE}/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0"' >> AppDir/AppRun && \
echo 'export WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1' >> AppDir/AppRun && \
echo 'export GIO_MODULE_DIR=""' >> AppDir/AppRun && \
echo 'export GST_PLUGIN_SCANNER_1_0=""' >> AppDir/AppRun && \
echo 'cd "${HERE}/usr/share/trilogy-save-editor" || cd "${HERE}"' >> AppDir/AppRun && \
echo 'exec "${HERE}/usr/bin/trilogy-save-editor" "$@"' >> AppDir/AppRun
RUN chmod +x AppDir/AppRun
# Create symbolic links for AppImage
RUN ln -s usr/share/applications/trilogy-save-editor.desktop AppDir/trilogy-save-editor.desktop
RUN ln -s usr/share/icons/hicolor/256x256/apps/trilogy-save-editor.png AppDir/trilogy-save-editor.png
# Build AppImage
# 1. Deploy files to AppDir
RUN ARCH=x86_64 ./linuxdeploy-squashfs-root/AppRun --appdir AppDir -i icon.png
# 2. Patch libwebkit libraries to use internal references
RUN find AppDir/usr/lib -name 'libwebkit*' -exec sed -i -e "s|/usr|././|g" '{}' \;
# Create symlink for lib so that ././lib resolves correctly from the execution directory
RUN ln -s ../../lib AppDir/usr/share/trilogy-save-editor/lib
# 3. Create AppImage using appimagetool
RUN ARCH=x86_64 ./appimagetool-squashfs-root/AppRun AppDir Trilogy_Save_Editor-x86_64.AppImage
# Final stage: Output
FROM scratch AS export
COPY --from=appimage /appimage/Trilogy_Save_Editor-*.AppImage /
# Default stage for running
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
libgtk-3-0 \
libwebkit2gtk-4.0-37 \
libfuse2 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy AppImage from appimage stage
COPY --from=appimage /appimage/Trilogy_Save_Editor-*.AppImage ./
# Make it executable
RUN chmod +x Trilogy_Save_Editor-*.AppImage
CMD ["bash"]
# Variables
DOCKER ?= docker
GIT ?= git
REPO_URL := https://github.com/KarlitosVII/trilogy-save-editor.git
REPO_DIR := source
DOCKER_IMAGE := trilogy-save-editor-builder
OUTPUT_DIR := output
# Default target
.PHONY: all
all: export
# Help target
.PHONY: help
help:
@echo "Available targets:"
@echo " all - Full build: fetch source, build image, and export AppImage (default)"
@echo " build - Build the Docker image (automatically fetches source)"
@echo " export - Export the AppImage from the build image"
@echo " clean - Remove source directory, output directory, and Docker image"
# Clone the repository if it doesn't exist
$(REPO_DIR):
@echo "==> Cloning repository..."
$(GIT) clone $(REPO_URL) $(REPO_DIR)
# Update the repository and prepare build context
.PHONY: fetch-source
fetch-source: $(REPO_DIR)
@echo "==> Updating repository..."
cd $(REPO_DIR) && $(GIT) pull
# Build the Docker image
.PHONY: build
build: fetch-source
@echo "==> Building Docker image: $(DOCKER_IMAGE)..."
$(DOCKER) build -t $(DOCKER_IMAGE) -f Dockerfile .
# Export the AppImage from the Docker image
.PHONY: export
export: build
@rm -f *.AppImage
@echo "==> Exporting AppImage to $(OUTPUT_DIR)..."
@mkdir -p $(OUTPUT_DIR)
@CONTAINER_ID=$$($(DOCKER) create $(DOCKER_IMAGE)); \
$(DOCKER) cp "$$CONTAINER_ID:/app/." $(OUTPUT_DIR)/; \
$(DOCKER) rm "$$CONTAINER_ID"
@echo "--------------------------------------------------"
@echo "Build complete! AppImage located in: $(OUTPUT_DIR)/"
@ls -lh $(OUTPUT_DIR)/*.AppImage
@echo "--------------------------------------------------"
# Clean up build artifacts
.PHONY: clean
clean:
@echo "==> Cleaning up..."
rm -rf $(REPO_DIR) $(OUTPUT_DIR)
echo "==> Removing Docker image: $(DOCKER_IMAGE)...";
$(DOCKER) rmi $(DOCKER_IMAGE) || true;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment