build: add canonical PortMaster packaging

This commit is contained in:
Alexander Sellite 2026-08-08 14:23:27 -04:00
parent cf7a963f18
commit 6fac52dd96
12 changed files with 595 additions and 2 deletions

155
scripts/build_portmaster.sh Executable file
View file

@ -0,0 +1,155 @@
#!/usr/bin/env bash
set -euo pipefail
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
readonly TEMPLATE_ROOT="${SCRIPT_DIR}/portmaster"
readonly GODOT_BIN="${GODOT_BIN:-godot}"
PACKAGE_ONLY=0
if [[ "${1:-}" == "--package-only" ]]; then
PACKAGE_ONLY=1
shift
fi
if [[ $# -ne 0 ]]; then
echo "Usage: $0 [--package-only]" >&2
exit 2
fi
readonly PROJECT_VERSION="$(
sed -n 's/^config\/version="\([^"]*\)"/\1/p' "${PROJECT_ROOT}/project.godot"
)"
if [[ -z "${PROJECT_VERSION}" ]]; then
echo "Could not read application/config/version from project.godot." >&2
exit 1
fi
readonly RELEASE_TAG="v${PROJECT_VERSION}"
readonly RELEASE_ROOT="${PROJECT_ROOT}/builds/${RELEASE_TAG}"
readonly ARM64_ROOT="${RELEASE_ROOT}/linux-arm64"
readonly ARM64_EXECUTABLE="${ARM64_ROOT}/NETfishing.arm64"
readonly ARM64_PCK="${ARM64_ROOT}/NETfishing.pck"
readonly STAGE_ROOT="${RELEASE_ROOT}/portmaster-stage"
readonly GAME_ROOT="${STAGE_ROOT}/netfishing"
readonly ARCHIVE="${RELEASE_ROOT}/netfishing.zip"
readonly LEGACY_ARCHIVE="${RELEASE_ROOT}/netfishing-${RELEASE_TAG}-portmaster-arm64.zip"
readonly HEAD_COMMIT="$(git -C "${PROJECT_ROOT}" rev-parse HEAD)"
readonly TAG_COMMIT="$(git -C "${PROJECT_ROOT}" rev-parse "${RELEASE_TAG}^{commit}")"
if [[ "${HEAD_COMMIT}" != "${TAG_COMMIT}" ]]; then
echo "HEAD does not match ${RELEASE_TAG}. Refusing to package mutable source." >&2
exit 1
fi
if [[ "${NETFISHING_ALLOW_DIRTY_RELEASE:-0}" != "1" ]]; then
dirty_tree=0
git -C "${PROJECT_ROOT}" diff --quiet || dirty_tree=1
git -C "${PROJECT_ROOT}" diff --cached --quiet || dirty_tree=1
if [[ -n "$(git -C "${PROJECT_ROOT}" status --porcelain --untracked-files=normal)" ]]; then
dirty_tree=1
fi
if [[ ${dirty_tree} -ne 0 ]]; then
echo "The repository is not clean. Refusing to build a release package." >&2
exit 1
fi
fi
for command_name in git file zip unzip sha256sum; do
command -v "${command_name}" >/dev/null 2>&1 || {
echo "Required command not found: ${command_name}" >&2
exit 1
}
done
mkdir -p -- "${ARM64_ROOT}" "${RELEASE_ROOT}"
if [[ ${PACKAGE_ONLY} -eq 0 ]]; then
rm -f -- "${ARM64_EXECUTABLE}" "${ARM64_PCK}"
"${GODOT_BIN}" \
--headless \
--path "${PROJECT_ROOT}" \
--export-release "Linux ARM64"
fi
test -s "${ARM64_EXECUTABLE}"
test -s "${ARM64_PCK}"
file "${ARM64_EXECUTABLE}" | grep -q "ARM aarch64"
rm -rf -- "${STAGE_ROOT}"
rm -f -- "${ARCHIVE}" "${LEGACY_ARCHIVE}"
mkdir -p -- "${GAME_ROOT}/licenses"
install -m 0755 "${TEMPLATE_ROOT}/NETfishing.sh" "${STAGE_ROOT}/NETfishing.sh"
install -m 0644 "${TEMPLATE_ROOT}/port.json" "${STAGE_ROOT}/port.json"
install -m 0755 "${ARM64_EXECUTABLE}" "${GAME_ROOT}/NETfishing.aarch64"
install -m 0644 "${ARM64_PCK}" "${GAME_ROOT}/NETfishing.pck"
install -m 0644 "${TEMPLATE_ROOT}/gameinfo.xml" "${GAME_ROOT}/gameinfo.xml"
install -m 0644 "${TEMPLATE_ROOT}/screenshot.png" "${GAME_ROOT}/screenshot.png"
install -m 0644 \
"${TEMPLATE_ROOT}/licenses/CREDITS.md" \
"${GAME_ROOT}/licenses/CREDITS.md"
install -m 0644 \
"${TEMPLATE_ROOT}/licenses/Tuffy-LICENSE.txt" \
"${GAME_ROOT}/licenses/Tuffy-LICENSE.txt"
cat >"${GAME_ROOT}/BUILD-INFO.txt" <<EOF
NETfishing PortMaster ARM64 build
Project version: ${PROJECT_VERSION}
Source commit: ${TAG_COMMIT}
Engine/export template: $("${GODOT_BIN}" --version)
Architecture: AArch64
Minimum linked GLIBC symbol version: GLIBC_2.28
Rendering method: gl_compatibility
The executable and PCK were exported from the release commit listed above.
Repository working-tree changes were not included in game content.
EOF
cat >"${GAME_ROOT}/README.md" <<EOF
# NETfishing for PortMaster
This package contains NETfishing \`${RELEASE_TAG}\`, exported from Godot 4.7.1
for 64-bit ARM Linux and wrapped for PortMaster.
## Installation
Install the complete \`netfishing.zip\` archive with PortMaster or HarbourMaster.
The package requires an ARM64 device, two analog sticks, GLIBC 2.28 or newer,
and the \`weston_pkg_0.2\` runtime.
Save data and device-local configuration remain under \`netfishing/conf/\`.
See \`netfishing/licenses/\` for bundled credits and license information.
EOF
(
cd "${STAGE_ROOT}"
zip -qry "${ARCHIVE}" NETfishing.sh netfishing port.json
)
unzip -tq "${ARCHIVE}" >/dev/null
readonly TOP_LEVELS="$(
unzip -Z1 "${ARCHIVE}" | cut -d/ -f1 | sort -u
)"
readonly EXPECTED_TOP_LEVELS="$(printf '%s\n' NETfishing.sh netfishing port.json)"
if [[ "${TOP_LEVELS}" != "${EXPECTED_TOP_LEVELS}" ]]; then
echo "Unexpected PortMaster archive roots:" >&2
printf '%s\n' "${TOP_LEVELS}" >&2
exit 1
fi
grep -q '"version": 4' "${STAGE_ROOT}/port.json"
grep -q '"name": "netfishing.zip"' "${STAGE_ROOT}/port.json"
grep -q '^# PORTMASTER: netfishing.zip, NETfishing.sh$' \
"${STAGE_ROOT}/NETfishing.sh"
if grep -q 'GPTOKEYB' "${STAGE_ROOT}/NETfishing.sh"; then
echo "GPTOKEYB must not be enabled for NETfishing." >&2
exit 1
fi
if unzip -Z1 "${ARCHIVE}" | grep -E \
'(^|/)(conf|\.git|\.godot|logs?|saves?|identities?)(/|$)|\.(gd|tscn|blend)$' \
>/dev/null; then
echo "The PortMaster archive contains prohibited release content." >&2
exit 1
fi
sha256sum "${ARCHIVE}"
echo "PortMaster package created at ${ARCHIVE}"

120
scripts/portmaster/NETfishing.sh Executable file
View file

@ -0,0 +1,120 @@
#!/bin/bash
# PORTMASTER: netfishing.zip, NETfishing.sh
XDG_DATA_HOME=${XDG_DATA_HOME:-$HOME/.local/share}
if [ -d "/opt/system/Tools/PortMaster/" ]; then
controlfolder="/opt/system/Tools/PortMaster"
elif [ -d "/opt/tools/PortMaster/" ]; then
controlfolder="/opt/tools/PortMaster"
elif [ -d "$XDG_DATA_HOME/PortMaster/" ]; then
controlfolder="$XDG_DATA_HOME/PortMaster"
else
controlfolder="/roms/ports/PortMaster"
fi
if [ ! -f "$controlfolder/control.txt" ]; then
echo "PortMaster control.txt was not found at $controlfolder" >&2
exit 1
fi
source "$controlfolder/control.txt"
[ -f "${controlfolder}/mod_${CFW_NAME}.txt" ] && source "${controlfolder}/mod_${CFW_NAME}.txt"
get_controls
GAMEDIR="/${directory}/ports/netfishing"
if [ ! -d "$GAMEDIR" ] && [ -d "/mnt/mmc/ports/netfishing" ]; then
GAMEDIR="/mnt/mmc/ports/netfishing"
fi
CONFDIR="$GAMEDIR/conf"
GAME_EXECUTABLE="$GAMEDIR/NETfishing.aarch64"
WESTON_DIR="/tmp/netfishing-weston"
WESTON_RUNTIME="weston_pkg_0.2"
HARBOURMASTER="$controlfolder/harbourmaster"
if [ ! -x "$HARBOURMASTER" ] && [ -x "/mnt/mmc/MUOS/PortMaster/harbourmaster" ]; then
HARBOURMASTER="/mnt/mmc/MUOS/PortMaster/harbourmaster"
fi
mkdir -p "$CONFDIR/data" "$CONFDIR/config" "$CONFDIR/cache" "$WESTON_DIR"
chmod +x "$GAME_EXECUTABLE"
> "$GAMEDIR/log.txt" && exec > >(tee "$GAMEDIR/log.txt") 2>&1
if [ ! -f "$controlfolder/libs/${WESTON_RUNTIME}.squashfs" ]; then
if [ ! -x "$HARBOURMASTER" ]; then
pm_message "NETfishing requires the latest PortMaster and WestonPack runtime."
sleep 5
exit 1
fi
$ESUDO "$HARBOURMASTER" --quiet --no-check runtime_check "${WESTON_RUNTIME}.squashfs"
fi
if [ ! -f "$controlfolder/libs/${WESTON_RUNTIME}.squashfs" ]; then
pm_message "WestonPack could not be installed. Check the network connection and PortMaster runtime manager."
sleep 5
exit 1
fi
if [[ "$PM_CAN_MOUNT" != "N" ]]; then
$ESUDO umount "$WESTON_DIR" 2>/dev/null
fi
$ESUDO mount "$controlfolder/libs/${WESTON_RUNTIME}.squashfs" "$WESTON_DIR"
cd "$GAMEDIR" || exit 1
# Godot 4.7 identifies the muOS H700 virtual controller with a CRC-bearing
# GUID and numbers its buttons without the volume keys exposed by SDL2. The
# PortMaster SDL2 database entry therefore cannot drive Godot's gamepad layer.
GODOT_MUOS_MAPPING="19004ca6010000000100000000010000,muOS-Keys,a:b0,b:b1,x:b3,y:b2,leftshoulder:b4,rightshoulder:b5,lefttrigger:b10,righttrigger:b11,guide:b8,start:b7,back:b6,dpup:h0.1,dpleft:h0.8,dpright:h0.2,dpdown:h0.4,leftx:a0,lefty:a1,leftstick:b9,rightx:a2,righty:a3,rightstick:b12,platform:Linux,"
MUOS_SDL2_GUID="19000000010000000100000000010000"
if [[ "$sdl_controllerconfig" == "${MUOS_SDL2_GUID},"* ]]; then
netfishing_controllerconfig="$GODOT_MUOS_MAPPING"
elif [ -n "$sdl_controllerconfig" ]; then
netfishing_controllerconfig="$sdl_controllerconfig"
else
netfishing_controllerconfig="$GODOT_MUOS_MAPPING"
fi
NETFISHING_GODOT_OPTIONS=()
NETFISHING_GAME_ENVIRONMENT=()
DEVICE_COMPATIBILITY=""
if [[ -r /proc/device-tree/compatible ]]; then
DEVICE_COMPATIBILITY="$(tr '\0' ' ' </proc/device-tree/compatible)"
elif [[ -r /sys/firmware/devicetree/base/compatible ]]; then
DEVICE_COMPATIBILITY="$(
tr '\0' ' ' </sys/firmware/devicetree/base/compatible
)"
fi
case "$DEVICE_COMPATIBILITY" in
*allwinner,h616*|*sun50iw9p1*|*allwinner,sun50i-h700*)
NETFISHING_GAME_ENVIRONMENT+=("NETFISHING_LOW_END=1")
NETFISHING_GODOT_OPTIONS+=(
--single-window
--disable-vsync
--max-fps 30
--audio-output-latency 40
)
;;
esac
$ESUDO env CRUSTY_RESOLUTION="${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}" \
"$WESTON_DIR/westonwrap.sh" headless noop kiosk crusty_x11egl \
XDG_DATA_HOME="$CONFDIR/data" \
XDG_CONFIG_HOME="$CONFDIR/config" \
XDG_CACHE_HOME="$CONFDIR/cache" \
SDL_GAMECONTROLLERCONFIG="$netfishing_controllerconfig" \
GODOT_SILENCE_ROOT_WARNING=1 \
"${NETFISHING_GAME_ENVIRONMENT[@]}" \
"$GAME_EXECUTABLE" \
"${NETFISHING_GODOT_OPTIONS[@]}" \
--resolution "${DISPLAY_WIDTH}x${DISPLAY_HEIGHT}" \
--fullscreen \
--rendering-driver opengl3_es \
--audio-driver ALSA
$ESUDO "$WESTON_DIR/westonwrap.sh" cleanup
if [[ "$PM_CAN_MOUNT" != "N" ]]; then
$ESUDO umount "$WESTON_DIR" 2>/dev/null
fi
pm_finish

13
scripts/portmaster/gameinfo.xml Executable file
View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<gameList>
<game>
<path>./NETfishing.sh</path>
<name>NETfishing</name>
<desc>A relaxed multiplayer fishing game about exploring a small island, catching and collecting fish, customizing your character, and spending time by the water.</desc>
<releasedate>20260804T000000</releasedate>
<developer>NETfishing project</developer>
<publisher>Independent</publisher>
<genre>adventure, simulation</genre>
<image>./netfishing/screenshot.png</image>
</game>
</gameList>

View file

@ -0,0 +1,50 @@
# Credits
## Project direction
NETfishing is designed, directed, reviewed, and released by its project
creator. A public-facing creator or studio credit has not yet been recorded in
this repository.
## Development assistance
Development has used automated coding assistance for implementation,
investigation, testing, documentation, and review. Design choices, supplied
artwork, acceptance decisions, repository operations, and releases remain
human-controlled.
This disclosure is intentionally about process. Commit style, code style, or
repository metadata cannot reliably prove whether a particular change was
written with or without assistance.
## Fonts
- Tuffy: Thatcher Ulrich, Karoly Barta, and Michael Evans. The bundled license
dedicates the work to the public domain; see `ui/fonts/Tuffy-LICENSE.txt`.
- Seattle Avenue: bundled as `ui/fonts/seattle_avenue.otf`. Author and
redistribution terms still need to be recorded before public distribution.
## Music
- `audio/music/title/as_in_four_wolves.ogg`: original title/ambient music by
the project owner.
## Sound effects
- “Spinning reel.wav” by tosha73, used as the source for the fishing fight and
manual-reeling loops. Freesound sound 509902, Creative Commons Zero (CC0):
https://freesound.org/s/509902/
- “Gentle Ocean Waves Loop” by kkenny101, used for the saltwater shoreline
ambience. Freesound sound 852826, Creative Commons Zero (CC0):
https://freesound.org/s/852826/
- “Quick Water Droplet” by qubodup, used for the bobber water-impact sound.
Freesound sound 792931, Creative Commons Zero (CC0):
https://freesound.org/s/792931/
## Artwork
- 2D artwork: Rheannon Eisworth, contributor.
- 3D models: original work by the project owner.
Asset categories and release-record requirements are listed in
[`docs/ASSET-PROVENANCE.md`](docs/ASSET-PROVENANCE.md).

View file

@ -0,0 +1,11 @@
We, the copyright holders of this work, hereby release it into the
public domain. This applies worldwide.
In case this is not legally possible,
We grant any entity the right to use this work for any purpose, without
any conditions, unless such conditions are required by law.
Thatcher Ulrich <tu@tulrich.com> http://tulrich.com
Karoly Barta bartakarcsi@gmail.com
Michael Evans http://www.evertype.com

View file

@ -0,0 +1,39 @@
{
"version": 4,
"name": "netfishing.zip",
"items": [
"NETfishing.sh",
"netfishing/"
],
"items_opt": null,
"attr": {
"title": "NETfishing",
"porter": [
"Voyager",
"asellite"
],
"desc": "A relaxed multiplayer fishing game about exploring a small island, catching and collecting fish, customizing your character, and spending time by the water.",
"desc_md": null,
"inst": "Ready to run on supported ARM64 PortMaster devices. This alpha package requires two analog sticks.",
"inst_md": null,
"genres": [
"adventure",
"simulation"
],
"image": {},
"rtr": false,
"exp": false,
"runtime": [
"weston_pkg_0.2.squashfs"
],
"store": [],
"availability": "full",
"reqs": [
"analog_2"
],
"arch": [
"aarch64"
],
"min_glibc": "2.28"
}
}

BIN
scripts/portmaster/screenshot.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ww0w8iubiwsf"
path="res://.godot/imported/screenshot.png-6eed5589b80ced9ab24aed11cadf34f5.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://scripts/portmaster/screenshot.png"
dest_files=["res://.godot/imported/screenshot.png-6eed5589b80ced9ab24aed11cadf34f5.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1