Adapting for pre-decoded inputs
This commit is contained in:
parent
67c93e664e
commit
6ca0537d45
|
@ -1 +1 @@
|
||||||
Subproject commit 6db55ef68011a6777f980f878a54501f42b6c894
|
Subproject commit e7fd15b6e3ffed9bd718c0bfc0b0a6247e5dfe76
|
|
@ -1,207 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// Base controller class
|
|
||||||
// by eien86
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace quickNES
|
|
||||||
{
|
|
||||||
|
|
||||||
class Controller
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum controller_t { none, joypad, fourscore1, fourscore2 };
|
|
||||||
|
|
||||||
typedef uint32_t port_t;
|
|
||||||
|
|
||||||
struct input_t
|
|
||||||
{
|
|
||||||
bool power = false;
|
|
||||||
bool reset = false;
|
|
||||||
port_t port1 = 0;
|
|
||||||
port_t port2 = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool parseInputString(const std::string& input, input_t* decoded) const
|
|
||||||
{
|
|
||||||
// Parse valid flag
|
|
||||||
bool isValid = true;
|
|
||||||
|
|
||||||
// Converting input into a stream for parsing
|
|
||||||
std::istringstream ss(input);
|
|
||||||
|
|
||||||
// Start separator
|
|
||||||
if (ss.get() != '|') isValid = false;
|
|
||||||
|
|
||||||
// Parsing console inputs
|
|
||||||
isValid &= parseConsoleInputs(decoded->reset, decoded->power, ss);
|
|
||||||
|
|
||||||
// Parsing controller 1 inputs
|
|
||||||
isValid &= parseControllerInputs(_controller1Type, decoded->port1, ss);
|
|
||||||
|
|
||||||
// Parsing controller 1 inputs
|
|
||||||
isValid &= parseControllerInputs(_controller2Type, decoded->port2, ss);
|
|
||||||
|
|
||||||
// End separator
|
|
||||||
if (ss.get() != '|') isValid = false;
|
|
||||||
|
|
||||||
// If its not the end of the stream, then extra values remain and its invalid
|
|
||||||
ss.get();
|
|
||||||
if (ss.eof() == false) isValid = false;
|
|
||||||
|
|
||||||
// Returning valid flag
|
|
||||||
return isValid;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void setController1Type(const controller_t type) { _controller1Type = type; }
|
|
||||||
inline void setController2Type(const controller_t type) { _controller2Type = type; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
static bool parseJoyPadInput(uint8_t& code, std::istringstream& ss)
|
|
||||||
{
|
|
||||||
// Currently read character
|
|
||||||
char c;
|
|
||||||
|
|
||||||
// Cleaning code
|
|
||||||
code = 0;
|
|
||||||
|
|
||||||
// Up
|
|
||||||
c = ss.get();
|
|
||||||
if (c != '.' && c != 'U') return false;
|
|
||||||
if (c == 'U') code |= 0b00010000;
|
|
||||||
|
|
||||||
// Down
|
|
||||||
c = ss.get();
|
|
||||||
if (c != '.' && c != 'D') return false;
|
|
||||||
if (c == 'D') code |= 0b00100000;
|
|
||||||
|
|
||||||
// Left
|
|
||||||
c = ss.get();
|
|
||||||
if (c != '.' && c != 'L') return false;
|
|
||||||
if (c == 'L') code |= 0b01000000;
|
|
||||||
|
|
||||||
// Right
|
|
||||||
c = ss.get();
|
|
||||||
if (c != '.' && c != 'R') return false;
|
|
||||||
if (c == 'R') code |= 0b10000000;
|
|
||||||
|
|
||||||
// Start
|
|
||||||
c = ss.get();
|
|
||||||
if (c != '.' && c != 'S') return false;
|
|
||||||
if (c == 'S') code |= 0b00001000;
|
|
||||||
|
|
||||||
// Select
|
|
||||||
c = ss.get();
|
|
||||||
if (c != '.' && c != 's') return false;
|
|
||||||
if (c == 's') code |= 0b00000100;
|
|
||||||
|
|
||||||
// B
|
|
||||||
c = ss.get();
|
|
||||||
if (c != '.' && c != 'B') return false;
|
|
||||||
if (c == 'B') code |= 0b00000010;
|
|
||||||
|
|
||||||
// A
|
|
||||||
c = ss.get();
|
|
||||||
if (c != '.' && c != 'A') return false;
|
|
||||||
if (c == 'A') code |= 0b00000001;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool parseControllerInputs(const controller_t type, port_t& port, std::istringstream& ss)
|
|
||||||
{
|
|
||||||
// Parse valid flag
|
|
||||||
bool isValid = true;
|
|
||||||
|
|
||||||
// If no controller assigned then, its port is all zeroes.
|
|
||||||
if (type == controller_t::none) { port = 0; return true; }
|
|
||||||
|
|
||||||
// Controller separator
|
|
||||||
if (ss.get() != '|') isValid = false;
|
|
||||||
|
|
||||||
// If normal joypad, parse its code now
|
|
||||||
if (type == controller_t::joypad)
|
|
||||||
{
|
|
||||||
// Storage for joypad's code
|
|
||||||
uint8_t code = 0;
|
|
||||||
|
|
||||||
// Parsing joypad code
|
|
||||||
isValid &= parseJoyPadInput(code, ss);
|
|
||||||
|
|
||||||
// Pushing input code into the port
|
|
||||||
port = code;
|
|
||||||
|
|
||||||
// Adding joypad signature
|
|
||||||
// Per https://www.nesdev.org/wiki/Standard_controller, the joypad reports 1s after the first 8 bits
|
|
||||||
port |= ~0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If its fourscore, its like two joypads separated by a |
|
|
||||||
if (type == controller_t::fourscore1 || type == controller_t::fourscore2)
|
|
||||||
{
|
|
||||||
// Storage for joypad's code
|
|
||||||
uint8_t code1 = 0;
|
|
||||||
uint8_t code2 = 0;
|
|
||||||
|
|
||||||
// Parsing joypad code1
|
|
||||||
isValid &= parseJoyPadInput(code1, ss);
|
|
||||||
|
|
||||||
// Separator
|
|
||||||
if (ss.get() != '|') return false;
|
|
||||||
|
|
||||||
// Parsing joypad code1
|
|
||||||
isValid &= parseJoyPadInput(code2, ss);
|
|
||||||
|
|
||||||
// Creating code
|
|
||||||
port = code1;
|
|
||||||
port |= (uint32_t)0 | code2 << 8;
|
|
||||||
if (type == controller_t::fourscore1) port |= (uint32_t)0 | 1 << 19;
|
|
||||||
if (type == controller_t::fourscore2) port |= (uint32_t)0 | 1 << 18;
|
|
||||||
port |= (uint32_t)0 | 1 << 24;
|
|
||||||
port |= (uint32_t)0 | 1 << 25;
|
|
||||||
port |= (uint32_t)0 | 1 << 26;
|
|
||||||
port |= (uint32_t)0 | 1 << 27;
|
|
||||||
port |= (uint32_t)0 | 1 << 28;
|
|
||||||
port |= (uint32_t)0 | 1 << 29;
|
|
||||||
port |= (uint32_t)0 | 1 << 30;
|
|
||||||
port |= (uint32_t)0 | 1 << 31;
|
|
||||||
}
|
|
||||||
// Return valid flag
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool parseConsoleInputs(bool& reset, bool& power, std::istringstream& ss)
|
|
||||||
{
|
|
||||||
// Parse valid flag
|
|
||||||
bool isValid = true;
|
|
||||||
|
|
||||||
// Currently read character
|
|
||||||
char c;
|
|
||||||
|
|
||||||
// Power trigger
|
|
||||||
c = ss.get();
|
|
||||||
if (c != '.' && c != 'P') isValid = false;
|
|
||||||
if (c == 'P') power = true;
|
|
||||||
if (c == '.') power = false;
|
|
||||||
|
|
||||||
// Reset trigger
|
|
||||||
c = ss.get();
|
|
||||||
if (c != '.' && c != 'r') isValid = false;
|
|
||||||
if (c == 'r') reset = true;
|
|
||||||
if (c == '.') reset = false;
|
|
||||||
|
|
||||||
// Return valid flag
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
controller_t _controller1Type;
|
|
||||||
controller_t _controller2Type;
|
|
||||||
|
|
||||||
}; // class Controller
|
|
||||||
|
|
||||||
} // namespace quickNES
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Base controller class
|
||||||
|
// by eien86
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <jaffarCommon/exceptions.hpp>
|
||||||
|
#include <jaffarCommon/json.hpp>
|
||||||
|
|
||||||
|
namespace jaffar
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef uint32_t port_t;
|
||||||
|
|
||||||
|
struct input_t
|
||||||
|
{
|
||||||
|
bool power = false;
|
||||||
|
bool reset = false;
|
||||||
|
port_t port1 = 0;
|
||||||
|
port_t port2 = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class InputParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum controller_t { none, joypad, fourscore1, fourscore2 };
|
||||||
|
|
||||||
|
InputParser(const nlohmann::json &config)
|
||||||
|
{
|
||||||
|
// Parsing controller 1 type
|
||||||
|
{
|
||||||
|
bool isTypeRecognized = false;
|
||||||
|
const auto controller1Type = jaffarCommon::json::getString(config, "Controller 1 Type");
|
||||||
|
if (controller1Type == "None") { _controller1Type = controller_t::none; isTypeRecognized = true; }
|
||||||
|
if (controller1Type == "Joypad") { _controller1Type = controller_t::joypad; isTypeRecognized = true; }
|
||||||
|
if (controller1Type == "FourScore1") { _controller1Type = controller_t::fourscore1; isTypeRecognized = true; }
|
||||||
|
if (controller1Type == "FourScore2") { _controller1Type = controller_t::fourscore2; isTypeRecognized = true; }
|
||||||
|
if (isTypeRecognized == false) JAFFAR_THROW_LOGIC("Controller 1 type not recognized: '%s'\n", controller1Type.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsing controller 2 type
|
||||||
|
{
|
||||||
|
bool isTypeRecognized = false;
|
||||||
|
const auto controller2Type = jaffarCommon::json::getString(config, "Controller 2 Type");
|
||||||
|
if (controller2Type == "None") { _controller2Type = controller_t::none; isTypeRecognized = true; }
|
||||||
|
if (controller2Type == "Joypad") { _controller2Type = controller_t::joypad; isTypeRecognized = true; }
|
||||||
|
if (controller2Type == "FourScore1") { _controller2Type = controller_t::fourscore1; isTypeRecognized = true; }
|
||||||
|
if (controller2Type == "FourScore2") { _controller2Type = controller_t::fourscore2; isTypeRecognized = true; }
|
||||||
|
if (isTypeRecognized == false) JAFFAR_THROW_LOGIC("Controller 2 type not recognized: '%s'\n", controller2Type.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline input_t parseInputString(const std::string& inputString) const
|
||||||
|
{
|
||||||
|
// Storage for the input
|
||||||
|
input_t input;
|
||||||
|
|
||||||
|
// Converting input into a stream for parsing
|
||||||
|
std::istringstream ss(inputString);
|
||||||
|
|
||||||
|
// Start separator
|
||||||
|
if (ss.get() != '|') reportBadInputString(inputString);
|
||||||
|
|
||||||
|
// Parsing console inputs
|
||||||
|
parseConsoleInputs(input.reset, input.power, ss, inputString);
|
||||||
|
|
||||||
|
// Parsing controller 1 inputs
|
||||||
|
parseControllerInputs(_controller1Type, input.port1, ss, inputString);
|
||||||
|
|
||||||
|
// Parsing controller 1 inputs
|
||||||
|
parseControllerInputs(_controller2Type, input.port2, ss, inputString);
|
||||||
|
|
||||||
|
// End separator
|
||||||
|
if (ss.get() != '|') reportBadInputString(inputString);
|
||||||
|
|
||||||
|
// If its not the end of the stream, then extra values remain and its invalid
|
||||||
|
ss.get();
|
||||||
|
if (ss.eof() == false) reportBadInputString(inputString);
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static inline void reportBadInputString(const std::string& inputString)
|
||||||
|
{
|
||||||
|
JAFFAR_THROW_LOGIC("Could not decode input string: '%s'\n", inputString.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseJoyPadInput(uint8_t& code, std::istringstream& ss, const std::string& inputString)
|
||||||
|
{
|
||||||
|
// Currently read character
|
||||||
|
char c;
|
||||||
|
|
||||||
|
// Cleaning code
|
||||||
|
code = 0;
|
||||||
|
|
||||||
|
// Up
|
||||||
|
c = ss.get();
|
||||||
|
if (c != '.' && c != 'U') reportBadInputString(inputString);
|
||||||
|
if (c == 'U') code |= 0b00010000;
|
||||||
|
|
||||||
|
// Down
|
||||||
|
c = ss.get();
|
||||||
|
if (c != '.' && c != 'D') reportBadInputString(inputString);
|
||||||
|
if (c == 'D') code |= 0b00100000;
|
||||||
|
|
||||||
|
// Left
|
||||||
|
c = ss.get();
|
||||||
|
if (c != '.' && c != 'L') reportBadInputString(inputString);
|
||||||
|
if (c == 'L') code |= 0b01000000;
|
||||||
|
|
||||||
|
// Right
|
||||||
|
c = ss.get();
|
||||||
|
if (c != '.' && c != 'R') reportBadInputString(inputString);
|
||||||
|
if (c == 'R') code |= 0b10000000;
|
||||||
|
|
||||||
|
// Start
|
||||||
|
c = ss.get();
|
||||||
|
if (c != '.' && c != 'S') reportBadInputString(inputString);
|
||||||
|
if (c == 'S') code |= 0b00001000;
|
||||||
|
|
||||||
|
// Select
|
||||||
|
c = ss.get();
|
||||||
|
if (c != '.' && c != 's') reportBadInputString(inputString);
|
||||||
|
if (c == 's') code |= 0b00000100;
|
||||||
|
|
||||||
|
// B
|
||||||
|
c = ss.get();
|
||||||
|
if (c != '.' && c != 'B') reportBadInputString(inputString);
|
||||||
|
if (c == 'B') code |= 0b00000010;
|
||||||
|
|
||||||
|
// A
|
||||||
|
c = ss.get();
|
||||||
|
if (c != '.' && c != 'A') reportBadInputString(inputString);
|
||||||
|
if (c == 'A') code |= 0b00000001;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseControllerInputs(const controller_t type, port_t& port, std::istringstream& ss, const std::string& inputString)
|
||||||
|
{
|
||||||
|
// If no controller assigned then, its port is all zeroes.
|
||||||
|
if (type == controller_t::none) { port = 0; return; }
|
||||||
|
|
||||||
|
// Controller separator
|
||||||
|
if (ss.get() != '|') reportBadInputString(inputString);
|
||||||
|
|
||||||
|
// If normal joypad, parse its code now
|
||||||
|
if (type == controller_t::joypad)
|
||||||
|
{
|
||||||
|
// Storage for joypad's code
|
||||||
|
uint8_t code = 0;
|
||||||
|
|
||||||
|
// Parsing joypad code
|
||||||
|
parseJoyPadInput(code, ss, inputString);
|
||||||
|
|
||||||
|
// Pushing input code into the port
|
||||||
|
port = code;
|
||||||
|
|
||||||
|
// Adding joypad signature
|
||||||
|
// Per https://www.nesdev.org/wiki/Standard_controller, the joypad reports 1s after the first 8 bits
|
||||||
|
port |= ~0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If its fourscore, its like two joypads separated by a |
|
||||||
|
if (type == controller_t::fourscore1 || type == controller_t::fourscore2)
|
||||||
|
{
|
||||||
|
// Storage for joypad's code
|
||||||
|
uint8_t code1 = 0;
|
||||||
|
uint8_t code2 = 0;
|
||||||
|
|
||||||
|
// Parsing joypad code1
|
||||||
|
parseJoyPadInput(code1, ss, inputString);
|
||||||
|
|
||||||
|
// Separator
|
||||||
|
if (ss.get() != '|') reportBadInputString(inputString);
|
||||||
|
|
||||||
|
// Parsing joypad code1
|
||||||
|
parseJoyPadInput(code2, ss, inputString);
|
||||||
|
|
||||||
|
// Creating code
|
||||||
|
port = code1;
|
||||||
|
port |= (uint32_t)0 | code2 << 8;
|
||||||
|
if (type == controller_t::fourscore1) port |= (uint32_t)0 | 1 << 19;
|
||||||
|
if (type == controller_t::fourscore2) port |= (uint32_t)0 | 1 << 18;
|
||||||
|
port |= (uint32_t)0 | 1 << 24;
|
||||||
|
port |= (uint32_t)0 | 1 << 25;
|
||||||
|
port |= (uint32_t)0 | 1 << 26;
|
||||||
|
port |= (uint32_t)0 | 1 << 27;
|
||||||
|
port |= (uint32_t)0 | 1 << 28;
|
||||||
|
port |= (uint32_t)0 | 1 << 29;
|
||||||
|
port |= (uint32_t)0 | 1 << 30;
|
||||||
|
port |= (uint32_t)0 | 1 << 31;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseConsoleInputs(bool& reset, bool& power, std::istringstream& ss, const std::string& inputString)
|
||||||
|
{
|
||||||
|
// Currently read character
|
||||||
|
char c;
|
||||||
|
|
||||||
|
// Power trigger
|
||||||
|
c = ss.get();
|
||||||
|
if (c != '.' && c != 'P') reportBadInputString(inputString);
|
||||||
|
if (c == 'P') power = true;
|
||||||
|
if (c == '.') power = false;
|
||||||
|
|
||||||
|
// Reset trigger
|
||||||
|
c = ss.get();
|
||||||
|
if (c != '.' && c != 'r') reportBadInputString(inputString);
|
||||||
|
if (c == 'r') reset = true;
|
||||||
|
if (c == '.') reset = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
controller_t _controller1Type;
|
||||||
|
controller_t _controller2Type;
|
||||||
|
|
||||||
|
}; // class InputParser
|
||||||
|
|
||||||
|
} // namespace jaffar
|
|
@ -3,7 +3,7 @@
|
||||||
#include "jaffarCommon/serializers/contiguous.hpp"
|
#include "jaffarCommon/serializers/contiguous.hpp"
|
||||||
#include "jaffarCommon/serializers/differential.hpp"
|
#include "jaffarCommon/serializers/differential.hpp"
|
||||||
#include "jaffarCommon/logger.hpp"
|
#include "jaffarCommon/logger.hpp"
|
||||||
#include "controller.hpp"
|
#include "inputParser.hpp"
|
||||||
|
|
||||||
// Size of image generated in graphics buffer
|
// Size of image generated in graphics buffer
|
||||||
static const uint16_t image_width = 256;
|
static const uint16_t image_width = 256;
|
||||||
|
@ -13,71 +13,14 @@ class NESInstanceBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NESInstanceBase() = default;
|
NESInstanceBase(const nlohmann::json& config)
|
||||||
|
{
|
||||||
|
_inputParser = std::make_unique<jaffar::InputParser>(config);
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~NESInstanceBase() = default;
|
virtual ~NESInstanceBase() = default;
|
||||||
|
|
||||||
inline void advanceState(const std::string &input)
|
virtual void advanceState(const jaffar::input_t &input) = 0;
|
||||||
{
|
|
||||||
// Storage for the decoded input
|
|
||||||
quickNES::Controller::input_t decodedInput;
|
|
||||||
|
|
||||||
// Getting decoded input from the input string
|
|
||||||
decodeInput(input, &decodedInput);
|
|
||||||
|
|
||||||
// Calling advance state with the decoded input
|
|
||||||
advanceState(&decodedInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void advanceState(const void* decodedInputBuffer)
|
|
||||||
{
|
|
||||||
// Casting decoded input to the right type
|
|
||||||
const auto decodedInput = (quickNES::Controller::input_t*) decodedInputBuffer;
|
|
||||||
|
|
||||||
// Parsing power
|
|
||||||
if (decodedInput->power == true) JAFFAR_THROW_LOGIC("Power button pressed, but not supported.");
|
|
||||||
|
|
||||||
// Parsing reset
|
|
||||||
if (decodedInput->reset == true) doSoftReset();
|
|
||||||
|
|
||||||
// Running specified inputs
|
|
||||||
advanceStateImpl(decodedInput->port1, decodedInput->port2);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t getDecodedInputSize() const
|
|
||||||
{
|
|
||||||
return sizeof(quickNES::Controller::input_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void decodeInput(const std::string &input, void* decodedInputBuffer) const
|
|
||||||
{
|
|
||||||
const auto decodedInput = (quickNES::Controller::input_t*) decodedInputBuffer;
|
|
||||||
bool isInputValid = _controller.parseInputString(input, decodedInput);
|
|
||||||
if (isInputValid == false) JAFFAR_THROW_LOGIC("Move provided cannot be parsed: '%s'\n", input.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setController1Type(const std::string& type)
|
|
||||||
{
|
|
||||||
bool isTypeRecognized = false;
|
|
||||||
|
|
||||||
if (type == "None") { _controller.setController1Type(quickNES::Controller::controller_t::none); isTypeRecognized = true; }
|
|
||||||
if (type == "Joypad") { _controller.setController1Type(quickNES::Controller::controller_t::joypad); isTypeRecognized = true; }
|
|
||||||
if (type == "FourScore1") { _controller.setController1Type(quickNES::Controller::controller_t::fourscore1); isTypeRecognized = true; }
|
|
||||||
if (type == "FourScore2") { _controller.setController1Type(quickNES::Controller::controller_t::fourscore2); isTypeRecognized = true; }
|
|
||||||
|
|
||||||
if (isTypeRecognized == false) JAFFAR_THROW_LOGIC("Input type not recognized: '%s'\n", type.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setController2Type(const std::string& type)
|
|
||||||
{
|
|
||||||
bool isTypeRecognized = false;
|
|
||||||
|
|
||||||
if (type == "None") { _controller.setController2Type(quickNES::Controller::controller_t::none); isTypeRecognized = true; }
|
|
||||||
if (type == "Joypad") { _controller.setController2Type(quickNES::Controller::controller_t::joypad); isTypeRecognized = true; }
|
|
||||||
if (type == "FourScore1") { _controller.setController2Type(quickNES::Controller::controller_t::fourscore1); isTypeRecognized = true; }
|
|
||||||
if (type == "FourScore2") { _controller.setController2Type(quickNES::Controller::controller_t::fourscore2); isTypeRecognized = true; }
|
|
||||||
|
|
||||||
if (isTypeRecognized == false) JAFFAR_THROW_LOGIC("Input type not recognized: '%s'\n", type.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void enableRendering() { _doRendering = true; };
|
inline void enableRendering() { _doRendering = true; };
|
||||||
inline void disableRendering() { _doRendering = false; };
|
inline void disableRendering() { _doRendering = false; };
|
||||||
|
@ -114,7 +57,8 @@ class NESInstanceBase
|
||||||
|
|
||||||
virtual size_t getFullStateSize() const = 0;
|
virtual size_t getFullStateSize() const = 0;
|
||||||
virtual size_t getDifferentialStateSize() const = 0;
|
virtual size_t getDifferentialStateSize() const = 0;
|
||||||
|
inline jaffar::InputParser* getInputParser() const { return _inputParser.get(); }
|
||||||
|
|
||||||
// Virtual functions
|
// Virtual functions
|
||||||
|
|
||||||
virtual uint8_t *getLowMem() const = 0;
|
virtual uint8_t *getLowMem() const = 0;
|
||||||
|
@ -134,7 +78,6 @@ class NESInstanceBase
|
||||||
virtual void enableStateBlockImpl(const std::string& block) = 0;
|
virtual void enableStateBlockImpl(const std::string& block) = 0;
|
||||||
virtual void disableStateBlockImpl(const std::string& block) = 0;
|
virtual void disableStateBlockImpl(const std::string& block) = 0;
|
||||||
virtual bool loadROMImpl(const uint8_t* romData, const size_t romSize) = 0;
|
virtual bool loadROMImpl(const uint8_t* romData, const size_t romSize) = 0;
|
||||||
virtual void advanceStateImpl(const quickNES::Controller::port_t controller1, const quickNES::Controller::port_t controller2) = 0;
|
|
||||||
|
|
||||||
// Storage for the light state size
|
// Storage for the light state size
|
||||||
size_t _stateSize;
|
size_t _stateSize;
|
||||||
|
@ -144,6 +87,7 @@ class NESInstanceBase
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Controller class for input parsing
|
// Input parser instance
|
||||||
quickNES::Controller _controller;
|
std::unique_ptr<jaffar::InputParser> _inputParser;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -112,12 +112,11 @@ int main(int argc, char *argv[])
|
||||||
jaffarCommon::logger::refreshTerminal();
|
jaffarCommon::logger::refreshTerminal();
|
||||||
|
|
||||||
// Creating emulator instance
|
// Creating emulator instance
|
||||||
|
nlohmann::json emulatorConfig;
|
||||||
|
emulatorConfig["Controller 1 Type"] = controller1Type;
|
||||||
|
emulatorConfig["Controller 2 Type"] = controller2Type;
|
||||||
NESInstance e;
|
NESInstance e;
|
||||||
|
|
||||||
// Setting controller types
|
|
||||||
e.setController1Type(controller1Type);
|
|
||||||
e.setController2Type(controller2Type);
|
|
||||||
|
|
||||||
// Loading ROM File
|
// Loading ROM File
|
||||||
std::string romFileData;
|
std::string romFileData;
|
||||||
if (jaffarCommon::file::loadStringFromFile(romFileData, romFilePath) == false) JAFFAR_THROW_LOGIC("Could not rom file: %s\n", romFilePath.c_str());
|
if (jaffarCommon::file::loadStringFromFile(romFileData, romFilePath) == false) JAFFAR_THROW_LOGIC("Could not rom file: %s\n", romFilePath.c_str());
|
||||||
|
|
|
@ -17,7 +17,8 @@ extern void register_mapper_70();
|
||||||
class NESInstance final : public NESInstanceBase
|
class NESInstance final : public NESInstanceBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NESInstance() : NESInstanceBase()
|
|
||||||
|
NESInstance(const nlohmann::json& config) : NESInstanceBase(config)
|
||||||
{
|
{
|
||||||
// If running the original QuickNES, register extra mappers now
|
// If running the original QuickNES, register extra mappers now
|
||||||
register_misc_mappers();
|
register_misc_mappers();
|
||||||
|
@ -60,6 +61,12 @@ class NESInstance final : public NESInstanceBase
|
||||||
|
|
||||||
void *getInternalEmulatorPointer() override { return &_nes; }
|
void *getInternalEmulatorPointer() override { return &_nes; }
|
||||||
|
|
||||||
|
void advanceState(const jaffar::input_t &input) override
|
||||||
|
{
|
||||||
|
if (_doRendering == true) _nes.emulate_frame(input.port1, input.port2);
|
||||||
|
if (_doRendering == false) _nes.emulate_skip_frame(input.port1, input.port2);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
bool loadROMImpl(const uint8_t* romData, const size_t romSize) override
|
bool loadROMImpl(const uint8_t* romData, const size_t romSize) override
|
||||||
|
@ -74,11 +81,6 @@ class NESInstance final : public NESInstanceBase
|
||||||
void enableStateBlockImpl(const std::string& block) override {};
|
void enableStateBlockImpl(const std::string& block) override {};
|
||||||
void disableStateBlockImpl(const std::string& block) override {};
|
void disableStateBlockImpl(const std::string& block) override {};
|
||||||
|
|
||||||
void advanceStateImpl(const quickNES::Controller::port_t controller1, const quickNES::Controller::port_t controller2) override
|
|
||||||
{
|
|
||||||
if (_doRendering == true) _nes.emulate_frame(controller1, controller2);
|
|
||||||
if (_doRendering == false) _nes.emulate_skip_frame(controller1, controller2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ class NESInstance final : public NESInstanceBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
NESInstance(const nlohmann::json& config) : NESInstanceBase(config) {}
|
||||||
|
|
||||||
uint8_t *getLowMem() const override { return _nes.get_low_mem(); };
|
uint8_t *getLowMem() const override { return _nes.get_low_mem(); };
|
||||||
size_t getLowMemSize() const override { return _nes.get_low_mem_size(); };
|
size_t getLowMemSize() const override { return _nes.get_low_mem_size(); };
|
||||||
|
|
||||||
|
@ -50,6 +52,12 @@ class NESInstance final : public NESInstanceBase
|
||||||
|
|
||||||
void setNTABBlockSize(const size_t size) override { _nes.setNTABBlockSize(size); }
|
void setNTABBlockSize(const size_t size) override { _nes.setNTABBlockSize(size); }
|
||||||
|
|
||||||
|
void advanceState(const jaffar::input_t &input) override
|
||||||
|
{
|
||||||
|
if (_doRendering == true) _nes.emulate_frame(input.port1, input.port2);
|
||||||
|
if (_doRendering == false) _nes.emulate_skip_frame(input.port1, input.port2);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
bool loadROMImpl(const uint8_t* romData, const size_t romSize) override
|
bool loadROMImpl(const uint8_t* romData, const size_t romSize) override
|
||||||
|
@ -61,11 +69,7 @@ class NESInstance final : public NESInstanceBase
|
||||||
|
|
||||||
void enableStateBlockImpl(const std::string& block) override { _nes.enableStateBlock(block); };
|
void enableStateBlockImpl(const std::string& block) override { _nes.enableStateBlock(block); };
|
||||||
void disableStateBlockImpl(const std::string& block) override { _nes.disableStateBlock(block); };
|
void disableStateBlockImpl(const std::string& block) override { _nes.disableStateBlock(block); };
|
||||||
void advanceStateImpl(const quickNES::Controller::port_t controller1, const quickNES::Controller::port_t controller2) override
|
|
||||||
{
|
|
||||||
if (_doRendering == true) _nes.emulate_frame(controller1, controller2);
|
|
||||||
if (_doRendering == false) _nes.emulate_skip_frame(controller1, controller2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ int main(int argc, char *argv[])
|
||||||
stateDisabledBlocks.push_back(entry.get<std::string>());
|
stateDisabledBlocks.push_back(entry.get<std::string>());
|
||||||
stateDisabledBlocksOutput += entry.get<std::string>() + std::string(" ");
|
stateDisabledBlocksOutput += entry.get<std::string>() + std::string(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting Controller 1 type
|
// Getting Controller 1 type
|
||||||
if (scriptJson.contains("Controller 1 Type") == false) JAFFAR_THROW_LOGIC("Script file missing 'Controller 1 Type' entry\n");
|
if (scriptJson.contains("Controller 1 Type") == false) JAFFAR_THROW_LOGIC("Script file missing 'Controller 1 Type' entry\n");
|
||||||
if (scriptJson["Controller 1 Type"].is_string() == false) JAFFAR_THROW_LOGIC("Script file 'Controller 1 Type' entry is not a string\n");
|
if (scriptJson["Controller 1 Type"].is_string() == false) JAFFAR_THROW_LOGIC("Script file 'Controller 1 Type' entry is not a string\n");
|
||||||
|
@ -116,11 +116,7 @@ int main(int argc, char *argv[])
|
||||||
const auto differentialCompressionUseZlib = differentialCompressionJs["Use Zlib"].get<bool>();
|
const auto differentialCompressionUseZlib = differentialCompressionJs["Use Zlib"].get<bool>();
|
||||||
|
|
||||||
// Creating emulator instance
|
// Creating emulator instance
|
||||||
NESInstance e;
|
NESInstance e(scriptJson);
|
||||||
|
|
||||||
// Setting controller types
|
|
||||||
e.setController1Type(controller1Type);
|
|
||||||
e.setController2Type(controller2Type);
|
|
||||||
|
|
||||||
// Loading ROM File
|
// Loading ROM File
|
||||||
std::string romFileData;
|
std::string romFileData;
|
||||||
|
@ -165,6 +161,13 @@ int main(int argc, char *argv[])
|
||||||
// Getting sequence lenght
|
// Getting sequence lenght
|
||||||
const auto sequenceLength = sequence.size();
|
const auto sequenceLength = sequence.size();
|
||||||
|
|
||||||
|
// Getting input parser from the emulator
|
||||||
|
const auto inputParser = e.getInputParser();
|
||||||
|
|
||||||
|
// Getting decoded emulator input for each entry in the sequence
|
||||||
|
std::vector<jaffar::input_t> decodedSequence;
|
||||||
|
for (const auto& inputString : sequence) decodedSequence.push_back(inputParser->parseInputString(inputString));
|
||||||
|
|
||||||
// Getting emulation core name
|
// Getting emulation core name
|
||||||
std::string emulationCoreName = e.getCoreName();
|
std::string emulationCoreName = e.getCoreName();
|
||||||
|
|
||||||
|
@ -174,7 +177,6 @@ int main(int argc, char *argv[])
|
||||||
printf("[] Cycle Type: '%s'\n", cycleType.c_str());
|
printf("[] Cycle Type: '%s'\n", cycleType.c_str());
|
||||||
printf("[] Emulation Core: '%s'\n", emulationCoreName.c_str());
|
printf("[] Emulation Core: '%s'\n", emulationCoreName.c_str());
|
||||||
printf("[] ROM File: '%s'\n", romFilePath.c_str());
|
printf("[] ROM File: '%s'\n", romFilePath.c_str());
|
||||||
printf("[] Controller Types: '%s' / '%s'\n", controller1Type.c_str(), controller2Type.c_str());
|
|
||||||
printf("[] ROM Hash: 'SHA1: %s'\n", romSHA1.c_str());
|
printf("[] ROM Hash: 'SHA1: %s'\n", romSHA1.c_str());
|
||||||
printf("[] Sequence File: '%s'\n", sequenceFilePath.c_str());
|
printf("[] Sequence File: '%s'\n", sequenceFilePath.c_str());
|
||||||
printf("[] Sequence Length: %lu\n", sequenceLength);
|
printf("[] Sequence Length: %lu\n", sequenceLength);
|
||||||
|
@ -218,7 +220,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
// Actually running the sequence
|
// Actually running the sequence
|
||||||
auto t0 = std::chrono::high_resolution_clock::now();
|
auto t0 = std::chrono::high_resolution_clock::now();
|
||||||
for (const std::string &input : sequence)
|
for (const auto &input : decodedSequence)
|
||||||
{
|
{
|
||||||
if (doPreAdvance == true) e.advanceState(input);
|
if (doPreAdvance == true) e.advanceState(input);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue