Files
cobblemon/utilityscripts/public_spawns_to_json.py
T

262 lines
12 KiB
Python

import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import pandas as pd
import cobblemon_spawn_csv_to_json
groups = ["basic", "boss", "fossil"]
contexts = ["grounded", "submerged", "seafloor", "surface"]
buckets = ["common", "uncommon", "rare", "ultra-rare"]
folders = set()
file_names = set()
process_button = None
def process_file(input_file, output_directory, filters, pokemon_number_start, pokemon_number_end):
# Filter the filters to only include options that have been toggled on
filtered_filters = {}
for category, options in filters.items():
filtered_filters[category] = [name for name, var in options.items() if var.get() == 1]
# Apply the filters to the groups, contexts, and buckets
cobblemon_spawn_csv_to_json.ui_init_filters(pokemon_number_start, pokemon_number_end,
included_grps=filtered_filters['included_groups'],
known_cntxts=filtered_filters['known_contexts'],
bucket_map=filtered_filters['bucket_mapping'],
cstm_files=filtered_filters['file_name'],
cstm_dirs=filtered_filters['folder'])
if not validate_number_range(pokemon_number_start, pokemon_number_end):
messagebox.showinfo("Invalid Pokémon number range. Please provide a valid range.")
return
cobblemon_spawn_csv_to_json.main(output_directory, input_file)
def validate_number_range(a, b):
return 0 <= a <= b
def select_input_file(input_file_var, input_file_label, output_dir_var, pokemon_number_start_var,
pokemon_number_end_var, filter_vars, frame3, folder_var, file_name_var):
global groups, contexts, buckets, process_button, folders, file_names
filepath = filedialog.askopenfilename()
if filepath:
input_file_var.set(filepath)
input_file_label.config(text=f"Selected file: {filepath}", foreground="black")
if filepath and output_dir_var.get():
process_button['state'] = 'normal'
# Display a loading message
loading_label = ttk.Label(frame3, text="Loading...")
loading_label.grid(column=0, row=0, pady=5)
# Disable all input options on frame3
for child in frame3.winfo_children():
if isinstance(child, (ttk.Button, ttk.Entry, ttk.Checkbutton, ttk.Combobox)):
child.config(state='disabled')
frame3.update()
# if the file is an excel file, read it with pandas
if input_file_var.get().endswith('.xlsx'):
csv_df = pd.read_excel(input_file_var.get(), engine='openpyxl',
dtype={'Pokémon': str, 'Entry': str, 'No.': int, 'Folder': str, 'File Name': str})
# if the file is a csv file, read it with pandas
elif input_file_var.get().endswith('.csv'):
csv_df = pd.read_csv(input_file_var.get(), dtype={'Pokémon': str, 'Entry': str, 'No.': int, 'Folder': str, 'File Name': str})
else:
# show message
messagebox.showinfo("Invalid file format. Please provide a valid excel or csv file")
return
# find all unique values in the 'group' column
groups = csv_df['Group'].unique()
groups = [group if group == group else '' for group in groups]
# find all unique values in the 'context' column
contexts = csv_df['Context'].unique()
contexts = [context if context == context else '' for context in contexts]
# find all unique values in the 'bucket' column
buckets = csv_df['Bucket'].unique()
buckets = [bucket if bucket == bucket else '' for bucket in buckets]
# Parse the Folder and File Name columns
folders = set(csv_df['Folder'].unique())
folders = {folder if folder == folder else "" for folder in folders}
folder_var.set(next(iter(folders), ""))
file_names = set(csv_df['File Name'].unique())
file_names = {file_name if file_name == file_name else "" for file_name in file_names}
file_name_var.set(next(iter(file_names), ""))
update_filter_ui(filter_vars, frame3, input_file_var, output_dir_var, pokemon_number_start_var,
pokemon_number_end_var, folder_var, file_name_var)
# Remove the loading message
loading_label.destroy()
if output_dir_var.get() and input_file_var.get():
process_button['state'] = 'normal'
def select_output_directory(output_dir_var, output_dir_label, input_file_var):
global process_button
directory = filedialog.askdirectory()
if directory:
output_dir_var.set(directory)
output_dir_label.config(text=f"Output directory: {directory}", foreground="black")
if input_file_var.get() and directory:
process_button['state'] = 'normal'
def toggle_filter(filter_var, button):
if filter_var.get():
filter_var.set(False)
button.config(style='Deactivated.TButton')
else:
filter_var.set(True)
button.config(style='Active.TButton')
def create_filter_toggle_buttons(filter_category, filter_vars, start_row, parent_frame, max_columns=5):
row, col = start_row, 0
for name, var in filter_vars[filter_category].items():
# Define btn before the lambda function
btn = ttk.Button(parent_frame, text=name, style='Active.TButton')
btn.config(command=lambda var1=var, btn1=btn: toggle_filter(var1, btn1))
btn.grid(column=col, row=row, sticky=tk.W, pady=2, padx=2)
col += 1
if col >= max_columns:
col = 0
row += 1
return row
def setup_ui(root):
# Variables for storing UI inputs
input_file_var = tk.StringVar()
output_dir_var = tk.StringVar()
pokemon_number_start_var = tk.IntVar(value=0) # Default start of dex range
pokemon_number_end_var = tk.IntVar(value=1111) # Default end of dex range
folder_var = tk.StringVar()
file_name_var = tk.StringVar()
frame = ttk.Frame(root, padding="10")
frame.grid()
ttk.Separator(root, orient='horizontal').grid(row=20, column=0, sticky="ew", pady=5)
frame3 = ttk.Frame(root, padding="10")
frame3.grid(sticky="wens")
filter_vars, frame3 = setup_filter_ui(frame3, input_file_var, output_dir_var,
pokemon_number_start_var, pokemon_number_end_var, folder_var, file_name_var)
input_file_label, output_dir_label = setup_file_selection_ui(frame, input_file_var, output_dir_var,
pokemon_number_start_var, pokemon_number_end_var,
filter_vars, frame3, folder_var, file_name_var)
# Display a warning popup to remind the user to backup their spawn.json files before they run the script
messagebox.showwarning("Warning",
"Please ensure you have backed up your spawn.json files before running this script!\n"
"This script will OVERWRITE the spawn.json files in the specified output directory with the new data.")
root.mainloop()
def setup_file_selection_ui(frame, input_file_var, output_dir_var, pokemon_number_start_var,
pokemon_number_end_var, filter_vars, frame3, folder_var, file_name_var):
input_file_button = ttk.Button(frame, text="Select Input File",
command=lambda: select_input_file(input_file_var, input_file_label,
output_dir_var,
pokemon_number_start_var, pokemon_number_end_var,
filter_vars, frame3, folder_var, file_name_var))
input_file_button.grid(column=0, row=0, pady=5)
input_file_label = ttk.Label(frame, text="No file selected", foreground='red')
input_file_label.grid(column=0, row=1, pady=5)
output_dir_button = ttk.Button(frame, text="Select Output Directory",
command=lambda: select_output_directory(output_dir_var, output_dir_label,
input_file_var))
output_dir_button.grid(column=0, row=2, pady=5)
output_dir_label = ttk.Label(frame, text="No directory selected", foreground='red')
output_dir_label.grid(column=0, row=3, pady=5)
return input_file_label, output_dir_label
def update_filter_ui(filter_vars, frame3, input_file_var, output_dir_var, pokemon_number_start_var,
pokemon_number_end_var, folder_var, file_name_var):
global folders, file_names
# Clear the current filter UI
for widget in frame3.winfo_children():
widget.destroy()
# Update the filter_vars based on the new unique values
filter_vars['included_groups'] = {name: tk.IntVar(value=1) for name in groups}
filter_vars['known_contexts'] = {name: tk.IntVar(value=1) for name in contexts}
filter_vars['bucket_mapping'] = {name: tk.IntVar(value=1) for name in buckets}
filter_vars['folder'] = {name: tk.IntVar(value=1) for name in folders}
filter_vars['file_name'] = {name: tk.IntVar(value=1) for name in file_names}
# Recreate the filter UI
setup_filter_ui(frame3, input_file_var, output_dir_var, pokemon_number_start_var, pokemon_number_end_var, folder_var, file_name_var)
def setup_filter_ui(frame3, input_file_var, output_dir_var, pokemon_number_start_var, pokemon_number_end_var, folder_var, file_name_var):
global process_button
# Label and entry for specifying the range of Pokémon numbers to include
ttk.Label(frame3, text="Pokédex Number Range:").grid(column=0, row=0, columnspan=5, pady=5)
ttk.Entry(frame3, textvariable=pokemon_number_start_var, width=5).grid(column=1, row=1, pady=5)
ttk.Label(frame3, text="-").grid(column=2, row=1, pady=5)
ttk.Entry(frame3, textvariable=pokemon_number_end_var, width=5).grid(column=3, row=1, pady=5)
filter_vars = {
'included_groups': {name: tk.IntVar(value=1) for name in groups},
'known_contexts': {name: tk.IntVar(value=1) for name in contexts},
'bucket_mapping': {name: tk.IntVar(value=1) for name in buckets},
'folder': {name: tk.IntVar(value=1) for name in folders},
'file_name': {name: tk.IntVar(value=1) for name in file_names},
}
# Custom styles for toggle buttons
style = ttk.Style()
style.configure('Deactivated.TButton', background='gray', foreground='gray', font=('Helvetica', 10, 'overstrike'))
style.configure('Active.TButton', background='#4CAF50', foreground='black', font=('Helvetica', 10))
# Organize filters into sections and create toggle buttons for each
filter_sections = [
('included_groups', "Groups"),
('known_contexts', "Contexts"),
('bucket_mapping', "Buckets"),
('folder', "Folders"),
('file_name', "File Names"),
]
current_row = 2
ttk.Label(frame3, text="Toggle the following filters to exclude certain "
"categories of cobblemon:").grid(column=0, row=current_row, columnspan=5, pady=5)
current_row += 1
(ttk.Label(frame3, text="An empty button means that you have some empty fields in your spreadsheet:").
grid(column=0, row=current_row, columnspan=5, pady=5))
current_row += 1
for category, label_text in filter_sections:
ttk.Label(frame3, text=f"{label_text}:").grid(column=0, row=current_row + 1, sticky=tk.W, pady=2)
current_row += 1
current_row = create_filter_toggle_buttons(category, filter_vars, current_row + 2, parent_frame=frame3)
ttk.Separator(frame3, orient='horizontal').grid(row=current_row + 1, column=0, columnspan=5, sticky="ew", pady=5)
current_row += 1
process_button = ttk.Button(frame3, text="Execute Spawns Writer",
command=lambda: process_file(input_file_var.get(), output_dir_var.get(), filter_vars,
pokemon_number_start_var.get(),
pokemon_number_end_var.get()),
state='disabled')
process_button.grid(column=0, row=current_row + 1, columnspan=5, sticky=(tk.W, tk.E), pady=5)
return filter_vars, frame3
if __name__ == "__main__":
root = tk.Tk()
root.title("Cobblemon Spawn Data Converter")
setup_ui(root)