Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
7a13119
Docs: Update max py version to 3.13 #5410
qwint Sep 3, 2025
8f88152
MultiServer: Validate CreateHints status arg #5408
qwint Sep 3, 2025
3c28db0
LADX: Drop a marin text option that makes patching fail #5398
Sep 3, 2025
e342a20
Celeste (Open World): Post-merge Logic Fix (#5415)
PoryGone Sep 4, 2025
03992c4
Docs: update mac install instructions to reflect 3.13 support (#5411)
qwint Sep 4, 2025
42ace29
Celeste 64: Logic Fixes #5417
PoryGone Sep 4, 2025
b0b3e36
TUNIC: The Big Refactor (#5195)
ScipioWright Sep 4, 2025
ef59a5e
TUNIC: Change non_local_items Earlier (#5249)
Exempt-Medic Sep 4, 2025
5b5e2c3
SMZ3: Fix distribution of SM prizes (#5303)
KScl Sep 5, 2025
89be26a
Heretic: Update Steam URL (#5304)
KScl Sep 5, 2025
64d3c55
Stardew Valley: Add money logic to traveling merchant (#5327)
Jouramie Sep 5, 2025
7a38e44
Test: Deprecate TestBase (#5339)
qwint Sep 5, 2025
e518e41
Hollow Knight: Make the connecting header separate from the yaml one …
ScipioWright Sep 5, 2025
b9fb5c8
Super Mario Land 2: Remove erroneous Coinsanity checks #5364
Alchav Sep 5, 2025
0d26b64
Core: Remove lttp module requirement from generation #5384
qwint Sep 5, 2025
8c2d246
SC2: Restrict allow Orphan to missions that already require that (#5405)
Ziktofel Sep 5, 2025
5c6dbdd
SC2: Update docs for Linux launch script to follow the core client mi…
Ziktofel Sep 5, 2025
90058ee
CommonClient: fix /items, /locations and /missing not working if the …
Berserker66 Sep 5, 2025
e23720a
LttP: shuffle around gitignore (#5307)
Berserker66 Sep 5, 2025
31b2eed
TUNIC: Make the local_fill option show up on the website #5348
ScipioWright Sep 5, 2025
77cab13
ArchipIDLE: Remove game #5422
NewSoupVi Sep 5, 2025
c5b404b
CI: only trigger release action for bare semver (#5065)
black-sliver Sep 5, 2025
c3c517a
DS3: use yaml.safe_load (#5360)
black-sliver Sep 6, 2025
8a091c9
Kivy: Fix MessageBox popups (#5193)
duckboycool Sep 6, 2025
1b200fb
Choo-Choo Charles: implement new game and documentations (#5287)
lgbarrere Sep 8, 2025
63f3512
Core: adds a custom KeyError for invalid item names (#4223)
qwint Sep 8, 2025
17dad83
Test: Remove most dependencies on lttp (#5338)
qwint Sep 8, 2025
18ac921
SA2B: Logic Fixes and Black Market Trap Name Improvements (#5427)
PoryGone Sep 9, 2025
287bb63
Docs: Kivy Style (#5425)
Berserker66 Sep 9, 2025
9aa0bf7
FF1: New Maintainership (#5027)
Rosalie-A Sep 9, 2025
78b529f
Timespinner: Adds Lantern Check flags, Missing Traps (#5188)
TriumphantBass Sep 10, 2025
1322ce8
Kingdom Hearts: Adding a bunch of new features (#5078)
gaithern Sep 10, 2025
aaaceeb
Timespinner: Add Boss Rando Type Options (#4466)
bendxn Sep 10, 2025
27e50aa
MultiServer: Make it so hint_location doesn't set an automatic priori…
NewSoupVi Sep 10, 2025
76a8b0d
CCCharles: Bug fix for cyclic connections of Entrances with the ignor…
lgbarrere Sep 12, 2025
4e08589
SC2: Region access rule speedups (#5426)
Salzkorn Sep 12, 2025
5975835
KH1: Remove top level script & remove script_name from its component …
NewSoupVi Sep 13, 2025
9c00eb9
WebHost: fix Internal Server Error if parallel access to /room/* happ…
Berserker66 Sep 14, 2025
71de33d
CI: Fix peer review tag on undrafting a PR (#5282)
duckboycool Sep 14, 2025
174d89c
feat(workflow): Implement new Github workflow for building and pushin…
a-priestley Sep 14, 2025
9fdeecd
KH2: Remove top level client script (#5446)
JaredWeakStrike Sep 15, 2025
8f2b4a9
Raft: Add Zipline Tool requirement to Engine controls blueprint #5455
SunnyBat Sep 16, 2025
73718bb
Core: make APContainer seek archipelago.json (#5261)
Berserker66 Sep 19, 2025
3af1e92
TUNIC: Update name of a chest in the UT poptracker map integration #5462
ScipioWright Sep 21, 2025
7badc3e
SC2: Logic bugfixes (#5461)
MatthewMarinets Sep 21, 2025
1bd44e1
Stardew Valley: Fixed Traveling merchant flaky test (#5434)
agilbert1412 Sep 21, 2025
9e96cec
LADX: Fix quickswap #5399
Sep 21, 2025
6c45c8d
Core: make countdown a "admin" only command (#5463)
Berserker66 Sep 21, 2025
68187ba
WebHost: remove team argument from tracker arguments where it's irrel…
Berserker66 Sep 21, 2025
fb9011d
WebHost: revamp /api/*tracker/ (#5388)
Berserker66 Sep 21, 2025
e256abf
Factorio: Allow to reconnect a timed out RCON client connection. (#5421)
CaitSith2 Sep 22, 2025
a99da85
Core: APWorld manifest (#4516)
Berserker66 Sep 24, 2025
dc27030
Core: improve formatting on /help command (#5381)
Berserker66 Sep 24, 2025
4525bae
Webhost: add total player location counts to tracker API (#5441)
Etsuna Sep 24, 2025
4ae87ed
Core: apworld manifest launcher component (#5340)
Berserker66 Sep 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
name: Build and Publish Docker Images

on:
push:
paths:
- "**"
- "!docs/**"
- "!deploy/**"
- "!setup.py"
- "!.gitignore"
- "!.github/workflows/**"
- ".github/workflows/docker.yml"
branches:
- "*"
tags:
- "v?[0-9]+.[0-9]+.[0-9]*"
workflow_dispatch:

env:
REGISTRY: ghcr.io

jobs:
prepare:
runs-on: ubuntu-latest
outputs:
image-name: ${{ steps.image.outputs.name }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
package-name: ${{ steps.package.outputs.name }}
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set lowercase image name
id: image
run: |
echo "name=${GITHUB_REPOSITORY,,}" >> $GITHUB_OUTPUT

- name: Set package name
id: package
run: |
echo "name=$(basename ${GITHUB_REPOSITORY,,})" >> $GITHUB_OUTPUT

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}
tags: |
type=ref,event=branch,enable={{is_not_default_branch}}
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=nightly,enable={{is_default_branch}}

- name: Compute final tags
id: final-tags
run: |
readarray -t tags <<< "${{ steps.meta.outputs.tags }}"

if [[ "${{ github.ref_type }}" == "tag" ]]; then
tag="${{ github.ref_name }}"
if [[ "$tag" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
full_latest="${{ env.REGISTRY }}/${{ steps.image.outputs.name }}:latest"
# Check if latest is already in tags to avoid duplicates
if ! printf '%s\n' "${tags[@]}" | grep -q "^$full_latest$"; then
tags+=("$full_latest")
fi
fi
fi

# Set multiline output
echo "tags<<EOF" >> $GITHUB_OUTPUT
printf '%s\n' "${tags[@]}" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

build:
needs: prepare
runs-on: ${{ matrix.runner }}
permissions:
contents: read
packages: write
strategy:
matrix:
include:
- platform: amd64
runner: ubuntu-latest
suffix: amd64
cache-scope: amd64
- platform: arm64
runner: ubuntu-24.04-arm
suffix: arm64
cache-scope: arm64
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Compute suffixed tags
id: tags
run: |
readarray -t tags <<< "${{ needs.prepare.outputs.tags }}"
suffixed=()
for t in "${tags[@]}"; do
suffixed+=("$t-${{ matrix.suffix }}")
done
echo "tags=$(IFS=','; echo "${suffixed[*]}")" >> $GITHUB_OUTPUT

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/${{ matrix.platform }}
push: true
tags: ${{ steps.tags.outputs.tags }}
labels: ${{ needs.prepare.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.cache-scope }}
cache-to: type=gha,mode=max,scope=${{ matrix.cache-scope }}
provenance: false

manifest:
needs: [prepare, build]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Create and push multi-arch manifest
run: |
readarray -t tag_array <<< "${{ needs.prepare.outputs.tags }}"

for tag in "${tag_array[@]}"; do
docker manifest create "$tag" \
"$tag-amd64" \
"$tag-arm64"

docker manifest push "$tag"
done
1 change: 0 additions & 1 deletion .github/workflows/label-pull-requests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ env:
jobs:
labeler:
name: 'Apply content-based labels'
if: github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize'
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: Release
on:
push:
tags:
- '*.*.*'
- 'v?[0-9]+.[0-9]+.[0-9]*'

env:
ENEMIZER_VERSION: 7.1
Expand Down
33 changes: 9 additions & 24 deletions CommonClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,6 @@ def _cmd_received(self) -> bool:
self.ctx.on_print_json({"data": parts, "cmd": "PrintJSON"})
return True

def get_current_datapackage(self) -> dict[str, typing.Any]:
"""
Return datapackage for current game if known.

:return: The datapackage for the currently registered game. If not found, an empty dictionary will be returned.
"""
if not self.ctx.game:
return {}
checksum = self.ctx.checksums[self.ctx.game]
return Utils.load_data_package_for_checksum(self.ctx.game, checksum)

def _cmd_missing(self, filter_text = "") -> bool:
"""List all missing location checks, from your local game state.
Can be given text, which will be used as filter."""
Expand All @@ -119,8 +108,8 @@ def _cmd_missing(self, filter_text = "") -> bool:
count = 0
checked_count = 0

lookup = self.get_current_datapackage().get("location_name_to_id", {})
for location, location_id in lookup.items():
lookup = self.ctx.location_names[self.ctx.game]
for location_id, location in lookup.items():
if filter_text and filter_text not in location:
continue
if location_id < 0:
Expand All @@ -141,11 +130,10 @@ def _cmd_missing(self, filter_text = "") -> bool:
self.output("No missing location checks found.")
return True

def output_datapackage_part(self, key: str, name: str) -> bool:
def output_datapackage_part(self, name: typing.Literal["Item Names", "Location Names"]) -> bool:
"""
Helper to digest a specific section of this game's datapackage.

:param key: The dictionary key in the datapackage.
:param name: Printed to the user as context for the part.

:return: Whether the process was successful.
Expand All @@ -154,23 +142,20 @@ def output_datapackage_part(self, key: str, name: str) -> bool:
self.output(f"No game set, cannot determine {name}.")
return False

lookup = self.get_current_datapackage().get(key)
if lookup is None:
self.output("datapackage not yet loaded, try again")
return False

lookup = self.ctx.item_names if name == "Item Names" else self.ctx.location_names
lookup = lookup[self.ctx.game]
self.output(f"{name} for {self.ctx.game}")
for key in lookup:
self.output(key)
for name in lookup.values():
self.output(name)
return True

def _cmd_items(self) -> bool:
"""List all item names for the currently running game."""
return self.output_datapackage_part("item_name_to_id", "Item Names")
return self.output_datapackage_part("Item Names")

def _cmd_locations(self) -> bool:
"""List all location names for the currently running game."""
return self.output_datapackage_part("location_name_to_id", "Location Names")
return self.output_datapackage_part("Location Names")

def output_group_part(self, group_key: typing.Literal["item_name_groups", "location_name_groups"],
filter_key: str,
Expand Down
37 changes: 14 additions & 23 deletions Generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,19 +166,10 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
f"A mix is also permitted.")

from worlds.AutoWorld import AutoWorldRegister
from worlds.alttp.EntranceRandomizer import parse_arguments
erargs = parse_arguments(['--multi', str(args.multi)])
erargs.seed = seed
erargs.plando_options = args.plando
erargs.spoiler = args.spoiler
erargs.race = args.race
erargs.outputname = seed_name
erargs.outputpath = args.outputpath
erargs.skip_prog_balancing = args.skip_prog_balancing
erargs.skip_output = args.skip_output
erargs.spoiler_only = args.spoiler_only
erargs.name = {}
erargs.csv_output = args.csv_output
args.outputname = seed_name
args.sprite = dict.fromkeys(range(1, args.multi+1), None)
args.sprite_pool = dict.fromkeys(range(1, args.multi+1), None)
args.name = {}

settings_cache: dict[str, tuple[argparse.Namespace, ...]] = \
{fname: (tuple(roll_settings(yaml, args.plando) for yaml in yamls) if args.sameoptions else None)
Expand All @@ -205,7 +196,7 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
for player in range(1, args.multi + 1):
player_path_cache[player] = player_files.get(player, args.weights_file_path)
name_counter = Counter()
erargs.player_options = {}
args.player_options = {}

player = 1
while player <= args.multi:
Expand All @@ -218,32 +209,32 @@ def main(args=None) -> tuple[argparse.Namespace, int]:
for k, v in vars(settingsObject).items():
if v is not None:
try:
getattr(erargs, k)[player] = v
getattr(args, k)[player] = v
except AttributeError:
setattr(erargs, k, {player: v})
setattr(args, k, {player: v})
except Exception as e:
raise Exception(f"Error setting {k} to {v} for player {player}") from e

# name was not specified
if player not in erargs.name:
if player not in args.name:
if path == args.weights_file_path:
# weights file, so we need to make the name unique
erargs.name[player] = f"Player{player}"
args.name[player] = f"Player{player}"
else:
# use the filename
erargs.name[player] = os.path.splitext(os.path.split(path)[-1])[0]
erargs.name[player] = handle_name(erargs.name[player], player, name_counter)
args.name[player] = os.path.splitext(os.path.split(path)[-1])[0]
args.name[player] = handle_name(args.name[player], player, name_counter)

player += 1
except Exception as e:
raise ValueError(f"File {path} is invalid. Please fix your yaml.") from e
else:
raise RuntimeError(f'No weights specified for player {player}')

if len(set(name.lower() for name in erargs.name.values())) != len(erargs.name):
raise Exception(f"Names have to be unique. Names: {Counter(name.lower() for name in erargs.name.values())}")
if len(set(name.lower() for name in args.name.values())) != len(args.name):
raise Exception(f"Names have to be unique. Names: {Counter(name.lower() for name in args.name.values())}")

return erargs, seed
return args, seed


def read_weights_yamls(path) -> tuple[Any, ...]:
Expand Down
9 changes: 0 additions & 9 deletions KH1Client.py

This file was deleted.

8 changes: 0 additions & 8 deletions KH2Client.py

This file was deleted.

2 changes: 1 addition & 1 deletion Main.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def main(args, seed=None, baked_server_options: dict[str, object] | None = None)

logger = logging.getLogger()
multiworld.set_seed(seed, args.race, str(args.outputname) if args.outputname else None)
multiworld.plando_options = args.plando_options
multiworld.plando_options = args.plando
multiworld.game = args.game.copy()
multiworld.player_name = args.name.copy()
multiworld.sprite = args.sprite.copy()
Expand Down
Loading
Loading