Skip to content

Commit 42ea278

Browse files
authored
Merge branch 'main' into ItemValue-Fixes
2 parents c2f095a + 5d067ec commit 42ea278

File tree

14 files changed

+637
-66
lines changed

14 files changed

+637
-66
lines changed

schemas/Manual.items.schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
},
2929
"category": {
3030
"description": "(Optional) A list of categories to be applied to this item.",
31-
"type": "array",
31+
"type": ["string", "array"],
3232
"items": {
3333
"type": "string"
3434
},

schemas/Manual.locations.schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
},
2929
"category": {
3030
"description": "(Optional) A list of categories to be applied to this location.",
31-
"type": "array",
31+
"type": ["string", "array"],
3232
"items": {
3333
"type": "string"
3434
},

schemas/Manual.options.schema.json

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"$id": "https://raw.githubusercontent.com/ManualForArchipelago/Manual/main/schemas/Manual.options.schema.json",
4+
"description": "Schema for Manual's options.json",
5+
"type": "object",
6+
"properties": {
7+
"$schema": {
8+
"description": "The schema to verify this document against.",
9+
"type":"string"
10+
11+
},
12+
"core": {
13+
"description": "Dictionary of the Modifications of Core Options of Manual",
14+
"type": "object",
15+
"patternProperties": {
16+
"^_.*$": {
17+
"description": "A commented out Option Modification",
18+
"$ref": "#/definitions/OptionCore"
19+
},
20+
"^.*$": {
21+
"description": "A Modification of a Core Option of Manual",
22+
"$ref": "#/definitions/OptionCore"
23+
}
24+
}
25+
},
26+
"user": {
27+
"description": "Dictionary of options for this apworld",
28+
"type": "object",
29+
"patternProperties": {
30+
"^_.*$": {
31+
"description": "A commented out Option",
32+
"allOf": [{"$ref": "#/definitions/OptionBase"}],
33+
"properties": {
34+
"type": {"$ref": "#/definitions/Type"}
35+
}
36+
},
37+
"^.*$": {
38+
"description": "An Option for your World, the possible properties depend on the type of option you set in \"type\"\nToggle: \"default\"* \n Let the player choose between yes or no \nChoice: \"values\"*, \"aliases\", \"default\" and \"allow_custom_value\" \n Let the player pick from a list of values \nRange: \"range_start\", \"range_end\", \"default\" and an \"values\"\nAllow the player to specify a number between 'start' and 'end'",
39+
"$ref": "#/definitions/OptionUser"
40+
}
41+
}
42+
},
43+
"_comment": {"$ref": "#/definitions/comment"}
44+
},
45+
"definitions": {
46+
"OptionBase": {
47+
"$comment": "The basic properties of an Option that are safe to modify",
48+
"type": "object",
49+
"properties": {
50+
"display_name": {
51+
"description": "(Optional) The name shown in the spoiler logs and on the website options pages",
52+
"type": "string"
53+
},
54+
"description": {
55+
"description": "(Optional) A long description of what this option is for, as shown in the yaml template or on hover of the (?) on the website options pages",
56+
"type": ["array", "string"],
57+
"items": {"type": "string"}
58+
},
59+
"rich_text_doc": {
60+
"description": "(Optional) Enables support for HTML generated from the standard Python reStructuredText format for your description. \nfor more info: https://github.com/ArchipelagoMW/Archipelago/blob/main/docs/options%20api.md#option-documentation",
61+
"type": "boolean",
62+
"default": false
63+
},
64+
"group": {
65+
"description": "(Optional) The name of the group this option is a part of on the website options pages",
66+
"type": "string",
67+
"default": "Game Options",
68+
"examples": ["Item & Location Options", "Example Options", "Option Group Name"]
69+
},
70+
"hidden": {
71+
"description": "(Optional) Should this option be Hidden everywhere? Use Visibility instead for a more precise control",
72+
"type": "boolean",
73+
"default": false
74+
},
75+
"visibility": {
76+
"description": "(Optional) (Advanced) Specify where this option can be seen. \nIt can be represented by the value names, an array of those, \nthe binary string representation of that choice (\"0b1111\") or the integer value of the binary \nEvery example values other than 'none' and 'all' gives the same results aka 14 aka 0b1110 aka that array \nMore info at https://github.com/ArchipelagoMW/Archipelago/blob/main/docs/options%20api.md#option-visibility",
77+
"type":["string","array","integer"],
78+
"items": {"type": "string", "enum": [ "template", "simple_ui", "complex_ui", "spoiler"]},
79+
"default": "all",
80+
"examples": ["none", "0b1110", ["spoiler", "simple_ui", "complex_ui"], 14 ],
81+
"if": {"type":"string", "pattern": "0b[01]..."},
82+
"else": {"if": {"type": "string"}, "then": {"enum": ["all", "none", "template", "simple_ui", "complex_ui", "spoiler"]} }
83+
},
84+
"_comment": {"$ref": "#/definitions/comment"}
85+
}
86+
},
87+
"OptionUser": {
88+
"type": "object",
89+
"$comment": "The version with all the type logic aka normal options",
90+
"allOf": [{"$ref": "#/definitions/OptionBase"}],
91+
"properties": {
92+
"type": {"$ref": "#/definitions/Type"}
93+
},
94+
"required": ["type"],
95+
"if": {"properties": { "type": {"const": "Toggle"}}},
96+
"then": {
97+
"properties": {
98+
"default": { "$ref": "#/definitions/DefaultToggle"}
99+
},
100+
"required": ["default", "type"]
101+
},
102+
"else": {
103+
"if": {"properties": { "type": {"const": "Choice"}}},
104+
"then": {
105+
"properties": {
106+
"values": {"$ref": "#/definitions/ChoiceValue"},
107+
"aliases": {"$ref": "#/definitions/ChoiceAlias"},
108+
"default": {"$ref": "#/definitions/DefaultInt"},
109+
"allow_custom_value": { "$ref": "#/definitions/ChoiceAllowCustomValue"}
110+
},
111+
"required": ["values", "type"]
112+
},
113+
"else": {
114+
"if": {"properties": { "type": {"const": "Range"}}},
115+
"then": {
116+
"properties": {
117+
"range_start": {"$ref": "#/definitions/RangeStart"},
118+
"range_end": {"$ref": "#/definitions/RangeEnd"},
119+
"default": {"$ref": "#/definitions/DefaultInt"},
120+
"values":{"$ref": "#/definitions/SpecialRangeNames"}
121+
}
122+
}
123+
}
124+
}
125+
},
126+
"OptionCore":{
127+
"type": "object",
128+
"allOf": [{"$ref": "#/definitions/OptionBase"}],
129+
"properties": {
130+
"default": {"$ref": "#/definitions/DefaultCore"},
131+
"aliases": {"$ref": "#/definitions/ChoiceAlias"},
132+
"values":{"$ref": "#/definitions/SpecialRangeNames_core"}
133+
}
134+
},
135+
136+
"Type": {
137+
"description": "The type of this options. \nHover your mouse on any uncommented option's name to get a list of valid types for Manual options and a short description for each",
138+
"type": "string",
139+
"enum": ["Toggle", "Choice", "Range"]
140+
},
141+
"ChoiceValue": {
142+
"description": "A dictionary of possible values in the format {\"name\":0, \"other name\":2} \nUnless the default is changed, there need to be a defined value of 0.",
143+
"type":"object",
144+
"patternProperties": {
145+
"^.*$": {
146+
"description": "An int value this option can have",
147+
"type": "integer"
148+
}
149+
}
150+
151+
},
152+
"ChoiceAlias": {
153+
"description": "(Optional) A dictionary of aliases in the format {\"name\":0, \"other name\":2} or {\"name\":\"name of another value/alias\"}",
154+
"type": "object",
155+
"patternProperties": {
156+
"^.*$": {
157+
"description": "An alias for one of this option's value",
158+
"type": ["integer", "string"]
159+
}
160+
}
161+
},
162+
"ChoiceAllowCustomValue": {
163+
"description": "(Optional) Allow the user to set their own custom string Value",
164+
"type": "boolean",
165+
"default": false
166+
},
167+
"RangeStart": {
168+
"type": "integer",
169+
"description": "(Optional) The lowest Value for this range",
170+
"default": 0
171+
},
172+
"RangeEnd": {
173+
"type":"integer",
174+
"description": "(Optional) The Highest Value for this range",
175+
"default": 1
176+
},
177+
"SpecialRangeNames_base": {
178+
"type":"object",
179+
"patternProperties": {
180+
"^.*$": {
181+
"description": "A named numerical value",
182+
"type": "integer"
183+
}
184+
},
185+
"default": {},
186+
"examples": [{"test": 1}]
187+
},
188+
"SpecialRangeNames": {
189+
"description": "(Optional) A Special Dictionary in the format {\"name\":0, \"other name\":2} of named values for this range \nAll names need to be lowercase",
190+
"allOf": [{"$ref": "#/definitions/SpecialRangeNames_base"}]
191+
},
192+
"SpecialRangeNames_core": {
193+
"description": "(Optional) A Special Dictionary in the format {\"name\":0, \"other name\":2} of named values for this range \nAll names need to be lowercase \nForbidden for Options of type Choice",
194+
"allOf": [{"$ref": "#/definitions/SpecialRangeNames_base"}]
195+
},
196+
"DefaultInt": {
197+
"description": "(Optional) The default integer value of this option",
198+
"type": "integer",
199+
"default": 0
200+
},
201+
"DefaultToggle": {
202+
"description": "The default value of this Toggle",
203+
"type": "boolean",
204+
"default": false
205+
},
206+
"DefaultCore": {
207+
"description": "The default value of this option, its type depend on the type of the option you are overriding",
208+
"type": ["integer", "boolean"]
209+
},
210+
"comment": {
211+
"description": "(Optional) Does nothing, Its mainly here for Dev notes for future devs to understand your logic",
212+
"type": ["string", "array"],
213+
"items": {
214+
"description": "A line of comment",
215+
"type":"string"
216+
}
217+
}
218+
}
219+
}

schemas/Manual.schema.catalog.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@
3636
"description": "meta.json schema file for APWorlds created with Manual",
3737
"fileMatch": [ "**/manual*/data/meta.json" ],
3838
"url": "https://raw.githubusercontent.com/ManualForArchipelago/Manual/main/schemas/Manual.meta.schema.json"
39+
},
40+
{
41+
"name": "Manual options.json",
42+
"description": "options.json schema file for APWorlds created with Manual",
43+
"fileMatch": [ "**/manual*/data/options.json" ],
44+
"url": "https://raw.githubusercontent.com/ManualForArchipelago/Manual/main/schemas/Manual.options.schema.json"
3945
}
4046
],
41-
"version": 20240429.01
47+
"version": 20240721.01
4248
}

src/Data.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
after_load_game_file, \
88
after_load_item_file, after_load_location_file, \
99
after_load_region_file, after_load_category_file, \
10-
after_load_meta_file
10+
after_load_option_file, after_load_meta_file
1111

1212
# blatantly copied from the minecraft ap world because why not
1313
def load_data_file(*args) -> dict:
@@ -19,7 +19,6 @@ def convert_to_list(data, property_name: str) -> list:
1919
data = data.get(property_name, [])
2020
return data
2121

22-
2322
class ManualFile:
2423
filename: str
2524
data_type: dict|list
@@ -42,6 +41,7 @@ def load(self):
4241
location_table = convert_to_list(ManualFile('locations.json', list).load(), 'data') #list
4342
region_table = ManualFile('regions.json', dict).load() #dict
4443
category_table = ManualFile('categories.json', dict).load() #dict
44+
option_table = ManualFile('options.json', dict).load() #dict
4545
meta_table = ManualFile('meta.json', dict).load() #dict
4646

