90 lines
3.6 KiB
C++
90 lines
3.6 KiB
C++
#include "StageRuntime.hpp"
|
|
#include "Gameplay.hpp"
|
|
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
#include <iostream>
|
|
|
|
namespace {
|
|
|
|
bool finite(openroller::psp::Vec3 value) {
|
|
return std::isfinite(value.x) && std::isfinite(value.y) && std::isfinite(value.z);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc != 2) {
|
|
std::cerr << "usage: openroller-psp-runtime-probe <stage.orps>\n";
|
|
return 2;
|
|
}
|
|
|
|
openroller::psp::StageView stage{};
|
|
char error[128]{};
|
|
if (!openroller::psp::loadStagePackage(argv[1], &stage, error, sizeof(error))) {
|
|
std::cerr << argv[1] << ": " << error << '\n';
|
|
return 1;
|
|
}
|
|
|
|
bool valid = true;
|
|
const float samples[] = {
|
|
0.0f,
|
|
static_cast<float>(stage.header->durationMs) * 0.5f,
|
|
static_cast<float>(stage.header->durationMs),
|
|
};
|
|
for (float timeMs : samples) {
|
|
const auto position = openroller::psp::trackPositionAt(stage, timeMs);
|
|
const auto camera = openroller::psp::evaluateCamera(stage, timeMs);
|
|
valid = valid && finite(position) && finite(camera.eye) && finite(camera.target) && finite(camera.up) &&
|
|
std::isfinite(camera.projectionBlend);
|
|
std::cout << "t=" << timeMs
|
|
<< " track=(" << position.x << ',' << position.y << ',' << position.z << ')'
|
|
<< " eye=(" << camera.eye.x << ',' << camera.eye.y << ',' << camera.eye.z << ')'
|
|
<< " target=(" << camera.target.x << ',' << camera.target.y << ',' << camera.target.z << ')'
|
|
<< " projection=" << camera.projectionBlend << '\n';
|
|
}
|
|
|
|
std::cout << "bytes=" << stage.storageSize
|
|
<< " track=" << stage.header->track.count
|
|
<< " notes=" << stage.header->notes.count
|
|
<< " cameras=" << stage.header->cameras.count
|
|
<< " bg_models=" << stage.header->backgroundModels.count
|
|
<< " bg_objects=" << stage.header->backgroundObjects.count
|
|
<< " bg_vertices=" << stage.header->backgroundVertices.count
|
|
<< " duration_ms=" << stage.header->durationMs << '\n';
|
|
|
|
openroller::psp::GameplayState gameplay{};
|
|
if (!openroller::psp::initializeGameplay(stage, &gameplay)) {
|
|
std::cerr << "could not initialize PSP gameplay state\n";
|
|
valid = false;
|
|
} else {
|
|
std::uint32_t tapIndex = 0;
|
|
while (tapIndex < stage.header->notes.count &&
|
|
stage.notes[tapIndex].effectiveType != 1 &&
|
|
stage.notes[tapIndex].effectiveType != 2) {
|
|
++tapIndex;
|
|
}
|
|
if (tapIndex == stage.header->notes.count) {
|
|
std::cerr << "stage has no single-tap note for gameplay probe\n";
|
|
valid = false;
|
|
tapIndex = 0;
|
|
}
|
|
const float firstNoteMs = static_cast<float>(stage.notes[tapIndex].timeMs);
|
|
const auto judgment = openroller::psp::pressGameplay(
|
|
stage, &gameplay, firstNoteMs, 1u);
|
|
valid = valid && judgment == openroller::psp::Judgment::Great && gameplay.combo == 1;
|
|
std::cout << "tap_at=" << firstNoteMs
|
|
<< " judgment=" << static_cast<int>(judgment)
|
|
<< " combo=" << gameplay.combo << '\n';
|
|
openroller::psp::seekGameplay(stage, &gameplay, 0.0f);
|
|
openroller::psp::updateGameplay(
|
|
stage, &gameplay,
|
|
firstNoteMs + stage.notes[tapIndex].lateTimingMs + 1.0f);
|
|
valid = valid && gameplay.missCount > 0;
|
|
std::cout << "misses_after_window=" << gameplay.missCount << '\n';
|
|
openroller::psp::destroyGameplay(&gameplay);
|
|
}
|
|
openroller::psp::unloadStagePackage(&stage);
|
|
return valid ? 0 : 1;
|
|
}
|