Implement save system

Add to .gitignore
Add to default CLI args
Add to each page that needs it
* Rom Adjuster
* Seed
* Generation attempts
* Enemizer CLI path
* Base ROM
* Multiworld worlds
* Multiworld names
This commit is contained in:
Mike A. Trethewey
2020-02-08 19:01:15 -08:00
parent 2c91550e50
commit 03431f0b83
8 changed files with 64 additions and 45 deletions

2
.gitignore vendored
View File

@@ -18,5 +18,7 @@ EnemizerCLI/
RaceRom.py RaceRom.py
weights/ weights/
working_dirs.json
venv venv
test test

17
CLI.py
View File

@@ -23,6 +23,9 @@ def parse_arguments(argv, no_defaults=False):
def defval(value): def defval(value):
return value if not no_defaults else None return value if not no_defaults else None
# get working dirs
working_dirs = get_working_dirs()
# we need to know how many players we have first # we need to know how many players we have first
parser = argparse.ArgumentParser(add_help=False) parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('--multi', default=defval(1), type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--multi', default=defval(1), type=lambda value: min(max(int(value), 1), 255))
@@ -203,10 +206,10 @@ def parse_arguments(argv, no_defaults=False):
parser.add_argument('--openpyramid', default=defval(False), help='''\ parser.add_argument('--openpyramid', default=defval(False), help='''\
Pre-opens the pyramid hole, this removes the Agahnim 2 requirement for it Pre-opens the pyramid hole, this removes the Agahnim 2 requirement for it
''', action='store_true') ''', action='store_true')
parser.add_argument('--rom', default=defval('Zelda no Densetsu - Kamigami no Triforce (Japan).sfc'), help='Path to an ALttP JAP(1.0) rom to use as a base.') parser.add_argument('--rom', default=defval(working_dirs["rom.base"]), help='Path to an ALttP JAP(1.0) rom to use as a base.')
parser.add_argument('--loglevel', default=defval('info'), const='info', nargs='?', choices=['error', 'info', 'warning', 'debug'], help='Select level of logging for output.') parser.add_argument('--loglevel', default=defval('info'), const='info', nargs='?', choices=['error', 'info', 'warning', 'debug'], help='Select level of logging for output.')
parser.add_argument('--seed', help='Define seed number to generate.', type=int) parser.add_argument('--seed', default=defval(int(working_dirs["gen.seed"]) if working_dirs["gen.seed"] is not "" and working_dirs["gen.seed"] is not None else None), help='Define seed number to generate.', type=int)
parser.add_argument('--count', help='''\ parser.add_argument('--count', default=defval(int(working_dirs["gen.count"])), help='''\
Use to batch generate multiple seeds with same settings. Use to batch generate multiple seeds with same settings.
If --seed is provided, it will be used for the first seed, then If --seed is provided, it will be used for the first seed, then
used to derive the next seed (i.e. generating 10 seeds with used to derive the next seed (i.e. generating 10 seeds with
@@ -271,7 +274,7 @@ def parse_arguments(argv, no_defaults=False):
for VT site integration, do not use otherwise. for VT site integration, do not use otherwise.
''') ''')
parser.add_argument('--skip_playthrough', action='store_true', default=defval(False)) parser.add_argument('--skip_playthrough', action='store_true', default=defval(False))
parser.add_argument('--enemizercli', default=defval('EnemizerCLI/EnemizerCLI.Core')) parser.add_argument('--enemizercli', default=defval(working_dirs["enemizer.cli"]))
parser.add_argument('--shufflebosses', default=defval('none'), choices=['none', 'basic', 'normal', 'chaos']) parser.add_argument('--shufflebosses', default=defval('none'), choices=['none', 'basic', 'normal', 'chaos'])
parser.add_argument('--shuffleenemies', default=defval('none'), choices=['none', 'shuffled', 'chaos']) parser.add_argument('--shuffleenemies', default=defval('none'), choices=['none', 'shuffled', 'chaos'])
parser.add_argument('--enemy_health', default=defval('default'), choices=['default', 'easy', 'normal', 'hard', 'expert']) parser.add_argument('--enemy_health', default=defval('default'), choices=['default', 'easy', 'normal', 'hard', 'expert'])
@@ -279,10 +282,10 @@ def parse_arguments(argv, no_defaults=False):
parser.add_argument('--shufflepots', default=defval(False), action='store_true') parser.add_argument('--shufflepots', default=defval(False), action='store_true')
parser.add_argument('--beemizer', default=defval(0), type=lambda value: min(max(int(value), 0), 4)) parser.add_argument('--beemizer', default=defval(0), type=lambda value: min(max(int(value), 0), 4))
parser.add_argument('--remote_items', default=defval(False), action='store_true') parser.add_argument('--remote_items', default=defval(False), action='store_true')
parser.add_argument('--multi', default=defval(1), type=lambda value: min(max(int(value), 1), 255)) parser.add_argument('--multi', default=defval(working_dirs["multi.worlds"]), type=lambda value: min(max(int(value), 1), 255))
parser.add_argument('--names', default=defval('')) parser.add_argument('--names', default=defval(working_dirs["multi.names"]))
parser.add_argument('--teams', default=defval(1), type=lambda value: max(int(value), 1)) parser.add_argument('--teams', default=defval(1), type=lambda value: max(int(value), 1))
parser.add_argument('--outputpath') parser.add_argument('--outputpath', default=defval(working_dirs["outputpath"]))
parser.add_argument('--race', default=defval(False), action='store_true') parser.add_argument('--race', default=defval(False), action='store_true')
parser.add_argument('--outputname') parser.add_argument('--outputname')

32
Gui.py
View File

@@ -6,11 +6,13 @@ import logging
import random import random
import os import os
import shutil import shutil
import sys
from tkinter import Checkbutton, OptionMenu, Toplevel, LabelFrame, PhotoImage, Tk, LEFT, RIGHT, BOTTOM, TOP, StringVar, IntVar, Frame, Label, W, E, X, BOTH, Entry, Spinbox, Button, filedialog, messagebox, ttk from tkinter import Checkbutton, OptionMenu, Toplevel, LabelFrame, PhotoImage, Tk, LEFT, RIGHT, BOTTOM, TOP, StringVar, IntVar, Frame, Label, W, E, X, BOTH, Entry, Spinbox, Button, filedialog, messagebox, ttk
from urllib.parse import urlparse from urllib.parse import urlparse
from urllib.request import urlopen from urllib.request import urlopen
from AdjusterMain import adjust from AdjusterMain import adjust
from CLI import get_working_dirs
from DungeonRandomizer import parse_arguments from DungeonRandomizer import parse_arguments
from gui.adjust.overview import adjust_page from gui.adjust.overview import adjust_page
from gui.custom.overview import custom_page from gui.custom.overview import custom_page
@@ -30,12 +32,34 @@ from Utils import is_bundled, local_path, output_path, open_file
def guiMain(args=None): def guiMain(args=None):
# save working dirs
def save_working_dirs():
user_resources_path = os.path.join(".","resources","user")
working_dirs_path = os.path.join(user_resources_path)
if not os.path.exists(working_dirs_path):
os.makedirs(working_dirs_path)
with open(os.path.join(working_dirs_path,"working_dirs.json"),"w+") as f:
f.write(json.dumps(self.working_dirs,indent=2))
os.chmod(os.path.join(working_dirs_path,"working_dirs.json"),0o755)
# routine for exiting the app
def guiExit():
save_working_dirs()
sys.exit(0)
# make main window
# add program title & version number
mainWindow = Tk() mainWindow = Tk()
self = mainWindow self = mainWindow
mainWindow.wm_title("Door Shuffle %s" % ESVersion) mainWindow.wm_title("Door Shuffle %s" % ESVersion)
mainWindow.protocol("WM_DELETE_WINDOW",guiExit) # intercept when user clicks the X
# set program icon
set_icon(mainWindow) set_icon(mainWindow)
# get working dirs
self.working_dirs = get_working_dirs()
notebook = ttk.Notebook(self) notebook = ttk.Notebook(self)
self.randomizerWindow = ttk.Frame(notebook) self.randomizerWindow = ttk.Frame(notebook)
self.adjustWindow = ttk.Frame(notebook) self.adjustWindow = ttk.Frame(notebook)
@@ -67,7 +91,7 @@ def guiMain(args=None):
self.randomizerNotebook.add(self.entrandoWindow, text="Entrances") self.randomizerNotebook.add(self.entrandoWindow, text="Entrances")
# Enemizer # Enemizer
self.enemizerWindow = enemizer_page(self.randomizerNotebook) self.enemizerWindow,self.working_dirs = enemizer_page(self.randomizerNotebook,self.working_dirs)
self.randomizerNotebook.add(self.enemizerWindow, text="Enemizer") self.randomizerNotebook.add(self.enemizerWindow, text="Enemizer")
# Dungeon Shuffle # Dungeon Shuffle
@@ -75,7 +99,7 @@ def guiMain(args=None):
self.randomizerNotebook.add(self.dungeonRandoWindow, text="Dungeon Shuffle") self.randomizerNotebook.add(self.dungeonRandoWindow, text="Dungeon Shuffle")
# Multiworld # Multiworld
self.multiworldWindow = multiworld_page(self.randomizerNotebook) self.multiworldWindow,self.working_dirs = multiworld_page(self.randomizerNotebook,self.working_dirs)
self.randomizerNotebook.add(self.multiworldWindow, text="Multiworld") self.randomizerNotebook.add(self.multiworldWindow, text="Multiworld")
# Game Options # Game Options
@@ -83,7 +107,7 @@ def guiMain(args=None):
self.randomizerNotebook.add(self.gameOptionsWindow, text="Game Options") self.randomizerNotebook.add(self.gameOptionsWindow, text="Game Options")
# Generation Setup # Generation Setup
self.generationSetupWindow = generation_page(self.randomizerNotebook) self.generationSetupWindow,self.working_dirs = generation_page(self.randomizerNotebook,self.working_dirs)
self.randomizerNotebook.add(self.generationSetupWindow, text="Generation Setup") self.randomizerNotebook.add(self.generationSetupWindow, text="Generation Setup")
# add randomizer notebook to main window # add randomizer notebook to main window
@@ -95,7 +119,7 @@ def guiMain(args=None):
self.farBottomFrame.pack(side=BOTTOM, fill=X, padx=5, pady=5) self.farBottomFrame.pack(side=BOTTOM, fill=X, padx=5, pady=5)
# Adjuster Controls # Adjuster Controls
self.adjustContent = adjust_page(self,self.adjustWindow) self.adjustContent,self.working_dirs = adjust_page(self,self.adjustWindow,self.working_dirs)
# self.adjustContent,self.working_dirs = adjust_page(self,self.adjustWindow,self.working_dirs) # self.adjustContent,self.working_dirs = adjust_page(self,self.adjustWindow,self.working_dirs)
self.adjustContent.pack(side=TOP, fill=BOTH, expand=True) self.adjustContent.pack(side=TOP, fill=BOTH, expand=True)

View File

@@ -4,7 +4,7 @@ from argparse import Namespace
from classes.SpriteSelector import SpriteSelector from classes.SpriteSelector import SpriteSelector
import logging import logging
def adjust_page(top,parent):#,working_dirs): def adjust_page(top,parent,working_dirs):
self = ttk.Frame(parent) self = ttk.Frame(parent)
# Disable BGM # Disable BGM
@@ -101,14 +101,13 @@ def adjust_page(top,parent):#,working_dirs):
adjustRomFrame = Frame(bottomAdjustFrame) adjustRomFrame = Frame(bottomAdjustFrame)
adjustRomLabel = Label(adjustRomFrame, text='Rom to adjust: ') adjustRomLabel = Label(adjustRomFrame, text='Rom to adjust: ')
self.romVar2 = StringVar() self.romVar2 = StringVar(value=working_dirs["adjust.rom"])
# romVar2 = StringVar(value=working_dirs["adjust.rom"])
romEntry2 = Entry(adjustRomFrame, textvariable=self.romVar2) romEntry2 = Entry(adjustRomFrame, textvariable=self.romVar2)
def RomSelect2(): def RomSelect2():
rom = filedialog.askopenfilename(filetypes=[("Rom Files", (".sfc", ".smc")), ("All Files", "*")]) rom = filedialog.askopenfilename(filetypes=[("Rom Files", (".sfc", ".smc")), ("All Files", "*")])
if rom: if rom:
# working_dirs["adjust.rom"] = rom working_dirs["adjust.rom"] = rom
self.romVar2.set(rom) self.romVar2.set(rom)
romSelectButton2 = Button(adjustRomFrame, text='Select Rom', command=RomSelect2) romSelectButton2 = Button(adjustRomFrame, text='Select Rom', command=RomSelect2)
@@ -140,4 +139,4 @@ def adjust_page(top,parent):#,working_dirs):
adjustButton = Button(bottomAdjustFrame, text='Adjust Rom', command=adjustRom) adjustButton = Button(bottomAdjustFrame, text='Adjust Rom', command=adjustRom)
adjustButton.pack(side=BOTTOM, padx=(5, 0)) adjustButton.pack(side=BOTTOM, padx=(5, 0))
return self#,working_dirs return self,working_dirs

View File

@@ -8,26 +8,23 @@ from Main import main
from Utils import local_path, output_path, open_file from Utils import local_path, output_path, open_file
def bottom_frame(self,parent,args=None): def bottom_frame(self,parent,args=None):
# working_dirs = get_working_dirs()
self = ttk.Frame(parent) self = ttk.Frame(parent)
seedCountFrame = Frame(self) seedCountFrame = Frame(self)
seedCountFrame.pack() seedCountFrame.pack()
## Seed # ## Seed #
seedLabel = Label(self, text='Seed #') seedLabel = Label(self, text='Seed #')
# self.seedVar = StringVar(value=parent.working_dirs["gen.seed"]) savedSeed = parent.working_dirs["gen.seed"]
self.seedVar = StringVar() self.seedVar = StringVar(value=savedSeed)
def saveSeed(caller,_,mode): def saveSeed(caller,_,mode):
pass savedSeed = self.seedVar.get()
# parent.working_dirs["gen.seed"] = self.seedVar.get() parent.working_dirs["gen.seed"] = int(savedSeed) if savedSeed.isdigit() else None
self.seedVar.trace_add("write",saveSeed) self.seedVar.trace_add("write",saveSeed)
seedEntry = Entry(self, width=15, textvariable=self.seedVar) seedEntry = Entry(self, width=15, textvariable=self.seedVar)
seedLabel.pack(side=LEFT) seedLabel.pack(side=LEFT)
seedEntry.pack(side=LEFT) seedEntry.pack(side=LEFT)
## Number of Generation attempts ## Number of Generation attempts
countLabel = Label(self, text='Count') countLabel = Label(self, text='Count')
# self.countVar = StringVar(value=working_dirs["gen.count"]) self.countVar = StringVar(value=parent.working_dirs["gen.count"])
self.countVar = StringVar()
countSpinbox = Spinbox(self, from_=1, to=100, width=5, textvariable=self.countVar) countSpinbox = Spinbox(self, from_=1, to=100, width=5, textvariable=self.countVar)
countLabel.pack(side=LEFT) countLabel.pack(side=LEFT)
countSpinbox.pack(side=LEFT) countSpinbox.pack(side=LEFT)
@@ -118,8 +115,7 @@ def bottom_frame(self,parent,args=None):
if args and args.outputpath: if args and args.outputpath:
open_file(output_path(args.outputpath)) open_file(output_path(args.outputpath))
else: else:
open_file(output_path(".")) open_file(output_path(parent.working_dirs["outputpath"]))
# open_file(output_path(working_dirs["outputpath"]))
openOutputButton = Button(self, text='Open Output Directory', command=open_output) openOutputButton = Button(self, text='Open Output Directory', command=open_output)
openOutputButton.pack(side=RIGHT) openOutputButton.pack(side=RIGHT)

View File

@@ -1,7 +1,7 @@
import os import os
from tkinter import ttk, filedialog, IntVar, StringVar, Button, Checkbutton, Entry, Frame, Label, LabelFrame, OptionMenu, E, W, LEFT, RIGHT, X from tkinter import ttk, filedialog, IntVar, StringVar, Button, Checkbutton, Entry, Frame, Label, LabelFrame, OptionMenu, E, W, LEFT, RIGHT, X
def enemizer_page(parent):#,working_dirs): def enemizer_page(parent,working_dirs):
self = ttk.Frame(parent) self = ttk.Frame(parent)
# Enemizer # Enemizer
@@ -16,10 +16,9 @@ def enemizer_page(parent):#,working_dirs):
enemizerPathFrame.grid(row=0, column=0, columnspan=3, sticky=W+E) enemizerPathFrame.grid(row=0, column=0, columnspan=3, sticky=W+E)
enemizerCLIlabel = Label(enemizerPathFrame, text="EnemizerCLI path: ") enemizerCLIlabel = Label(enemizerPathFrame, text="EnemizerCLI path: ")
enemizerCLIlabel.pack(side=LEFT) enemizerCLIlabel.pack(side=LEFT)
self.enemizerCLIpathVar = StringVar() self.enemizerCLIpathVar = StringVar(value=working_dirs["enemizer.cli"])
def saveEnemizerPath(caller,_,mode): def saveEnemizerPath(caller,_,mode):
pass working_dirs["enemizer.cli"] = self.enemizerCLIpathVar.get()
#working_dirs["enemizer.cli"] = self.enemizerCLIpathVar.get()
self.enemizerCLIpathVar.trace_add("write",saveEnemizerPath) self.enemizerCLIpathVar.trace_add("write",saveEnemizerPath)
enemizerCLIpathEntry = Entry(enemizerPathFrame, textvariable=self.enemizerCLIpathVar) enemizerCLIpathEntry = Entry(enemizerPathFrame, textvariable=self.enemizerCLIpathVar)
enemizerCLIpathEntry.pack(side=LEFT, fill=X, expand=True) enemizerCLIpathEntry.pack(side=LEFT, fill=X, expand=True)
@@ -27,7 +26,7 @@ def enemizer_page(parent):#,working_dirs):
path = filedialog.askopenfilename(filetypes=[("EnemizerCLI executable", "*EnemizerCLI*")], initialdir=os.path.join(".")) path = filedialog.askopenfilename(filetypes=[("EnemizerCLI executable", "*EnemizerCLI*")], initialdir=os.path.join("."))
if path: if path:
self.enemizerCLIpathVar.set(path) self.enemizerCLIpathVar.set(path)
#working_dirs["enemizer.cli"] = path working_dirs["enemizer.cli"] = path
enemizerCLIbrowseButton = Button(enemizerPathFrame, text='...', command=EnemizerSelectPath) enemizerCLIbrowseButton = Button(enemizerPathFrame, text='...', command=EnemizerSelectPath)
enemizerCLIbrowseButton.pack(side=LEFT) enemizerCLIbrowseButton.pack(side=LEFT)
@@ -76,4 +75,4 @@ def enemizer_page(parent):#,working_dirs):
enemizerHealthOption = OptionMenu(enemizerHealthFrame, self.enemizerHealthVar, 'default', 'easy', 'normal', 'hard', 'expert') enemizerHealthOption = OptionMenu(enemizerHealthFrame, self.enemizerHealthVar, 'default', 'easy', 'normal', 'hard', 'expert')
enemizerHealthOption.pack(side=LEFT) enemizerHealthOption.pack(side=LEFT)
return self#,working_dirs return self,working_dirs

View File

@@ -1,7 +1,7 @@
import os import os
from tkinter import ttk, filedialog, IntVar, StringVar, Button, Checkbutton, Entry, Frame, Label, E, W, LEFT, RIGHT, X from tkinter import ttk, filedialog, IntVar, StringVar, Button, Checkbutton, Entry, Frame, Label, E, W, LEFT, RIGHT, X
def generation_page(parent):#,working_dirs): def generation_page(parent,working_dirs):
self = ttk.Frame(parent) self = ttk.Frame(parent)
# Generation Setup options # Generation Setup options
@@ -22,11 +22,10 @@ def generation_page(parent):#,working_dirs):
baseRomLabel = Label(baseRomFrame, text='Base Rom: ') baseRomLabel = Label(baseRomFrame, text='Base Rom: ')
self.romVar = StringVar() self.romVar = StringVar()
def saveBaseRom(caller,_,mode): def saveBaseRom(caller,_,mode):
pass working_dirs["rom.base"] = self.romVar.get()
# working_dirs["rom.base"] = self.romVar.get()
self.romVar.trace_add("write",saveBaseRom) self.romVar.trace_add("write",saveBaseRom)
romEntry = Entry(baseRomFrame, textvariable=self.romVar) romEntry = Entry(baseRomFrame, textvariable=self.romVar)
# self.romVar.set(working_dirs["rom.base"]) self.romVar.set(working_dirs["rom.base"])
def RomSelect(): def RomSelect():
rom = filedialog.askopenfilename(filetypes=[("Rom Files", (".sfc", ".smc")), ("All Files", "*")], initialdir=os.path.join(".")) rom = filedialog.askopenfilename(filetypes=[("Rom Files", (".sfc", ".smc")), ("All Files", "*")], initialdir=os.path.join("."))
@@ -38,4 +37,4 @@ def generation_page(parent):#,working_dirs):
romSelectButton.pack(side=LEFT) romSelectButton.pack(side=LEFT)
baseRomFrame.pack(fill=X, expand=True) baseRomFrame.pack(fill=X, expand=True)
return self#,working_dirs return self,working_dirs

View File

@@ -1,28 +1,25 @@
from tkinter import ttk, StringVar, Entry, Frame, Label, Spinbox, E, W, LEFT, RIGHT from tkinter import ttk, StringVar, Entry, Frame, Label, Spinbox, E, W, LEFT, RIGHT
def multiworld_page(parent):#,working_dirs): def multiworld_page(parent,working_dirs):
self = ttk.Frame(parent) self = ttk.Frame(parent)
# Multiworld # Multiworld
multiFrame = Frame(self) multiFrame = Frame(self)
## Number of Worlds ## Number of Worlds
worldLabel = Label(multiFrame, text='Worlds') worldLabel = Label(multiFrame, text='Worlds')
# self.worldVar = StringVar(value=working_dirs["multi.worlds"]) self.worldVar = StringVar(value=working_dirs["multi.worlds"])
self.worldVar = StringVar(value="1")
worldSpinbox = Spinbox(multiFrame, from_=1, to=100, width=5, textvariable=self.worldVar) worldSpinbox = Spinbox(multiFrame, from_=1, to=100, width=5, textvariable=self.worldVar)
worldLabel.pack(side=LEFT) worldLabel.pack(side=LEFT)
worldSpinbox.pack(side=LEFT) worldSpinbox.pack(side=LEFT)
## List of Player Names ## List of Player Names
namesLabel = Label(multiFrame, text='Player names') namesLabel = Label(multiFrame, text='Player names')
self.namesVar = StringVar() self.namesVar = StringVar(value=working_dirs["multi.names"])
# self.namesVar = StringVar(value=working_dirs["multi.names"])
def saveMultiNames(caller,_,mode): def saveMultiNames(caller,_,mode):
pass working_dirs["multi.names"] = self.namesVar.get()
#working_dirs["multi.names"] = self.namesVar.get()
self.namesVar.trace_add("write",saveMultiNames) self.namesVar.trace_add("write",saveMultiNames)
namesEntry = Entry(multiFrame, textvariable=self.namesVar) namesEntry = Entry(multiFrame, textvariable=self.namesVar)
namesLabel.pack(side=LEFT) namesLabel.pack(side=LEFT)
namesEntry.pack(side=LEFT) namesEntry.pack(side=LEFT)
multiFrame.pack(anchor=W) multiFrame.pack(anchor=W)
return self#,working_dirs return self,working_dirs