mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-08-04 15:19:47 +00:00
Merge branch 'master' into libc++19
This commit is contained in:
commit
b2a14c47ab
47 changed files with 390 additions and 164 deletions
2
3rdparty/FAudio
vendored
2
3rdparty/FAudio
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 54bff0446152a9646965e4892c0c00d45b94076f
|
Subproject commit 74d45e615c2e7510c7e0f2ccb91dc6d7ccae4bec
|
2
3rdparty/libsdl-org/SDL
vendored
2
3rdparty/libsdl-org/SDL
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 79ec168f3c1e2fe27335cb8886439f7ef676fb49
|
Subproject commit c98c4fbff6d8f3016a3ce6685bf8f43433c3efcc
|
|
@ -2635,7 +2635,7 @@ bool fs::pending_file::commit(bool overwrite)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
stx::generator<fs::dir_entry&> fs::list_dir_recursively(std::string path)
|
stx::generator<fs::dir_entry&> fs::list_dir_recursively(const std::string& path)
|
||||||
{
|
{
|
||||||
for (auto& entry : fs::dir(path))
|
for (auto& entry : fs::dir(path))
|
||||||
{
|
{
|
||||||
|
|
|
@ -837,5 +837,5 @@ namespace fs
|
||||||
|
|
||||||
file make_gather(std::vector<file>);
|
file make_gather(std::vector<file>);
|
||||||
|
|
||||||
stx::generator<dir_entry&> list_dir_recursively(std::string path);
|
stx::generator<dir_entry&> list_dir_recursively(const std::string& path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2731,7 +2731,7 @@ void thread_base::exec()
|
||||||
|
|
||||||
[[noreturn]] void thread_ctrl::emergency_exit(std::string_view reason)
|
[[noreturn]] void thread_ctrl::emergency_exit(std::string_view reason)
|
||||||
{
|
{
|
||||||
if (std::string info = dump_useful_thread_info(); !info.empty())
|
if (const std::string info = dump_useful_thread_info(); !info.empty())
|
||||||
{
|
{
|
||||||
sys_log.notice("\n%s", info);
|
sys_log.notice("\n%s", info);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
LOG_CHANNEL(dec_log, "DECRYPT");
|
LOG_CHANNEL(dec_log, "DECRYPT");
|
||||||
|
|
||||||
usz decrypt_binaries_t::decrypt(std::string klic_input)
|
usz decrypt_binaries_t::decrypt(std::string_view klic_input)
|
||||||
{
|
{
|
||||||
if (m_index >= m_modules.size())
|
if (m_index >= m_modules.size())
|
||||||
{
|
{
|
||||||
|
@ -41,7 +41,7 @@ usz decrypt_binaries_t::decrypt(std::string klic_input)
|
||||||
m_klics.insert(m_klics.end(), Emu.klic.begin(), Emu.klic.end());
|
m_klics.insert(m_klics.end(), Emu.klic.begin(), Emu.klic.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::string_view text = std::string_view{klic_input}.substr(klic_input.find_first_of('x') + 1); text.size() == 32)
|
if (std::string_view text = klic_input.substr(klic_input.find_first_of('x') + 1); text.size() == 32)
|
||||||
{
|
{
|
||||||
// Allowed to fail (would simply repeat the operation if fails again)
|
// Allowed to fail (would simply repeat the operation if fails again)
|
||||||
u64 lo = 0;
|
u64 lo = 0;
|
||||||
|
|
|
@ -12,7 +12,7 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
usz decrypt(std::string klic_input = {});
|
usz decrypt(std::string_view klic_input = {});
|
||||||
|
|
||||||
bool done() const
|
bool done() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -894,7 +894,7 @@ void rec_info::stop_video_provider(bool flush)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool create_path(std::string& out, std::string dir_name, std::string file_name)
|
bool create_path(std::string& out, std::string dir_name, const std::string& file_name)
|
||||||
{
|
{
|
||||||
out.clear();
|
out.clear();
|
||||||
|
|
||||||
|
@ -903,7 +903,7 @@ bool create_path(std::string& out, std::string dir_name, std::string file_name)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
out = dir_name;
|
out = std::move(dir_name);
|
||||||
|
|
||||||
if (!out.empty() && out.back() != '/')
|
if (!out.empty() && out.back() != '/')
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include "Emu/Cell/PPUModule.h"
|
#include "Emu/Cell/PPUModule.h"
|
||||||
#include "Emu/Cell/Modules/cellSysutil.h"
|
#include "Emu/Cell/Modules/cellSysutil.h"
|
||||||
#include "Emu/Cell/Modules/cellUserInfo.h"
|
#include "Emu/Cell/Modules/cellUserInfo.h"
|
||||||
|
#include "Emu/RSX/Overlays/overlay_message.h"
|
||||||
|
#include "Emu/system_config.h"
|
||||||
|
|
||||||
#include "cellSaveData.h"
|
#include "cellSaveData.h"
|
||||||
#include "cellMsgDialog.h"
|
#include "cellMsgDialog.h"
|
||||||
|
@ -1750,6 +1752,50 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||||
|
|
||||||
fileGet->excSize = 0;
|
fileGet->excSize = 0;
|
||||||
|
|
||||||
|
// show indicator for automatic save or auto load interactions if the game requests it (statSet->indicator)
|
||||||
|
const bool show_auto_indicator = operation <= SAVEDATA_OP_LIST_AUTO_LOAD && statSet && statSet->indicator && g_cfg.misc.show_autosave_autoload_hint;
|
||||||
|
|
||||||
|
if (show_auto_indicator)
|
||||||
|
{
|
||||||
|
auto msg_text = localized_string_id::INVALID;
|
||||||
|
|
||||||
|
if (operation == SAVEDATA_OP_AUTO_SAVE || operation == SAVEDATA_OP_LIST_AUTO_SAVE)
|
||||||
|
{
|
||||||
|
msg_text = localized_string_id::CELL_SAVEDATA_AUTOSAVE;
|
||||||
|
}
|
||||||
|
else if (operation == SAVEDATA_OP_AUTO_LOAD || operation == SAVEDATA_OP_LIST_AUTO_LOAD)
|
||||||
|
{
|
||||||
|
msg_text = localized_string_id::CELL_SAVEDATA_AUTOLOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto msg_location = rsx::overlays::message_pin_location::top_left;
|
||||||
|
|
||||||
|
switch (statSet->indicator->dispPosition & 0x0F)
|
||||||
|
{
|
||||||
|
case CELL_SAVEDATA_INDICATORPOS_LOWER_RIGHT:
|
||||||
|
msg_location = rsx::overlays::message_pin_location::bottom_right;
|
||||||
|
break;
|
||||||
|
case CELL_SAVEDATA_INDICATORPOS_LOWER_LEFT:
|
||||||
|
msg_location = rsx::overlays::message_pin_location::bottom_left;
|
||||||
|
break;
|
||||||
|
case CELL_SAVEDATA_INDICATORPOS_UPPER_RIGHT:
|
||||||
|
msg_location = rsx::overlays::message_pin_location::top_right;
|
||||||
|
break;
|
||||||
|
case CELL_SAVEDATA_INDICATORPOS_UPPER_LEFT:
|
||||||
|
case CELL_SAVEDATA_INDICATORPOS_CENTER:
|
||||||
|
default:
|
||||||
|
msg_location = rsx::overlays::message_pin_location::top_left;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Blinking variants
|
||||||
|
|
||||||
|
// RPCS3 saves basically instantaneously so there's not much point in showing auto indicator
|
||||||
|
// WHILE saving is in progress. Instead we show the indicator for 3 seconds to let the user
|
||||||
|
// know when the game autosaves.
|
||||||
|
rsx::overlays::queue_message(msg_text, 3'000'000, {}, msg_location);
|
||||||
|
}
|
||||||
|
|
||||||
error_code savedata_result = CELL_OK;
|
error_code savedata_result = CELL_OK;
|
||||||
|
|
||||||
u64 delay_save_until = 0;
|
u64 delay_save_until = 0;
|
||||||
|
@ -2098,6 +2144,11 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||||
fs::remove_all(old_path);
|
fs::remove_all(old_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (show_auto_indicator)
|
||||||
|
{
|
||||||
|
// auto indicator should be hidden here if save/load throttling is added
|
||||||
|
}
|
||||||
|
|
||||||
if (savedata_result + 0u == CELL_SAVEDATA_ERROR_CBRESULT)
|
if (savedata_result + 0u == CELL_SAVEDATA_ERROR_CBRESULT)
|
||||||
{
|
{
|
||||||
return display_callback_result_error_message(ppu, *result, errDialog);
|
return display_callback_result_error_message(ppu, *result, errDialog);
|
||||||
|
|
|
@ -463,7 +463,7 @@ std::string gdb_thread::get_reg(ppu_thread* thread, u32 rid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gdb_thread::set_reg(ppu_thread* thread, u32 rid, std::string value)
|
bool gdb_thread::set_reg(ppu_thread* thread, u32 rid, const std::string& value)
|
||||||
{
|
{
|
||||||
switch (rid)
|
switch (rid)
|
||||||
{
|
{
|
||||||
|
@ -492,7 +492,7 @@ bool gdb_thread::set_reg(ppu_thread* thread, u32 rid, std::string value)
|
||||||
if (rid > 70) return false;
|
if (rid > 70) return false;
|
||||||
if (rid > 31)
|
if (rid > 31)
|
||||||
{
|
{
|
||||||
u64 val = hex_to_u64(value);
|
const u64 val = hex_to_u64(value);
|
||||||
thread->fpr[rid - 32] = std::bit_cast<f64>(val);
|
thread->fpr[rid - 32] = std::bit_cast<f64>(val);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -58,7 +58,7 @@ class gdb_thread
|
||||||
//returns register value as hex string by register id (in gdb), in case of wrong id returns empty string
|
//returns register value as hex string by register id (in gdb), in case of wrong id returns empty string
|
||||||
static std::string get_reg(ppu_thread* thread, u32 rid);
|
static std::string get_reg(ppu_thread* thread, u32 rid);
|
||||||
//sets register value to hex string by register id (in gdb), in case of wrong id returns false
|
//sets register value to hex string by register id (in gdb), in case of wrong id returns false
|
||||||
static bool set_reg(ppu_thread* thread, u32 rid, std::string value);
|
static bool set_reg(ppu_thread* thread, u32 rid, const std::string& value);
|
||||||
//returns size of register with id rid in bytes, zero if invalid rid is provided
|
//returns size of register with id rid in bytes, zero if invalid rid is provided
|
||||||
static u32 get_reg_size(ppu_thread* thread, u32 rid);
|
static u32 get_reg_size(ppu_thread* thread, u32 rid);
|
||||||
//send reason of stop, returns false if sending response failed
|
//send reason of stop, returns false if sending response failed
|
||||||
|
|
|
@ -259,9 +259,9 @@ dimensions_figure& dimensions_toypad::get_figure_by_index(u8 index)
|
||||||
void dimensions_toypad::random_uid(u8* uid_buffer)
|
void dimensions_toypad::random_uid(u8* uid_buffer)
|
||||||
{
|
{
|
||||||
uid_buffer[0] = 0x04;
|
uid_buffer[0] = 0x04;
|
||||||
uid_buffer[6] = 0x80;
|
uid_buffer[7] = 0x80;
|
||||||
|
|
||||||
for (u8 i = 1; i < 6; i++)
|
for (u8 i = 1; i < 7; i++)
|
||||||
{
|
{
|
||||||
u8 random = rand() % 255;
|
u8 random = rand() % 255;
|
||||||
uid_buffer[i] = random;
|
uid_buffer[i] = random;
|
||||||
|
@ -384,10 +384,10 @@ u32 dimensions_toypad::load_figure(const std::array<u8, 0x2D * 0x04>& buf, fs::f
|
||||||
std::memcpy(figure.data.data(), buf.data(), buf.size());
|
std::memcpy(figure.data.data(), buf.data(), buf.size());
|
||||||
// When a figure is added to the toypad, respond to the game with the pad they were added to, their index,
|
// When a figure is added to the toypad, respond to the game with the pad they were added to, their index,
|
||||||
// the direction (0x00 in byte 6 for added) and their UID
|
// the direction (0x00 in byte 6 for added) and their UID
|
||||||
std::array<u8, 32> figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x00};
|
std::array<u8, 32> figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x00,
|
||||||
std::memcpy(&figure_change_response[6], buf.data(), 7);
|
buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]};
|
||||||
figure_change_response[13] = generate_checksum(figure_change_response, 13);
|
figure_change_response[13] = generate_checksum(figure_change_response, 13);
|
||||||
m_figure_added_removed_responses.push(figure_change_response);
|
m_figure_added_removed_responses.push(std::move(figure_change_response));
|
||||||
|
|
||||||
if (lock)
|
if (lock)
|
||||||
{
|
{
|
||||||
|
@ -396,7 +396,7 @@ u32 dimensions_toypad::load_figure(const std::array<u8, 0x2D * 0x04>& buf, fs::f
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool save, bool lock)
|
bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool full_remove, bool lock)
|
||||||
{
|
{
|
||||||
dimensions_figure& figure = get_figure_by_index(index);
|
dimensions_figure& figure = get_figure_by_index(index);
|
||||||
if (figure.index == 255)
|
if (figure.index == 255)
|
||||||
|
@ -411,17 +411,20 @@ bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool save, bool lock)
|
||||||
|
|
||||||
// When a figure is removed from the toypad, respond to the game with the pad they were removed from, their index,
|
// When a figure is removed from the toypad, respond to the game with the pad they were removed from, their index,
|
||||||
// the direction (0x01 in byte 6 for removed) and their UID
|
// the direction (0x01 in byte 6 for removed) and their UID
|
||||||
std::array<u8, 32> figure_change_response = {0x56, 0x0b, pad, 0x00, figure.index, 0x01};
|
if (full_remove)
|
||||||
std::memcpy(&figure_change_response[6], figure.data.data(), 7);
|
|
||||||
if (save)
|
|
||||||
{
|
{
|
||||||
|
std::array<u8, 32> figure_change_response = {0x56, 0x0b, pad, 0x00, figure.index, 0x01,
|
||||||
|
figure.data[0], figure.data[1], figure.data[2],
|
||||||
|
figure.data[4], figure.data[5], figure.data[6], figure.data[7]};
|
||||||
|
figure_change_response[13] = generate_checksum(figure_change_response, 13);
|
||||||
|
m_figure_added_removed_responses.push(std::move(figure_change_response));
|
||||||
figure.save();
|
figure.save();
|
||||||
figure.dim_file.close();
|
figure.dim_file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
figure.index = 255;
|
figure.index = 255;
|
||||||
figure.pad = 255;
|
figure.pad = 255;
|
||||||
figure_change_response[13] = generate_checksum(figure_change_response, 13);
|
figure.id = 0;
|
||||||
m_figure_added_removed_responses.push(figure_change_response);
|
|
||||||
|
|
||||||
if (lock)
|
if (lock)
|
||||||
{
|
{
|
||||||
|
@ -430,23 +433,56 @@ bool dimensions_toypad::remove_figure(u8 pad, u8 index, bool save, bool lock)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dimensions_toypad::move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index)
|
bool dimensions_toypad::temp_remove(u8 index)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(m_dimensions_mutex);
|
std::lock_guard lock(m_dimensions_mutex);
|
||||||
|
|
||||||
|
const dimensions_figure& figure = get_figure_by_index(index);
|
||||||
|
if (figure.index == 255)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Send a response to the game that the figure has been "Picked up" from existing slot,
|
||||||
|
// until either the movement is cancelled, or user chooses a space to move to
|
||||||
|
std::array<u8, 32> figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x01,
|
||||||
|
figure.data[0], figure.data[1], figure.data[2],
|
||||||
|
figure.data[4], figure.data[5], figure.data[6], figure.data[7]};
|
||||||
|
|
||||||
|
figure_change_response[13] = generate_checksum(figure_change_response, 13);
|
||||||
|
m_figure_added_removed_responses.push(std::move(figure_change_response));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dimensions_toypad::cancel_remove(u8 index)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(m_dimensions_mutex);
|
||||||
|
|
||||||
|
dimensions_figure& figure = get_figure_by_index(index);
|
||||||
|
if (figure.index == 255)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Cancel the previous movement of the figure
|
||||||
|
std::array<u8, 32> figure_change_response = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x00,
|
||||||
|
figure.data[0], figure.data[1], figure.data[2],
|
||||||
|
figure.data[4], figure.data[5], figure.data[6], figure.data[7]};
|
||||||
|
|
||||||
|
figure_change_response[13] = generate_checksum(figure_change_response, 13);
|
||||||
|
m_figure_added_removed_responses.push(std::move(figure_change_response));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dimensions_toypad::move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index)
|
||||||
|
{
|
||||||
if (old_index == index)
|
if (old_index == index)
|
||||||
{
|
{
|
||||||
// Don't bother removing and loading again, just send response to the game
|
// Don't bother removing and loading again, just send response to the game
|
||||||
const dimensions_figure& figure = get_figure_by_index(old_index);
|
cancel_remove(index);
|
||||||
std::array<u8, 32> figure_remove_response = {0x56, 0x0b, pad, 0x00, figure.index, 0x01};
|
|
||||||
figure_remove_response[13] = generate_checksum(figure_remove_response, 13);
|
|
||||||
std::array<u8, 32> figure_add_response = {0x56, 0x0b, pad, 0x00, figure.index, 0x00};
|
|
||||||
figure_add_response[13] = generate_checksum(figure_add_response, 13);
|
|
||||||
m_figure_added_removed_responses.push(std::move(figure_remove_response));
|
|
||||||
m_figure_added_removed_responses.push(std::move(figure_add_response));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::lock_guard lock(m_dimensions_mutex);
|
||||||
|
|
||||||
// When moving figures between spaces on the toypad, remove any figure from the space they are moving to,
|
// When moving figures between spaces on the toypad, remove any figure from the space they are moving to,
|
||||||
// then remove them from their current space, then load them to the space they are moving to
|
// then remove them from their current space, then load them to the space they are moving to
|
||||||
remove_figure(pad, index, true, false);
|
remove_figure(pad, index, true, false);
|
||||||
|
@ -465,14 +501,16 @@ bool dimensions_toypad::move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index)
|
||||||
bool dimensions_toypad::create_blank_character(std::array<u8, 0x2D * 0x04>& buf, u16 id)
|
bool dimensions_toypad::create_blank_character(std::array<u8, 0x2D * 0x04>& buf, u16 id)
|
||||||
{
|
{
|
||||||
random_uid(buf.data());
|
random_uid(buf.data());
|
||||||
buf[7] = id & 0xFF;
|
buf[3] = id & 0xFF;
|
||||||
std::array<u8, 7> uid = {buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]};
|
|
||||||
|
|
||||||
// Only characters are created with their ID encrypted and stored in pages 36 and 37,
|
// Only characters are created with their ID encrypted and stored in pages 36 and 37,
|
||||||
// as well as a password stored in page 43. Blank tags have their information populated
|
// as well as a password stored in page 43. Blank tags have their information populated
|
||||||
// by the game when it calls the write_block command.
|
// by the game when it calls the write_block command.
|
||||||
if (id != 0)
|
if (id != 0)
|
||||||
{
|
{
|
||||||
|
// LEGO Dimensions figures use NTAG213 tag types, and the UID for these is stored in
|
||||||
|
// bytes 0, 1, 2, 4, 5, 6 and 7 (out of 180 bytes)
|
||||||
|
std::array<u8, 7> uid = {buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]};
|
||||||
const std::array<u8, 16> figure_key = generate_figure_key(buf);
|
const std::array<u8, 16> figure_key = generate_figure_key(buf);
|
||||||
|
|
||||||
std::array<u8, 8> value_to_encrypt = {};
|
std::array<u8, 8> value_to_encrypt = {};
|
||||||
|
|
|
@ -30,7 +30,9 @@ public:
|
||||||
void get_model(const u8* buf, u8 sequence, std::array<u8, 32>& reply_buf);
|
void get_model(const u8* buf, u8 sequence, std::array<u8, 32>& reply_buf);
|
||||||
std::optional<std::array<u8, 32>> pop_added_removed_response();
|
std::optional<std::array<u8, 32>> pop_added_removed_response();
|
||||||
|
|
||||||
bool remove_figure(u8 pad, u8 index, bool save, bool lock);
|
bool remove_figure(u8 pad, u8 index, bool full_remove, bool lock);
|
||||||
|
bool temp_remove(u8 index);
|
||||||
|
bool cancel_remove(u8 index);
|
||||||
u32 load_figure(const std::array<u8, 0x2D * 0x04>& buf, fs::file in_file, u8 pad, u8 index, bool lock);
|
u32 load_figure(const std::array<u8, 0x2D * 0x04>& buf, fs::file in_file, u8 pad, u8 index, bool lock);
|
||||||
bool move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index);
|
bool move_figure(u8 pad, u8 index, u8 old_pad, u8 old_index);
|
||||||
static bool create_blank_character(std::array<u8, 0x2D * 0x04>& buf, u16 id);
|
static bool create_blank_character(std::array<u8, 0x2D * 0x04>& buf, u16 id);
|
||||||
|
|
|
@ -233,7 +233,7 @@ struct emulated_pads_config : cfg::node
|
||||||
|
|
||||||
if (fs::file cfg_file{ cfg_name, fs::read })
|
if (fs::file cfg_file{ cfg_name, fs::read })
|
||||||
{
|
{
|
||||||
if (std::string content = cfg_file.to_string(); !content.empty())
|
if (const std::string content = cfg_file.to_string(); !content.empty())
|
||||||
{
|
{
|
||||||
result = from_string(content);
|
result = from_string(content);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ bool cfg_input::load(const std::string& title_id, const std::string& config_file
|
||||||
{
|
{
|
||||||
input_log.notice("Loading input configuration: '%s'", cfg_name);
|
input_log.notice("Loading input configuration: '%s'", cfg_name);
|
||||||
|
|
||||||
if (std::string content = cfg_file.to_string(); !content.empty())
|
if (const std::string content = cfg_file.to_string(); !content.empty())
|
||||||
{
|
{
|
||||||
return from_string(content);
|
return from_string(content);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1182,6 +1182,8 @@ namespace np
|
||||||
vm::ptr<SceNpScoreRankData> rankArray = vm::static_ptr_cast<SceNpScoreRankData>(tdata->rankArray);
|
vm::ptr<SceNpScoreRankData> rankArray = vm::static_ptr_cast<SceNpScoreRankData>(tdata->rankArray);
|
||||||
vm::ptr<SceNpScoreRankData_deprecated> rankArray_deprecated = vm::static_ptr_cast<SceNpScoreRankData_deprecated>(tdata->rankArray);
|
vm::ptr<SceNpScoreRankData_deprecated> rankArray_deprecated = vm::static_ptr_cast<SceNpScoreRankData_deprecated>(tdata->rankArray);
|
||||||
|
|
||||||
|
u32 num_scores_registered = 0;
|
||||||
|
|
||||||
for (flatbuffers::uoffset_t i = 0; i < fb_rankarray->size(); i++)
|
for (flatbuffers::uoffset_t i = 0; i < fb_rankarray->size(); i++)
|
||||||
{
|
{
|
||||||
const auto* fb_rankdata = fb_rankarray->Get(i);
|
const auto* fb_rankdata = fb_rankarray->Get(i);
|
||||||
|
@ -1190,6 +1192,8 @@ namespace np
|
||||||
if (fb_rankdata->recordDate() == 0)
|
if (fb_rankdata->recordDate() == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
num_scores_registered++;
|
||||||
|
|
||||||
if (tdata->player_rank_data)
|
if (tdata->player_rank_data)
|
||||||
{
|
{
|
||||||
if (tdata->deprecated)
|
if (tdata->deprecated)
|
||||||
|
@ -1262,7 +1266,7 @@ namespace np
|
||||||
tdata->lastSortDate->tick = resp->lastSortDate();
|
tdata->lastSortDate->tick = resp->lastSortDate();
|
||||||
*tdata->totalRecord = resp->totalRecord();
|
*tdata->totalRecord = resp->totalRecord();
|
||||||
|
|
||||||
if (fb_rankarray->size())
|
if (num_scores_registered)
|
||||||
score_trans->result = simple_result ? CELL_OK : not_an_error(fb_rankarray->size());
|
score_trans->result = simple_result ? CELL_OK : not_an_error(fb_rankarray->size());
|
||||||
else
|
else
|
||||||
score_trans->result = SCE_NP_COMMUNITY_SERVER_ERROR_GAME_RANKING_NOT_FOUND;
|
score_trans->result = SCE_NP_COMMUNITY_SERVER_ERROR_GAME_RANKING_NOT_FOUND;
|
||||||
|
|
|
@ -2614,7 +2614,7 @@ namespace rpcn
|
||||||
NotificationType ntype = static_cast<NotificationType>(command);
|
NotificationType ntype = static_cast<NotificationType>(command);
|
||||||
vec_stream vdata(data);
|
vec_stream vdata(data);
|
||||||
|
|
||||||
auto call_callbacks = [&](NotificationType ntype, std::string username, bool status)
|
const auto call_callbacks = [&](NotificationType ntype, const std::string& username, bool status)
|
||||||
{
|
{
|
||||||
for (auto& friend_cb : friend_cbs)
|
for (auto& friend_cb : friend_cbs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,6 +97,7 @@ namespace rsx
|
||||||
add_checkbox(&g_cfg.misc.show_rpcn_popups, "Show RPCN Popups");
|
add_checkbox(&g_cfg.misc.show_rpcn_popups, "Show RPCN Popups");
|
||||||
add_checkbox(&g_cfg.misc.show_shader_compilation_hint, "Show Shader Compilation Hint");
|
add_checkbox(&g_cfg.misc.show_shader_compilation_hint, "Show Shader Compilation Hint");
|
||||||
add_checkbox(&g_cfg.misc.show_ppu_compilation_hint, "Show PPU Compilation Hint");
|
add_checkbox(&g_cfg.misc.show_ppu_compilation_hint, "Show PPU Compilation Hint");
|
||||||
|
add_checkbox(&g_cfg.misc.show_autosave_autoload_hint, "Show Autosave/Autoload Hint");
|
||||||
|
|
||||||
apply_layout();
|
apply_layout();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace rsx
|
||||||
localized_string_id::RSX_OVERLAYS_COMPILING_SHADERS,
|
localized_string_id::RSX_OVERLAYS_COMPILING_SHADERS,
|
||||||
5'000'000,
|
5'000'000,
|
||||||
{},
|
{},
|
||||||
message_pin_location::bottom,
|
message_pin_location::bottom_left,
|
||||||
s_shader_loading_icon24,
|
s_shader_loading_icon24,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ namespace rsx
|
||||||
localized_string_id::RSX_OVERLAYS_COMPILING_PPU_MODULES,
|
localized_string_id::RSX_OVERLAYS_COMPILING_PPU_MODULES,
|
||||||
20'000'000,
|
20'000'000,
|
||||||
refs,
|
refs,
|
||||||
message_pin_location::bottom,
|
message_pin_location::bottom_left,
|
||||||
s_ppu_loading_icon24,
|
s_ppu_loading_icon24,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace rsx
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
message_item::message_item(T msg_id, u64 expiration, std::shared_ptr<atomic_t<u32>> refs, std::shared_ptr<overlay_element> icon)
|
message_item::message_item(const T& msg_id, u64 expiration, std::shared_ptr<atomic_t<u32>> refs, std::shared_ptr<overlay_element> icon)
|
||||||
{
|
{
|
||||||
m_visible_duration = expiration;
|
m_visible_duration = expiration;
|
||||||
m_refs = std::move(refs);
|
m_refs = std::move(refs);
|
||||||
|
@ -52,8 +52,8 @@ namespace rsx
|
||||||
set_size(m_text.w + m_margin + m_margin, m_text.h + m_margin + m_margin);
|
set_size(m_text.w + m_margin + m_margin, m_text.h + m_margin + m_margin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template message_item::message_item(std::string msg_id, u64, std::shared_ptr<atomic_t<u32>>, std::shared_ptr<overlay_element>);
|
template message_item::message_item(const std::string& msg_id, u64, std::shared_ptr<atomic_t<u32>>, std::shared_ptr<overlay_element>);
|
||||||
template message_item::message_item(localized_string_id msg_id, u64, std::shared_ptr<atomic_t<u32>>, std::shared_ptr<overlay_element>);
|
template message_item::message_item(const localized_string_id& msg_id, u64, std::shared_ptr<atomic_t<u32>>, std::shared_ptr<overlay_element>);
|
||||||
|
|
||||||
void message_item::reset_expiration()
|
void message_item::reset_expiration()
|
||||||
{
|
{
|
||||||
|
@ -117,12 +117,12 @@ namespace rsx
|
||||||
return compiled_resources;
|
return compiled_resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
void message_item::update(usz index, u64 timestamp_us, s16 y_offset)
|
void message_item::update(usz index, u64 timestamp_us, s16 x_offset, s16 y_offset)
|
||||||
{
|
{
|
||||||
if (m_cur_pos != index)
|
if (m_cur_pos != index)
|
||||||
{
|
{
|
||||||
m_cur_pos = index;
|
m_cur_pos = index;
|
||||||
set_pos(10, y_offset);
|
set_pos(x_offset, y_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_processed)
|
if (!m_processed)
|
||||||
|
@ -197,19 +197,30 @@ namespace rsx
|
||||||
|
|
||||||
// Render reversed list. Oldest entries are furthest from the border
|
// Render reversed list. Oldest entries are furthest from the border
|
||||||
constexpr u16 spacing = 4;
|
constexpr u16 spacing = 4;
|
||||||
|
s16 x_offset = 10;
|
||||||
s16 y_offset = 8;
|
s16 y_offset = 8;
|
||||||
usz index = 0;
|
usz index = 0;
|
||||||
|
|
||||||
for (auto it = vis_set.rbegin(); it != vis_set.rend(); ++it, ++index)
|
for (auto it = vis_set.rbegin(); it != vis_set.rend(); ++it, ++index)
|
||||||
{
|
{
|
||||||
if (origin == message_pin_location::top) [[ likely ]]
|
switch (origin)
|
||||||
{
|
{
|
||||||
it->update(index, cur_time, y_offset);
|
case message_pin_location::bottom_right:
|
||||||
y_offset += (spacing + it->h);
|
y_offset += (spacing + it->h);
|
||||||
}
|
it->update(index, cur_time, virtual_width - x_offset - it->w, virtual_height - y_offset);
|
||||||
else
|
break;
|
||||||
{
|
case message_pin_location::bottom_left:
|
||||||
y_offset += (spacing + it->h);
|
y_offset += (spacing + it->h);
|
||||||
it->update(index, cur_time, virtual_height - y_offset);
|
it->update(index, cur_time, x_offset, virtual_height - y_offset);
|
||||||
|
break;
|
||||||
|
case message_pin_location::top_right:
|
||||||
|
it->update(index, cur_time, virtual_width - x_offset - it->w, y_offset);
|
||||||
|
y_offset += (spacing + it->h);
|
||||||
|
break;
|
||||||
|
case message_pin_location::top_left:
|
||||||
|
it->update(index, cur_time, x_offset, y_offset);
|
||||||
|
y_offset += (spacing + it->h);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,10 +234,13 @@ namespace rsx
|
||||||
|
|
||||||
std::lock_guard lock(m_mutex_queue);
|
std::lock_guard lock(m_mutex_queue);
|
||||||
|
|
||||||
update_queue(m_visible_items_top, m_ready_queue_top, message_pin_location::top);
|
update_queue(m_visible_items_bottom_right, m_ready_queue_bottom_right, message_pin_location::bottom_right);
|
||||||
update_queue(m_visible_items_bottom, m_ready_queue_bottom, message_pin_location::bottom);
|
update_queue(m_visible_items_bottom_left, m_ready_queue_bottom_left, message_pin_location::bottom_left);
|
||||||
|
update_queue(m_visible_items_top_right, m_ready_queue_top_right, message_pin_location::top_right);
|
||||||
|
update_queue(m_visible_items_top_left, m_ready_queue_top_left, message_pin_location::top_left);
|
||||||
|
|
||||||
visible = !m_visible_items_top.empty() || !m_visible_items_bottom.empty();
|
visible = !m_visible_items_bottom_right.empty() || !m_visible_items_bottom_left.empty() ||
|
||||||
|
!m_visible_items_top_right.empty() || !m_visible_items_top_left.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
compiled_resource message::get_compiled()
|
compiled_resource message::get_compiled()
|
||||||
|
@ -240,12 +254,22 @@ namespace rsx
|
||||||
|
|
||||||
compiled_resource cr{};
|
compiled_resource cr{};
|
||||||
|
|
||||||
for (auto& item : m_visible_items_top)
|
for (auto& item : m_visible_items_bottom_right)
|
||||||
{
|
{
|
||||||
cr.add(item.get_compiled());
|
cr.add(item.get_compiled());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& item : m_visible_items_bottom)
|
for (auto& item : m_visible_items_bottom_left)
|
||||||
|
{
|
||||||
|
cr.add(item.get_compiled());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& item : m_visible_items_top_right)
|
||||||
|
{
|
||||||
|
cr.add(item.get_compiled());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& item : m_visible_items_top_left)
|
||||||
{
|
{
|
||||||
cr.add(item.get_compiled());
|
cr.add(item.get_compiled());
|
||||||
}
|
}
|
||||||
|
@ -283,10 +307,14 @@ namespace rsx
|
||||||
|
|
||||||
switch (location)
|
switch (location)
|
||||||
{
|
{
|
||||||
case message_pin_location::top:
|
case message_pin_location::bottom_right:
|
||||||
return check_list(m_ready_queue_top) || check_list(m_visible_items_top);
|
return check_list(m_ready_queue_bottom_right) || check_list(m_visible_items_bottom_right);
|
||||||
case message_pin_location::bottom:
|
case message_pin_location::bottom_left:
|
||||||
return check_list(m_ready_queue_bottom) || check_list(m_visible_items_bottom);
|
return check_list(m_ready_queue_bottom_left) || check_list(m_visible_items_bottom_left);
|
||||||
|
case message_pin_location::top_right:
|
||||||
|
return check_list(m_ready_queue_top_right) || check_list(m_visible_items_top_right);
|
||||||
|
case message_pin_location::top_left:
|
||||||
|
return check_list(m_ready_queue_top_left) || check_list(m_visible_items_top_left);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -11,16 +11,18 @@ namespace rsx
|
||||||
{
|
{
|
||||||
enum class message_pin_location
|
enum class message_pin_location
|
||||||
{
|
{
|
||||||
top,
|
bottom_right,
|
||||||
bottom
|
bottom_left,
|
||||||
|
top_right,
|
||||||
|
top_left
|
||||||
};
|
};
|
||||||
|
|
||||||
class message_item : public rounded_rect
|
class message_item : public rounded_rect
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
message_item(T msg_id, u64 expiration, std::shared_ptr<atomic_t<u32>> refs, std::shared_ptr<overlay_element> icon = {});
|
message_item(const T& msg_id, u64 expiration, std::shared_ptr<atomic_t<u32>> refs, std::shared_ptr<overlay_element> icon = {});
|
||||||
void update(usz index, u64 timestamp_us, s16 y_offset);
|
void update(usz index, u64 timestamp_us, s16 x_offset, s16 y_offset);
|
||||||
void set_pos(s16 _x, s16 _y) override;
|
void set_pos(s16 _x, s16 _y) override;
|
||||||
|
|
||||||
void reset_expiration();
|
void reset_expiration();
|
||||||
|
@ -55,15 +57,29 @@ namespace rsx
|
||||||
T msg_id,
|
T msg_id,
|
||||||
u64 expiration,
|
u64 expiration,
|
||||||
std::shared_ptr<atomic_t<u32>> refs,
|
std::shared_ptr<atomic_t<u32>> refs,
|
||||||
message_pin_location location = message_pin_location::top,
|
message_pin_location location = message_pin_location::top_left,
|
||||||
std::shared_ptr<overlay_element> icon = {},
|
std::shared_ptr<overlay_element> icon = {},
|
||||||
bool allow_refresh = false)
|
bool allow_refresh = false)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(m_mutex_queue);
|
std::lock_guard lock(m_mutex_queue);
|
||||||
|
|
||||||
auto& queue = location == message_pin_location::top
|
auto* queue = &m_ready_queue_top_left;
|
||||||
? m_ready_queue_top
|
|
||||||
: m_ready_queue_bottom;
|
switch (location)
|
||||||
|
{
|
||||||
|
case message_pin_location::bottom_right:
|
||||||
|
queue = &m_ready_queue_bottom_right;
|
||||||
|
break;
|
||||||
|
case message_pin_location::bottom_left:
|
||||||
|
queue = &m_ready_queue_bottom_left;
|
||||||
|
break;
|
||||||
|
case message_pin_location::top_right:
|
||||||
|
queue = &m_ready_queue_top_right;
|
||||||
|
break;
|
||||||
|
case message_pin_location::top_left:
|
||||||
|
queue = &m_ready_queue_top_left;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if constexpr (std::is_same_v<T, std::initializer_list<localized_string_id>>)
|
if constexpr (std::is_same_v<T, std::initializer_list<localized_string_id>>)
|
||||||
{
|
{
|
||||||
|
@ -71,13 +87,13 @@ namespace rsx
|
||||||
{
|
{
|
||||||
if (!message_exists(location, id, allow_refresh))
|
if (!message_exists(location, id, allow_refresh))
|
||||||
{
|
{
|
||||||
queue.emplace_back(id, expiration, refs, icon);
|
queue->emplace_back(id, expiration, refs, icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!message_exists(location, msg_id, allow_refresh))
|
else if (!message_exists(location, msg_id, allow_refresh))
|
||||||
{
|
{
|
||||||
queue.emplace_back(msg_id, expiration, std::move(refs), icon);
|
queue->emplace_back(msg_id, expiration, std::move(refs), icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
visible = true;
|
visible = true;
|
||||||
|
@ -89,12 +105,16 @@ namespace rsx
|
||||||
shared_mutex m_mutex_queue;
|
shared_mutex m_mutex_queue;
|
||||||
|
|
||||||
// Top and bottom enqueued sets
|
// Top and bottom enqueued sets
|
||||||
std::deque<message_item> m_ready_queue_top;
|
std::deque<message_item> m_ready_queue_bottom_right;
|
||||||
std::deque<message_item> m_ready_queue_bottom;
|
std::deque<message_item> m_ready_queue_bottom_left;
|
||||||
|
std::deque<message_item> m_ready_queue_top_right;
|
||||||
|
std::deque<message_item> m_ready_queue_top_left;
|
||||||
|
|
||||||
// Top and bottom visible sets
|
// Top and bottom visible sets
|
||||||
std::deque<message_item> m_visible_items_top;
|
std::deque<message_item> m_visible_items_bottom_right;
|
||||||
std::deque<message_item> m_visible_items_bottom;
|
std::deque<message_item> m_visible_items_bottom_left;
|
||||||
|
std::deque<message_item> m_visible_items_top_right;
|
||||||
|
std::deque<message_item> m_visible_items_top_left;
|
||||||
|
|
||||||
void update_queue(std::deque<message_item>& vis_set, std::deque<message_item>& ready_set, message_pin_location origin);
|
void update_queue(std::deque<message_item>& vis_set, std::deque<message_item>& ready_set, message_pin_location origin);
|
||||||
|
|
||||||
|
@ -109,7 +129,7 @@ namespace rsx
|
||||||
T msg_id,
|
T msg_id,
|
||||||
u64 expiration = 5'000'000,
|
u64 expiration = 5'000'000,
|
||||||
std::shared_ptr<atomic_t<u32>> refs = {},
|
std::shared_ptr<atomic_t<u32>> refs = {},
|
||||||
message_pin_location location = message_pin_location::top,
|
message_pin_location location = message_pin_location::top_left,
|
||||||
std::shared_ptr<overlay_element> icon = {},
|
std::shared_ptr<overlay_element> icon = {},
|
||||||
bool allow_refresh = false)
|
bool allow_refresh = false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -581,7 +581,7 @@ void Emulator::Init()
|
||||||
fs::write_file(games_common_dir + "/Disc Games Can Be Put Here For Automatic Detection.txt", fs::create + fs::excl + fs::write, ""s);
|
fs::write_file(games_common_dir + "/Disc Games Can Be Put Here For Automatic Detection.txt", fs::create + fs::excl + fs::write, ""s);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (std::string rpcs3_shortcuts = games_common_dir + "/shortcuts"; make_path_verbose(rpcs3_shortcuts, false))
|
if (const std::string rpcs3_shortcuts = games_common_dir + "/shortcuts"; make_path_verbose(rpcs3_shortcuts, false))
|
||||||
{
|
{
|
||||||
fs::write_file(rpcs3_shortcuts + "/Copyable Shortcuts For Installed Games Would Be Added Here.txt", fs::create + fs::excl + fs::write, ""s);
|
fs::write_file(rpcs3_shortcuts + "/Copyable Shortcuts For Installed Games Would Be Added Here.txt", fs::create + fs::excl + fs::write, ""s);
|
||||||
}
|
}
|
||||||
|
@ -732,37 +732,72 @@ std::string Emulator::GetBackgroundPicturePath() const
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = m_sfo_dir + "/PIC1.PNG";
|
std::string disc_dir = vfs::get("/dev_bdvd/PS3_GAME");
|
||||||
|
|
||||||
if (!fs::is_file(path))
|
if (m_sfo_dir == disc_dir)
|
||||||
{
|
{
|
||||||
const std::string disc_dir = vfs::get("/dev_bdvd/PS3_GAME");
|
disc_dir.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (disc_dir.empty())
|
constexpr auto search_barrier = "barrier";
|
||||||
{
|
|
||||||
// Fallback to ICON0.PNG
|
|
||||||
path = m_sfo_dir + "/ICON0.PNG";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Fallback to PIC1.PNG in disc dir
|
|
||||||
path = disc_dir + "/PIC1.PNG";
|
|
||||||
|
|
||||||
if (!fs::is_file(path))
|
std::initializer_list<std::string> testees =
|
||||||
|
{
|
||||||
|
m_sfo_dir + "/PIC0.PNG",
|
||||||
|
m_sfo_dir + "/PIC1.PNG",
|
||||||
|
m_sfo_dir + "/PIC2.PNG",
|
||||||
|
m_sfo_dir + "/PIC3.PNG",
|
||||||
|
search_barrier,
|
||||||
|
!disc_dir.empty() ? (disc_dir + "/PIC0.PNG") : disc_dir,
|
||||||
|
!disc_dir.empty() ? (disc_dir + "/PIC1.PNG") : disc_dir,
|
||||||
|
!disc_dir.empty() ? (disc_dir + "/PIC2.PNG") : disc_dir,
|
||||||
|
!disc_dir.empty() ? (disc_dir + "/PIC3.PNG") : disc_dir,
|
||||||
|
search_barrier,
|
||||||
|
m_sfo_dir + "/ICON0.PNG",
|
||||||
|
search_barrier,
|
||||||
|
!disc_dir.empty() ? (disc_dir + "/ICON0.PNG") : disc_dir,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try to return the picture with the highest resultion
|
||||||
|
// Be naive and assume that its the one that spans over the most bytes
|
||||||
|
usz max_file_size = 0;
|
||||||
|
usz index_of_largest_file = umax;
|
||||||
|
|
||||||
|
for (usz index = 0; index < testees.size(); index++)
|
||||||
|
{
|
||||||
|
const std::string& path = testees.begin()[index];
|
||||||
|
|
||||||
|
fs::stat_t file_stat{};
|
||||||
|
|
||||||
|
if (path == search_barrier)
|
||||||
|
{
|
||||||
|
if (index_of_largest_file != umax)
|
||||||
{
|
{
|
||||||
// Fallback to ICON0.PNG in update dir
|
// Found a file in the preferred image group
|
||||||
path = m_sfo_dir + "/ICON0.PNG";
|
break;
|
||||||
|
|
||||||
if (!fs::is_file(path))
|
|
||||||
{
|
|
||||||
// Fallback to ICON0.PNG in disc dir
|
|
||||||
path = disc_dir + "/ICON0.PNG";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.empty() || !fs::get_stat(path, file_stat) || file_stat.is_directory)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_file_size < file_stat.size)
|
||||||
|
{
|
||||||
|
max_file_size = file_stat.size;
|
||||||
|
index_of_largest_file = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
if (index_of_largest_file == umax)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return testees.begin()[index_of_largest_file];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Emulator::BootRsxCapture(const std::string& path)
|
bool Emulator::BootRsxCapture(const std::string& path)
|
||||||
|
|
|
@ -138,6 +138,8 @@ enum class localized_string_id
|
||||||
CELL_SAVEDATA_SAVE,
|
CELL_SAVEDATA_SAVE,
|
||||||
CELL_SAVEDATA_LOAD,
|
CELL_SAVEDATA_LOAD,
|
||||||
CELL_SAVEDATA_OVERWRITE,
|
CELL_SAVEDATA_OVERWRITE,
|
||||||
|
CELL_SAVEDATA_AUTOSAVE,
|
||||||
|
CELL_SAVEDATA_AUTOLOAD,
|
||||||
|
|
||||||
CELL_CROSS_CONTROLLER_MSG,
|
CELL_CROSS_CONTROLLER_MSG,
|
||||||
CELL_CROSS_CONTROLLER_FW_MSG,
|
CELL_CROSS_CONTROLLER_FW_MSG,
|
||||||
|
|
|
@ -345,6 +345,7 @@ struct cfg_root : cfg::node
|
||||||
cfg::_bool show_pressure_intensity_toggle_hint{ this, "Show pressure intensity toggle hint", true, true };
|
cfg::_bool show_pressure_intensity_toggle_hint{ this, "Show pressure intensity toggle hint", true, true };
|
||||||
cfg::_bool show_analog_limiter_toggle_hint{ this, "Show analog limiter toggle hint", true, true };
|
cfg::_bool show_analog_limiter_toggle_hint{ this, "Show analog limiter toggle hint", true, true };
|
||||||
cfg::_bool show_mouse_and_keyboard_toggle_hint{ this, "Show mouse and keyboard toggle hint", true, true };
|
cfg::_bool show_mouse_and_keyboard_toggle_hint{ this, "Show mouse and keyboard toggle hint", true, true };
|
||||||
|
cfg::_bool show_autosave_autoload_hint{ this, "Show autosave/autoload hint", false, true };
|
||||||
cfg::_bool use_native_interface{ this, "Use native user interface", true };
|
cfg::_bool use_native_interface{ this, "Use native user interface", true };
|
||||||
cfg::string gdb_server{ this, "GDB Server", "127.0.0.1:2345" };
|
cfg::string gdb_server{ this, "GDB Server", "127.0.0.1:2345" };
|
||||||
cfg::_bool silence_all_logs{ this, "Silence All Logs", false, true };
|
cfg::_bool silence_all_logs{ this, "Silence All Logs", false, true };
|
||||||
|
|
|
@ -70,7 +70,7 @@ bool raw_mice_config::load()
|
||||||
|
|
||||||
if (fs::file cfg_file{ cfg_name, fs::read })
|
if (fs::file cfg_file{ cfg_name, fs::read })
|
||||||
{
|
{
|
||||||
if (std::string content = cfg_file.to_string(); !content.empty())
|
if (const std::string content = cfg_file.to_string(); !content.empty())
|
||||||
{
|
{
|
||||||
result = from_string(content);
|
result = from_string(content);
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ std::unique_ptr<utils::serial> tar_object::get_file(const std::string& path, std
|
||||||
filename += name;
|
filename += name;
|
||||||
|
|
||||||
// Save header and offset
|
// Save header and offset
|
||||||
m_map.insert_or_assign(filename, std::make_pair(offset, header));
|
m_map.insert_or_assign(filename, std::make_pair(offset, std::move(header)));
|
||||||
|
|
||||||
if (new_file_path)
|
if (new_file_path)
|
||||||
{
|
{
|
||||||
|
@ -132,10 +132,8 @@ std::unique_ptr<utils::serial> tar_object::get_file(const std::string& path, std
|
||||||
|
|
||||||
return { size, std::move(filename) };
|
return { size, std::move(filename) };
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
tar_log.error("tar_object::get_file() failed to convert header.size=%s, filesize=0x%x", size_sv, max_size);
|
||||||
tar_log.error("tar_object::get_file() failed to convert header.size=%s, filesize=0x%x", size_sv, max_size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -200,7 +198,7 @@ std::unique_ptr<utils::serial> tar_object::get_file(const std::string& path, std
|
||||||
return m_out;
|
return m_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tar_object::extract(std::string prefix_path, bool is_vfs)
|
bool tar_object::extract(const std::string& prefix_path, bool is_vfs)
|
||||||
{
|
{
|
||||||
std::vector<u8> filedata_buffer(0x80'0000);
|
std::vector<u8> filedata_buffer(0x80'0000);
|
||||||
std::span<u8> filedata_span{filedata_buffer.data(), filedata_buffer.size()};
|
std::span<u8> filedata_span{filedata_buffer.data(), filedata_buffer.size()};
|
||||||
|
|
|
@ -55,7 +55,7 @@ public:
|
||||||
|
|
||||||
// Extract all files in archive to destination (as VFS if is_vfs is true)
|
// Extract all files in archive to destination (as VFS if is_vfs is true)
|
||||||
// Allow to optionally specify explicit mount point (which may be directory meant for extraction)
|
// Allow to optionally specify explicit mount point (which may be directory meant for extraction)
|
||||||
bool extract(std::string prefix_path = {}, bool is_vfs = false);
|
bool extract(const std::string& prefix_path = {}, bool is_vfs = false);
|
||||||
|
|
||||||
static void save_directory(const std::string& src_dir, utils::serial& ar, const process_func& func = {}, std::vector<fs::dir_entry>&& = std::vector<fs::dir_entry>{}, bool has_evaluated_results = false, usz src_dir_pos = umax);
|
static void save_directory(const std::string& src_dir, utils::serial& ar, const process_func& func = {}, std::vector<fs::dir_entry>&& = std::vector<fs::dir_entry>{}, bool has_evaluated_results = false, usz src_dir_pos = umax);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ LOG_CHANNEL(disc_log, "DISC");
|
||||||
|
|
||||||
namespace disc
|
namespace disc
|
||||||
{
|
{
|
||||||
disc_type get_disc_type(std::string path, std::string& disc_root, std::string& ps3_game_dir)
|
disc_type get_disc_type(const std::string& path, std::string& disc_root, std::string& ps3_game_dir)
|
||||||
{
|
{
|
||||||
disc_type type = disc_type::unknown;
|
disc_type type = disc_type::unknown;
|
||||||
|
|
||||||
|
|
|
@ -11,5 +11,5 @@ namespace disc
|
||||||
ps3
|
ps3
|
||||||
};
|
};
|
||||||
|
|
||||||
disc_type get_disc_type(std::string path, std::string& disc_root, std::string& ps3_game_dir);
|
disc_type get_disc_type(const std::string& path, std::string& disc_root, std::string& ps3_game_dir);
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,13 +65,12 @@ namespace cfg_adapter
|
||||||
|
|
||||||
bool get_is_dynamic(emu_settings_type type)
|
bool get_is_dynamic(emu_settings_type type)
|
||||||
{
|
{
|
||||||
const cfg_location loc = settings_location[type];
|
return get_is_dynamic(::at32(settings_location, type));
|
||||||
return get_is_dynamic(loc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_setting_name(emu_settings_type type)
|
std::string get_setting_name(emu_settings_type type)
|
||||||
{
|
{
|
||||||
const cfg_location loc = settings_location[type];
|
const cfg_location& loc = ::at32(settings_location, type);
|
||||||
return loc[loc.size() - 1];
|
return ::at32(loc, loc.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -724,6 +724,7 @@ void dimensions_dialog::move_figure(u8 pad, u8 index)
|
||||||
{
|
{
|
||||||
ensure(index < figure_slots.size());
|
ensure(index < figure_slots.size());
|
||||||
minifig_move_dialog move_dlg(this, index);
|
minifig_move_dialog move_dlg(this, index);
|
||||||
|
g_dimensionstoypad.temp_remove(index);
|
||||||
if (move_dlg.exec() == Accepted)
|
if (move_dlg.exec() == Accepted)
|
||||||
{
|
{
|
||||||
g_dimensionstoypad.move_figure(move_dlg.get_new_pad(), move_dlg.get_new_index(), pad, index);
|
g_dimensionstoypad.move_figure(move_dlg.get_new_pad(), move_dlg.get_new_index(), pad, index);
|
||||||
|
@ -735,6 +736,10 @@ void dimensions_dialog::move_figure(u8 pad, u8 index)
|
||||||
m_edit_figures[index]->setText(tr("None"));
|
m_edit_figures[index]->setText(tr("None"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_dimensionstoypad.cancel_remove(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dimensions_dialog::load_figure_path(u8 pad, u8 index, const QString& path)
|
void dimensions_dialog::load_figure_path(u8 pad, u8 index, const QString& path)
|
||||||
|
|
|
@ -145,7 +145,7 @@ void emu_settings::LoadSettings(const std::string& title_id, bool create_config_
|
||||||
|
|
||||||
if (std::string config_path = rpcs3::utils::get_custom_config_path(m_title_id); fs::is_file(config_path))
|
if (std::string config_path = rpcs3::utils::get_custom_config_path(m_title_id); fs::is_file(config_path))
|
||||||
{
|
{
|
||||||
custom_config_path = config_path;
|
custom_config_path = std::move(config_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!custom_config_path.empty())
|
if (!custom_config_path.empty())
|
||||||
|
@ -837,12 +837,12 @@ void emu_settings::SaveSelectedLibraries(const std::vector<std::string>& libs)
|
||||||
|
|
||||||
QStringList emu_settings::GetSettingOptions(emu_settings_type type)
|
QStringList emu_settings::GetSettingOptions(emu_settings_type type)
|
||||||
{
|
{
|
||||||
return cfg_adapter::get_options(const_cast<cfg_location&&>(settings_location[type]));
|
return cfg_adapter::get_options(::at32(settings_location, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string emu_settings::GetSettingDefault(emu_settings_type type) const
|
std::string emu_settings::GetSettingDefault(emu_settings_type type) const
|
||||||
{
|
{
|
||||||
if (const auto node = cfg_adapter::get_node(m_default_settings, settings_location[type]); node && node.IsScalar())
|
if (const auto node = cfg_adapter::get_node(m_default_settings, ::at32(settings_location, type)); node && node.IsScalar())
|
||||||
{
|
{
|
||||||
return node.Scalar();
|
return node.Scalar();
|
||||||
}
|
}
|
||||||
|
@ -853,7 +853,7 @@ std::string emu_settings::GetSettingDefault(emu_settings_type type) const
|
||||||
|
|
||||||
std::string emu_settings::GetSetting(emu_settings_type type) const
|
std::string emu_settings::GetSetting(emu_settings_type type) const
|
||||||
{
|
{
|
||||||
if (const auto node = cfg_adapter::get_node(m_current_settings, settings_location[type]); node && node.IsScalar())
|
if (const auto node = cfg_adapter::get_node(m_current_settings, ::at32(settings_location, type)); node && node.IsScalar())
|
||||||
{
|
{
|
||||||
return node.Scalar();
|
return node.Scalar();
|
||||||
}
|
}
|
||||||
|
@ -864,7 +864,7 @@ std::string emu_settings::GetSetting(emu_settings_type type) const
|
||||||
|
|
||||||
void emu_settings::SetSetting(emu_settings_type type, const std::string& val) const
|
void emu_settings::SetSetting(emu_settings_type type, const std::string& val) const
|
||||||
{
|
{
|
||||||
cfg_adapter::get_node(m_current_settings, settings_location[type]) = val;
|
cfg_adapter::get_node(m_current_settings, ::at32(settings_location, type)) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emu_settings::OpenCorrectionDialog(QWidget* parent)
|
void emu_settings::OpenCorrectionDialog(QWidget* parent)
|
||||||
|
@ -1355,9 +1355,9 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_
|
||||||
if (strict)
|
if (strict)
|
||||||
{
|
{
|
||||||
std::string type_string;
|
std::string type_string;
|
||||||
if (settings_location.contains(type))
|
if (const auto it = settings_location.find(type); it != settings_location.cend())
|
||||||
{
|
{
|
||||||
for (const char* loc : settings_location.value(type))
|
for (const char* loc : it->second)
|
||||||
{
|
{
|
||||||
if (!type_string.empty()) type_string += ": ";
|
if (!type_string.empty()) type_string += ": ";
|
||||||
type_string += loc;
|
type_string += loc;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QMap>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// Node location
|
// Node location
|
||||||
|
@ -178,6 +178,7 @@ enum class emu_settings_type
|
||||||
ShowPressureIntensityToggleHint,
|
ShowPressureIntensityToggleHint,
|
||||||
ShowAnalogLimiterToggleHint,
|
ShowAnalogLimiterToggleHint,
|
||||||
ShowMouseAndKeyboardToggleHint,
|
ShowMouseAndKeyboardToggleHint,
|
||||||
|
ShowAutosaveAutoloadHint,
|
||||||
WindowTitleFormat,
|
WindowTitleFormat,
|
||||||
PauseDuringHomeMenu,
|
PauseDuringHomeMenu,
|
||||||
|
|
||||||
|
@ -202,7 +203,7 @@ enum class emu_settings_type
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A helper map that keeps track of where a given setting type is located*/
|
/** A helper map that keeps track of where a given setting type is located*/
|
||||||
inline static const QMap<emu_settings_type, cfg_location> settings_location =
|
inline static const std::map<emu_settings_type, cfg_location> settings_location =
|
||||||
{
|
{
|
||||||
// Core Tab
|
// Core Tab
|
||||||
{ emu_settings_type::PPUDecoder, { "Core", "PPU Decoder"}},
|
{ emu_settings_type::PPUDecoder, { "Core", "PPU Decoder"}},
|
||||||
|
@ -375,6 +376,7 @@ inline static const QMap<emu_settings_type, cfg_location> settings_location =
|
||||||
{ emu_settings_type::SilenceAllLogs, { "Miscellaneous", "Silence All Logs" }},
|
{ emu_settings_type::SilenceAllLogs, { "Miscellaneous", "Silence All Logs" }},
|
||||||
{ emu_settings_type::WindowTitleFormat, { "Miscellaneous", "Window Title Format" }},
|
{ emu_settings_type::WindowTitleFormat, { "Miscellaneous", "Window Title Format" }},
|
||||||
{ emu_settings_type::PauseDuringHomeMenu, { "Miscellaneous", "Pause Emulation During Home Menu" }},
|
{ emu_settings_type::PauseDuringHomeMenu, { "Miscellaneous", "Pause Emulation During Home Menu" }},
|
||||||
|
{ emu_settings_type::ShowAutosaveAutoloadHint, { "Miscellaneous", "Show autosave/autoload hint" }},
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
{ emu_settings_type::InternetStatus, { "Net", "Internet enabled"}},
|
{ emu_settings_type::InternetStatus, { "Net", "Internet enabled"}},
|
||||||
|
|
|
@ -186,7 +186,7 @@ bool game_compatibility::ReadJSON(const QJsonObject& json_data, bool after_downl
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add status to map
|
// Add status to map
|
||||||
m_compat_database.emplace(std::pair<std::string, compat::status>(key.toStdString(), status));
|
m_compat_database.emplace(key.toStdString(), std::move(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -34,8 +34,8 @@ public:
|
||||||
virtual void clear_list(){};
|
virtual void clear_list(){};
|
||||||
virtual void populate(
|
virtual void populate(
|
||||||
[[maybe_unused]] const std::vector<game_info>& game_data,
|
[[maybe_unused]] const std::vector<game_info>& game_data,
|
||||||
[[maybe_unused]] const QMap<QString, QString>& notes_map,
|
[[maybe_unused]] const std::map<QString, QString>& notes_map,
|
||||||
[[maybe_unused]] const QMap<QString, QString>& title_map,
|
[[maybe_unused]] const std::map<QString, QString>& title_map,
|
||||||
[[maybe_unused]] const std::string& selected_item_id,
|
[[maybe_unused]] const std::string& selected_item_id,
|
||||||
[[maybe_unused]] bool play_hover_movies){};
|
[[maybe_unused]] bool play_hover_movies){};
|
||||||
|
|
||||||
|
|
|
@ -672,8 +672,6 @@ void game_list_frame::OnParsingFinished()
|
||||||
m_games_mutex.lock();
|
m_games_mutex.lock();
|
||||||
|
|
||||||
// Read persistent_settings values
|
// Read persistent_settings values
|
||||||
const QString note = m_persistent_settings->GetValue(gui::persistent::notes, serial, "").toString();
|
|
||||||
const QString title = m_persistent_settings->GetValue(gui::persistent::titles, serial, "").toString().simplified();
|
|
||||||
const QString last_played = m_persistent_settings->GetValue(gui::persistent::last_played, serial, "").toString();
|
const QString last_played = m_persistent_settings->GetValue(gui::persistent::last_played, serial, "").toString();
|
||||||
const quint64 playtime = m_persistent_settings->GetValue(gui::persistent::playtime, serial, 0).toULongLong();
|
const quint64 playtime = m_persistent_settings->GetValue(gui::persistent::playtime, serial, 0).toULongLong();
|
||||||
|
|
||||||
|
@ -689,14 +687,14 @@ void game_list_frame::OnParsingFinished()
|
||||||
|
|
||||||
m_serials.insert(serial);
|
m_serials.insert(serial);
|
||||||
|
|
||||||
if (!note.isEmpty())
|
if (QString note = m_persistent_settings->GetValue(gui::persistent::notes, serial, "").toString(); !note.isEmpty())
|
||||||
{
|
{
|
||||||
m_notes.insert(serial, note);
|
m_notes.insert_or_assign(serial, std::move(note));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!title.isEmpty())
|
if (QString title = m_persistent_settings->GetValue(gui::persistent::titles, serial, "").toString().simplified(); !title.isEmpty())
|
||||||
{
|
{
|
||||||
m_titles.insert(serial, title);
|
m_titles.insert_or_assign(serial, std::move(title));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_games_mutex.unlock();
|
m_games_mutex.unlock();
|
||||||
|
@ -893,8 +891,10 @@ void game_list_frame::OnRefreshFinished()
|
||||||
// Sort by name at the very least.
|
// Sort by name at the very least.
|
||||||
std::sort(m_game_data.begin(), m_game_data.end(), [&](const game_info& game1, const game_info& game2)
|
std::sort(m_game_data.begin(), m_game_data.end(), [&](const game_info& game1, const game_info& game2)
|
||||||
{
|
{
|
||||||
const QString title1 = m_titles.value(qstr(game1->info.serial), qstr(game1->info.name));
|
const QString serial1 = QString::fromStdString(game1->info.serial);
|
||||||
const QString title2 = m_titles.value(qstr(game2->info.serial), qstr(game2->info.name));
|
const QString serial2 = QString::fromStdString(game2->info.serial);
|
||||||
|
const QString& title1 = m_titles.contains(serial1) ? m_titles.at(serial1) : QString::fromStdString(game1->info.name);
|
||||||
|
const QString& title2 = m_titles.contains(serial2) ? m_titles.at(serial2) : QString::fromStdString(game2->info.name);
|
||||||
return title1.toLower() < title2.toLower();
|
return title1.toLower() < title2.toLower();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1185,7 +1185,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
|
||||||
|
|
||||||
connect(boot_manual, &QAction::triggered, [this, gameinfo]
|
connect(boot_manual, &QAction::triggered, [this, gameinfo]
|
||||||
{
|
{
|
||||||
if (std::string file_path = QFileDialog::getOpenFileName(this, "Select Config File", "", tr("Config Files (*.yml);;All files (*.*)")).toStdString(); !file_path.empty())
|
if (const std::string file_path = QFileDialog::getOpenFileName(this, "Select Config File", "", tr("Config Files (*.yml);;All files (*.*)")).toStdString(); !file_path.empty())
|
||||||
{
|
{
|
||||||
sys_log.notice("Booting from gamelist per context menu...");
|
sys_log.notice("Booting from gamelist per context menu...");
|
||||||
Q_EMIT RequestBoot(gameinfo, cfg_mode::custom_selection, file_path);
|
Q_EMIT RequestBoot(gameinfo, cfg_mode::custom_selection, file_path);
|
||||||
|
@ -1912,12 +1912,12 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
|
||||||
|
|
||||||
if (new_title.isEmpty() || new_title == name)
|
if (new_title.isEmpty() || new_title == name)
|
||||||
{
|
{
|
||||||
m_titles.remove(serial);
|
m_titles.erase(serial);
|
||||||
m_persistent_settings->RemoveValue(gui::persistent::titles, serial);
|
m_persistent_settings->RemoveValue(gui::persistent::titles, serial);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_titles.insert(serial, new_title);
|
m_titles.insert_or_assign(serial, new_title);
|
||||||
m_persistent_settings->SetValue(gui::persistent::titles, serial, new_title);
|
m_persistent_settings->SetValue(gui::persistent::titles, serial, new_title);
|
||||||
}
|
}
|
||||||
Refresh(true); // full refresh in order to reliably sort the list
|
Refresh(true); // full refresh in order to reliably sort the list
|
||||||
|
@ -1933,12 +1933,12 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
if (new_notes.simplified().isEmpty())
|
if (new_notes.simplified().isEmpty())
|
||||||
{
|
{
|
||||||
m_notes.remove(serial);
|
m_notes.erase(serial);
|
||||||
m_persistent_settings->RemoveValue(gui::persistent::notes, serial);
|
m_persistent_settings->RemoveValue(gui::persistent::notes, serial);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_notes.insert(serial, new_notes);
|
m_notes.insert_or_assign(serial, new_notes);
|
||||||
m_persistent_settings->SetValue(gui::persistent::notes, serial, new_notes);
|
m_persistent_settings->SetValue(gui::persistent::notes, serial, new_notes);
|
||||||
}
|
}
|
||||||
Refresh();
|
Refresh();
|
||||||
|
@ -2831,7 +2831,16 @@ bool game_list_frame::SearchMatchesApp(const QString& name, const QString& seria
|
||||||
if (!m_search_text.isEmpty())
|
if (!m_search_text.isEmpty())
|
||||||
{
|
{
|
||||||
QString search_text = m_search_text.toLower();
|
QString search_text = m_search_text.toLower();
|
||||||
QString title_name = m_titles.value(serial, name).toLower();
|
QString title_name;
|
||||||
|
|
||||||
|
if (const auto it = m_titles.find(serial); it != m_titles.cend())
|
||||||
|
{
|
||||||
|
title_name = it->second.toLower();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
title_name = name.toLower();
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore trademarks when no search results have been yielded by unmodified search
|
// Ignore trademarks when no search results have been yielded by unmodified search
|
||||||
static const QRegularExpression s_ignored_on_fallback(reinterpret_cast<const char*>(u8"[:\\-®©™]+"));
|
static const QRegularExpression s_ignored_on_fallback(reinterpret_cast<const char*>(u8"[:\\-®©™]+"));
|
||||||
|
|
|
@ -166,8 +166,8 @@ private:
|
||||||
Qt::SortOrder m_col_sort_order{};
|
Qt::SortOrder m_col_sort_order{};
|
||||||
int m_sort_column{};
|
int m_sort_column{};
|
||||||
bool m_initial_refresh_done = false;
|
bool m_initial_refresh_done = false;
|
||||||
QMap<QString, QString> m_notes;
|
std::map<QString, QString> m_notes;
|
||||||
QMap<QString, QString> m_titles;
|
std::map<QString, QString> m_titles;
|
||||||
|
|
||||||
// Categories
|
// Categories
|
||||||
QStringList m_category_filters;
|
QStringList m_category_filters;
|
||||||
|
|
|
@ -42,8 +42,8 @@ void game_list_grid::clear_list()
|
||||||
|
|
||||||
void game_list_grid::populate(
|
void game_list_grid::populate(
|
||||||
const std::vector<game_info>& game_data,
|
const std::vector<game_info>& game_data,
|
||||||
const QMap<QString, QString>& notes_map,
|
const std::map<QString, QString>& notes_map,
|
||||||
const QMap<QString, QString>& title_map,
|
const std::map<QString, QString>& title_map,
|
||||||
const std::string& selected_item_id,
|
const std::string& selected_item_id,
|
||||||
bool play_hover_movies)
|
bool play_hover_movies)
|
||||||
{
|
{
|
||||||
|
@ -54,11 +54,20 @@ void game_list_grid::populate(
|
||||||
|
|
||||||
blockSignals(true);
|
blockSignals(true);
|
||||||
|
|
||||||
|
const auto get_title = [&title_map](const QString& serial, const std::string& name) -> QString
|
||||||
|
{
|
||||||
|
if (const auto it = title_map.find(serial); it != title_map.cend())
|
||||||
|
{
|
||||||
|
return it->second.simplified();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString::fromStdString(name).simplified();
|
||||||
|
};
|
||||||
|
|
||||||
for (const auto& game : game_data)
|
for (const auto& game : game_data)
|
||||||
{
|
{
|
||||||
const QString serial = QString::fromStdString(game->info.serial);
|
const QString serial = QString::fromStdString(game->info.serial);
|
||||||
const QString title = title_map.value(serial, QString::fromStdString(game->info.name)).simplified();
|
const QString title = get_title(serial, game->info.name);
|
||||||
const QString notes = notes_map.value(serial);
|
|
||||||
|
|
||||||
game_list_grid_item* item = new game_list_grid_item(this, game, title);
|
game_list_grid_item* item = new game_list_grid_item(this, game, title);
|
||||||
item->installEventFilter(this);
|
item->installEventFilter(this);
|
||||||
|
@ -66,13 +75,13 @@ void game_list_grid::populate(
|
||||||
|
|
||||||
game->item = item;
|
game->item = item;
|
||||||
|
|
||||||
if (notes.isEmpty())
|
if (const auto it = notes_map.find(serial); it != notes_map.cend() && !it->second.isEmpty())
|
||||||
{
|
{
|
||||||
item->setToolTip(tr("%0 [%1]").arg(title).arg(serial));
|
item->setToolTip(tr("%0 [%1]\n\nNotes:\n%2").arg(title).arg(serial).arg(it->second));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
item->setToolTip(tr("%0 [%1]\n\nNotes:\n%2").arg(title).arg(serial).arg(notes));
|
item->setToolTip(tr("%0 [%1]").arg(title).arg(serial));
|
||||||
}
|
}
|
||||||
|
|
||||||
item->set_icon_func([this, item, game](const QVideoFrame& frame)
|
item->set_icon_func([this, item, game](const QVideoFrame& frame)
|
||||||
|
|
|
@ -16,8 +16,8 @@ public:
|
||||||
|
|
||||||
void populate(
|
void populate(
|
||||||
const std::vector<game_info>& game_data,
|
const std::vector<game_info>& game_data,
|
||||||
const QMap<QString, QString>& notes_map,
|
const std::map<QString, QString>& notes_map,
|
||||||
const QMap<QString, QString>& title_map,
|
const std::map<QString, QString>& title_map,
|
||||||
const std::string& selected_item_id,
|
const std::string& selected_item_id,
|
||||||
bool play_hover_movies) override;
|
bool play_hover_movies) override;
|
||||||
|
|
||||||
|
|
|
@ -203,8 +203,8 @@ void game_list_table::set_custom_config_icon(const game_info& game)
|
||||||
|
|
||||||
void game_list_table::populate(
|
void game_list_table::populate(
|
||||||
const std::vector<game_info>& game_data,
|
const std::vector<game_info>& game_data,
|
||||||
const QMap<QString, QString>& notes_map,
|
const std::map<QString, QString>& notes_map,
|
||||||
const QMap<QString, QString>& title_map,
|
const std::map<QString, QString>& title_map,
|
||||||
const std::string& selected_item_id,
|
const std::string& selected_item_id,
|
||||||
bool play_hover_movies)
|
bool play_hover_movies)
|
||||||
{
|
{
|
||||||
|
@ -223,13 +223,22 @@ void game_list_table::populate(
|
||||||
int index = -1;
|
int index = -1;
|
||||||
int selected_row = -1;
|
int selected_row = -1;
|
||||||
|
|
||||||
|
const auto get_title = [&title_map](const QString& serial, const std::string& name) -> QString
|
||||||
|
{
|
||||||
|
if (const auto it = title_map.find(serial); it != title_map.cend())
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString::fromStdString(name);
|
||||||
|
};
|
||||||
|
|
||||||
for (const auto& game : game_data)
|
for (const auto& game : game_data)
|
||||||
{
|
{
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
const QString serial = QString::fromStdString(game->info.serial);
|
const QString serial = QString::fromStdString(game->info.serial);
|
||||||
const QString title = title_map.value(serial, QString::fromStdString(game->info.name));
|
const QString title = get_title(serial, game->info.name);
|
||||||
const QString notes = notes_map.value(serial);
|
|
||||||
|
|
||||||
// Icon
|
// Icon
|
||||||
custom_table_widget_item* icon_item = new custom_table_widget_item;
|
custom_table_widget_item* icon_item = new custom_table_widget_item;
|
||||||
|
@ -302,9 +311,9 @@ void game_list_table::populate(
|
||||||
// Serial
|
// Serial
|
||||||
custom_table_widget_item* serial_item = new custom_table_widget_item(game->info.serial);
|
custom_table_widget_item* serial_item = new custom_table_widget_item(game->info.serial);
|
||||||
|
|
||||||
if (!notes.isEmpty())
|
if (const auto it = notes_map.find(serial); it != notes_map.cend() && !it->second.isEmpty())
|
||||||
{
|
{
|
||||||
const QString tool_tip = tr("%0 [%1]\n\nNotes:\n%2").arg(title).arg(serial).arg(notes);
|
const QString tool_tip = tr("%0 [%1]\n\nNotes:\n%2").arg(title).arg(serial).arg(it->second);
|
||||||
title_item->setToolTip(tool_tip);
|
title_item->setToolTip(tool_tip);
|
||||||
serial_item->setToolTip(tool_tip);
|
serial_item->setToolTip(tool_tip);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ public:
|
||||||
|
|
||||||
void populate(
|
void populate(
|
||||||
const std::vector<game_info>& game_data,
|
const std::vector<game_info>& game_data,
|
||||||
const QMap<QString, QString>& notes_map,
|
const std::map<QString, QString>& notes_map,
|
||||||
const QMap<QString, QString>& title_map,
|
const std::map<QString, QString>& title_map,
|
||||||
const std::string& selected_item_id,
|
const std::string& selected_item_id,
|
||||||
bool play_hover_movies) override;
|
bool play_hover_movies) override;
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,8 @@ private:
|
||||||
case localized_string_id::CELL_SAVEDATA_DELETE: return tr("Delete this data?\n\n%0", "Savedata entry info").arg(std::forward<Args>(args)...);
|
case localized_string_id::CELL_SAVEDATA_DELETE: return tr("Delete this data?\n\n%0", "Savedata entry info").arg(std::forward<Args>(args)...);
|
||||||
case localized_string_id::CELL_SAVEDATA_LOAD: return tr("Load this data?\n\n%0", "Savedata entry info").arg(std::forward<Args>(args)...);
|
case localized_string_id::CELL_SAVEDATA_LOAD: return tr("Load this data?\n\n%0", "Savedata entry info").arg(std::forward<Args>(args)...);
|
||||||
case localized_string_id::CELL_SAVEDATA_OVERWRITE: return tr("Do you want to overwrite the saved data?\n\n%0", "Savedata entry info").arg(std::forward<Args>(args)...);
|
case localized_string_id::CELL_SAVEDATA_OVERWRITE: return tr("Do you want to overwrite the saved data?\n\n%0", "Savedata entry info").arg(std::forward<Args>(args)...);
|
||||||
|
case localized_string_id::CELL_SAVEDATA_AUTOSAVE: return tr("Saving");
|
||||||
|
case localized_string_id::CELL_SAVEDATA_AUTOLOAD: return tr("Loading");
|
||||||
case localized_string_id::CELL_CROSS_CONTROLLER_MSG: return tr("Start [%0] on the PS Vita system.\nIf you have not installed [%0], go to [Remote Play] on the PS Vita system and start [Cross-Controller] from the LiveArea™ screen.", "Cross-Controller message").arg(std::forward<Args>(args)...);
|
case localized_string_id::CELL_CROSS_CONTROLLER_MSG: return tr("Start [%0] on the PS Vita system.\nIf you have not installed [%0], go to [Remote Play] on the PS Vita system and start [Cross-Controller] from the LiveArea™ screen.", "Cross-Controller message").arg(std::forward<Args>(args)...);
|
||||||
case localized_string_id::CELL_CROSS_CONTROLLER_FW_MSG: return tr("If your system software version on the PS Vita system is earlier than 1.80, you must update the system software to the latest version.", "Cross-Controller firmware message");
|
case localized_string_id::CELL_CROSS_CONTROLLER_FW_MSG: return tr("If your system software version on the PS Vita system is earlier than 1.80, you must update the system software to the latest version.", "Cross-Controller firmware message");
|
||||||
case localized_string_id::CELL_NP_RECVMESSAGE_DIALOG_TITLE: return tr("Select Message", "RECVMESSAGE_DIALOG");
|
case localized_string_id::CELL_NP_RECVMESSAGE_DIALOG_TITLE: return tr("Select Message", "RECVMESSAGE_DIALOG");
|
||||||
|
|
|
@ -1175,7 +1175,7 @@ bool main_window::HandlePackageInstallation(QStringList file_paths, bool from_bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowOptionalGamePreparations(tr("Success!"), tr("Successfully installed software from package(s)!"), paths);
|
ShowOptionalGamePreparations(tr("Success!"), tr("Successfully installed software from package(s)!"), std::move(paths));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1554,7 +1554,7 @@ void main_window::HandlePupInstallation(const QString& file_path, const QString&
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::string installed = utils::get_firmware_version(); !installed.empty())
|
if (const std::string installed = utils::get_firmware_version(); !installed.empty())
|
||||||
{
|
{
|
||||||
gui_log.warning("Reinstalling firmware: old=%s, new=%s", installed, version_string);
|
gui_log.warning("Reinstalling firmware: old=%s, new=%s", installed, version_string);
|
||||||
|
|
||||||
|
@ -3793,7 +3793,7 @@ void main_window::AddGamesFromDirs(QStringList&& paths)
|
||||||
{
|
{
|
||||||
if (Emu.IsPathInsideDir(game->info.path, sstr(dir_path)))
|
if (Emu.IsPathInsideDir(game->info.path, sstr(dir_path)))
|
||||||
{
|
{
|
||||||
// Try to claim operaion on directory path
|
// Try to claim operation on directory path
|
||||||
|
|
||||||
std::string resolved_path = Emu.GetCallbacks().resolve_path(game->info.path);
|
std::string resolved_path = Emu.GetCallbacks().resolve_path(game->info.path);
|
||||||
|
|
||||||
|
@ -3815,7 +3815,7 @@ void main_window::AddGamesFromDirs(QStringList&& paths)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ShowOptionalGamePreparations(tr("Success!"), tr("Successfully added software to game list from path(s)!"), paths_added);
|
ShowOptionalGamePreparations(tr("Success!"), tr("Successfully added software to game list from path(s)!"), std::move(paths_added));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,6 @@ public Q_SLOTS:
|
||||||
void SetLastPlayed(const QString& serial, const QString& date, bool sync);
|
void SetLastPlayed(const QString& serial, const QString& date, bool sync);
|
||||||
QString GetLastPlayed(const QString& serial);
|
QString GetLastPlayed(const QString& serial);
|
||||||
private:
|
private:
|
||||||
QMap<QString, quint64> m_playtime;
|
std::map<QString, quint64> m_playtime;
|
||||||
QMap<QString, QString> m_last_played;
|
std::map<QString, QString> m_last_played;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1850,6 +1850,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
|
||||||
m_emu_settings->EnhanceCheckBox(ui->showMouseAndKeyboardToggleHint, emu_settings_type::ShowMouseAndKeyboardToggleHint);
|
m_emu_settings->EnhanceCheckBox(ui->showMouseAndKeyboardToggleHint, emu_settings_type::ShowMouseAndKeyboardToggleHint);
|
||||||
SubscribeTooltip(ui->showMouseAndKeyboardToggleHint, tooltips.settings.show_mouse_and_keyboard_toggle_hint);
|
SubscribeTooltip(ui->showMouseAndKeyboardToggleHint, tooltips.settings.show_mouse_and_keyboard_toggle_hint);
|
||||||
|
|
||||||
|
m_emu_settings->EnhanceCheckBox(ui->showAutosaveAutoloadHint, emu_settings_type::ShowAutosaveAutoloadHint);
|
||||||
|
SubscribeTooltip(ui->showAutosaveAutoloadHint, tooltips.settings.show_autosave_autoload_hint);
|
||||||
|
|
||||||
m_emu_settings->EnhanceCheckBox(ui->pauseDuringHomeMenu, emu_settings_type::PauseDuringHomeMenu);
|
m_emu_settings->EnhanceCheckBox(ui->pauseDuringHomeMenu, emu_settings_type::PauseDuringHomeMenu);
|
||||||
SubscribeTooltip(ui->pauseDuringHomeMenu, tooltips.settings.pause_during_home_menu);
|
SubscribeTooltip(ui->pauseDuringHomeMenu, tooltips.settings.pause_during_home_menu);
|
||||||
|
|
||||||
|
|
|
@ -3007,6 +3007,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="showAutosaveAutoloadHint">
|
||||||
|
<property name="text">
|
||||||
|
<string>Show autosave/autoload hint</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="startGameFullscreen">
|
<widget class="QCheckBox" name="startGameFullscreen">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
|
@ -145,6 +145,7 @@ public:
|
||||||
const QString show_pressure_intensity_toggle_hint = tr("Shows pressure intensity toggle hint using the native overlay.");
|
const QString show_pressure_intensity_toggle_hint = tr("Shows pressure intensity toggle hint using the native overlay.");
|
||||||
const QString show_analog_limiter_toggle_hint = tr("Shows analog limiter toggle hint using the native overlay.");
|
const QString show_analog_limiter_toggle_hint = tr("Shows analog limiter toggle hint using the native overlay.");
|
||||||
const QString show_mouse_and_keyboard_toggle_hint = tr("Shows mouse and keyboard toggle hint using the native overlay.");
|
const QString show_mouse_and_keyboard_toggle_hint = tr("Shows mouse and keyboard toggle hint using the native overlay.");
|
||||||
|
const QString show_autosave_autoload_hint = tr("Shows autosave/autoload hint using the native overlay.");
|
||||||
const QString use_native_interface = tr("Enables use of native HUD within the game window that can interact with game controllers.\nWhen disabled, regular Qt dialogs are used instead.\nCurrently, the on-screen keyboard only supports the English key layout.");
|
const QString use_native_interface = tr("Enables use of native HUD within the game window that can interact with game controllers.\nWhen disabled, regular Qt dialogs are used instead.\nCurrently, the on-screen keyboard only supports the English key layout.");
|
||||||
const QString pause_during_home_menu = tr("When enabled, opening the home menu will also pause emulation.\nWhile most games pause themselves while the home menu is shown, some do not.\nIn that case it can be helpful to pause the emulation whenever the home menu is open.");
|
const QString pause_during_home_menu = tr("When enabled, opening the home menu will also pause emulation.\nWhile most games pause themselves while the home menu is shown, some do not.\nIn that case it can be helpful to pause the emulation whenever the home menu is open.");
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue