2024-01-10 18:48:57 +00:00
|
|
|
#pragma once
|
|
|
|
|
2024-01-12 18:14:57 +00:00
|
|
|
#include "sha1/sha1.hpp"
|
2024-01-20 10:21:34 +00:00
|
|
|
#include <utils.hpp>
|
2024-01-21 14:34:15 +00:00
|
|
|
#include <controller.hpp>
|
2024-01-10 18:48:57 +00:00
|
|
|
|
|
|
|
#define _LOW_MEM_SIZE 0x800
|
|
|
|
#define _HIGH_MEM_SIZE 0x2000
|
2024-01-12 20:13:51 +00:00
|
|
|
#define _NAMETABLES_MEM_SIZE 0x1000
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-15 19:56:58 +00:00
|
|
|
// Size of image generated in graphics buffer
|
2024-01-20 10:21:34 +00:00
|
|
|
static const uint16_t image_width = 256;
|
|
|
|
static const uint16_t image_height = 240;
|
2024-01-15 19:56:58 +00:00
|
|
|
|
2024-01-22 17:50:52 +00:00
|
|
|
class EmuInstanceBase
|
2024-01-10 18:48:57 +00:00
|
|
|
{
|
2024-01-20 10:21:34 +00:00
|
|
|
public:
|
|
|
|
|
2024-01-22 17:50:52 +00:00
|
|
|
EmuInstanceBase() = default;
|
|
|
|
virtual ~EmuInstanceBase() = default;
|
2024-01-20 10:21:34 +00:00
|
|
|
|
2024-01-21 14:34:15 +00:00
|
|
|
inline void advanceState(const std::string &move)
|
2024-01-20 10:21:34 +00:00
|
|
|
{
|
2024-01-21 14:34:15 +00:00
|
|
|
bool isInputValid = _controller.parseInputString(move);
|
|
|
|
if (isInputValid == false) EXIT_WITH_ERROR("Move provided cannot be parsed: '%s'\n", move.c_str());
|
|
|
|
|
|
|
|
// Parsing power
|
|
|
|
if (_controller.getPowerButtonState() == true) EXIT_WITH_ERROR("Power button pressed, but not supported: '%s'\n", move.c_str());
|
|
|
|
|
|
|
|
// Parsing reset
|
|
|
|
if (_controller.getResetButtonState() == true) doSoftReset();
|
|
|
|
|
|
|
|
// Parsing Controllers
|
|
|
|
const auto controller1 = _controller.getController1Code();
|
|
|
|
const auto controller2 = _controller.getController2Code();
|
|
|
|
|
|
|
|
advanceStateImpl(controller1, controller2);
|
2024-01-20 10:21:34 +00:00
|
|
|
}
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-21 14:34:15 +00:00
|
|
|
inline void setController1Type(const std::string& type)
|
2024-01-20 10:21:34 +00:00
|
|
|
{
|
2024-01-21 14:34:15 +00:00
|
|
|
bool isTypeRecognized = false;
|
|
|
|
|
|
|
|
if (type == "None") { _controller.setController1Type(Controller::controller_t::none); isTypeRecognized = true; }
|
|
|
|
if (type == "Joypad") { _controller.setController1Type(Controller::controller_t::joypad); isTypeRecognized = true; }
|
|
|
|
if (type == "FourScore1") { _controller.setController1Type(Controller::controller_t::fourscore1); isTypeRecognized = true; }
|
|
|
|
if (type == "FourScore2") { _controller.setController1Type(Controller::controller_t::fourscore2); isTypeRecognized = true; }
|
|
|
|
|
|
|
|
if (isTypeRecognized == false) EXIT_WITH_ERROR("Input type not recognized: '%s'\n", type.c_str());
|
2024-01-20 10:21:34 +00:00
|
|
|
}
|
2024-01-10 19:11:49 +00:00
|
|
|
|
2024-01-21 14:34:15 +00:00
|
|
|
inline void setController2Type(const std::string& type)
|
2024-01-20 10:21:34 +00:00
|
|
|
{
|
2024-01-21 14:34:15 +00:00
|
|
|
bool isTypeRecognized = false;
|
|
|
|
|
|
|
|
if (type == "None") { _controller.setController2Type(Controller::controller_t::none); isTypeRecognized = true; }
|
|
|
|
if (type == "Joypad") { _controller.setController2Type(Controller::controller_t::joypad); isTypeRecognized = true; }
|
|
|
|
if (type == "FourScore1") { _controller.setController2Type(Controller::controller_t::fourscore1); isTypeRecognized = true; }
|
|
|
|
if (type == "FourScore2") { _controller.setController2Type(Controller::controller_t::fourscore2); isTypeRecognized = true; }
|
|
|
|
|
|
|
|
if (isTypeRecognized == false) EXIT_WITH_ERROR("Input type not recognized: '%s'\n", type.c_str());
|
2024-01-20 10:21:34 +00:00
|
|
|
}
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-20 10:21:34 +00:00
|
|
|
inline std::string getRomSHA1() const { return _romSHA1String; }
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-20 10:21:34 +00:00
|
|
|
inline hash_t getStateHash() const
|
2024-01-10 18:48:57 +00:00
|
|
|
{
|
2024-01-20 10:21:34 +00:00
|
|
|
MetroHash128 hash;
|
|
|
|
|
|
|
|
hash.Update(getLowMem(), _LOW_MEM_SIZE);
|
2024-01-20 17:30:24 +00:00
|
|
|
// hash.Update(getHighMem(), _HIGH_MEM_SIZE);
|
|
|
|
// hash.Update(getNametableMem(), _NAMETABLES_MEM_SIZE);
|
|
|
|
// hash.Update(getChrMem(), getChrMemSize());
|
2024-01-20 10:21:34 +00:00
|
|
|
|
|
|
|
hash_t result;
|
|
|
|
hash.Finalize(reinterpret_cast<uint8_t *>(&result));
|
|
|
|
return result;
|
2024-01-10 18:48:57 +00:00
|
|
|
}
|
|
|
|
|
2024-01-20 10:21:34 +00:00
|
|
|
inline void enableRendering() { _doRendering = true; };
|
|
|
|
inline void disableRendering() { _doRendering = false; };
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-20 10:21:34 +00:00
|
|
|
inline void loadStateFile(const std::string &stateFilePath)
|
|
|
|
{
|
|
|
|
std::string stateData;
|
|
|
|
bool status = loadStringFromFile(stateData, stateFilePath);
|
|
|
|
if (status == false) EXIT_WITH_ERROR("Could not find/read state file: %s\n", stateFilePath.c_str());
|
2024-01-20 14:26:14 +00:00
|
|
|
deserializeFullState((uint8_t *)stateData.data());
|
2024-01-20 10:21:34 +00:00
|
|
|
}
|
2024-01-10 18:48:57 +00:00
|
|
|
|
2024-01-20 10:21:34 +00:00
|
|
|
inline void saveStateFile(const std::string &stateFilePath) const
|
|
|
|
{
|
|
|
|
std::string stateData;
|
2024-01-20 14:26:14 +00:00
|
|
|
stateData.resize(_fullStateSize);
|
|
|
|
serializeFullState((uint8_t *)stateData.data());
|
2024-01-20 10:21:34 +00:00
|
|
|
saveStringToFile(stateData, stateFilePath.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void loadROMFile(const std::string &romFilePath)
|
|
|
|
{
|
|
|
|
// Loading ROM data
|
|
|
|
bool status = loadStringFromFile(_romData, romFilePath);
|
|
|
|
if (status == false) EXIT_WITH_ERROR("Could not find/read ROM file: %s\n", romFilePath.c_str());
|
|
|
|
|
|
|
|
// Calculating ROM hash value
|
|
|
|
_romSHA1String = SHA1::GetHash((uint8_t *)_romData.data(), _romData.size());
|
|
|
|
|
|
|
|
// Actually loading rom file
|
|
|
|
status = loadROMFileImpl(_romData);
|
|
|
|
if (status == false) EXIT_WITH_ERROR("Could not process ROM file: %s\n", romFilePath.c_str());
|
|
|
|
|
|
|
|
// Detecting full state size
|
2024-01-20 14:26:14 +00:00
|
|
|
_fullStateSize = getFullStateSize();
|
2024-01-20 10:21:34 +00:00
|
|
|
|
|
|
|
// Detecting lite state size
|
2024-01-20 14:26:14 +00:00
|
|
|
_liteStateSize = getLiteStateSize();
|
2024-01-20 10:21:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Virtual functions
|
|
|
|
|
|
|
|
virtual bool loadROMFileImpl(const std::string &romFilePath) = 0;
|
2024-01-21 14:34:15 +00:00
|
|
|
virtual void advanceStateImpl(const Controller::port_t controller1, const Controller::port_t controller2) = 0;
|
2024-01-20 10:21:34 +00:00
|
|
|
virtual uint8_t *getLowMem() const = 0;
|
|
|
|
virtual uint8_t *getNametableMem() const = 0;
|
|
|
|
virtual uint8_t *getHighMem() const = 0;
|
|
|
|
virtual const uint8_t *getChrMem() const = 0;
|
|
|
|
virtual size_t getChrMemSize() const = 0;
|
2024-01-20 14:26:14 +00:00
|
|
|
virtual void serializeFullState(uint8_t *state) const = 0;
|
|
|
|
virtual void deserializeFullState(const uint8_t *state) = 0;
|
|
|
|
virtual void serializeLiteState(uint8_t *state) const = 0;
|
|
|
|
virtual void deserializeLiteState(const uint8_t *state) = 0;
|
|
|
|
virtual size_t getFullStateSize() const = 0;
|
|
|
|
virtual size_t getLiteStateSize() const = 0;
|
2024-01-20 15:48:38 +00:00
|
|
|
virtual void enableLiteStateBlock(const std::string& block) = 0;
|
|
|
|
virtual void disableLiteStateBlock(const std::string& block) = 0;
|
|
|
|
|
2024-01-20 10:21:34 +00:00
|
|
|
virtual void doSoftReset() = 0;
|
|
|
|
virtual void doHardReset() = 0;
|
|
|
|
virtual std::string getCoreName() const = 0;
|
|
|
|
virtual void *getInternalEmulatorPointer() const = 0;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
// Storage for the light state size
|
|
|
|
size_t _liteStateSize;
|
|
|
|
|
|
|
|
// Storage for the full state size
|
2024-01-20 14:26:14 +00:00
|
|
|
size_t _fullStateSize;
|
2024-01-20 10:21:34 +00:00
|
|
|
|
|
|
|
// Flag to determine whether to enable/disable rendering
|
|
|
|
bool _doRendering = true;
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Storage for the ROM data
|
|
|
|
std::string _romData;
|
|
|
|
|
|
|
|
// SHA1 rom hash
|
|
|
|
std::string _romSHA1String;
|
2024-01-21 14:34:15 +00:00
|
|
|
|
|
|
|
// Controller class for input parsing
|
|
|
|
Controller _controller;
|
2024-01-10 18:48:57 +00:00
|
|
|
};
|