Skip to content

Commit c00ab64

Browse files
SunnyBatBerserker66CaitSith2Ijwujtoyoda
authored
Raft generation working, Update to latest Archipelago commit (ArchipelagoMW#2)
* Factorio: fix selecting wrong goal requirements due to convoluted if tree. * Tie the need for satellite recipe to satellite goal, not max science pack. * WebHost: remove outdated data * Death link default true/false values for super metroid. * Update README.md * SM: raise Exception instead of sys.exit for custom presets * Updating ff1 gameinfo * Adding in missing comas in ff1 game info * Clients: compatibility change for old Intel graphics. * OoTAdjuster: check on subprocess compressor * Minecraft client: update Forge to 1.17.1-37.1.1 This fixes the critical security issue recently found in Minecraft. * tutorials: place a missing / oops * WebHost: don't bother queuing empty commands * WebHost: split autolaunch and autogen services * Allow update_sprites to work on strict text only systems * [WebHost] Add Super Metroid support to Web Tracker (ArchipelagoMW#153) * [WebHost]: Added Super Metroid tracker, based on TimeSpinner & OOT * Added sanity check to see if all locations can be assigned to regions * TS: Starting with Jewelrybox, Talaria or Meyef in your starting inventory will now set the corresponding flag * TS: putting non consumable items in starting inventory will now remove them from the pool so a duplicate wont drop * TS: no longer reward a progression item if you already have one in your starting inventory * TS: putting items as non local will correctly be handled by your starting orbs and your first progression item excluding locations now correctly works for your first progression item in an non inverted seed Aura blast can now be your starting spell * TS: Fixed unit test * TS: removed todo list :D * TS: Fixed review comments * Fix bug where there is less locations than hint count. * LttPAdjuster: ignore alttpr cert * TS: Relaxed entry logic for lower caves * Starting to update * Factorio: add some more tech tree shapes * Factorio: fix singles layout not generating correctly. * Generating now * Remove prints * Adding rules, but build is breaking now lol * Still not generating reeee * It's generting something wow * Enable rules * Small update * SoE: make doc point to upstream guide.md * SoE: fix macos wheel urls * SoE: Rename difficulty 'Chaos' to 'Mystery' * SoE: Rename 'chaos' to 'full' in options * was changed upstream * also update tooltips to be a bit more helpful * SoE: Update to pyevermizer v0.40.0 see https://github.com/black-sliver/pyevermizer/releases/tag/v0.40.0 * Minecraft client: more general search for mod name Co-authored-by: Fabian Dill <fabian.dill@web.de> Co-authored-by: CaitSith2 <d_good@caitsith2.com> Co-authored-by: Hussein Farran <hmfarran@gmail.com> Co-authored-by: jtoyoda <jamietoyoda@gmail.com> Co-authored-by: espeon65536 <espeon65536@gmail.com> Co-authored-by: alwaysintreble <mmmcheese158@gmail.com> Co-authored-by: TauAkiou <karaken@gmail.com> Co-authored-by: Jarno Westhof <jarnowesthof@gmail.com> Co-authored-by: Jarno Westhof <jarno.westhof@wolterskluwer.com> Co-authored-by: black-sliver <59490463+black-sliver@users.noreply.github.com>
1 parent b8ba1ed commit c00ab64

39 files changed

+755
-2818
lines changed

LttPAdjuster.py

+44-14
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from urllib.request import urlopen
2121

2222
from worlds.alttp.Rom import Sprite, LocalRom, apply_rom_settings, get_base_rom_bytes
23-
from Utils import output_path, local_path, open_file
23+
from Utils import output_path, local_path, open_file, get_cert_none_ssl_context, persistent_store
2424

2525

2626
class AdjusterWorld(object):
@@ -102,14 +102,15 @@ def main():
102102
parser.add_argument('--update_sprites', action='store_true', help='Update Sprite Database, then exit.')
103103
args = parser.parse_args()
104104
args.music = not args.disablemusic
105-
if args.update_sprites:
106-
run_sprite_update()
107-
sys.exit()
108105
# set up logger
109106
loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[
110107
args.loglevel]
111108
logging.basicConfig(format='%(message)s', level=loglevel)
112109

110+
if args.update_sprites:
111+
run_sprite_update()
112+
sys.exit()
113+
113114
if not os.path.isfile(args.rom):
114115
adjustGUI()
115116
else:
@@ -118,7 +119,6 @@ def main():
118119
sys.exit(1)
119120

120121
args, path = adjust(args=args)
121-
from Utils import persistent_store
122122
if isinstance(args.sprite, Sprite):
123123
args.sprite = args.sprite.name
124124
persistent_store("adjuster", "last_settings_3", args)
@@ -224,7 +224,6 @@ def adjustRom():
224224
messagebox.showerror(title="Error while adjusting Rom", message=str(e))
225225
else:
226226
messagebox.showinfo(title="Success", message=f"Rom patched successfully to {path}")
227-
from Utils import persistent_store
228227
if isinstance(guiargs.sprite, Sprite):
229228
guiargs.sprite = guiargs.sprite.name
230229
persistent_store("adjuster", "last_settings_3", guiargs)
@@ -241,28 +240,32 @@ def adjustRom():
241240
def run_sprite_update():
242241
import threading
243242
done = threading.Event()
244-
top = Tk()
245-
top.withdraw()
246-
BackgroundTaskProgress(top, update_sprites, "Updating Sprites", lambda succesful, resultmessage: done.set())
243+
try:
244+
top = Tk()
245+
except:
246+
task = BackgroundTaskProgressNullWindow(update_sprites, lambda successful, resultmessage: done.set())
247+
else:
248+
top.withdraw()
249+
task = BackgroundTaskProgress(top, update_sprites, "Updating Sprites", lambda succesful, resultmessage: done.set())
247250
while not done.isSet():
248-
top.update()
249-
print("Done updating sprites")
251+
task.do_events()
252+
logging.info("Done updating sprites")
250253

251254

252255
def update_sprites(task, on_finish=None):
253256
resultmessage = ""
254257
successful = True
255258
sprite_dir = local_path("data", "sprites", "alttpr")
256259
os.makedirs(sprite_dir, exist_ok=True)
257-
260+
ctx = get_cert_none_ssl_context()
258261
def finished():
259262
task.close_window()
260263
if on_finish:
261264
on_finish(successful, resultmessage)
262265

263266
try:
264267
task.update_status("Downloading alttpr sprites list")
265-
with urlopen('https://alttpr.com/sprites') as response:
268+
with urlopen('https://alttpr.com/sprites', context=ctx) as response:
266269
sprites_arr = json.loads(response.read().decode("utf-8"))
267270
except Exception as e:
268271
resultmessage = "Error getting list of alttpr sprites. Sprites not updated.\n\n%s: %s" % (type(e).__name__, e)
@@ -289,7 +292,7 @@ def finished():
289292

290293
def dl(sprite_url, filename):
291294
target = os.path.join(sprite_dir, filename)
292-
with urlopen(sprite_url) as response, open(target, 'wb') as out:
295+
with urlopen(sprite_url, context=ctx) as response, open(target, 'wb') as out:
293296
shutil.copyfileobj(response, out)
294297

295298
def rem(sprite):
@@ -400,12 +403,39 @@ def __init__(self, parent, code_to_run, title, *args):
400403
def update_status(self, text):
401404
self.queue_event(lambda: self.label_var.set(text))
402405

406+
def do_events(self):
407+
self.parent.update()
408+
403409
# only call this in an event callback
404410
def close_window(self):
405411
self.stop()
406412
self.window.destroy()
407413

408414

415+
class BackgroundTaskProgressNullWindow(BackgroundTask):
416+
def __init__(self, code_to_run, *args):
417+
super().__init__(None, code_to_run, *args)
418+
419+
def process_queue(self):
420+
try:
421+
while True:
422+
if not self.running:
423+
return
424+
event = self.queue.get_nowait()
425+
event()
426+
except queue.Empty:
427+
pass
428+
429+
def do_events(self):
430+
self.process_queue()
431+
432+
def update_status(self, text):
433+
self.queue_event(lambda: logging.info(text))
434+
435+
def close_window(self):
436+
self.stop()
437+
438+
409439
def get_rom_frame(parent=None):
410440
romFrame = Frame(parent)
411441
baseRomLabel = Label(romFrame, text='LttP Base Rom: ')

MinecraftClient.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
# 1 or more digits followed by m or g, then optional b
1717
max_heap_re = re.compile(r"^\d+[mMgG][bB]?$")
18-
forge_version = "1.17.1-37.0.109"
18+
forge_version = "1.17.1-37.1.1"
1919

2020

2121
def prompt_yes_no(prompt):
@@ -35,12 +35,10 @@ def prompt_yes_no(prompt):
3535
def find_ap_randomizer_jar(forge_dir):
3636
mods_dir = os.path.join(forge_dir, 'mods')
3737
if os.path.isdir(mods_dir):
38-
ap_mod_re = re.compile(r"^aprandomizer-[\d\.]+\.jar$")
3938
for entry in os.scandir(mods_dir):
40-
match = ap_mod_re.match(entry.name)
41-
if match:
42-
logging.info(f"Found AP randomizer mod: {match.group()}")
43-
return match.group()
39+
if entry.name.startswith("aprandomizer") and entry.name.endswith(".jar"):
40+
logging.info(f"Found AP randomizer mod: {entry.name}")
41+
return entry.name
4442
return None
4543
else:
4644
os.mkdir(mods_dir)

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Currently, the following games are supported:
1313
* Timespinner
1414
* Super Metroid
1515
* Secret of Evermore
16+
* Final Fantasy
1617

1718
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
1819
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled

SNIClient.py

+1
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,7 @@ async def game_watcher(ctx: Context):
10481048
ctx.location_name_getter(item.location), itemOutPtr, len(ctx.items_received)))
10491049
await snes_flush_writes(ctx)
10501050

1051+
10511052
async def run_game(romfile):
10521053
auto_start = Utils.get_options()["lttp_options"].get("rom_start", True)
10531054
if auto_start is True:

WebHost.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from waitress import serve
1515

1616
from WebHostLib.models import db
17-
from WebHostLib.autolauncher import autohost
17+
from WebHostLib.autolauncher import autohost, autogen
1818
from WebHostLib.lttpsprites import update_sprites_lttp
1919
from WebHostLib.options import create as create_options_files
2020

@@ -45,6 +45,8 @@ def get_app():
4545
create_options_files()
4646
if app.config["SELFLAUNCH"]:
4747
autohost(app.config)
48+
if app.config["SELFGEN"]:
49+
autogen(app.config)
4850
if app.config["SELFHOST"]: # using WSGI, you just want to run get_app()
4951
if app.config["DEBUG"]:
5052
autohost(app.config)

WebHostLib/__init__.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@
2222
app.jinja_env.filters['any'] = any
2323
app.jinja_env.filters['all'] = all
2424

25-
app.config["SELFHOST"] = True
25+
app.config["SELFHOST"] = True # application process is in charge of running the websites
2626
app.config["GENERATORS"] = 8 # maximum concurrent world gens
27-
app.config["SELFLAUNCH"] = True
27+
app.config["SELFLAUNCH"] = True # application process is in charge of launching Rooms.
28+
app.config["SELFGEN"] = True # application process is in charge of scheduling Generations.
2829
app.config["DEBUG"] = False
2930
app.config["PORT"] = 80
3031
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
@@ -166,8 +167,9 @@ def host_room(room: UUID):
166167
if request.method == "POST":
167168
if room.owner == session["_id"]:
168169
cmd = request.form["cmd"]
169-
Command(room=room, commandtext=cmd)
170-
commit()
170+
if cmd:
171+
Command(room=room, commandtext=cmd)
172+
commit()
171173

