skate3recomp-multiplayer/src/skate3_app_common.h
MiTHRAL 269fbcee32 Add ghost multiplayer: UDP relay + pose broadcasting + placeholder cubes
Bolt-on multiplayer layer confined to src/native and hand-written code (no
codegen output touched):

- GhostRelay core (src/native/skate3_native_ghost_relay.*): small UDP relay
  matching clients into rooms by a shareable code; forwards each client's
  pose to the other room members. Used by both the standalone binary and
  the in-game LAN host fallback.
- Standalone server (tools/ghost_relay_main.cpp, ghost_relay target): runs
  on a public VPS or behind a free tunnel; clients connect OUTBOUND, so no
  port forwarding is needed on any client.
- In-game module (skate3_native_ghost.*): captures the local player's world
  transform at Sk8::UpdateBoneTransforms exit (pack-owner entity +416,
  verified layout) and broadcasts it at a fixed rate; auto-connects to the
  default public relay, falls back to LAN auto-host + UDP broadcast
  discovery when unreachable.
- Renderer: draws a solid-color cube per remote player in RenderScene via
  the existing scene PSO tint.a>0 branch (no new shader/SPIR-V).
- UI: GhostDialog (M key) with enable toggle, room code, relay override,
  status readout. Off by default.

Wire protocol in skate3_native_ghost_proto.h (JOIN/HELLO/POSE/PING/LEAVE).
2026-08-26 20:12:45 -04:00

69 lines
2.1 KiB
C++

#pragma once
#include "generated/skate3_init.h"
#include <atomic>
#include <filesystem>
#include <functional>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <rex/rex_app.h>
#include <rex/ui/overlay/simple_settings_overlay.h>
#include "skate3_native_debug_dialog.h"
#include "skate3_native_ghost_dialog.h"
namespace rex::ui {
class ImGuiDrawer;
}
class Skate3BaseApp : public rex::ReXApp {
public:
using rex::ReXApp::ReXApp;
~Skate3BaseApp() override;
protected:
std::optional<rex::PathConfig> OnFinalizePaths(
const rex::PathConfig& defaults,
std::function<void(rex::PathConfig)> resume) override;
void OnConfigurePaths(rex::PathConfig& paths) override;
void OnConfigureFonts(ImFontAtlas* atlas) override;
void OnCreateDialogs(rex::ui::ImGuiDrawer* drawer) override;
void OnPostSetup() override;
void OnShutdown() override;
private:
void InstallRecipeOverlay();
void InstallBigDeviceAliases();
void InstallDlcPackages();
void ToggleSimpleSettings();
void ToggleNativeDebug();
void ToggleGhost();
void ApplySettingsCursorMode();
void ApplyGameplayCursorMode();
void RestartGame();
void SaveDrawFingerprintLog();
void LogUserMarker();
void LogDebugMarker();
void ApplySelectedProfileToRuntime();
static bool IsRecipeNameChar(char c);
static std::set<std::string> DiscoverRecipeAliases(
const std::filesystem::path& content_root);
static bool CreateOverlayDirectory(const std::filesystem::path& overlay_root,
std::string_view guest_path);
std::filesystem::path config_path_;
std::filesystem::path user_settings_path_;
std::filesystem::path profiles_path_;
std::unique_ptr<rex::ui::SimpleSettingsDialog> simple_settings_dialog_;
std::unique_ptr<skate3::NativeDebugDialog> native_debug_dialog_;
std::unique_ptr<skate3::GhostDialog> ghost_dialog_;
std::unique_ptr<skate3::RenderModeIndicator> render_mode_indicator_;
bool recipe_overlay_installed_ = false;
bool big_device_aliases_installed_ = false;
std::atomic<uint32_t> debug_marker_count_{0};
};