Initial commit: OpenRA game engine
Some checks failed
Continuous Integration / Linux (.NET 8.0) (push) Has been cancelled
Continuous Integration / Windows (.NET 8.0) (push) Has been cancelled

Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
let5sne.win10
2026-01-10 21:46:54 +08:00
commit 9cf6ebb986
4065 changed files with 635973 additions and 0 deletions

18
packaging/linux/AppRun.in Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
set -o errexit || exit $?
LAUNCHER=$(readlink -f "${0}")
HERE=$(dirname "${LAUNCHER}")
# Run the game or server
if [ -n "$1" ] && [ "$1" = "--server" ]; then
# Drop the --server argument
shift
"${HERE}/usr/bin/openra-{MODID}-server" "$@"
elif [ -n "$1" ] && [ "$1" = "--utility" ]; then
# Drop the --utility argument
shift
"${HERE}/usr/bin/openra-{MODID}-utility" "$@"
else
"${HERE}/usr/bin/openra-{MODID}" "$@"
fi

View File

@@ -0,0 +1,127 @@
#!/bin/bash
# OpenRA packaging script for Linux (AppImage)
set -o errexit -o pipefail || exit $?
command -v tar >/dev/null 2>&1 || { echo >&2 "Linux packaging requires tar."; exit 1; }
command -v curl >/dev/null 2>&1 || command -v wget > /dev/null 2>&1 || { echo >&2 "Linux packaging requires curl or wget."; exit 1; }
DEPENDENCIES_TAG="20201222"
if [ $# -eq "0" ]; then
echo "Usage: $(basename "$0") version [outputdir]"
exit 1
fi
# Set the working dir to the location of this script
HERE=$(dirname "$0")
cd "${HERE}"
. ../functions.sh
TAG="$1"
OUTPUTDIR="$2"
SRCDIR="$(pwd)/../.."
ARTWORK_DIR="$(pwd)/../artwork/"
UPDATE_CHANNEL=""
SUFFIX="-devel"
if [[ ${TAG} == release* ]]; then
UPDATE_CHANNEL="release"
SUFFIX=""
elif [[ ${TAG} == playtest* ]]; then
UPDATE_CHANNEL="playtest"
SUFFIX="-playtest"
elif [[ ${TAG} == pkgtest* ]]; then
UPDATE_CHANNEL="pkgtest"
SUFFIX="-pkgtest"
fi
if [ ! -d "${OUTPUTDIR}" ]; then
echo "Output directory '${OUTPUTDIR}' does not exist.";
exit 1
fi
# Add native libraries
echo "Downloading appimagetool"
if command -v curl >/dev/null 2>&1; then
curl -s -L -O https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
else
wget -cq https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
fi
chmod a+x appimagetool-x86_64.AppImage
echo "Building AppImages"
build_appimage() {
MOD_ID=${1}
DISPLAY_NAME=${2}
DISCORD_ID=${3}
APPDIR="$(pwd)/${MOD_ID}.appdir"
APPIMAGE="OpenRA-$(echo "${DISPLAY_NAME}" | sed 's/ /-/g')${SUFFIX}-x86_64.AppImage"
IS_D2K="False"
if [ "${MOD_ID}" = "d2k" ]; then
IS_D2K="True"
fi
install_assemblies "${SRCDIR}" "${APPDIR}/usr/lib/openra" "linux-x64" "True" "True" "${IS_D2K}"
install_data "${SRCDIR}" "${APPDIR}/usr/lib/openra" "${MOD_ID}"
set_engine_version "${TAG}" "${APPDIR}/usr/lib/openra"
set_mod_version "${TAG}" "${APPDIR}/usr/lib/openra/mods/${MOD_ID}/mod.yaml" "${APPDIR}/usr/lib/openra/mods/${MOD_ID}-content/mod.yaml"
# Add launcher and icons
sed "s/{MODID}/${MOD_ID}/g" AppRun.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" > "${APPDIR}/AppRun"
chmod 0755 "${APPDIR}/AppRun"
mkdir -p "${APPDIR}/usr/share/applications"
# Note that the non-discord version of the desktop file is used by the Mod SDK and must be maintained in parallel with the discord version!
sed "s/{MODID}/${MOD_ID}/g" openra.desktop.discord.in | sed "s/{MODNAME}/${DISPLAY_NAME}/g" | sed "s/{TAG}/${TAG}/g" | sed "s/{DISCORDAPPID}/${DISCORD_ID}/g" > "${APPDIR}/usr/share/applications/openra-${MOD_ID}.desktop"
chmod 0755 "${APPDIR}/usr/share/applications/openra-${MOD_ID}.desktop"
cp "${APPDIR}/usr/share/applications/openra-${MOD_ID}.desktop" "${APPDIR}/openra-${MOD_ID}.desktop"
mkdir -p "${APPDIR}/usr/share/mime/packages"
# Note that the non-discord version of the mimeinfo file is used by the Mod SDK and must be maintained in parallel with the discord version!
sed "s/{MODID}/${MOD_ID}/g" openra-mimeinfo.xml.discord.in | sed "s/{TAG}/${TAG}/g" | sed "s/{DISCORDAPPID}/${DISCORD_ID}/g" > "${APPDIR}/usr/share/mime/packages/openra-${MOD_ID}.xml"
chmod 0755 "${APPDIR}/usr/share/mime/packages/openra-${MOD_ID}.xml"
if [ -f "${ARTWORK_DIR}/${MOD_ID}_scalable.svg" ]; then
install -Dm644 "${ARTWORK_DIR}/${MOD_ID}_scalable.svg" "${APPDIR}/usr/share/icons/hicolor/scalable/apps/openra-${MOD_ID}.svg"
fi
for i in 16x16 32x32 48x48 64x64 128x128 256x256 512x512 1024x1024; do
if [ -f "${ARTWORK_DIR}/${MOD_ID}_${i}.png" ]; then
install -Dm644 "${ARTWORK_DIR}/${MOD_ID}_${i}.png" "${APPDIR}/usr/share/icons/hicolor/${i}/apps/openra-${MOD_ID}.png"
install -m644 "${ARTWORK_DIR}/${MOD_ID}_${i}.png" "${APPDIR}/openra-${MOD_ID}.png"
fi
done
mkdir -p "${APPDIR}/usr/bin"
sed "s/{MODID}/${MOD_ID}/g" openra.appimage.in | sed "s/{TAG}/${TAG}/g" | sed "s/{MODNAME}/${DISPLAY_NAME}/g" > "${APPDIR}/usr/bin/openra-${MOD_ID}"
chmod 0755 "${APPDIR}/usr/bin/openra-${MOD_ID}"
sed "s/{MODID}/${MOD_ID}/g" openra-server.appimage.in > "${APPDIR}/usr/bin/openra-${MOD_ID}-server"
chmod 0755 "${APPDIR}/usr/bin/openra-${MOD_ID}-server"
sed "s/{MODID}/${MOD_ID}/g" openra-utility.appimage.in > "${APPDIR}/usr/bin/openra-${MOD_ID}-utility"
chmod 0755 "${APPDIR}/usr/bin/openra-${MOD_ID}-utility"
install -m 0755 gtk-dialog.py "${APPDIR}/usr/bin/gtk-dialog.py"
# Embed update metadata if (and only if) compiled on GitHub Actions
if [ -n "${GITHUB_REPOSITORY}" ]; then
ARCH=x86_64 ./appimagetool-x86_64.AppImage --no-appstream -u "zsync|https://master.openra.net/appimagecheck.zsync?mod=${MOD_ID}&channel=${UPDATE_CHANNEL}" "${APPDIR}" "${OUTPUTDIR}/${APPIMAGE}"
zsyncmake -u "https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}/${APPIMAGE}" -o "${OUTPUTDIR}/${APPIMAGE}.zsync" "${OUTPUTDIR}/${APPIMAGE}"
else
ARCH=x86_64 ./appimagetool-x86_64.AppImage --no-appstream "${APPDIR}" "${OUTPUTDIR}/${APPIMAGE}"
fi
rm -rf "${APPDIR}"
}
build_appimage "ra" "Red Alert" "699222659766026240"
build_appimage "cnc" "Tiberian Dawn" "699223250181292033"
build_appimage "d2k" "Dune 2000" "712711732770111550"
# Clean up
rm -rf appimagetool-x86_64.AppImage "${BUILTDIR}"

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env python3
"""A simple GTK3 graphical dialog helper that can be used as a fallback if zenity is not available
Compatible with python 2 or 3 with the gi bindings.
Three modes are available:
test: accepts no arguments, returns 0 if the python dependencies are available, or 1 if not
error: show a gtk-3 error dialog
accepts arguments --title and --text
question: show a gtk-3 question dialog
accepts arguments --title and --text
returns 0 on Yes, or 1 on No
"""
import sys
try:
import argparse
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
except ImportError:
sys.exit(1)
class Error():
def __init__(self, title, text):
dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK, title)
dialog.format_secondary_text(text)
dialog.run()
dialog.destroy()
class Question():
def __init__(self, title, text):
dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, title)
dialog.format_secondary_text(text)
response = dialog.run()
dialog.destroy()
sys.exit(0 if response == Gtk.ResponseType.YES else 1)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('type', choices=['error', 'question', 'test'])
parser.add_argument('--title', type=str, required=False, default='')
parser.add_argument('--text', type=str, required=False, default='')
args = parser.parse_args()
if args.type == 'question':
Question(args.title, args.text)
elif args.type == 'error':
Error(args.title, args.text)

View File

@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
<mime-type type="x-scheme-handler/openra-{MODID}-{TAG}">
<icon name="openra-{MODID}" />
<generic-icon name="applications-games"/>
<comment>Join OpenRA server</comment>
<glob weight="60" pattern="openra-{MODID}-{TAG}://*"/>
</mime-type>
<mime-type type="x-scheme-handler/discord-{DISCORDAPPID}">
<generic-icon name="applications-games"/>
<comment>Launch OpenRA from Discord</comment>
<glob weight="60" pattern="discord-{DISCORDAPPID}://*"/>
</mime-type>
</mime-info>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
<mime-type type="x-scheme-handler/openra-{MODID}-{TAG}">
<icon name="openra-{MODID}" />
<generic-icon name="applications-games"/>
<comment>Join OpenRA server</comment>
<glob weight="60" pattern="openra-{MODID}-{TAG}://*"/>
</mime-type>
</mime-info>

View File

@@ -0,0 +1,8 @@
#!/bin/sh
set -o errexit || exit $?
LAUNCHER=$(readlink -f "${0}")
HERE=$(dirname "${LAUNCHER}")
cd "${HERE}/../lib/openra"
./OpenRA.Server Game.Mod="{MODID}" "$@"

View File

@@ -0,0 +1,10 @@
#!/bin/sh
set -o errexit || exit $?
cd "{GAME_INSTALL_DIR}"
if test -f "OpenRA.Server"; then
./OpenRA.Server Game.Mod={MODID} "$@"
else
dotnet OpenRA.Server.dll Game.Mod={MODID} "$@"
fi

View File

@@ -0,0 +1,7 @@
#!/bin/sh
set -o errexit || exit $?
# OpenRA.Utility relies on keeping the original working directory, so don't change directory
LAUNCHER=$(readlink -f "${0}")
HERE=$(dirname "${LAUNCHER}")
"${HERE}/../lib/openra/OpenRA.Utility" {MODID} "$@"

View File

@@ -0,0 +1,72 @@
#!/bin/sh
set -o errexit || exit $?
LAUNCHER=$(readlink -f "${0}")
HERE="$(dirname "${LAUNCHER}")"
cd "${HERE}/../lib/openra"
# APPIMAGE is an environment variable set by the runtime
# defining the absolute path to the .AppImage file
if [ -n "${APPIMAGE}" ]; then
LAUNCHER=${APPIMAGE}
APPIMAGEID=$(printf "file://%s" "${APPIMAGE}" | md5sum | cut -d' ' -f1)
test -n "${APPIMAGEID}"
LAUNCHER_NAME="appimagekit_${APPIMAGEID}-openra-{MODID}.desktop"
LAUNCHER_PATH="${HOME}/.local/share/applications/${LAUNCHER_NAME}"
export SDL_VIDEO_X11_WMCLASS="openra-{MODID}-{TAG}"
if [ -f "${LAUNCHER_PATH}" ]; then
# The KDE task switcher limits itself to the 128px icon unless we
# set an X11 _KDE_NET_WM_DESKTOP_FILE property on the window
export OPENRA_DESKTOP_FILENAME="${LAUNCHER_NAME}"
# appimaged doesn't update the mime or icon caches when registering AppImages.
# Run update-desktop-database and gtk-update-icon-cache ourselves if we detect
# that the desktop file has been installed but the handler is not cached
if command -v update-desktop-database > /dev/null; then
MIMECACHE_PATH="${HOME}/.local/share/applications/mimeinfo.cache"
SCHEME="x-scheme-handler/openra-{MODID}-{TAG}"
if ! grep -qs "${SCHEME}=" "${MIMECACHE_PATH}"; then
update-desktop-database "${HOME}/.local/share/applications"
if command -v gtk-update-icon-cache > /dev/null; then
gtk-update-icon-cache ~/.local/share/icons/hicolor/ -t
fi
fi
fi
fi
fi
# Search for server connection
PROTOCOL_PREFIX="openra-{MODID}-{TAG}://"
JOIN_SERVER=""
if [ "${1#${PROTOCOL_PREFIX}}" != "${1}" ]; then
JOIN_SERVER="Launch.Connect=${1#${PROTOCOL_PREFIX}}"
fi
# Run the game
export SDL_VIDEO_X11_WMCLASS="openra-{MODID}-{TAG}"
./OpenRA Game.Mod={MODID} Engine.LaunchPath="${LAUNCHER}" "${JOIN_SERVER}" "$@" && rc=0 || rc=$?
# Show a crash dialog if something went wrong
if [ "${rc}" != 0 ] && [ "${rc}" != 1 ]; then
LOGS="${XDG_CONFIG_HOME:-${HOME}/.config}/openra/Logs"
if [ ! -d "${LOGS}" ] && [ -d "${HOME}/.openra/Logs" ]; then
LOGS="${HOME}/.openra/Logs"
fi
if [ -d Support/Logs ]; then
LOGS="${PWD}/Support/Logs"
fi
ERROR_MESSAGE=$(printf "%s has encountered a fatal error.\nPlease refer to the crash logs and FAQ for more information.\n\nLog files are located in %s\nThe FAQ is available at https://wiki.openra.net/FAQ" "{MODNAME}" "${LOGS}")
if command -v zenity > /dev/null; then
zenity --no-wrap --error --title "{MODNAME}" --no-markup --text "${ERROR_MESSAGE}" 2> /dev/null || :
elif command -v kdialog > /dev/null; then
kdialog --title "{MODNAME}" --error "${ERROR_MESSAGE}" || :
elif "${HERE}/gtk-dialog.py" test > /dev/null; then
"${HERE}/gtk-dialog.py" error --title "{MODNAME}" --text "${ERROR_MESSAGE}" 2> /dev/null
else
echo "${ERROR_MESSAGE}"
fi
exit 1
fi