172174
with db_session:
173175
room.last_activity = datetime.utcnow() # will trigger a spinup, if it's not already running

WebHostLib/autolauncher.py

+23-8
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,26 @@ def autohost(config: dict):
110110
def keep_running():
111111
try:
112112
with Locker("autohost"):
113+
while 1:
114+
time.sleep(0.1)
115+
with db_session:
116+
rooms = select(
117+
room for room in Room if
118+
room.last_activity >= datetime.utcnow() - timedelta(days=3))
119+
for room in rooms:
120+
launch_room(room, config)
121+
122+
except AlreadyRunningException:
123+
logging.info("Autohost reports as already running, not starting another.")
124+
125+
import threading
126+
threading.Thread(target=keep_running, name="AP_Autohost").start()
127+
128+
129+
def autogen(config: dict):
130+
def keep_running():
131+
try:
132+
with Locker("autogen"):
113133

114134
with multiprocessing.Pool(config["GENERATORS"], initializer=init_db,
115135
initargs=(config["PONY"],)) as generator_pool:
@@ -129,22 +149,17 @@ def keep_running():
129149
select(generation for generation in Generation if generation.state == STATE_ERROR).delete()
130150

131151
while 1:
132-
time.sleep(0.50)
152+
time.sleep(0.1)
133153
with db_session:
134-
rooms = select(
135-
room for room in Room if
136-
room.last_activity >= datetime.utcnow() - timedelta(days=3))
137-
for room in rooms:
138-
launch_room(room, config)
139154
to_start = select(
140155
generation for generation in Generation if generation.state == STATE_QUEUED)
141156
for generation in to_start:
142157
launch_generator(generator_pool, generation)
143158
except AlreadyRunningException:
144-
pass
159+
logging.info("Autogen reports as already running, not starting another.")
145160

