1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-21 10:12:32 +01:00

Qt: Replace QMap with std::map

This should reduce the amount of string conversions during list refreshes
This commit is contained in:
Megamouse 2024-11-05 22:34:38 +01:00
parent c68f42e0ee
commit 2262ac1684
32 changed files with 108 additions and 84 deletions

View File

@ -2634,7 +2634,7 @@ bool fs::pending_file::commit(bool overwrite)
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))
{

View File

@ -837,5 +837,5 @@ namespace fs
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);
}

View File

@ -2731,7 +2731,7 @@ void thread_base::exec()
[[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);
}

View File

@ -11,7 +11,7 @@
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())
{
@ -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());
}
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)
u64 lo = 0;

View File

@ -12,7 +12,7 @@ public:
{
}
usz decrypt(std::string klic_input = {});
usz decrypt(std::string_view klic_input = {});
bool done() const
{

View File

@ -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();
@ -903,7 +903,7 @@ bool create_path(std::string& out, std::string dir_name, std::string file_name)
return false;
}
out = dir_name;
out = std::move(dir_name);
if (!out.empty() && out.back() != '/')
{

View File

@ -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)
{
@ -492,7 +492,7 @@ bool gdb_thread::set_reg(ppu_thread* thread, u32 rid, std::string value)
if (rid > 70) return false;
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);
}
else

View File

@ -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
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
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
static u32 get_reg_size(ppu_thread* thread, u32 rid);
//send reason of stop, returns false if sending response failed

View File

@ -233,7 +233,7 @@ struct emulated_pads_config : cfg::node
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);
}

View File

@ -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);
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);
}

View File

@ -2614,7 +2614,7 @@ namespace rpcn
NotificationType ntype = static_cast<NotificationType>(command);
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)
{

View File

@ -17,7 +17,7 @@ namespace rsx
}
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_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);
}
}
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(localized_string_id 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(const localized_string_id& msg_id, u64, std::shared_ptr<atomic_t<u32>>, std::shared_ptr<overlay_element>);
void message_item::reset_expiration()
{

View File

@ -21,7 +21,7 @@ namespace rsx
{
public:
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 x_offset, s16 y_offset);
void set_pos(s16 _x, s16 _y) override;

View File

@ -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);
#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);
}

View File

@ -70,7 +70,7 @@ bool raw_mice_config::load()
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);
}

View File