View File

@@ -0,0 +1,12 @@
[Desktop Entry]
Type=Application
Version=1.0
Name=OpenRA - {MODNAME}
GenericName=Real Time Strategy Game
GenericName[de]=Echtzeit-Strategiespiel
Icon=openra-{MODID}
Exec=openra-{MODID} %U
Terminal=false
Categories=Game;StrategyGame;
StartupWMClass=openra-{MODID}-{TAG}
MimeType=x-scheme-handler/openra-{MODID}-{TAG};x-scheme-handler/discord-{DISCORDAPPID};

View File

@@ -0,0 +1,13 @@
[Desktop Entry]
Type=Application
Version=1.0
Name=OpenRA - {MODNAME}
GenericName=Real Time Strategy Game
GenericName[de]=Echtzeit-Strategiespiel
Icon=openra-{MODID}
Exec=openra-{MODID} %U
Terminal=false
Categories=Game;StrategyGame;
StartupWMClass=openra-{MODID}-{TAG}
MimeType=x-scheme-handler/openra-{MODID}-{TAG};
PrefersNonDefaultGPU=true

39
packaging/linux/openra.in Normal file
View File

@@ -0,0 +1,39 @@
#!/bin/sh
set -o errexit || exit $?
cd "{GAME_INSTALL_DIR}"
# Search for server connection
PROTOCOL_PREFIX="openra-{MODID}-{TAG}://"
JOIN_SERVER=""
if [ "${1#${PROTOCOL_PREFIX}}" != "${1}" ]; then
JOIN_SERVER="Launch.Connect=${1#${PROTOCOL_PREFIX}}"
fi
# Run the game
if test -f "OpenRA"; then
./OpenRA Game.Mod={MODID} Engine.LaunchPath="{BIN_DIR}/openra-{MODID}" "${JOIN_SERVER}" "$@" && rc=0 || rc=$?
else
dotnet OpenRA.dll Game.Mod={MODID} Engine.LaunchPath="{BIN_DIR}/openra-{MODID}" "${JOIN_SERVER}" "$@" && rc=0 || rc=$?
fi
# Show a crash dialog if something went wrong
if [ "${rc}" != 0 ] && [ "${rc}" != 1 ]; then
LOGS="${XDG_CONFIG_HOME:-${HOME}/.config}/openra/Logs"
if [ ! -d "${LOGS}" ] && [ -d "${HOME}/.openra/Logs" ]; then
LOGS="${HOME}/.openra/Logs"
fi
if [ -d Support/Logs ]; then
LOGS="${PWD}/Support/Logs"
fi
ERROR_MESSAGE=$(printf "%s has encountered a fatal error.\nPlease refer to the crash logs and FAQ for more information.\n\nLog files are located in %s\nThe FAQ is available at https://wiki.openra.net/FAQ" "{MODNAME}" "${LOGS}")
if command -v zenity > /dev/null; then
zenity --no-wrap --error --title "{MODNAME}" --no-markup --text "${ERROR_MESSAGE}" 2> /dev/null || :
elif command -v kdialog > /dev/null; then
kdialog --title "{MODNAME}" --error "${ERROR_MESSAGE}" || :
else
echo "${ERROR_MESSAGE}"
fi
exit 1
fi

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>openra-{MODID}.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0</project_license>
<name>OpenRA - {MOD_NAME}</name>
<summary>Reimagining of early Westwood real-time strategy games</summary>
<description>
<p>
OpenRA is a project that recreates and modernizes the classic Command &amp; Conquer real time strategy games. We have developed a flexible open source game engine (the OpenRA engine) that provides a common platform for rebuilding and reimagining classic 2D and 2.5D RTS games (the OpenRA mods).
</p>
<p>
The OpenRA mods include new features and gameplay improvements that bring them into the modern era:
</p>
<ul>
<li>A choice between “right click” and classic “left click” control schemes</li>
<li>Overhauled sidebar interfaces for managing production</li>
<li>Support for game replays and an observer interface designed for streaming games online</li>
<li>The “fog of war” that obscures the battlefield outside your units' line of sight</li>
<li>Civilian structures that can be captured to provide benefits</li>
<li>Units gain experience as they fight and improve when they earn new ranks</li>
</ul>
<p>
OpenRA is 100% free, and comes bundled with three distinct mods. When you run a mod for the first time the game can automatically download the original game assets, or you can use the original game disks.
</p>
</description>
<launchable type="desktop-id">openra-{MODID}.desktop</launchable>
<screenshots>
<screenshot{SCREENSHOT_RA}>
<image>https://www.openra.net/images/appdata/ingame-ra.png</image>
<caption>Red Alert mod</caption>
</screenshot>
<screenshot{SCREENSHOT_CNC}>
<image>https://www.openra.net/images/appdata/ingame-cnc.png</image>
<caption>Tiberian Dawn mod</caption>
</screenshot>
<screenshot{SCREENSHOT_D2K}>
<image>https://www.openra.net/images/appdata/ingame-d2k.png</image>
<caption>Dune 2000 Mod</caption>
</screenshot>
<screenshot>
<image>https://www.openra.net/images/appdata/multiplayer.png</image>
<caption>Multiplayer lobby in the Tiberian Dawn mod</caption>
</screenshot>
</screenshots>
<branding>
<color type="primary" scheme_preference="light">#ffffff</color>
<color type="primary" scheme_preference="dark">#1a191e</color>
</branding>
<url type="homepage">https://www.openra.net</url>
<url type="bugtracker">https://github.com/OpenRA/OpenRA/issues</url>
<url type="donation">https://www.patreon.com/orahosting</url>
<update_contact>paul_at_chote.net</update_contact>
<developer_name>The OpenRA Developers</developer_name>
<developer id="net.openra">
<name>The OpenRA Developers</name>
</developer>
<content_rating type="oars-1.1">
<content_attribute id="violence-realistic">moderate</content_attribute>
<content_attribute id="violence-bloodshed">moderate</content_attribute>
<content_attribute id="violence-worship">moderate</content_attribute>
<content_attribute id="drugs-tobacco">moderate</content_attribute>
<content_attribute id="language-profanity">mild</content_attribute>
<content_attribute id="language-humor">mild</content_attribute>
<content_attribute id="social-chat">intense</content_attribute>
</content_rating>
</component>