mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-27 17:27:08 +01:00
Follow-ups to the trainer (PR 37), and one multiplayer change.
Off until asked for (Extension/Trainer)
- The jump read-out and the LB+RB controller shortcuts start off. Jumps
are logged only while the read-out or telemetry recording is on, and
trick launches only when the trainer scaled them. A saved trainer.json
keeps what the player chose.
Memory search on demand (trainer.cpp, trainer_classes.cpp)
- The search for the game's tuning classes reads all writable memory.
It ran for every player after a level loaded, and up to seven times
when it found nothing. It now runs only when a class value or the flip
speed is not the game's own (the player's, or a host's they skate
with) or the EVERYTHING list is open, and at most three times a level.
- For those players it runs again on each level, which brings fresh
copies; a search from an earlier level used to count as done.
Guests under enforced physics
- A guest is locked by the session's enforce setting, from the moment
of joining (Engine/Game/Multiplayer/session_physics.h), not by whether
the enforcement status text was set yet.
- A guest's class values no longer come back after a map change.
The host's whole setup reaches its guests (protocol 39)
- Only Gameplay/SkatePhysicsTuning travelled, so a host could push,
sprint or jump further than the guests it held to the game's own.
- New packet physics_extras (30): the host's class values, trick
multipliers and auto push (trainer_session.h), sent when they change
and to players who join later, taken from the host only. A dedicated
server's are the game's own and it ignores the packet.
- Under enforcement a guest's own trick multipliers stand down for the
host's, whatever the boosts switch says. With enforcement off nothing
changes.
- A guest refuses bytes that are not an encoding, holds values to the
trainer's own ranges, and leaves out class values written for another
game build's table.
- protocol_version 38 -> 39: released versions disconnect from a peer
that sends a packet they cannot decode.
Out-of-view players are posed every frame again (Session/session.cpp)
- Players outside the camera's view and past 8 m were sampled at 20 Hz
(b763631). The game's replays record each skater as it stood every
frame and their camera looks anywhere, so those players moved at
20 Hz in replays. Removed; the distance rule (20 Hz past 200 m, 10 Hz
past 350 m) stays. This gives back the client-tick time it saved on
busy servers.
127 lines
5.7 KiB
C++
127 lines
5.7 KiB
C++
#pragma once
|
|
// The ReSkate Trainer: live physics tuning, presets, practice markers and a telemetry HUD.
|
|
//
|
|
// The game thread owns the trainer's state (trainer.cpp). Every change is a `trainer ...`
|
|
// console command, so the menu page (presentation thread) only queues commands and reads
|
|
// the two snapshots below; nothing here touches the game from the UI.
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
namespace dingosdk::trainer {
|
|
// curve: a FloatCurve the asset points at; graph: a table of points stored in the asset
|
|
// itself (X0..X15, Y0..Y15). Both are edited as one multiplier on their outputs.
|
|
enum class Kind : std::uint8_t { real, integer, flag, curve, graph };
|
|
// The Tune tab's two short lists: which of them a value is on (Row::modes).
|
|
inline constexpr std::uint8_t mode_realistic = 1, mode_fun = 2;
|
|
|
|
// One editable value of Gameplay/SkatePhysicsTuning. `id` is the name the game's data gives
|
|
// it ("PhysicsMode.JumpMaxHeight").
|
|
struct Row {
|
|
std::string id, label, group;
|
|
Kind kind{};
|
|
double value{}, stock{};
|
|
bool touched{}, frozen{};
|
|
bool detail{}; // a single point or bound of a graph: hidden unless asked for
|
|
std::string friendly; // a plain name, for the handful of values on the Essentials list
|
|
int rank{}; // its place on that list, from 1; 0: not on it
|
|
std::uint8_t modes{}; // which short lists it is on (trainer_presets.h: mode_realistic, mode_fun)
|
|
bool used{}; // the game's code was found to read it
|
|
};
|
|
struct PresetRow {
|
|
std::string name, note;
|
|
bool builtin{}, active{}; // active: every value it sets holds what it sets, right now
|
|
// A dial: one multiplier that moves everything the preset moves, 1 = the game's own and
|
|
// `amount` = the preset as it ships. `factor` is where its first value stands.
|
|
bool dial{};
|
|
std::string title;
|
|
double factor{1}, amount{1};
|
|
std::uint8_t modes{}; // which of the short lists show it (mode_realistic, mode_fun)
|
|
};
|
|
struct Marker {
|
|
bool set{};
|
|
std::array<float, 3> position{};
|
|
};
|
|
struct Spot {
|
|
std::string name;
|
|
std::array<float, 3> position{};
|
|
};
|
|
inline constexpr std::size_t marker_slots = 5;
|
|
|
|
// Changes rarely: rebuilt when a command or a level load changes something.
|
|
struct View {
|
|
std::uint64_t revision{};
|
|
bool ready{}; // the game's tuning is read and the running game's copy was found
|
|
std::string status; // why not
|
|
std::string last; // what the last command answered
|
|
bool editable{}; // false while a session's host sets everyone's physics (the host's apply)
|
|
std::string blocked; // the reason shown on locked rows
|
|
std::vector<Row> rows;
|
|
std::vector<std::string> groups;
|
|
std::vector<PresetRow> presets;
|
|
std::size_t touched{};
|
|
// Practice
|
|
int slot{};
|
|
std::array<Marker, marker_slots> markers{};
|
|
bool auto_return{};
|
|
float return_delay{1.5f};
|
|
bool pad_shortcuts{};
|
|
// Height of the hippy jump, which the game scripts instead of tuning (x of its own height).
|
|
float hippy_height{1};
|
|
// The same for the no comply and the boneless.
|
|
float nocomply_height{1}, boneless_height{1};
|
|
float offboard_height{1}; // a jump on foot
|
|
float flip_speed{1}; // board flip tricks: x of the game's own speed
|
|
// HUD
|
|
bool hud{}, hud_jump{}, logging{};
|
|
// The loaded map and what its author ships for the trainer (Mods/<mod>/trainer.json).
|
|
std::string map, map_note, map_preset, profile_preset;
|
|
std::vector<Spot> spots;
|
|
// `trainer open <tab>`: each new serial opens the menu on the trainer page at that tab.
|
|
std::uint64_t open_serial{};
|
|
int open_tab{};
|
|
};
|
|
|
|
struct Jump {
|
|
std::uint64_t serial{}; // 0: none yet
|
|
float takeoff_speed{}, takeoff_angle{}, air_time{}, height{}, distance{}, drop{}, landing_speed{};
|
|
float spin{}, spin_rate{}; // degrees turned about the vertical in the air, and the fastest rate (deg/s)
|
|
float flip{}; // degrees the skater's up axis tumbled (body flips and rolls)
|
|
float board_turn{}; // the board's fastest turn rate, degrees per second (flip tricks, shuvits)
|
|
std::uint32_t state{}; // the physics state it took off into (tells trick kinds apart)
|
|
std::array<float, 3> takeoff{}, landing{};
|
|
};
|
|
// Changes every client tick.
|
|
struct Telemetry {
|
|
bool skater{};
|
|
std::array<float, 3> position{};
|
|
float heading{}; // degrees, 0 = +Z, clockwise seen from above
|
|
float speed{}, vertical{}; // metres per second: over the ground, and upward
|
|
bool airborne{};
|
|
float air_time{}, height{}; // of the jump in progress
|
|
std::uint32_t physics_state{};
|
|
Jump last, best;
|
|
float top_speed{};
|
|
};
|
|
|
|
// Thread-safe snapshots (trainer_view.cpp, part of the overlay).
|
|
std::shared_ptr<const View> view() noexcept;
|
|
Telemetry telemetry() noexcept;
|
|
void publish(std::shared_ptr<const View>) noexcept;
|
|
void publish(const Telemetry &) noexcept;
|
|
// The menu is drawing the list of every value, the game's tuning classes among them. Those
|
|
// have to be found in memory before an edit to one does anything, and the search is only run
|
|
// for a player who has a use for it: this is one. Any thread; the game thread takes the note.
|
|
void note_class_list_shown() noexcept;
|
|
bool take_class_list_shown() noexcept;
|
|
|
|
// Game thread (trainer.cpp).
|
|
// Each client tick; `playing` while a local skater can exist, `level` the loaded level asset.
|
|
void tick(std::uintptr_t base, std::uintptr_t client, bool playing, const std::string &level) noexcept;
|
|
// Runs one `trainer` command and returns the line to print. Only from the console dispatcher.
|
|
std::string command(std::string_view verb, const std::vector<std::string> &arguments);
|
|
} // namespace dingosdk::trainer
|