mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2025-10-30 08:02:29 +00:00
Make ModernRuntime Integration Ready (#26)
Co-authored-by: angie <angheloalf95@gmail.com>
This commit is contained in:
parent
e3e7024342
commit
56cfbb2d31
16 changed files with 53 additions and 255 deletions
|
|
@ -1,14 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
project(librecomp)
|
project(librecomp)
|
||||||
|
|
||||||
# Check for headers
|
|
||||||
include(CheckIncludeFile)
|
|
||||||
check_include_file("malloc.h" HAVE_MALLOC_H)
|
|
||||||
|
|
||||||
if(HAVE_MALLOC_H)
|
|
||||||
add_compile_definitions(HAVE_MALLOC_H)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Define the library
|
# Define the library
|
||||||
add_library(librecomp STATIC
|
add_library(librecomp STATIC
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/ai.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/ai.cpp"
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <setjmp.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_MALLOC_H
|
|
||||||
#include <malloc.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef uint64_t gpr;
|
typedef uint64_t gpr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ namespace recomp {
|
||||||
std::span<const char> cache_data;
|
std::span<const char> cache_data;
|
||||||
bool is_enabled;
|
bool is_enabled;
|
||||||
|
|
||||||
void (*entrypoint)();
|
gpr entrypoint_address;
|
||||||
|
void (*entrypoint)(uint8_t* rdram, recomp_context* context);
|
||||||
|
|
||||||
std::u8string stored_filename() const;
|
std::u8string stored_filename() const;
|
||||||
};
|
};
|
||||||
|
|
@ -29,6 +30,7 @@ namespace recomp {
|
||||||
IncorrectVersion,
|
IncorrectVersion,
|
||||||
OtherError
|
OtherError
|
||||||
};
|
};
|
||||||
|
void register_config_path(std::filesystem::path path);
|
||||||
bool register_game(const recomp::GameEntry& entry);
|
bool register_game(const recomp::GameEntry& entry);
|
||||||
void register_patch(const char* patch, std::size_t size);
|
void register_patch(const char* patch, std::size_t size);
|
||||||
void check_all_stored_roms();
|
void check_all_stored_roms();
|
||||||
|
|
@ -41,12 +43,7 @@ namespace recomp {
|
||||||
void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr);
|
void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr);
|
||||||
void start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks, const ultramodern::events::callbacks_t& thread_callbacks, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_);
|
void start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks, const ultramodern::events::callbacks_t& thread_callbacks, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_);
|
||||||
void start_game(const std::u8string& game_id);
|
void start_game(const std::u8string& game_id);
|
||||||
std::filesystem::path get_app_folder_path();
|
|
||||||
std::u8string current_game_id();
|
std::u8string current_game_id();
|
||||||
|
|
||||||
// TODO: implement both
|
|
||||||
const std::u8string& get_program_id();
|
|
||||||
void set_program_id(const std::u8string& program_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,174 +0,0 @@
|
||||||
#ifndef __RECOMP_INPUT_H__
|
|
||||||
#define __RECOMP_INPUT_H__
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <variant>
|
|
||||||
#include <vector>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <span>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
#include "json/json.hpp"
|
|
||||||
|
|
||||||
namespace recomp {
|
|
||||||
// x-macros to build input enums and arrays.
|
|
||||||
// First parameter is the enum name, second parameter is the bit field for the input (or 0 if there is no associated one), third is the readable name.
|
|
||||||
// TODO refactor this to allow projects to rename these, or get rid of the readable name and leave that up to individual projects to map.
|
|
||||||
#define DEFINE_N64_BUTTON_INPUTS() \
|
|
||||||
DEFINE_INPUT(A, 0x8000, "Action") \
|
|
||||||
DEFINE_INPUT(B, 0x4000, "Attack/Cancel") \
|
|
||||||
DEFINE_INPUT(Z, 0x2000, "Target") \
|
|
||||||
DEFINE_INPUT(START, 0x1000, "Start") \
|
|
||||||
DEFINE_INPUT(L, 0x0020, "Toggle map") \
|
|
||||||
DEFINE_INPUT(R, 0x0010, "Shield") \
|
|
||||||
DEFINE_INPUT(C_UP, 0x0008, "Look/Fairy") \
|
|
||||||
DEFINE_INPUT(C_LEFT, 0x0002, "Item 1") \
|
|
||||||
DEFINE_INPUT(C_DOWN, 0x0004, "Item 2") \
|
|
||||||
DEFINE_INPUT(C_RIGHT, 0x0001, "Item 3") \
|
|
||||||
DEFINE_INPUT(DPAD_UP, 0x0800, "Special Item 1") \
|
|
||||||
DEFINE_INPUT(DPAD_RIGHT, 0x0100, "Special Item 2") \
|
|
||||||
DEFINE_INPUT(DPAD_DOWN, 0x0400, "Special Item 3") \
|
|
||||||
DEFINE_INPUT(DPAD_LEFT, 0x0200, "Special Item 4")
|
|
||||||
|
|
||||||
#define DEFINE_N64_AXIS_INPUTS() \
|
|
||||||
DEFINE_INPUT(Y_AXIS_POS, 0, "Up") \
|
|
||||||
DEFINE_INPUT(Y_AXIS_NEG, 0, "Down") \
|
|
||||||
DEFINE_INPUT(X_AXIS_NEG, 0, "Left") \
|
|
||||||
DEFINE_INPUT(X_AXIS_POS, 0, "Right") \
|
|
||||||
|
|
||||||
#define DEFINE_ALL_INPUTS() \
|
|
||||||
DEFINE_N64_BUTTON_INPUTS() \
|
|
||||||
DEFINE_N64_AXIS_INPUTS()
|
|
||||||
|
|
||||||
// Enum containing every recomp input.
|
|
||||||
#define DEFINE_INPUT(name, value, readable) name,
|
|
||||||
enum class GameInput {
|
|
||||||
DEFINE_ALL_INPUTS()
|
|
||||||
|
|
||||||
COUNT,
|
|
||||||
N64_BUTTON_START = A,
|
|
||||||
N64_BUTTON_COUNT = C_RIGHT - N64_BUTTON_START + 1,
|
|
||||||
N64_AXIS_START = X_AXIS_NEG,
|
|
||||||
N64_AXIS_COUNT = Y_AXIS_POS - N64_AXIS_START + 1,
|
|
||||||
};
|
|
||||||
#undef DEFINE_INPUT
|
|
||||||
|
|
||||||
struct InputField {
|
|
||||||
uint32_t input_type;
|
|
||||||
int32_t input_id;
|
|
||||||
std::string to_string() const;
|
|
||||||
auto operator<=>(const InputField& rhs) const = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
void poll_inputs();
|
|
||||||
float get_input_analog(const InputField& field);
|
|
||||||
float get_input_analog(const std::span<const recomp::InputField> fields);
|
|
||||||
bool get_input_digital(const InputField& field);
|
|
||||||
bool get_input_digital(const std::span<const recomp::InputField> fields);
|
|
||||||
void get_gyro_deltas(float* x, float* y);
|
|
||||||
void get_mouse_deltas(float* x, float* y);
|
|
||||||
|
|
||||||
enum class InputDevice {
|
|
||||||
Controller,
|
|
||||||
Keyboard,
|
|
||||||
COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
void start_scanning_input(InputDevice device);
|
|
||||||
void stop_scanning_input();
|
|
||||||
void finish_scanning_input(InputField scanned_field);
|
|
||||||
void cancel_scanning_input();
|
|
||||||
void config_menu_set_cont_or_kb(bool cont_interacted);
|
|
||||||
InputField get_scanned_input();
|
|
||||||
|
|
||||||
struct DefaultN64Mappings {
|
|
||||||
std::vector<InputField> a;
|
|
||||||
std::vector<InputField> b;
|
|
||||||
std::vector<InputField> l;
|
|
||||||
std::vector<InputField> r;
|
|
||||||
std::vector<InputField> z;
|
|
||||||
std::vector<InputField> start;
|
|
||||||
|
|
||||||
std::vector<InputField> c_left;
|
|
||||||
std::vector<InputField> c_right;
|
|
||||||
std::vector<InputField> c_up;
|
|
||||||
std::vector<InputField> c_down;
|
|
||||||
|
|
||||||
std::vector<InputField> dpad_left;
|
|
||||||
std::vector<InputField> dpad_right;
|
|
||||||
std::vector<InputField> dpad_up;
|
|
||||||
std::vector<InputField> dpad_down;
|
|
||||||
|
|
||||||
std::vector<InputField> analog_left;
|
|
||||||
std::vector<InputField> analog_right;
|
|
||||||
std::vector<InputField> analog_up;
|
|
||||||
std::vector<InputField> analog_down;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const DefaultN64Mappings default_n64_keyboard_mappings;
|
|
||||||
extern const DefaultN64Mappings default_n64_controller_mappings;
|
|
||||||
|
|
||||||
constexpr size_t bindings_per_input = 2;
|
|
||||||
|
|
||||||
size_t get_num_inputs();
|
|
||||||
const std::string& get_input_name(GameInput input);
|
|
||||||
const std::string& get_input_enum_name(GameInput input);
|
|
||||||
GameInput get_input_from_enum_name(const std::string_view name);
|
|
||||||
InputField& get_input_binding(GameInput input, size_t binding_index, InputDevice device);
|
|
||||||
void set_input_binding(GameInput input, size_t binding_index, InputDevice device, InputField value);
|
|
||||||
|
|
||||||
void get_n64_input(uint16_t* buttons_out, float* x_out, float* y_out);
|
|
||||||
void set_rumble(bool);
|
|
||||||
void update_rumble();
|
|
||||||
void handle_events();
|
|
||||||
|
|
||||||
// Rumble strength ranges from 0 to 100.
|
|
||||||
int get_rumble_strength();
|
|
||||||
void set_rumble_strength(int strength);
|
|
||||||
|
|
||||||
// Gyro and mouse sensitivities range from 0 to 100.
|
|
||||||
int get_gyro_sensitivity();
|
|
||||||
int get_mouse_sensitivity();
|
|
||||||
void set_gyro_sensitivity(int strength);
|
|
||||||
void set_mouse_sensitivity(int strength);
|
|
||||||
|
|
||||||
enum class TargetingMode {
|
|
||||||
Switch,
|
|
||||||
Hold,
|
|
||||||
OptionCount
|
|
||||||
};
|
|
||||||
|
|
||||||
NLOHMANN_JSON_SERIALIZE_ENUM(recomp::TargetingMode, {
|
|
||||||
{recomp::TargetingMode::Switch, "Switch"},
|
|
||||||
{recomp::TargetingMode::Hold, "Hold"}
|
|
||||||
});
|
|
||||||
|
|
||||||
TargetingMode get_targeting_mode();
|
|
||||||
void set_targeting_mode(TargetingMode mode);
|
|
||||||
|
|
||||||
enum class BackgroundInputMode {
|
|
||||||
On,
|
|
||||||
Off,
|
|
||||||
OptionCount
|
|
||||||
};
|
|
||||||
|
|
||||||
NLOHMANN_JSON_SERIALIZE_ENUM(recomp::BackgroundInputMode, {
|
|
||||||
{recomp::BackgroundInputMode::On, "On"},
|
|
||||||
{recomp::BackgroundInputMode::Off, "Off"}
|
|
||||||
});
|
|
||||||
|
|
||||||
BackgroundInputMode get_background_input_mode();
|
|
||||||
void set_background_input_mode(BackgroundInputMode mode);
|
|
||||||
|
|
||||||
bool game_input_disabled();
|
|
||||||
bool all_input_disabled();
|
|
||||||
|
|
||||||
// TODO move these somewhere else.
|
|
||||||
void quicksave_save();
|
|
||||||
void quicksave_load();
|
|
||||||
|
|
||||||
void open_quit_game_prompt();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -16,8 +16,9 @@ namespace recomp {
|
||||||
size_t len;
|
size_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void register_overlays(const overlay_section_table_data_t& sections, const overlays_by_index_t& overlays);
|
void register_overlays(const overlay_section_table_data_t& sections, const overlays_by_index_t& overlays);
|
||||||
extern void register_patch_section(SectionTableEntry* code_sections);
|
void register_patch_section(SectionTableEntry* code_sections);
|
||||||
|
void load_patch_functions();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" void load_overlays(uint32_t rom, int32_t ram_addr, uint32_t size);
|
extern "C" void load_overlays(uint32_t rom, int32_t ram_addr, uint32_t size);
|
||||||
|
|
|
||||||
|
|
@ -110,8 +110,8 @@ struct RSP {
|
||||||
bool divdp;
|
bool divdp;
|
||||||
} vpu;
|
} vpu;
|
||||||
|
|
||||||
static constexpr r128 zero{0};
|
static constexpr r128 zero{{0}};
|
||||||
static constexpr r128 invert{(uint64_t)-1, (uint64_t)-1};
|
static constexpr r128 invert{{(uint64_t)-1, (uint64_t)-1}};
|
||||||
|
|
||||||
inline auto accumulatorGet(u32 index) const -> u64;
|
inline auto accumulatorGet(u32 index) const -> u64;
|
||||||
inline auto accumulatorSet(u32 index, u64 value) -> void;
|
inline auto accumulatorSet(u32 index, u64 value) -> void;
|
||||||
|
|
|
||||||
|
|
@ -142,8 +142,6 @@ extern "C" void unload_overlays(int32_t ram_addr, uint32_t size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_patch_functions();
|
|
||||||
|
|
||||||
void init_overlays() {
|
void init_overlays() {
|
||||||
section_addresses = (int32_t *)malloc(sections_info.total_num_sections * sizeof(int32_t));
|
section_addresses = (int32_t *)malloc(sections_info.total_num_sections * sizeof(int32_t));
|
||||||
|
|
||||||
|
|
@ -158,7 +156,7 @@ void init_overlays() {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
load_patch_functions();
|
recomp::load_patch_functions();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" recomp_func_t * get_function(int32_t addr) {
|
extern "C" recomp_func_t * get_function(int32_t addr) {
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ static SectionTableEntry* code_sections = nullptr;
|
||||||
|
|
||||||
void load_special_overlay(const SectionTableEntry& section, int32_t ram);
|
void load_special_overlay(const SectionTableEntry& section, int32_t ram);
|
||||||
|
|
||||||
void register_patch_section(SectionTableEntry* sections) {
|
void recomp::register_patch_section(SectionTableEntry* sections) {
|
||||||
code_sections = sections;
|
code_sections = sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_patch_functions() {
|
void recomp::load_patch_functions() {
|
||||||
load_special_overlay(code_sections[0], code_sections[0].ram_addr);
|
load_special_overlay(code_sections[0], code_sections[0].ram_addr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,10 +94,11 @@ struct {
|
||||||
} save_context;
|
} save_context;
|
||||||
|
|
||||||
const std::u8string save_folder = u8"saves";
|
const std::u8string save_folder = u8"saves";
|
||||||
const std::u8string save_filename = std::u8string{recomp::current_game_id()} + u8".bin";
|
|
||||||
|
extern std::filesystem::path config_path;
|
||||||
|
|
||||||
std::filesystem::path get_save_file_path() {
|
std::filesystem::path get_save_file_path() {
|
||||||
return recomp::get_app_folder_path() / save_folder / save_filename;
|
return config_path / save_folder / (std::u8string{recomp::current_game_id()} + u8".bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_save_file() {
|
void update_save_file() {
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,6 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <Shlobj.h>
|
|
||||||
#elif defined(__linux__)
|
|
||||||
#include <pwd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "recomp.h"
|
#include "recomp.h"
|
||||||
#include "recomp_overlays.h"
|
#include "recomp_overlays.h"
|
||||||
#include "recomp_game.h"
|
#include "recomp_game.h"
|
||||||
|
|
@ -46,6 +40,7 @@ std::mutex patch_data_mutex;
|
||||||
std::mutex current_game_mutex;
|
std::mutex current_game_mutex;
|
||||||
|
|
||||||
// Global variables
|
// Global variables
|
||||||
|
std::filesystem::path config_path;
|
||||||
std::vector<char> patch_data;
|
std::vector<char> patch_data;
|
||||||
std::unordered_map<std::u8string, recomp::GameEntry> game_roms {};
|
std::unordered_map<std::u8string, recomp::GameEntry> game_roms {};
|
||||||
|
|
||||||
|
|
@ -53,6 +48,10 @@ std::u8string recomp::GameEntry::stored_filename() const {
|
||||||
return game_id + u8".z64";
|
return game_id + u8".z64";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void recomp::register_config_path(std::filesystem::path path) {
|
||||||
|
config_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
bool recomp::register_game(const recomp::GameEntry& entry) {
|
bool recomp::register_game(const recomp::GameEntry& entry) {
|
||||||
std::lock_guard<std::mutex> lock(game_roms_mutex);
|
std::lock_guard<std::mutex> lock(game_roms_mutex);
|
||||||
game_roms.insert({ entry.game_id, entry });
|
game_roms.insert({ entry.game_id, entry });
|
||||||
|
|
@ -61,6 +60,7 @@ bool recomp::register_game(const recomp::GameEntry& entry) {
|
||||||
|
|
||||||
void recomp::register_patch(const char* patch, std::size_t size) {
|
void recomp::register_patch(const char* patch, std::size_t size) {
|
||||||
std::lock_guard<std::mutex> lock(patch_data_mutex);
|
std::lock_guard<std::mutex> lock(patch_data_mutex);
|
||||||
|
patch_data.resize(size);
|
||||||
std::memcpy(patch_data.data(), patch, size);
|
std::memcpy(patch_data.data(), patch, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,39 +97,12 @@ bool write_file(const std::filesystem::path& path, const std::vector<uint8_t>& d
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path recomp::get_app_folder_path() {
|
|
||||||
std::filesystem::path recomp_dir{};
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
// Deduce local app data path.
|
|
||||||
PWSTR known_path = NULL;
|
|
||||||
HRESULT result = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &known_path);
|
|
||||||
if (result == S_OK) {
|
|
||||||
recomp_dir = std::filesystem::path{known_path} / recomp::get_program_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
CoTaskMemFree(known_path);
|
|
||||||
#elif defined(__linux__)
|
|
||||||
const char *homedir;
|
|
||||||
|
|
||||||
if ((homedir = getenv("HOME")) == nullptr) {
|
|
||||||
homedir = getpwuid(getuid())->pw_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (homedir != nullptr) {
|
|
||||||
recomp_dir = std::filesystem::path{homedir} / (std::u8string{u8".config/"} + recomp::get_program_id());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return recomp_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool check_stored_rom(const recomp::GameEntry& game_entry) {
|
bool check_stored_rom(const recomp::GameEntry& game_entry) {
|
||||||
std::vector stored_rom_data = read_file(recomp::get_app_folder_path() / game_entry.stored_filename());
|
std::vector stored_rom_data = read_file(config_path / game_entry.stored_filename());
|
||||||
|
|
||||||
if (!check_hash(stored_rom_data, game_entry.rom_hash)) {
|
if (!check_hash(stored_rom_data, game_entry.rom_hash)) {
|
||||||
// Incorrect hash, remove the stored ROM file if it exists.
|
// Incorrect hash, remove the stored ROM file if it exists.
|
||||||
std::filesystem::remove(recomp::get_app_folder_path() / game_entry.stored_filename());
|
std::filesystem::remove(config_path / game_entry.stored_filename());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,11 +130,11 @@ bool recomp::load_stored_rom(std::u8string& game_id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> stored_rom_data = read_file(recomp::get_app_folder_path() / find_it->second.stored_filename());
|
std::vector<uint8_t> stored_rom_data = read_file(config_path / find_it->second.stored_filename());
|
||||||
|
|
||||||
if (!check_hash(stored_rom_data, find_it->second.rom_hash)) {
|
if (!check_hash(stored_rom_data, find_it->second.rom_hash)) {
|
||||||
// The ROM no longer has the right hash, delete it.
|
// The ROM no longer has the right hash, delete it.
|
||||||
std::filesystem::remove(recomp::get_app_folder_path() / find_it->second.stored_filename());
|
std::filesystem::remove(config_path / find_it->second.stored_filename());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -272,7 +245,7 @@ recomp::RomValidationError recomp::select_rom(const std::filesystem::path& rom_p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write_file(recomp::get_app_folder_path() / game_entry.stored_filename(), rom_data);
|
write_file(config_path / game_entry.stored_filename(), rom_data);
|
||||||
|
|
||||||
return recomp::RomValidationError::Good;
|
return recomp::RomValidationError::Good;
|
||||||
}
|
}
|
||||||
|
|
@ -346,24 +319,16 @@ void run_thread_function(uint8_t* rdram, uint64_t addr, uint64_t sp, uint64_t ar
|
||||||
func(rdram, &ctx);
|
func(rdram, &ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recomp generation functions
|
|
||||||
extern "C" void recomp_entrypoint(uint8_t * rdram, recomp_context * ctx);
|
|
||||||
gpr get_entrypoint_address();
|
|
||||||
const char* get_rom_name();
|
|
||||||
|
|
||||||
void read_patch_data(uint8_t* rdram, gpr patch_data_address) {
|
void read_patch_data(uint8_t* rdram, gpr patch_data_address) {
|
||||||
for (size_t i = 0; i < patch_data.size(); i++) {
|
for (size_t i = 0; i < patch_data.size(); i++) {
|
||||||
MEM_B(i, patch_data_address) = patch_data[i];
|
MEM_B(i, patch_data_address) = patch_data[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(uint8_t* rdram, recomp_context* ctx) {
|
void init(uint8_t* rdram, recomp_context* ctx, gpr entrypoint) {
|
||||||
// Initialize the overlays
|
// Initialize the overlays
|
||||||
init_overlays();
|
init_overlays();
|
||||||
|
|
||||||
// Get entrypoint from recomp function
|
|
||||||
gpr entrypoint = get_entrypoint_address();
|
|
||||||
|
|
||||||
// Load overlays in the first 1MB
|
// Load overlays in the first 1MB
|
||||||
load_overlays(0x1000, (int32_t)entrypoint, 1024 * 1024);
|
load_overlays(0x1000, (int32_t)entrypoint, 1024 * 1024);
|
||||||
|
|
||||||
|
|
@ -407,6 +372,7 @@ void recomp::start_game(const std::u8string& game_id) {
|
||||||
std::lock_guard<std::mutex> lock(current_game_mutex);
|
std::lock_guard<std::mutex> lock(current_game_mutex);
|
||||||
current_game = game_id;
|
current_game = game_id;
|
||||||
game_status.store(GameStatus::Running);
|
game_status.store(GameStatus::Running);
|
||||||
|
game_status.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ultramodern::is_game_started() {
|
bool ultramodern::is_game_started() {
|
||||||
|
|
@ -479,13 +445,15 @@ void recomp::start(ultramodern::WindowHandle window_handle, const recomp::rsp::c
|
||||||
ultramodern::error_handling::message_box("Error opening stored ROM! Please restart this program.");
|
ultramodern::error_handling::message_box("Error opening stored ROM! Please restart this program.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ultramodern::init_saving(rdram);
|
||||||
|
|
||||||
auto find_it = game_roms.find(current_game.value());
|
auto find_it = game_roms.find(current_game.value());
|
||||||
const recomp::GameEntry& game_entry = find_it->second;
|
const recomp::GameEntry& game_entry = find_it->second;
|
||||||
|
|
||||||
ultramodern::load_shader_cache(game_entry.cache_data);
|
ultramodern::load_shader_cache(game_entry.cache_data);
|
||||||
init(rdram, &context);
|
init(rdram, &context, game_entry.entrypoint_address);
|
||||||
try {
|
try {
|
||||||
recomp_entrypoint(rdram, &context);
|
game_entry.entrypoint(rdram, &context);
|
||||||
} catch (ultramodern::thread_terminated& terminated) {
|
} catch (ultramodern::thread_terminated& terminated) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ bool recomp::rsp::run_task(uint8_t* rdram, const OSTask* task) {
|
||||||
|
|
||||||
// Ensure that the ucode exited correctly
|
// Ensure that the ucode exited correctly
|
||||||
if (exit_reason != RspExitReason::Broke) {
|
if (exit_reason != RspExitReason::Broke) {
|
||||||
fprintf(stderr, "RSP ucode %" PRIu32 " exited unexpectedly. exit_reason: %i\n", task->t.type, exit_reason);
|
fprintf(stderr, "RSP ucode %" PRIu32 " exited unexpectedly. exit_reason: %i\n", task->t.type, static_cast<int>(exit_reason));
|
||||||
assert(exit_reason == RspExitReason::Broke);
|
assert(exit_reason == RspExitReason::Broke);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,12 @@ namespace ultramodern {
|
||||||
Window window;
|
Window window;
|
||||||
auto operator<=>(const WindowHandle&) const = default;
|
auto operator<=>(const WindowHandle&) const = default;
|
||||||
};
|
};
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
struct WindowHandle {
|
||||||
|
void* window;
|
||||||
|
void* view;
|
||||||
|
auto operator<=>(const WindowHandle&) const = default;
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We need a place in rdram to hold the PI handles, so pick an address in extended rdram
|
// We need a place in rdram to hold the PI handles, so pick an address in extended rdram
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,11 @@ void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_r
|
||||||
if (!ultramodern::rsp::run_task(PASS_RDRAM task)) {
|
if (!ultramodern::rsp::run_task(PASS_RDRAM task)) {
|
||||||
fprintf(stderr, "Failed to execute task type: %" PRIu32 "\n", task->t.type);
|
fprintf(stderr, "Failed to execute task type: %" PRIu32 "\n", task->t.type);
|
||||||
assert(false);
|
assert(false);
|
||||||
|
# ifdef __APPLE__
|
||||||
|
std::_Exit(EXIT_FAILURE);
|
||||||
|
# else
|
||||||
std::quick_exit(EXIT_FAILURE);
|
std::quick_exit(EXIT_FAILURE);
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the game that the RSP has completed
|
// Tell the game that the RSP has completed
|
||||||
|
|
@ -508,6 +512,8 @@ std::string get_graphics_api_name(ultramodern::GraphicsApi api) {
|
||||||
api = ultramodern::GraphicsApi::D3D12;
|
api = ultramodern::GraphicsApi::D3D12;
|
||||||
#elif defined(__gnu_linux__)
|
#elif defined(__gnu_linux__)
|
||||||
api = ultramodern::GraphicsApi::Vulkan;
|
api = ultramodern::GraphicsApi::Vulkan;
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
api = ultramodern::GraphicsApi::Vulkan;
|
||||||
#else
|
#else
|
||||||
static_assert(false && "Unimplemented")
|
static_assert(false && "Unimplemented")
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,9 @@ ultramodern::RT64Context::RT64Context(uint8_t* rdram, ultramodern::WindowHandle
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
appCore.window.display = window_handle.display;
|
appCore.window.display = window_handle.display;
|
||||||
appCore.window.window = window_handle.window;
|
appCore.window.window = window_handle.window;
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
appCore.window.window = window_handle.window;
|
||||||
|
appCore.window.view = window_handle.view;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
appCore.checkInterrupts = dummy_check_interrupts;
|
appCore.checkInterrupts = dummy_check_interrupts;
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,12 @@ void ultramodern::set_native_thread_priority(ThreadPriority pri) {
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
void ultramodern::set_native_thread_name(const std::string& name) {
|
||||||
|
pthread_setname_np(name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ultramodern::set_native_thread_priority(ThreadPriority pri) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::atomic_int temporary_threads = 0;
|
std::atomic_int temporary_threads = 0;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ void ultramodern::preinit(RDRAM_ARG ultramodern::WindowHandle window_handle) {
|
||||||
ultramodern::init_events(PASS_RDRAM window_handle);
|
ultramodern::init_events(PASS_RDRAM window_handle);
|
||||||
ultramodern::init_timers(PASS_RDRAM1);
|
ultramodern::init_timers(PASS_RDRAM1);
|
||||||
ultramodern::init_audio();
|
ultramodern::init_audio();
|
||||||
ultramodern::init_saving(PASS_RDRAM1);
|
|
||||||
ultramodern::init_thread_cleanup();
|
ultramodern::init_thread_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue