mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-27 19:47:08 +01:00
Mod Manager: a pause menu tab after Mod Options to browse, install, update and switch mods in game
A third ReSkate tab in the game's pause menu (native_menu.cpp slot 2, the Store's tab art), drawn by the overlay as the other two are (mod_manager_page.inl, included into hub_page.cpp): - BROWSE: search, categories in a panel of their own (shown only, hidden or either, kept in the profile), sort, a featured carousel and rows (most popular, recently updated, new, the biggest categories), a grid for results, and a mod's own page with its README, what it brings with it, and INSTALL, switch on or off and uninstall. Works from a controller: the carousel's card is one stop that left and right turn, and B goes back from a mod's page (the page's Back is held meanwhile). - MY MODS: the Mods folder with the states the ReSkate menu shows; UPDATES: Update all. - The foot of the page shows the install's progress and the apply's, and Apply (View on a pad). Leaving the menu with changes not applied asks first (a two-answer card in message_card.cpp, answered by the runtime as the message is); LATER closes the menu. Behind it, Extension/Assets/mod_store: Thunderstore's listing (cached on disk), the installed mods, and a queue that downloads and installs packages with their dependencies, updates and uninstalls them. An update or uninstall of a mod the game holds open waits in Mods/.reskate-pending and the launcher makes it before the next start (launcher_mods::apply_pending). Package icons load into their own SRV slots (store_icons.cpp), sharing the launcher's icon cache. Tests: mod_store_view (search, categories, the front page's rows, install plans), the pending updates and uninstalls in mod_manager_tests, and the third tab in native_menu_view_tests.
This commit is contained in:
1 parent
54716f2798
commit
725c18ef3d
25 files changed
+3164
-52
No files matched your search
+18
-6
@@ -712,14 +712,16 @@ void update_model(std::uintptr_t client, TickState& frame) {
|
||||
const bool map_prompt = dingosdk::map_download::asking();
|
||||
// The vote for the next map comes up the same way (overlay.h: map_vote_asking), when no map is being asked about.
|
||||
const bool map_vote = !map_prompt && dingosdk::overlay::map_vote_asking();
|
||||
// And a message to say OK to (overlay.h: message_asking), over either.
|
||||
// And a message to say OK to (overlay.h: message_asking), over either; and a question with two
|
||||
// answers (overlay.h: ask_question), under the message.
|
||||
const bool message_up = dingosdk::overlay::message_asking();
|
||||
const bool question_up = !message_up && dingosdk::overlay::question_asking();
|
||||
// The hold on the game's input outlasts the card's question until everything pressed is let
|
||||
// go (or a moment has passed): the button that answered must not also be a press in the
|
||||
// game, or in the pause menu behind the card.
|
||||
static bool prompt_held{};
|
||||
static ULONGLONG prompt_release_by{};
|
||||
if (map_prompt || map_vote || message_up) {
|
||||
if (map_prompt || map_vote || message_up || question_up) {
|
||||
prompt_held = true;
|
||||
prompt_release_by = 0;
|
||||
} else if (prompt_held) {
|
||||
@@ -730,7 +732,7 @@ void update_model(std::uintptr_t client, TickState& frame) {
|
||||
std::ranges::any_of(held.keys, [](std::uint64_t word) { return word != 0; });
|
||||
if (!pressed || GetTickCount64() >= prompt_release_by) prompt_held = false;
|
||||
}
|
||||
DingoSDKOverlaySetPromptInputCapture(map_prompt || map_vote || message_up || prompt_held);
|
||||
DingoSDKOverlaySetPromptInputCapture(map_prompt || map_vote || message_up || question_up || prompt_held);
|
||||
const unsigned poll_answers = dingosdk::multiplayer::server_poll_answers();
|
||||
const bool placement_flight = dingosdk::pad_flight::requested();
|
||||
bool freecam_controller = dingosdk::local_freecam_controller() || placement_flight;
|
||||
@@ -761,10 +763,10 @@ void update_model(std::uintptr_t client, TickState& frame) {
|
||||
dingosdk::plugins::plugin_input_capture());
|
||||
dingosdk::ControllerInput controller;
|
||||
if (freecam_controller_combo || freecam_combo || tp_to_freecam_combo || noclip_combo || forward_velocity_combo || up_velocity_combo || offboard_up_velocity_combo ||
|
||||
vote_yes_combo || vote_no_combo || poll_answers || map_prompt || map_vote || message_up ||
|
||||
vote_yes_combo || vote_no_combo || poll_answers || map_prompt || map_vote || message_up || question_up ||
|
||||
std::ranges::any_of(action_combos, [](auto combo) { return combo != 0; }))
|
||||
// (The card that asks has the pointer, as a menu does: it is still read for.)
|
||||
DingoSDKOverlayReadControllerInput(&controller, map_prompt || map_vote || message_up);
|
||||
DingoSDKOverlayReadControllerInput(&controller, map_prompt || map_vote || message_up || question_up);
|
||||
for (std::size_t i = 0; i < action_combos.size(); ++i)
|
||||
if (r.action_bind_latches[i].update(action_combos[i], controller, r.observer_failed || placement_flight)) {
|
||||
std::array<char, 256> result{};
|
||||
@@ -790,7 +792,7 @@ void update_model(std::uintptr_t client, TickState& frame) {
|
||||
static bool prompt_before{};
|
||||
static std::uint32_t buttons_before{};
|
||||
// The keyboard's arrows, Enter and Esc do the same, above the pad's bits.
|
||||
const bool prompt = map_prompt || map_vote || message_up;
|
||||
const bool prompt = map_prompt || map_vote || message_up || question_up;
|
||||
const std::uint32_t buttons = !prompt ? 0
|
||||
: (controller.available ? controller.buttons : 0) | (DingoSDKOverlayReadPromptKeys() << 20);
|
||||
// The message is over the others and is answered first: A or B, Enter or Esc, is its OK.
|
||||
@@ -804,6 +806,16 @@ void update_model(std::uintptr_t client, TickState& frame) {
|
||||
if (pressed & (0x1000 | 1u << 22)) dingosdk::map_download::answer(dingosdk::map_download::picked());
|
||||
else if (pressed & (0x2000 | 1u << 23)) dingosdk::map_download::answer(false);
|
||||
}
|
||||
// The question: left and right pick, A takes the pick, B is its second answer.
|
||||
static bool question_before{};
|
||||
if (question_up && question_before) {
|
||||
const auto pressed = buttons & ~buttons_before;
|
||||
if (pressed & (0x0004 | 1u << 20)) dingosdk::overlay::question_pick(true);
|
||||
if (pressed & (0x0008 | 1u << 21)) dingosdk::overlay::question_pick(false);
|
||||
if (pressed & (0x1000 | 1u << 22)) dingosdk::overlay::question_answer(dingosdk::overlay::question_picked());
|
||||
else if (pressed & (0x2000 | 1u << 23)) dingosdk::overlay::question_answer(false);
|
||||
}
|
||||
question_before = question_up;
|
||||
// The vote's popup: left and right move the pick, A votes for it, B closes it.
|
||||
static bool vote_before{};
|
||||
if (!message_up && map_vote && vote_before) {
|
||||
|
||||
Reference in new issue
Block a user