146161
import threading
147-
threading.Thread(target=keep_running).start()
162+
threading.Thread(target=keep_running, name="AP_Autogen").start()
148163

149164

150165
multiworlds = {}

WebHostLib/lttpsprites.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ def update_sprites_lttp():
1010
from tkinter import Tk
1111
from LttPAdjuster import get_image_for_sprite
1212
from LttPAdjuster import BackgroundTaskProgress
13+
from LttPAdjuster import BackgroundTaskProgressNullWindow
1314
from LttPAdjuster import update_sprites
1415

1516
# Target directories
@@ -19,11 +20,15 @@ def update_sprites_lttp():
1920
os.makedirs(os.path.join(output_dir, "sprites"), exist_ok=True)
2021
# update sprites through gui.py's functions
2122
done = threading.Event()
22-
top = Tk()
23-
top.withdraw()
24-
BackgroundTaskProgress(top, update_sprites, "Updating Sprites", lambda succesful, resultmessage: done.set())
23+
try:
24+
top = Tk()
25+
except:
26+
task = BackgroundTaskProgressNullWindow(update_sprites, lambda successful, resultmessage: done.set())
27+
else:
28+
top.withdraw()
29+
task = BackgroundTaskProgress(top, update_sprites, "Updating Sprites", lambda succesful, resultmessage: done.set())
2530
while not done.isSet():
26-
top.update()
31+
task.do_events()
2732

2833
spriteData = []
2934

WebHostLib/static/assets/gameInfo/en_Final Fantasy.md