4747
# Removal of schemas in root of tables
@@ -54,6 +54,7 @@ def load(self):
5454
location_table = after_load_location_file(location_table)
5555
region_table = after_load_region_file(region_table)
5656
category_table = after_load_category_file(category_table)
57+
option_table = after_load_option_file(option_table)
5758
meta_table = after_load_meta_file(meta_table)
5859

5960
# seed all of the tables for validation

src/Helpers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ def get_items_with_value(world: World, multiworld: MultiWorld, value: str, playe
170170
world.item_values[player][value] = item_with_values
171171
return world.item_values[player].get(value)
172172

173+
173174
def filter_used_regions(player_regions: dict|list) -> set:
174175
"""Return a set of regions that are actually used in Generation. It includes region that have no locations but are required by other regions\n
175176
The dict version of the player_regions must be in the format: dict(region name str: region)
@@ -198,3 +199,9 @@ def checkParent(parent_region):
198199
return
199200
checkParent(region)
200201
return used_regions
202+
203+
def convert_to_long_string(input: str | list[str]) -> str:
204+
"""Verify that the input is a str. If it's a list[str] then it combine them into a str in a way that works with yaml template/website options descriptions"""
205+
if not isinstance(input, str):
206+
return str.join("\n ", input)
207+
return input

src/Items.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232

3333
item_table[key]["id"] = count
3434
item_table[key]["progression"] = val["progression"] if "progression" in val else False
35+
if isinstance(val.get("category", []), str):
36+
item_table[key]["category"] = [val["category"]]
37+
3538
count += 1
3639

3740
for item in item_table:

src/Locations.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@
2424

2525
location_table[key]["id"] = count
2626

27-
if not "region" in location_table[key]:
27+
if "region" not in location_table[key]:
2828
location_table[key]["region"] = "Manual" # all locations are in the same region for Manual
2929

30+
if isinstance(location_table[key].get("category", []), str):
31+
location_table[key]["category"] = [location_table[key]["category"]]
32+
3033
count += 1
3134

3235
if not victory_names:

src/ManualClient.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import typing
66
from worlds import AutoWorldRegister, network_data_package
77
import json
8+
import traceback
89

910
import asyncio, re
1011

@@ -213,6 +214,26 @@ def on_tracker_events(self, events: list[str]):
213214
if events:
214215
self.ui.request_update_tracker_and_locations_table(update_highlights=True)
215216

217+
def handle_connection_loss(self, msg: str) -> None:
218+
"""Helper for logging and displaying a loss of connection. Must be called from an except block."""
219+
exc_info = sys.exc_info()
220+
logger.exception(msg, exc_info=exc_info, extra={'compact_gui': True})
221+
tracker_error = False
222+
e = exc_info[2]
223+
formatted_tb = ''.join(traceback.format_tb(e))
224+
while e:
225+
if '/tracker/' in e.tb_frame.f_code.co_filename:
226+
tracker_error = True
227+
break
228+
e = e.tb_next
229+
230+
if tracker_error:
231+
self._messagebox_connection_loss = self.gui_error(
232+
"A Universal Tracker error has occurred. Please ensure that your version of UT matches your version of Archipelago.",
233+
formatted_tb)
234+
else:
235+
self._messagebox_connection_loss = self.gui_error(msg, formatted_tb)
236+
216237
def run_gui(self):
217238
"""Import kivy UI system from make_gui() and start running it as self.ui_task."""
218239
if hasattr(SuperContext, "make_gui"):

0 commit comments

Comments
 (0)