Files
ReSkate/Extension/UI/NativeMenu/native_menu_internal.h
T
AyeZeeBB 76330e40bb Skater slot, menu and throwdown fixes; MY MODS rework; lobby parties
Skater slot, menu and throwdown fixes; MY MODS rework; lobby parties

Saved skaters (Extension/Customization, Extension/Skater)
- The selected slot, and slots before it, came up as the standard
  skater after a start or map change. The game asks for a slot's saved
  outfit once per level, and that happened before the cosmetics catalog
  could be read. The first selection now waits for the catalog (60 s at
  most), and later map changes check against the catalog already read.
- The retry from abdda77 is removed: the record it wrote to is a
  temporary on the game's stack, so it could never work.

Pause menu (Extension/UI/NativeMenu)
- ReSkate's entries stopped working after enough map changes: each
  level change took new slots in a fixed table of 1024 for the same
  buttons. A button now keeps its slot, and a full table hands out the
  slot that has gone longest unused.

Throwdowns (Extension/Throwdowns, Runtime/runtime_init.cpp)
- Multiplayer crashed when someone placed a throwdown after a map
  change. The event types are freed with the level but were cached for
  the process. They are now cleared when a level is left, checked
  before use, and looked for again in each level.

MY MODS (Launcher/gui_mods.cpp, gui.cpp)
- Search, a filter and an order; a switch per mod; a menu per row.
- Multi-select with tick boxes, Shift-click and Ctrl+A, and a bar to
  enable, disable, move, update or uninstall everything ticked.

Lobby parties (Extension/Multiplayer/Session)
- A lobby is no longer one party. Its host keeps parties the way a
  dedicated server does: invite, accept, join, leave, kick, promote,
  open and close, with "/p" party chat. The "Lobby party" switch is
  gone. Protocol version unchanged (38).

Mod merge (Engine/Vfs), follow-ups to e715b9b
- Files rewritten into the merged patch are tracked by position, so
  another mod's added assets no longer shift the lookup.
- Two mods adding different assets under one name is now noted, with
  whose copy the maps get.
- mod_merge_unshift_tests compiles with the launcher tests on.
2026-10-04 13:27:21 -05:00

108 lines
5.4 KiB
C++

#pragma once
#include "native_menu_data.h"
#include "native_menu_lifetime.h"
#include "native_menu_view.h"
#include "native_tools_view.h"
#include "Engine/Game/Multiplayer/session_model.h"
#include <array>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <deque>
#include <map>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
// Pause-menu page state shared by the native_menu*.cpp files.
namespace dingosdk::multiplayer::native_menu_detail {
using menu_data::Address, menu_data::Context, menu_data::OwnedMenuModels, menu_data::Ref, menu_data::Schema,
menu_data::Value;
constexpr std::uint32_t content = 0x716496c8, items = 0x61742cb4,
tab_data = 0x0791c4f7, label = 0x58c9d354, text_field = 0x4d8e01b9,
button_field = 0x0fb0d794, value_field = 0x71f0e0b6, key_field = 0x1e95752c,
our_key = 0x52534d50;
constexpr std::size_t max_actions = 1024;
enum class Section { browser, host, join, session, voice };
// Most sections on any owned page: Multiplayer and Custom Stuff both have five.
constexpr unsigned section_count = 5;
static_assert(native_tools::sections.size() <= section_count);
constexpr float main_width = 1800.f, side_width = 1080.f;
constexpr Schema horizontal_panel{0xf0b42cc6, 104}, vertical_panel{0x4b60a61d, 96};
constexpr const char* anchored_widget = "UI/Foundations/Templates/Layouts/Anchored/AnchoredContentPresenter_Widget";
constexpr const char* horizontal_widget = "UI/Foundations/Templates/Layouts/Partitions/Horizontal/HorizontalPartition_LinearFocus_Widget";
constexpr const char* vertical_widget = "UI/Foundations/Templates/Layouts/Partitions/Vertical/VerticalPartition_LinearFocus_Widget";
enum class RowKind { button, input, text };
using Action = menu_data::MenuAction;
struct NativeAction {
// An unbound native FunctionTypeInfo reference. The native delegate copier
// borrows untagged references, so descriptors live for the process lifetime.
alignas(8) std::array<std::byte, 0x70> descriptor{};
Address info{};
Action action;
};
struct Row { Value model, presenter; RowKind kind{}; std::string last_text; Address callback{}; bool primary{}; Ref dark_text_style; float width{}, height{}; };
struct State {
unsigned slot{};
unsigned section_total = section_count;
unsigned failures{};
native_tools::State tools;
overlay::Model tools_model;
overlay::CallbacksV3 tools_callbacks{};
std::mutex mutex;
std::string status = "Native multiplayer menu: waiting for the pause menu.";
std::deque<Action> pending;
std::array<NativeAction, max_actions> actions;
std::atomic<unsigned> action_count{};
std::atomic<std::uint64_t> generation{};
std::uint64_t pass{}; // render passes so far; see menu_data::action_slot
Address base{}, manager{};
Value core, page, list, menu_item;
OwnedMenuModels<Value> owned_models;
std::array<Value, section_count> lists, side_lists, bodies;
std::array<std::vector<Value>, section_count * 2> fixed_rows;
std::string selected_player;
bool copy_code_requested{};
Value menu_style, primary_style;
Ref white_text_style;
float row_width = main_width;
std::map<std::string, Address, std::less<>> assets;
std::map<std::string, Row, std::less<>> rows;
std::array<std::vector<std::string>, section_count * 2> displayed;
Section section{Section::browser};
menu_view::BrowserOptions browser;
std::string protected_lobby;
unsigned capacity = multiplayer_lobby_player_limit;
unsigned tps = multiplayer_default_tps;
// A voice change sent but not yet reflected in the model, so a second
// press before the model catches up builds on the first.
std::optional<VoiceSettings> voice_pending;
std::uint64_t voice_pending_until{};
bool public_lobby{true}, was_active{}, host_seeded{};
bool browsing{}; // the lobby browser was on screen at the last render
std::uint64_t next_id = 1, next_scan{}, next_retry{}, next_update{}, next_render{}, owner{}, feedback_until{};
std::string feedback, feedback_status;
};
State& page_state(unsigned slot);
State& state();
Address action(const Context& context, std::string command, std::string argument = {});
Address blueprint(std::string_view name);
Value make(const Context& context, Schema schema);
// native_menu_rows.cpp
void add_text(const Context& context, std::vector<std::string>& visible, const std::string& id, const std::string& title, float height = 60.f);
void add_button(const Context& context, std::vector<std::string>& visible, const std::string& id,
std::string title, std::string command = {}, std::string argument = {}, bool primary = false, float row_height = 0.f);
void add_input(const Context& context, std::vector<std::string>& visible, const std::string& id,
const std::string& title, const std::string& initial = {});
std::string input_text(const Context& context, const char* id);
void clear_input(const Context& context, const char* id);
bool scrolling_list(unsigned page_slot, unsigned slot);
void publish_rows(const Context& context, Value list, unsigned slot, const std::vector<std::string>& visible);
// native_menu_multiplayer.cpp
void process_clipboard() noexcept;
void process_actions(const Context& context, const MultiplayerModel& model);
void render_section(const Context& context, const MultiplayerModel& model, Section section);
} // namespace dingosdk::multiplayer::native_menu_detail