Skip to content

Commit ec8b016

Browse files
committed
hook menus together
1 parent d1423fd commit ec8b016

File tree

5 files changed

+121
-29
lines changed

5 files changed

+121
-29
lines changed

src/willow1_mod_menu/lobby.py

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
from .util import find_focused_item
1313

14-
# from .options import create_mod_options_menu
15-
1614
type WillowGFxLobbyMultiplayer = UObject
1715
type WillowGFxMenuFrontend = UObject
1816

@@ -27,6 +25,25 @@
2725
drawn_mods: list[Mod] = []
2826

2927

28+
def open_lobby_mods_menu(frontend: WillowGFxMenuFrontend) -> None:
29+
"""
30+
Opens the multiplayer lobby-based mods menu.
31+
32+
Args:
33+
frontend: The frontend movie to open under.
34+
"""
35+
block_search_delegate.enable()
36+
init_content.enable()
37+
play_sound.enable()
38+
menu_close.enable()
39+
40+
frontend.OpenMP()
41+
42+
43+
# Avoid circular import
44+
from .options import create_mod_options_menu # noqa: E402
45+
46+
3047
# This is called when the movie is first started, to start looking for online games. We just want to
3148
# completely block it
3249
@hook("WillowGame.WillowGFxLobbyMultiplayer:UpdateSearchDelegate")
@@ -177,7 +194,12 @@ def play_sound(
177194
if (menu := current_menu()) is None:
178195
return
179196
mod = get_focused_mod(menu)
180-
print("selected", None if mod is None else mod.name)
197+
if mod is None:
198+
return
199+
200+
menu.Close()
201+
frontend = menu.PlayerOwner.GFxUIManager.GetPlayingMovie()
202+
create_mod_options_menu(frontend, mod)
181203
case _:
182204
return
183205

@@ -211,18 +233,3 @@ def menu_close(
211233
global current_menu
212234
current_menu = WeakPointer()
213235
drawn_mods.clear()
214-
215-
216-
def open_lobby_mods_menu(frontend: WillowGFxMenuFrontend) -> None:
217-
"""
218-
Opens the multiplayer lobby-based mods menu.
219-
220-
Args:
221-
frontend: The frontend movie to open under.
222-
"""
223-
block_search_delegate.enable()
224-
init_content.enable()
225-
play_sound.enable()
226-
menu_close.enable()
227-
228-
frontend.OpenMP()

src/willow1_mod_menu/options.py

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,61 @@
1010

1111
from mods_base import Mod, NestedOption, hook, html_to_plain_text
1212

13+
from .lobby import open_lobby_mods_menu
1314
from .util import find_focused_item
1415

1516
if TYPE_CHECKING:
1617
from .populators import Populator
1718
from .util import WillowGFxMenu
1819

1920
CUSTOM_OPTIONS_MENU_TAG = "willow1-mod-menu:custom-option"
20-
RE_SELECTED_IDX = re.compile(r"^_level\d+\.menu\.selections\.mMenu\.mList\.item(\d+)$")
21+
RE_SELECTED_IDX = re.compile(r"^_level\d+\.(menu\.selections|content)\.mMenu\.mList\.item(\d+)$")
2122

2223
populator_stack: list[Populator] = []
2324

2425

26+
def create_mod_list_options_menu(menu: WillowGFxMenu) -> None:
27+
"""
28+
Creates a new menu holding the full mods list.
29+
30+
Args:
31+
menu: The current menu to create the new one under.
32+
"""
33+
populator_stack.append(ModListPopulator("Mods"))
34+
open_new_generic_menu(menu)
35+
36+
2537
def create_mod_options_menu(menu: WillowGFxMenu, mod: Mod) -> None:
26-
populator_stack.append(OptionPopulator(mod.name, mod.options))
38+
"""
39+
Creates a new menu holding a single mod's options.
40+
41+
Args:
42+
menu: The current menu to create the new one under.
43+
mod: The mod to create the options menu for.
44+
"""
45+
populator_stack.append(ModOptionPopulator(mod.name, mod.options, mod))
2746
open_new_generic_menu(menu)
2847

2948

3049
def create_nested_options_menu(menu: WillowGFxMenu, option: NestedOption) -> None:
50+
"""
51+
Creates a new menu holding a nested option's children.
52+
53+
Args:
54+
menu: The current menu to create the new one under.
55+
option: The options whose children to create a menu for.
56+
"""
3157
populator_stack.append(OptionPopulator(option.display_name, option.children))
3258
open_new_generic_menu(menu)
3359

3460

61+
# ==================================================================================================
62+
3563
# Avoid circular imports
64+
from .populators.mod_list import ModListPopulator # noqa: E402
65+
from .populators.mod_options import ModOptionPopulator # noqa: E402
3666
from .populators.options import OptionPopulator # noqa: E402
3767

38-
# ==================================================================================================
39-
4068

4169
def open_new_generic_menu(menu: WillowGFxMenu) -> None:
4270
if len(populator_stack) == 1:
@@ -82,7 +110,7 @@ def get_selected_idx(menu: WillowGFxMenu) -> int | None:
82110
return None
83111

84112
try:
85-
return int(match.group(1))
113+
return int(match.group(2))
86114
except ValueError:
87115
return None
88116

@@ -145,15 +173,19 @@ def generic_screen_deactivate(
145173
_ret: Any,
146174
_func: BoundFunction,
147175
) -> None:
148-
if obj.MenuTag == CUSTOM_OPTIONS_MENU_TAG:
149-
populator_stack.pop()
150-
# TODO: save mod settings
176+
if obj.MenuTag == CUSTOM_OPTIONS_MENU_TAG and populator_stack:
177+
last_populator = populator_stack.pop()
178+
if isinstance(last_populator, ModOptionPopulator):
179+
last_populator.mod.save_settings()
151180

152181
if not populator_stack:
153182
custom_menu_activate.disable()
154183
custom_menu_spinner_change.disable()
155184
custom_menu_slider_change.disable()
156185

186+
if (owner := obj.MenuOwner).Class.Name == "WillowGFxMenuFrontend":
187+
open_lobby_mods_menu(owner)
188+
157189

158190
# ==================================================================================================
159191
# experimental

src/willow1_mod_menu/pause.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
# ruff: noqa: D103, T201, TD002, TD003, TD004, TD005, FIX002
1+
# ruff: noqa: D103
22
from typing import Any
33

44
from unrealsdk.hooks import Block, Type
55
from unrealsdk.unreal import BoundFunction, UObject, WrappedStruct
66

77
from mods_base import hook
88

9+
from .options import create_mod_list_options_menu
10+
911
MODS_MENU_TAG = "willow1-mod-menu:mods-pause"
1012

1113

@@ -41,9 +43,14 @@ def open_pause_post(*_: Any) -> None:
4143

4244

4345
@hook("WillowGame.WillowGFxMenuPause:extMainDebug", immediately_enable=True)
44-
def pause_activate(*_: Any) -> type[Block]:
46+
def pause_activate(
47+
obj: UObject,
48+
_args: WrappedStruct,
49+
_ret: Any,
50+
_func: BoundFunction,
51+
) -> type[Block]:
4552
# We don't seem to be able to open the multiplayer lobby menu from in game - even if we force
4653
# load it's definition - so instead just open a standard options list showing each mod
47-
print("OPEN SIMPLE MODS MENU") # TODO
54+
create_mod_list_options_menu(obj)
4855

4956
return Block
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from dataclasses import dataclass
2+
from types import EllipsisType
3+
from typing import override
4+
5+
from mods_base import JSON, BaseOption, get_ordered_mod_list, html_to_plain_text
6+
from willow1_mod_menu.options import create_mod_options_menu
7+
8+
from . import Populator, WillowGFxLobbyTools, WillowGFxMenu
9+
10+
11+
@dataclass
12+
class ModProxyOption(BaseOption):
13+
@override
14+
def _to_json(self) -> EllipsisType:
15+
return ...
16+
17+
@override
18+
def _from_json(self, value: JSON) -> None:
19+
pass
20+
21+
22+
@dataclass
23+
class ModListPopulator(Populator):
24+
@override
25+
def populate(self, tools: WillowGFxLobbyTools) -> None:
26+
self.drawn_options.clear()
27+
28+
for mod in get_ordered_mod_list():
29+
opt = ModProxyOption(mod.name)
30+
opt.mod = mod
31+
self.draw_text(tools, html_to_plain_text(mod.name), opt)
32+
33+
@override
34+
def handle_activate(self, menu: WillowGFxMenu, option: BaseOption) -> None:
35+
assert option.mod is not None
36+
create_mod_options_menu(menu, option.mod)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from dataclasses import dataclass
2+
3+
from mods_base import Mod
4+
5+
from .options import OptionPopulator
6+
7+
8+
@dataclass
9+
class ModOptionPopulator(OptionPopulator):
10+
mod: Mod

0 commit comments

Comments
 (0)