@ -123,7 +123,7 @@ std::unique_ptr<utils::serial> tar_object::get_file(const std::string& path, std
filename += name;
// 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)
{
@ -132,10 +132,8 @@ std::unique_ptr<utils::serial> tar_object::get_file(const std::string& path, std
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
{
@ -200,7 +198,7 @@ std::unique_ptr<utils::serial> tar_object::get_file(const std::string& path, std
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::span<u8> filedata_span{filedata_buffer.data(), filedata_buffer.size()};

View File

@ -55,7 +55,7 @@ public:
// 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)
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);
};

View File

@ -10,7 +10,7 @@ LOG_CHANNEL(disc_log, "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;

View File

@ -11,5 +11,5 @@ namespace disc
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);
}

View File

@ -65,13 +65,12 @@ namespace cfg_adapter
bool get_is_dynamic(emu_settings_type type)
{
const cfg_location loc = settings_location[type];
return get_is_dynamic(loc);
return get_is_dynamic(::at32(settings_location, type));
}
std::string get_setting_name(emu_settings_type type)
{
const cfg_location loc = settings_location[type];
return loc[loc.size() - 1];
const cfg_location& loc = ::at32(settings_location, type);
return ::at32(loc, loc.size() - 1);
}
}

View File

@ -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))
{
custom_config_path = config_path;
custom_config_path = std::move(config_path);
}
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)
{
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
{
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();
}
@ -853,7 +853,7 @@ std::string emu_settings::GetSettingDefault(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();
}
@ -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
{
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)
@ -1355,9 +1355,9 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_
if (strict)
{
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 += ": ";
type_string += loc;

View File

@ -1,6 +1,6 @@
#pragma once
#include <QMap>
#include <map>
#include <vector>
// Node location
@ -203,7 +203,7 @@ enum class emu_settings_type
};
/** 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
{ emu_settings_type::PPUDecoder, { "Core", "PPU Decoder"}},

View File

@ -186,7 +186,7 @@ bool game_compatibility::ReadJSON(const QJsonObject& json_data, bool after_downl
}
// 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;

View File

@ -34,8 +34,8 @@ public:
virtual void clear_list(){};
virtual void populate(
[[maybe_unused]] const std::vector<game_info>& game_data,
[[maybe_unused]] const QMap<QString, QString>& notes_map,
[[maybe_unused]] const QMap<QString, QString>& title_map,
[[maybe_unused]] const std::map<QString, QString>& notes_map,
[[maybe_unused]] const std::map<QString, QString>& title_map,
[[maybe_unused]] const std::string& selected_item_id,
[[maybe_unused]] bool play_hover_movies){};

View File

@ -672,8 +672,6 @@ void game_list_frame::OnParsingFinished()
m_games_mutex.lock();
// 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 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);
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();
@ -893,8 +891,10 @@ void game_list_frame::OnRefreshFinished()
// 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)
{
const QString title1 = m_titles.value(qstr(game1->info.serial), qstr(game1->info.name));
const QString title2 = m_titles.value(qstr(game2->info.serial), qstr(game2->info.name));
const QString serial1 = QString::fromStdString(game1->info.serial);
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();
});
@ -1185,7 +1185,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
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...");
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)
{
m_titles.remove(serial);
m_titles.erase(serial);
m_persistent_settings->RemoveValue(gui::persistent::titles, serial);
}
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);
}
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())
{
m_notes.remove(serial);
m_notes.erase(serial);
m_persistent_settings->RemoveValue(gui::persistent::notes, serial);
}
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);
}
Refresh();
@ -2831,7 +2831,16 @@ bool game_list_frame::SearchMatchesApp(const QString& name, const QString& seria
if (!m_search_text.isEmpty())
{
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
static const QRegularExpression s_ignored_on_fallback(reinterpret_cast<const char*>(u8"[:\\-®©™]+"));

View File

@ -166,8 +166,8 @@ private:
Qt::SortOrder m_col_sort_order{};
int m_sort_column{};
bool m_initial_refresh_done = false;
QMap<QString, QString> m_notes;
QMap<QString, QString> m_titles;
std::map<QString, QString> m_notes;
std::map<QString, QString> m_titles;
// Categories
QStringList m_category_filters;

View File

@ -42,8 +42,8 @@ void game_list_grid::clear_list()
void game_list_grid::populate(
const std::vector<game_info>& game_data,
const QMap<QString, QString>& notes_map,
const QMap<QString, QString>& title_map,
const std::map<QString, QString>& notes_map,
const std::map<QString, QString>& title_map,
const std::string& selected_item_id,
bool play_hover_movies)
{
@ -54,11 +54,20 @@ void game_list_grid::populate(
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)
{
const QString serial = QString::fromStdString(game->info.serial);
const QString title = title_map.value(serial, QString::fromStdString(game->info.name)).simplified();
const QString notes = notes_map.value(serial);
const QString title = get_title(serial, game->info.name);
game_list_grid_item* item = new game_list_grid_item(this, game, title);
item->installEventFilter(this);
@ -66,13 +75,13 @@ void game_list_grid::populate(
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
{
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)

View File

@ -16,8 +16,8 @@ public:
void populate(
const std::vector<game_info>& game_data,
const QMap<QString, QString>& notes_map,
const QMap<QString, QString>& title_map,
const std::map<QString, QString>& notes_map,
const std::map<QString, QString>& title_map,
const std::string& selected_item_id,
bool play_hover_movies) override;

View File

@ -203,8 +203,8 @@ void game_list_table::set_custom_config_icon(const game_info& game)
void game_list_table::populate(
const std::vector<game_info>& game_data,
const QMap<QString, QString>& notes_map,
const QMap<QString, QString>& title_map,
const std::map<QString, QString>& notes_map,
const std::map<QString, QString>& title_map,
const std::string& selected_item_id,
bool play_hover_movies)
{
@ -223,13 +223,22 @@ void game_list_table::populate(
int index = -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)
{
index++;
const QString serial = QString::fromStdString(game->info.serial);
const QString title = title_map.value(serial, QString::fromStdString(game->info.name));
const QString notes = notes_map.value(serial);
const QString title = get_title(serial, game->info.name);
// Icon
custom_table_widget_item* icon_item = new custom_table_widget_item;
@ -302,9 +311,9 @@ void game_list_table::populate(
// 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);
serial_item->setToolTip(tool_tip);
}

View File

@ -26,8 +26,8 @@ public:
void populate(
const std::vector<game_info>& game_data,
const QMap<QString, QString>& notes_map,
const QMap<QString, QString>& title_map,
const std::map<QString, QString>& notes_map,
const std::map<QString, QString>& title_map,
const std::string& selected_item_id,
bool play_hover_movies) override;

View File

@ -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;
}
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);
@ -3793,7 +3793,7 @@ void main_window::AddGamesFromDirs(QStringList&& paths)
{
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);
@ -3815,7 +3815,7 @@ void main_window::AddGamesFromDirs(QStringList&& paths)
}
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));
}
});

View File

@ -45,6 +45,6 @@ public Q_SLOTS:
void SetLastPlayed(const QString& serial, const QString& date, bool sync);
QString GetLastPlayed(const QString& serial);
private:
QMap<QString, quint64> m_playtime;
QMap<QString, QString> m_last_played;
std::map<QString, quint64> m_playtime;
std::map<QString, QString> m_last_played;
};