+2-5
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,9 @@ locations. So ,for example, Princess Sarah may have the CANOE instead of the LUT
1212
Pot or some armor. There are plenty of other things that can be randomized on our
1313
[main randomizer site](https://finalfantasyrandomizer.com/)
1414

15-
Some features are not currently supported by AP. A non-exhaustive list includes:
16-
- Shard Hunt
17-
- Deep Dungeon
18-
1915
## What Final Fantasy items can appear in other players' worlds?
20-
Currently, only progression items can appear in other players' worlds. Armor, Weapons and Consumable Items can not.
16+
All items can appear in other players worlds. This includes consumables, shards, weapons, armor and, of course,
17+
key items.
2118

2219
## What does another world's item look like in Final Fantasy
2320
All local and remote items appear the same. It will say that you received an item and then BOTH the client log and

WebHostLib/static/assets/gameInfo/en_Secret of Evermore.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ so the game is always able to be completed. However, because of the item shuffle
1010
areas before they would in the vanilla game. For example, the Windwalker (flying machine) is accessible as soon as any
1111
weapon is obtained.
1212

13-
Additional help can be found in the [guide](https://github.com/black-sliver/evermizer/blob/feat-mw/guide.md).
13+
Additional help can be found in the [guide](https://github.com/black-sliver/evermizer/blob/master/guide.md).
1414

1515
## What items and locations get shuffled?
1616
All gourds/chests/pots, boss drops and alchemists are shuffled. Alchemy ingredients, sniff spot items, call bead spells
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
window.addEventListener('load', () => {
2+
// Reload tracker every 15 seconds
3+
const url = window.location;
4+
setInterval(() => {
5+
const ajax = new XMLHttpRequest();
6+
ajax.onreadystatechange = () => {
7+
if (ajax.readyState !== 4) { return; }
8+
9+
// Create a fake DOM using the returned HTML
10+
const domParser = new DOMParser();
11+
const fakeDOM = domParser.parseFromString(ajax.responseText, 'text/html');
12+
13+
// Update item tracker
14+
document.getElementById('inventory-table').innerHTML = fakeDOM.getElementById('inventory-table').innerHTML;
15+
// Update only counters in the location-table
16+
let counters = document.getElementsByClassName('counter');
17+
const fakeCounters = fakeDOM.getElementsByClassName('counter');
18+
for (let i = 0; i < counters.length; i++) {
19+
counters[i].innerHTML = fakeCounters[i].innerHTML;
20+
}
21+
};
22+
ajax.open('GET', url);
23+
ajax.send();
24+
}, 15000)
25+
26+
// Collapsible advancement sections
27+
const categories = document.getElementsByClassName("location-category");
28+
for (let i = 0; i < categories.length; i++) {
29+
let hide_id = categories[i].id.split('-')[0];
30+
if (hide_id == 'Total') {
31+
continue;
32+
}
33+
categories[i].addEventListener('click', function() {
34+
// Toggle the advancement list
35+
document.getElementById(hide_id).classList.toggle("hide");
36+
// Change text of the header
37+
const tab_header = document.getElementById(hide_id+'-header').children[0];
38+
const orig_text = tab_header.innerHTML;
39+
let new_text;
40+
if (orig_text.includes("▼")) {
41+
new_text = orig_text.replace("▼", "▲");
42+
}
43+
else {
44+
new_text = orig_text.replace("▲", "▼");
45+
}
46+
tab_header.innerHTML = new_text;
47+
});
48+
}
49+
});

WebHostLib/static/assets/tutorial/archipelago/advanced_settings_en.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ that can be rolled by these settings. If a game can be rolled it **must** have a
7676

7777
Some options in Archipelago can be used by every game but must still be placed within the relevant game's section.
7878
Currently, these options are `start_inventory`, `start_hints`, `local_items`, `non_local_items`, `start_location_hints`,
79-
`exclude_locations`, and various [plando options](tutorial/archipelago/plando/en).
79+
`exclude_locations`, and various [plando options](/tutorial/archipelago/plando/en).
8080
* `start_inventory` will give any items defined here to you at the beginning of your game. The format for this must be
8181
the name as it appears in the game files and the amount you would like to start with. For example `Rupees(5): 6` which
8282
will give you 30 rupees.

0 commit comments

Comments
 (0)