Files
ReSkate/Extension/UI/Overlay/scripted_pad.cpp
T
AyeZeeBB 41b5973896 Plugins: the character room and typing into a drawn field, and Animator Studio on both
- reskate.room.open, leave and state, with the room permission: ReSkate walks the game's menu to the Skaters page (its navigation events and RB on an internal scripted pad, as PR 297 and PR 230 did), draws the local skater on the room's floor and hides the room's own skater and board; other players are not sent the room. Extension/World/character_room, the room placement and hiding in skater_animation, and post_native_ui_event made general.
- reskate.input.text: what is typed while the plugin's screen is open; while it types, Esc is the plugin's.
- Animator Studio opens in its room (the Studio room setting, as the PR's), under its loading screen, or where the skater is when the walk fails; its card's name, trick and numbers are typed into in place.
2026-10-20 17:43:40 -05:00

62 lines
2.0 KiB
C++

#include "scripted_pad.h"
#include <atomic>
#include <chrono>
#include <mutex>
namespace dingosdk::overlay {
namespace {
struct State {
std::mutex mutex;
std::vector<PadStep> steps;
std::size_t current{};
std::uint32_t ticks{};
std::chrono::steady_clock::time_point last_tick, done_at;
bool active{};
DWORD packet{};
};
State &state() { static auto *value = new State; return *value; }
constexpr std::chrono::milliseconds linger{2000}, no_ticks{250}, tick_length{17};
// One game tick of the script. The caller holds s.mutex.
void advance(State &s, std::chrono::steady_clock::time_point now) {
++s.ticks;
s.last_tick = now;
while (s.current + 1 < s.steps.size() && s.steps[s.current + 1].tick <= s.ticks) {
++s.current;
if (s.current + 1 == s.steps.size()) s.done_at = now;
}
}
} // namespace
void play_pad(std::vector<PadStep> steps) {
auto &s = state();
std::lock_guard lock(s.mutex);
s.steps = std::move(steps);
s.current = 0;
s.ticks = 0;
s.last_tick = s.done_at = std::chrono::steady_clock::now();
s.active = !s.steps.empty();
}
void pad_tick() noexcept {
auto &s = state();
std::lock_guard lock(s.mutex);
if (s.active) advance(s, std::chrono::steady_clock::now());
}
bool scripted_pad(DWORD user, XINPUT_STATE &output) noexcept {
auto &s = state();
if (user != 0) return false;
std::lock_guard lock(s.mutex);
if (!s.active) return false;
const auto now = std::chrono::steady_clock::now();
// With no game ticks, time alone moves the script on.
while (s.current + 1 < s.steps.size() && now - s.last_tick > no_ticks) advance(s, s.last_tick + tick_length);
const bool done = s.current + 1 == s.steps.size();
if (done && now - s.done_at > linger) {
s.active = false;
return false;
}
output.Gamepad = done ? XINPUT_GAMEPAD{} : s.steps[s.current].pad;
output.dwPacketNumber = ++s.packet;
return true;
}
} // namespace dingosdk::overlay