Files
ReSkate/Extension/Trainer/Test/tuning_dump.cpp
T
andrewnakasandClaude Opus 5.5 8eedd0a5c4 Add the ReSkate Trainer: a TRAINER page with live physics tuning, presets, practice tools and jump telemetry
All new code is in Extension/Trainer. The game thread owns the trainer's state; the menu
page only queues `trainer ...` console commands and reads two snapshots.

- physics_tuning_model keeps the field and curve names the game's EBX carries, so the
  editable table is built at run time from the player's own data.
- physics_tuning exports game_tuning / read_live / write_live / refresh_skater, with the
  same field whitelist and curve rules as the session sync.
- no_bail publishes the physics state the local skater's selector last chose (air time,
  wipeouts).
- A guest under host tuning cannot edit; teleports follow the host's noclip permission.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-03 09:49:58 -06:00

54 lines
2.4 KiB
C++

// Lists every value of Gameplay/SkatePhysicsTuning the trainer can edit, as the game's own
// data names it.
// dingosdk_trainer_tuning_dump <Skate folder>
#include "Extension/Skater/physics_tuning_model.h"
#include <cstring>
#include <iostream>
int main(int argc, char **argv) {
if (argc < 2) {
std::cerr << "usage: dingosdk_trainer_tuning_dump <Skate folder>\n";
return 2;
}
try {
const auto model = dingosdk::physics_tuning::read_game_tuning(argv[1]);
std::size_t unnamed{};
for (std::size_t i = 0; i < model.fields.size(); ++i) {
const auto &f = model.fields[i];
const auto &name = model.field_names[i];
if (name.empty()) ++unnamed;
std::cout << (name.empty() ? "?" : name) << '\t' << std::hex << "0x" << f.offset << std::dec << '\t';
if (f.real) {
float value;
std::memcpy(&value, model.image.data() + f.offset, 4);
std::cout << "real\t" << value;
} else if (f.flag) {
std::cout << "flag\t" << static_cast<int>(model.image[f.offset]);
} else {
std::int64_t value{};
std::memcpy(&value, model.image.data() + f.offset, f.size);
std::cout << "int" << f.size * 8 << '\t' << value;
}
std::cout << '\n';
}
for (std::size_t i = 0; i < model.curve_slots.size(); ++i) {
const auto &curve = model.curves[i];
std::cout << (model.curve_names[i].empty() ? "?" : model.curve_names[i]) << '\t' << std::hex << "0x" << model.curve_slots[i]
<< std::dec << "\tcurve\t" << (curve ? curve->points.size() / 0x1c : 0) << " points";
if (curve)
for (std::size_t p = 0; p + 0x1c <= curve->points.size(); p += 0x1c) {
float x, y;
std::memcpy(&x, curve->points.data() + p + 0xc, 4);
std::memcpy(&y, curve->points.data() + p + 0x14, 4);
std::cout << " (" << x << ", " << y << ")";
}
std::cout << '\n';
}
std::cerr << model.fields.size() << " values (" << unnamed << " unnamed), " << model.curve_slots.size() << " curves\n";
return unnamed ? 1 : 0;
} catch (const std::exception &error) {
std::cerr << "error: " << error.what() << '\n';
return 1;
}
}