Files
ReSkate/Extension/Skater/pad_hide.cpp
T
AyeZeeBB 721ed9e64d Plugins: a general launch API in place of grind_exit; grind exits is all Lua, and 701 is a grind
The SDK knew grind exits: reskate.skater.grind_exit took a toe/heel/left/right wish, and C++ worked
out the rail's direction, toe and heel from the stance and facing, the 1.8 m/s and the strength.
That logic is now the grind-exits mod's own Lua (plugin/exits.lua, kept on this machine). What has
to run on the physics thread is general:
- Extension/Skater/launches: every launch of the local skater (ollie, grind, no_comply, boneless),
  classified by its call site and the state before it, with the board's direction of travel; the
  `launch` event for plugins with events.skater; reskate.skater.shape_launch(from, {across, along,
  up}) sets those speeds against the travel, one plugin a kind.
- reskate.skater.get() gains `right` (the root's right axis) and `switch` (the game's stance flag).
- Extension/Skater/pad_hide: reskate.input.hide's pad filter, out of the old grind exit file.
Removed: reskate.skater.grind_exit, the grind_exit event, GrindExitWish and GrindPop.

Physics state 701 is a grind too (the game checks it with 400 in about a dozen places; the
2026-10-11 measurement only reached the 400s): pops out of it were dropped, and skater_state called
it "other". Launches, skater_state ("grinding") and the trainer's grind pop all count it now.
Tests: the grind-exits plugin test drives the new path (11 checks of its own).
2026-10-21 21:41:04 -05:00

69 lines
2.9 KiB
C++

#include "pad_hide.h"
#include "launches.h"
#include "Extension/UI/Overlay/overlay.h"
#include <atomic>
#include <map>
#include <mutex>
#include <string>
namespace dingosdk::pad_hide {
namespace {
struct Control {
std::mutex mutex;
std::map<std::string, Hidden, std::less<>> hidden;
std::atomic<bool> lt{}, rt{}, left_x{}, right_stick{}, l3{}, r3{};
};
Control& control() {
static auto* value = new Control; // process lifetime: the game polls its pad until exit
return *value;
}
// Any thread the game polls its pad from.
void filter_pad(unsigned, overlay::GamepadValues& pad) noexcept {
auto& c = control();
if (c.lt.load(std::memory_order_acquire)) pad.left_trigger = 0;
if (c.rt.load(std::memory_order_acquire)) pad.right_trigger = 0;
if (c.left_x.load(std::memory_order_acquire) && launches::grinding()) pad.left_x = 0;
if (c.right_stick.load(std::memory_order_acquire)) pad.right_x = pad.right_y = 0;
if (c.l3.load(std::memory_order_acquire)) pad.buttons &= static_cast<std::uint16_t>(~0x0040u); // XINPUT_GAMEPAD_LEFT_THUMB
if (c.r3.load(std::memory_order_acquire)) pad.buttons &= static_cast<std::uint16_t>(~0x0080u); // XINPUT_GAMEPAD_RIGHT_THUMB
}
void publish(Control& c) {
Hidden all;
for (const auto& [owner, h] : c.hidden) {
all.left_trigger = all.left_trigger || h.left_trigger;
all.right_trigger = all.right_trigger || h.right_trigger;
all.left_x_grinding = all.left_x_grinding || h.left_x_grinding;
all.right_stick = all.right_stick || h.right_stick;
all.left_stick_click = all.left_stick_click || h.left_stick_click;
all.right_stick_click = all.right_stick_click || h.right_stick_click;
}
c.lt.store(all.left_trigger, std::memory_order_release);
c.rt.store(all.right_trigger, std::memory_order_release);
c.left_x.store(all.left_x_grinding, std::memory_order_release);
c.right_stick.store(all.right_stick, std::memory_order_release);
c.l3.store(all.left_stick_click, std::memory_order_release);
c.r3.store(all.right_stick_click, std::memory_order_release);
DingoSDKOverlaySetGamepadFilter(c.hidden.empty() ? nullptr : &filter_pad);
}
} // namespace
bool available() noexcept { return launches::available(); }
void hide(std::string_view owner, Hidden hidden) {
if (!available()) return;
if (hidden.left_x_grinding) (void)launches::grinding(); // the physics steps followed from now on
auto& c = control();
std::lock_guard lock(c.mutex);
if (hidden.any()) c.hidden.insert_or_assign(std::string(owner), hidden);
else if (const auto found = c.hidden.find(owner); found != c.hidden.end()) c.hidden.erase(found);
publish(c);
}
void release(std::string_view owner) {
auto& c = control();
std::lock_guard lock(c.mutex);
if (const auto found = c.hidden.find(owner); found != c.hidden.end()) {
c.hidden.erase(found);
publish(c);
}
}
}