1
0
mirror of https://github.com/blawar/ooot.git synced 2024-07-02 09:03:36 +00:00

Added Command Line Arguments (#156)

* Cleaned up the input stuff.

* Put all the input related classes into the namespace `hid` and did some further cleanup.

* TAS support is now working.
Generates `last-run.tas`.

* Added *.tas to .gitignore.

* Put `hid` into namespace `oot`.

* Added a trivial form of compression for TAS files.

* End of TAS playback results in end of execution.
Added command line arguments:
-tas <filename> Selects the TAS file that should be played back
-no-graphics Disabled graphics. The window is still open though
-fast-forward Disables frame pacing, makes the game run as fast as possible

* Window now doesn't open anymore when -no-graphics is provided.
However, to make GLideN64 not crash a patch is required (PR for GLideN64 incoming).

* Cleanup.

Co-authored-by: DaMarkov <DaMarkovZED@gmail.com>
This commit is contained in:
DaMarkov 2022-02-16 01:09:11 +01:00 committed by GitHub
parent 0dec26fce0
commit 63e415c816
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 216 additions and 103 deletions

View File

@ -37,6 +37,8 @@
#include "def/z_game_dlftbls.h"
#include "def/z_prenmi_buff.h"
#include "def/z_play.h" // FORCE
#include "../port/controller/tas.h"
#include "../port/options.h"
extern GameStateOverlay gGameStateOverlayTable[6];
extern PreNmiBuff* gAppNmiBufferPtr;
@ -206,7 +208,8 @@ void Graph_TaskSet00(GraphicsContext* gfxCtx) {
osSendMesg(&gSchedContext.cmdQ, scTask, OS_MESG_BLOCK);
Sched_SendEntryMsg(&gSchedContext);
gfx_run(task, sizeof(OSTask_t));
if (!oot::config().game().isGraphicsDisabled())
gfx_run(task, sizeof(OSTask_t));
}
void Graph_Update(GraphicsContext* gfxCtx, GameState* gameState) {
@ -393,11 +396,25 @@ void Graph_ThreadEntry(void* arg0) {
GameState_Init(gameState, (GameStateFunc)ovl->init, &gfxCtx);
while (GameState_IsRunning(gameState) && isRunning()) {
if(gfx_start_frame())
//Has the TAS playback completed?
if (oot::hid::tas::isTasPlaying() && oot::hid::tas::hasTasEnded())
break;
if (oot::config().game().isGraphicsDisabled())
{
gfx_start_frame();
Graph_Update(&gfxCtx, gameState);
gfx_end_frame();
}
else
{
if (gfx_start_frame())
{
Graph_Update(&gfxCtx, gameState);
gfx_end_frame();
}
}
}
nextOvl = Graph_GetNextGameState(gameState);

View File

@ -117,7 +117,7 @@ void N64Controller::resolveInputs()
#define SRAM_SIZE 0x8000//But this in ultra_reimplementation.h?
//Recording TAS?
if (!Tas::isTasPlaying() && oot::config().game().recordTas())
if (!tas::isTasPlaying() && oot::config().game().recordTas())
{
//stream().write((const char*)&m_state, sizeof(m_state));
@ -159,7 +159,7 @@ void N64Controller::resolveInputs()
}
//Playing back a TAS?
else if (Tas::isTasPlaying())
else if (tas::isTasPlaying())
{
if (!m_tasFile)
{
@ -188,8 +188,12 @@ void N64Controller::resolveInputs()
{
//fread(&m_state, sizeof(m_state), 1, m_tasFile);//Uncompressed read
StateCompressed compressed;
compressed.read(m_tasFile);//Read the compressed state
m_state = compressed;//Uncompress
bool end_of_file = compressed.read(m_tasFile);//Read the compressed state
if (end_of_file)//End of file reached, playback is complete
tas::TasEnded();
else
m_state = compressed;//Uncompress
}
}

View File

@ -52,11 +52,13 @@ namespace oot
return ret;
}
void read(FILE* in) {
fread(&m_isUsed, sizeof(u8), 1, in);//Read the flag
bool read(FILE* in) {
if (fread(&m_isUsed, sizeof(u8), 1, in) != 1)//Read the flag
return true;//End of file reached
if (m_isUsed)//Is there even any input?
fread(&m_data, sizeof(InputFrame), 1, in);//Write the full state
return false;
}
void write(FILE* out) {

View File

@ -302,7 +302,7 @@ void Keyboard::update()
if (state[SDL_SCANCODE_F5] && (m_lastKeyState[SDL_SCANCODE_F5] ^ state[SDL_SCANCODE_F5]))
m_state.button |= (uint16_t)Button::U_JPAD | (uint16_t)Button::D_JPAD | (uint16_t)Button::L_JPAD | (uint16_t)Button::R_JPAD;
if (Tas::isTasPlaying())
if (tas::isTasPlaying())
return;
for (const auto& [scancode, input] : m_keyBindings)

View File

@ -369,7 +369,7 @@ bool Joypad::updateRebind(Button input)
void Joypad::update()
{
if (!m_context || Tas::isTasPlaying())
if (!m_context || tas::isTasPlaying())
return;
bool walk = false;

View File

@ -4,81 +4,114 @@
#include "../options.h"
#include "tas.h"
static u64 g_counter = 0;
static bool g_tasPlaying = false;
using namespace oot::hid;
using namespace oot::hid::tas;
bool g_tasPlaying = false;
bool g_tasEnded = false;
std::string g_tasFilename;
bool Tas::isTasPlaying()
bool oot::hid::tas::isTasPlaying()
{
return g_tasPlaying;
return g_tasPlaying;
}
void oot::hid::tas::playTas(bool enable)
{
g_tasPlaying = enable;
}
void oot::hid::tas::setTasFileName(const std::string& newFilename)
{
g_tasFilename = newFilename;
}
std::string oot::hid::tas::getTasFileName()
{
if (g_tasFilename.empty())
g_tasFilename = "last-run.tas";
return g_tasFilename;
/*std::error_code error;
std::filesystem::create_directory(TAS_DIR, error);
time_t now = time(0);
tm* ltm = localtime(&now);
if (!ltm)
return TAS_DIR"/record.tas";
char buf[64] = { 0 };
sprintf(buf, TAS_DIR"/%04d.%02d.%02d-%04d.tas", ltm->tm_year, ltm->tm_mon + 1, ltm->tm_mday, ltm->tm_hour * 60 + ltm->tm_min);
return buf;*/
}
void oot::hid::tas::TasEnded()
{
g_tasEnded = true;
}
bool oot::hid::tas::hasTasEnded()
{
return g_tasEnded;
}
void Tas::playTas(bool enabled)
/*namespace controller
{
g_tasPlaying = enabled;
}
class Tas : public Controller
{
public:
Tas() : Controller()
{
fp = fopen("cont.tas", "rb");
if(fp != NULL)
{
fread(&oot::config(), 1, sizeof(oot::config()), fp);
g_tasPlaying = true;
}
}
virtual ~Tas()
{
if(fp)
{
fclose(fp);
}
}
Tas::Tas() : N64Controller()
void update()
{
if(fp != NULL)
{
auto r = fread(&m_state, 1, sizeof(m_state), fp);
if (m_state.button)
{
int x = 0;
}
}
}
protected:
FILE* fp;
};
} // namespace controller
Tas::Tas() : Driver()
{
fp = fopen("last-run.tas", "rb");
if (fp)
{
//fread(&oot::config(), 1, sizeof(oot::config()), fp);
#define SRAM_SIZE 0x8000//But this in ultra_reimplementation.h?
uint8_t* sram = new uint8_t[SRAM_SIZE];
fread(sram, sizeof(uint8_t), SRAM_SIZE, fp);
FILE* save = nullptr;
fopen_s(&save, "oot.sav", "wb");
if (save)
{
fwrite(sram, sizeof(uint8_t), SRAM_SIZE, save);
fclose(save);
}
delete[] sram;
g_tasPlaying = true;
}
}
Tas::~Tas()
{
if (fp)
fclose(fp);
}
void Tas::update()
void Tas::scan(class Controllers* controllers)
{
if (fp)
{
auto r = fread(&m_state, 1, sizeof(m_state), fp);
if (m_state.button)
int x = 0;
}
}
void Tas::scan()
{
if (!size())
{
auto controller = std::make_shared<Tas>();
m_controllers.push_back(controller);
Players::get().attach(controller, 0);
}
}
if (!size())
{
auto controller = std::make_shared<controller::Tas>();
m_controllers.push_back(controller);
players().attach(controller, 0);
}
}*/

View File

@ -1,26 +1,19 @@
#pragma once
#include <stdio.h>
#include "controllers.h"
#include <string>
namespace oot
namespace oot::hid
{
namespace hid
{
class Tas : public N64Controller, public InputDevice
{
public:
static bool isTasPlaying();
static void playTas(bool enabled);
namespace tas
{
bool isTasPlaying();
void playTas(bool enable);
Tas();
virtual ~Tas();
void scan() override;
void update();
std::string getTasFileName();
void setTasFileName(const std::string& newFilename);
private:
FILE* fp = nullptr;
};
}
void TasEnded();//Called when the TAS has ended (end of file of .tas file reached)
bool hasTasEnded();//Returns true when playback was complete
}
}

View File

@ -1,4 +1,8 @@
#include "global.h"
#include <string>
#include <vector>
#include "global.h"
#include "options.h"
#include "controller/tas.h"
#include "ultra64/types.h"
#include "ultra64/vi.h"
#include "z64audio.h"
@ -129,7 +133,40 @@ extern f32 gViConfigXScale;
extern f32 gViConfigYScale;
extern u32 gViConfigFeatures;
int main() {
void ParseCommandLineArguments(const std::vector<std::string>& commands)
{
auto size_left = commands.size();
for (size_t i = 0; i < commands.size(); i++)
{
auto& cmd = commands[i];
size_left--;
if (cmd == "-tas" && size_left > 0)
{
auto tas_filename = std::move(commands[++i]);
oot::hid::tas::setTasFileName(tas_filename);
oot::hid::tas::playTas(true);
}
else if (cmd == "-no-graphics")
oot::config().game().disableGraphics();
else if (cmd == "-fast-forward")
oot::config().game().disableFramePacing();
}
}
int main(int argc, char** argv) {
std::vector<std::string> commands;
for (int i = 1; i < argc; i++)
commands.push_back(argv[i]);
ParseCommandLineArguments(commands);
s16* msg;

View File

@ -273,14 +273,29 @@ namespace oot
return m_blindowl;
}
bool& Game::isGraphicsDisabled()
{
return m_disableGraphics;
}
void Game::disableGraphics()
{
m_disableGraphics = true;
}
bool& Game::disableSound()
{
return m_disableSound;
}
bool& Game::disableFramePacing()
bool Game::isFramePacing()
{
return m_paceFrames;
return !m_paceFramesDisabled;
}
void Game::disableFramePacing()
{
m_paceFramesDisabled = true;
}
bool& Game::recordTas()

View File

@ -172,13 +172,16 @@ namespace oot
float framerateScaler() const;
u8 framerateScalerInv() const;
bool& isGraphicsDisabled();
void disableGraphics();
bool& disableSound();
bool& fullscreen();
const bool mirror() const;
bool& setMirror();
bool& blindOwl();
bool& disableFramePacing();
bool isFramePacing();
void disableFramePacing();
bool& recordTas();
void recordTas(bool enable);
@ -187,14 +190,15 @@ namespace oot
protected:
u8 m_overclock;
u8 m_framerate;
bool m_disableGraphics;
bool m_disableSound;
bool m_fullscreen;
bool m_mirror;
bool m_blindowl;
bool m_paceFrames;
bool m_paceFramesDisabled;
bool m_recordTas;
bool m_forceMouse;
u8 m_padding[0x40 - 9];
u8 m_padding[0x40 - 10];
};
static_assert(sizeof(Game) == 0x40, "Game Incorrect Size");

View File

@ -291,9 +291,9 @@ void main_func(void)
#endif
#ifdef _DEBUG//Record TAS to capture bugs and crashes
oot::hid::Tas::playTas(true);//Uncomment to play back TAS/crash report from end-users
//oot::hid::tas::playTas(true);//Uncomment to play back TAS/crash report from end-users
if (!oot::hid::Tas::isTasPlaying())
if (!oot::hid::tas::isTasPlaying())
oot::config().game().recordTas(true);
#endif
@ -316,7 +316,8 @@ void main_func(void)
//audio_init();
//interface_init();
gWindow = platform::window::create("The Legend of Zelda - Ocarina of Time", false);
if (!oot::config().game().isGraphicsDisabled())
gWindow = platform::window::create("The Legend of Zelda - Ocarina of Time", false);
#ifdef USE_F3D
gfx_init(&gfx_sdl, &gfx_opengl_api, "Zelda OOT PC-Port", 0);
@ -327,10 +328,15 @@ void main_func(void)
screen_init(&config);
#elif defined(USE_GLIDEN64)
gfx_init("THE LEGEND OF ZELDA", &osViModeNtscLan1);
//gfx_fbe_enable(0);//Uncomment to disable frame buffer emulation
if (!oot::config().game().isGraphicsDisabled())
{
gfx_init("THE LEGEND OF ZELDA", &osViModeNtscLan1);
//gfx_fbe_enable(0);//Uncomment to disable frame buffer emulation
}
#endif
gWindow->resize(-1, -1);
if (!oot::config().game().isGraphicsDisabled())
gWindow->resize(-1, -1);
hid_init();
game_init(NULL);
@ -451,5 +457,4 @@ bool isRunning()
void quit()
{
g_isRunning = false;
}
}

View File

@ -1,6 +1,7 @@
#include "../window.h"
#include <thread>
#include "z64.h"
#include "../options.h"
namespace platform::window
{
@ -108,8 +109,10 @@ namespace platform::window
bool Base::begin_frame()
{
handle_events();
while(!run_paced_loop())
if (oot::config().game().isFramePacing())
{
while (!run_paced_loop())
{}
}
return !dropped_frame;
}