GfxPack: Refactor + better unicode support

This commit is contained in:
Exzap 2023-11-22 17:57:20 +01:00
parent 67f7ce815c
commit bffeb818d1
6 changed files with 64 additions and 81 deletions

View File

@ -209,7 +209,7 @@ bool GameProfile::Load(uint64_t title_id)
m_gameName = std::string(game_name.begin(), game_name.end()); m_gameName = std::string(game_name.begin(), game_name.end());
trim(m_gameName.value()); trim(m_gameName.value());
} }
IniParser iniParser(*profileContents, gameProfilePath.string()); IniParser iniParser(*profileContents, _pathToUtf8(gameProfilePath));
// parse ini // parse ini
while (iniParser.NextSection()) while (iniParser.NextSection())
{ {

View File

@ -28,7 +28,7 @@ void GraphicPack2::LoadGraphicPack(fs::path graphicPackPath)
return; return;
std::vector<uint8> rulesData; std::vector<uint8> rulesData;
fs_rules->extract(rulesData); fs_rules->extract(rulesData);
IniParser iniParser(rulesData, rulesPath.string()); IniParser iniParser(rulesData, _pathToUtf8(rulesPath));
if (!iniParser.NextSection()) if (!iniParser.NextSection())
{ {
@ -51,10 +51,9 @@ void GraphicPack2::LoadGraphicPack(fs::path graphicPackPath)
cemuLog_log(LogType::Force, "{}: Unable to parse version", _pathToUtf8(rulesPath)); cemuLog_log(LogType::Force, "{}: Unable to parse version", _pathToUtf8(rulesPath));
return; return;
} }
if (versionNum > GP_LEGACY_VERSION) if (versionNum > GP_LEGACY_VERSION)
{ {
GraphicPack2::LoadGraphicPack(_pathToUtf8(rulesPath), iniParser); GraphicPack2::LoadGraphicPack(rulesPath, iniParser);
return; return;
} }
} }
@ -79,22 +78,22 @@ void GraphicPack2::LoadAll()
} }
} }
bool GraphicPack2::LoadGraphicPack(const std::string& filename, IniParser& rules) bool GraphicPack2::LoadGraphicPack(const fs::path& rulesPath, IniParser& rules)
{ {
try try
{ {
auto gp = std::make_shared<GraphicPack2>(filename, rules); auto gp = std::make_shared<GraphicPack2>(rulesPath, rules);
// check if enabled and preset set // check if enabled and preset set
const auto& config_entries = g_config.data().graphic_pack_entries; const auto& config_entries = g_config.data().graphic_pack_entries;
// legacy absolute path checking for not breaking compatibility // legacy absolute path checking for not breaking compatibility
auto file = gp->GetFilename2(); auto file = gp->GetRulesPath();
auto it = config_entries.find(file.lexically_normal()); auto it = config_entries.find(file.lexically_normal());
if (it == config_entries.cend()) if (it == config_entries.cend())
{ {
// check for relative path // check for relative path
it = config_entries.find(MakeRelativePath(ActiveSettings::GetUserDataPath(), gp->GetFilename2()).lexically_normal()); it = config_entries.find(_utf8ToPath(gp->GetNormalizedPathString()));
} }
if (it != config_entries.cend()) if (it != config_entries.cend())
@ -145,7 +144,7 @@ bool GraphicPack2::DeactivateGraphicPack(const std::shared_ptr<GraphicPack2>& gr
const auto it = std::find_if(s_active_graphic_packs.begin(), s_active_graphic_packs.end(), const auto it = std::find_if(s_active_graphic_packs.begin(), s_active_graphic_packs.end(),
[graphic_pack](const GraphicPackPtr& gp) [graphic_pack](const GraphicPackPtr& gp)
{ {
return gp->GetFilename() == graphic_pack->GetFilename(); return gp->GetNormalizedPathString() == graphic_pack->GetNormalizedPathString();
} }
); );
@ -173,12 +172,12 @@ void GraphicPack2::ActivateForCurrentTitle()
{ {
if (gp->GetPresets().empty()) if (gp->GetPresets().empty())
{ {
cemuLog_log(LogType::Force, "Activate graphic pack: {}", gp->GetPath()); cemuLog_log(LogType::Force, "Activate graphic pack: {}", gp->GetVirtualPath());
} }
else else
{ {
std::string logLine; std::string logLine;
logLine.assign(fmt::format("Activate graphic pack: {} [Presets: ", gp->GetPath())); logLine.assign(fmt::format("Activate graphic pack: {} [Presets: ", gp->GetVirtualPath()));
bool isFirst = true; bool isFirst = true;
for (auto& itr : gp->GetPresets()) for (auto& itr : gp->GetPresets())
{ {
@ -249,8 +248,8 @@ std::unordered_map<std::string, GraphicPack2::PresetVar> GraphicPack2::ParsePres
return vars; return vars;
} }
GraphicPack2::GraphicPack2(std::string filename, IniParser& rules) GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
: m_filename(std::move(filename)) : m_rulesPath(std::move(rulesPath))
{ {
// we're already in [Definition] // we're already in [Definition]
auto option_version = rules.FindOption("version"); auto option_version = rules.FindOption("version");
@ -259,7 +258,7 @@ GraphicPack2::GraphicPack2(std::string filename, IniParser& rules)
m_version = StringHelpers::ToInt(*option_version, -1); m_version = StringHelpers::ToInt(*option_version, -1);
if (m_version < 0) if (m_version < 0)
{ {
cemuLog_log(LogType::Force, "{}: Invalid version", m_filename); cemuLog_log(LogType::Force, "{}: Invalid version", _pathToUtf8(m_rulesPath));
throw std::exception(); throw std::exception();
} }
@ -305,7 +304,7 @@ GraphicPack2::GraphicPack2(std::string filename, IniParser& rules)
cemuLog_log(LogType::Force, "[Definition] section from '{}' graphic pack must contain option: path", gp_name_log.has_value() ? *gp_name_log : "Unknown"); cemuLog_log(LogType::Force, "[Definition] section from '{}' graphic pack must contain option: path", gp_name_log.has_value() ? *gp_name_log : "Unknown");
throw std::exception(); throw std::exception();
} }
m_path = *option_path; m_virtualPath = *option_path;
auto option_gp_name = rules.FindOption("name"); auto option_gp_name = rules.FindOption("name");
if (option_gp_name) if (option_gp_name)
@ -508,6 +507,11 @@ bool GraphicPack2::Reload()
return Activate(); return Activate();
} }
std::string GraphicPack2::GetNormalizedPathString() const
{
return _pathToUtf8(MakeRelativePath(ActiveSettings::GetUserDataPath(), GetRulesPath()).lexically_normal());
}
bool GraphicPack2::ContainsTitleId(uint64_t title_id) const bool GraphicPack2::ContainsTitleId(uint64_t title_id) const
{ {
const auto it = std::find_if(m_title_ids.begin(), m_title_ids.end(), [title_id](uint64 id) { return id == title_id; }); const auto it = std::find_if(m_title_ids.begin(), m_title_ids.end(), [title_id](uint64 id) { return id == title_id; });
@ -650,7 +654,7 @@ bool GraphicPack2::SetActivePreset(std::string_view category, std::string_view n
void GraphicPack2::LoadShaders() void GraphicPack2::LoadShaders()
{ {
fs::path path(m_filename); fs::path path = GetRulesPath();
for (auto& it : fs::directory_iterator(path.remove_filename())) for (auto& it : fs::directory_iterator(path.remove_filename()))
{ {
if (!is_regular_file(it)) if (!is_regular_file(it))
@ -676,7 +680,7 @@ void GraphicPack2::LoadShaders()
{ {
std::ifstream file(p); std::ifstream file(p);
if (!file.is_open()) if (!file.is_open())
throw std::runtime_error(fmt::format("can't open graphic pack file: {}", p.filename().string()).c_str()); throw std::runtime_error(fmt::format("can't open graphic pack file: {}", _pathToUtf8(p.filename())));
file.seekg(0, std::ios::end); file.seekg(0, std::ios::end);
m_output_shader_source.reserve(file.tellg()); m_output_shader_source.reserve(file.tellg());
@ -689,7 +693,7 @@ void GraphicPack2::LoadShaders()
{ {
std::ifstream file(p); std::ifstream file(p);
if (!file.is_open()) if (!file.is_open())
throw std::runtime_error(fmt::format("can't open graphic pack file: {}", p.filename().string()).c_str()); throw std::runtime_error(fmt::format("can't open graphic pack file: {}", _pathToUtf8(p.filename())));
file.seekg(0, std::ios::end); file.seekg(0, std::ios::end);
m_upscaling_shader_source.reserve(file.tellg()); m_upscaling_shader_source.reserve(file.tellg());
@ -702,7 +706,7 @@ void GraphicPack2::LoadShaders()
{ {
std::ifstream file(p); std::ifstream file(p);
if (!file.is_open()) if (!file.is_open())
throw std::runtime_error(fmt::format("can't open graphic pack file: {}", p.filename().string()).c_str()); throw std::runtime_error(fmt::format("can't open graphic pack file: {}", _pathToUtf8(p.filename())));
file.seekg(0, std::ios::end); file.seekg(0, std::ios::end);
m_downscaling_shader_source.reserve(file.tellg()); m_downscaling_shader_source.reserve(file.tellg());
@ -805,7 +809,7 @@ void GraphicPack2::AddConstantsForCurrentPreset(ExpressionParser& ep)
} }
} }
void GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, std::wstring& internalPath, bool isAOC) void GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, bool isAOC)
{ {
uint64 currentTitleId = CafeSystem::GetForegroundTitleId(); uint64 currentTitleId = CafeSystem::GetForegroundTitleId();
uint64 aocTitleId = (currentTitleId & 0xFFFFFFFFull) | 0x0005000c00000000ull; uint64 aocTitleId = (currentTitleId & 0xFFFFFFFFull) | 0x0005000c00000000ull;
@ -833,7 +837,7 @@ void GraphicPack2::LoadReplacedFiles()
return; return;
m_patchedFilesLoaded = true; m_patchedFilesLoaded = true;
fs::path gfxPackPath = _utf8ToPath(m_filename); fs::path gfxPackPath = GetRulesPath();
gfxPackPath = gfxPackPath.remove_filename(); gfxPackPath = gfxPackPath.remove_filename();
// /content/ // /content/
@ -843,10 +847,9 @@ void GraphicPack2::LoadReplacedFiles()
std::error_code ec; std::error_code ec;
if (fs::exists(contentPath, ec)) if (fs::exists(contentPath, ec))
{ {
std::wstring internalPath(L"/vol/content/");
// setup redirections // setup redirections
fscDeviceRedirect_map(); fscDeviceRedirect_map();
_iterateReplacedFiles(contentPath, internalPath, false); _iterateReplacedFiles(contentPath, false);
} }
// /aoc/ // /aoc/
fs::path aocPath(gfxPackPath); fs::path aocPath(gfxPackPath);
@ -857,13 +860,9 @@ void GraphicPack2::LoadReplacedFiles()
uint64 aocTitleId = CafeSystem::GetForegroundTitleId(); uint64 aocTitleId = CafeSystem::GetForegroundTitleId();
aocTitleId = aocTitleId & 0xFFFFFFFFULL; aocTitleId = aocTitleId & 0xFFFFFFFFULL;
aocTitleId |= 0x0005000c00000000ULL; aocTitleId |= 0x0005000c00000000ULL;
wchar_t internalAocPath[128];
swprintf(internalAocPath, sizeof(internalAocPath)/sizeof(wchar_t), L"/aoc/%016llx/", aocTitleId);
std::wstring internalPath(internalAocPath);
// setup redirections // setup redirections
fscDeviceRedirect_map(); fscDeviceRedirect_map();
_iterateReplacedFiles(aocPath, internalPath, true); _iterateReplacedFiles(aocPath, true);
} }
} }
@ -886,14 +885,14 @@ bool GraphicPack2::Activate()
return false; return false;
} }
FileStream* fs_rules = FileStream::openFile2(_utf8ToPath(m_filename)); FileStream* fs_rules = FileStream::openFile2(m_rulesPath);
if (!fs_rules) if (!fs_rules)
return false; return false;
std::vector<uint8> rulesData; std::vector<uint8> rulesData;
fs_rules->extract(rulesData); fs_rules->extract(rulesData);
delete fs_rules; delete fs_rules;
IniParser rules({ (char*)rulesData.data(), rulesData.size()}, m_filename); IniParser rules({ (char*)rulesData.data(), rulesData.size()}, GetNormalizedPathString());
// load rules // load rules
try try
@ -947,7 +946,7 @@ bool GraphicPack2::Activate()
else if (anisotropyValue == 16) else if (anisotropyValue == 16)
rule.overwrite_settings.anistropic_value = 4; rule.overwrite_settings.anistropic_value = 4;
else else
cemuLog_log(LogType::Force, "Invalid value {} for overwriteAnisotropy in graphic pack {}. Only the values 1, 2, 4, 8 or 16 are allowed.", anisotropyValue, m_filename); cemuLog_log(LogType::Force, "Invalid value {} for overwriteAnisotropy in graphic pack {}. Only the values 1, 2, 4, 8 or 16 are allowed.", anisotropyValue, GetNormalizedPathString());
} }
m_texture_rules.emplace_back(rule); m_texture_rules.emplace_back(rule);
} }
@ -992,11 +991,11 @@ bool GraphicPack2::Activate()
if (LatteTiming_getCustomVsyncFrequency(globalCustomVsyncFreq)) if (LatteTiming_getCustomVsyncFrequency(globalCustomVsyncFreq))
{ {
if (customVsyncFreq != globalCustomVsyncFreq) if (customVsyncFreq != globalCustomVsyncFreq)
cemuLog_log(LogType::Force, "rules.txt error: Mismatching vsync frequency {} in graphic pack \'{}\'", customVsyncFreq, GetPath()); cemuLog_log(LogType::Force, "rules.txt error: Mismatching vsync frequency {} in graphic pack \'{}\'", customVsyncFreq, GetVirtualPath());
} }
else else
{ {
cemuLog_log(LogType::Force, "Set vsync frequency to {} (graphic pack {})", customVsyncFreq, GetPath()); cemuLog_log(LogType::Force, "Set vsync frequency to {} (graphic pack {})", customVsyncFreq, GetVirtualPath());
LatteTiming_setCustomVsyncFrequency(customVsyncFreq); LatteTiming_setCustomVsyncFrequency(customVsyncFreq);
} }
} }

View File

@ -97,20 +97,20 @@ public:
}; };
using PresetPtr = std::shared_ptr<Preset>; using PresetPtr = std::shared_ptr<Preset>;
GraphicPack2(std::string filename, IniParser& rules); GraphicPack2(fs::path rulesPath, IniParser& rules);
bool IsEnabled() const { return m_enabled; } bool IsEnabled() const { return m_enabled; }
bool IsActivated() const { return m_activated; } bool IsActivated() const { return m_activated; }
sint32 GetVersion() const { return m_version; } sint32 GetVersion() const { return m_version; }
const std::string& GetFilename() const { return m_filename; } const fs::path GetRulesPath() const { return m_rulesPath; }
const fs::path GetFilename2() const { return fs::path(m_filename); } std::string GetNormalizedPathString() const;
bool RequiresRestart(bool changeEnableState, bool changePreset); bool RequiresRestart(bool changeEnableState, bool changePreset);
bool Reload(); bool Reload();
bool HasName() const { return !m_name.empty(); } bool HasName() const { return !m_name.empty(); }
const std::string& GetName() const { return m_name.empty() ? m_path : m_name; } const std::string& GetName() const { return m_name.empty() ? m_virtualPath : m_name; }
const std::string& GetPath() const { return m_path; } const std::string& GetVirtualPath() const { return m_virtualPath; } // returns the path in the gfx tree hierarchy
const std::string& GetDescription() const { return m_description; } const std::string& GetDescription() const { return m_description; }
bool IsDefaultEnabled() const { return m_default_enabled; } bool IsDefaultEnabled() const { return m_default_enabled; }
@ -164,7 +164,7 @@ public:
static const std::vector<std::shared_ptr<GraphicPack2>>& GetGraphicPacks() { return s_graphic_packs; } static const std::vector<std::shared_ptr<GraphicPack2>>& GetGraphicPacks() { return s_graphic_packs; }
static const std::vector<std::shared_ptr<GraphicPack2>>& GetActiveGraphicPacks() { return s_active_graphic_packs; } static const std::vector<std::shared_ptr<GraphicPack2>>& GetActiveGraphicPacks() { return s_active_graphic_packs; }
static void LoadGraphicPack(fs::path graphicPackPath); static void LoadGraphicPack(fs::path graphicPackPath);
static bool LoadGraphicPack(const std::string& filename, class IniParser& rules); static bool LoadGraphicPack(const fs::path& rulesPath, class IniParser& rules);
static bool ActivateGraphicPack(const std::shared_ptr<GraphicPack2>& graphic_pack); static bool ActivateGraphicPack(const std::shared_ptr<GraphicPack2>& graphic_pack);
static bool DeactivateGraphicPack(const std::shared_ptr<GraphicPack2>& graphic_pack); static bool DeactivateGraphicPack(const std::shared_ptr<GraphicPack2>& graphic_pack);
static void ClearGraphicPacks(); static void ClearGraphicPacks();
@ -208,11 +208,11 @@ private:
parser.TryAddConstant(var.first, (TType)var.second.second); parser.TryAddConstant(var.first, (TType)var.second.second);
} }
std::string m_filename; fs::path m_rulesPath;
sint32 m_version; sint32 m_version;
std::string m_name; std::string m_name;
std::string m_path; std::string m_virtualPath;
std::string m_description; std::string m_description;
bool m_default_enabled = false; bool m_default_enabled = false;
@ -257,7 +257,7 @@ private:
CustomShader LoadShader(const fs::path& path, uint64 shader_base_hash, uint64 shader_aux_hash, GP_SHADER_TYPE shader_type) const; CustomShader LoadShader(const fs::path& path, uint64 shader_base_hash, uint64 shader_aux_hash, GP_SHADER_TYPE shader_type) const;
void ApplyShaderPresets(std::string& shader_source) const; void ApplyShaderPresets(std::string& shader_source) const;
void LoadReplacedFiles(); void LoadReplacedFiles();
void _iterateReplacedFiles(const fs::path& currentPath, std::wstring& internalPath, bool isAOC); void _iterateReplacedFiles(const fs::path& currentPath, bool isAOC);
// ram mappings // ram mappings
std::vector<std::pair<MPTR, MPTR>> m_ramMappings; std::vector<std::pair<MPTR, MPTR>> m_ramMappings;

View File

@ -71,19 +71,8 @@ void PatchErrorHandler::showStageErrorMessageBox()
// returns true if at least one file was found even if it could not be successfully parsed // returns true if at least one file was found even if it could not be successfully parsed
bool GraphicPack2::LoadCemuPatches() bool GraphicPack2::LoadCemuPatches()
{ {
// todo - once we have updated to C++20 we can replace these with the new std::string functions
auto startsWith = [](const std::wstring& str, const std::wstring& prefix)
{
return str.size() >= prefix.size() && 0 == str.compare(0, prefix.size(), prefix);
};
auto endsWith = [](const std::wstring& str, const std::wstring& suffix)
{
return str.size() >= suffix.size() && 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
};
bool foundPatches = false; bool foundPatches = false;
fs::path path(_utf8ToPath(m_filename)); fs::path path(m_rulesPath);
path.remove_filename(); path.remove_filename();
for (auto& p : fs::directory_iterator(path)) for (auto& p : fs::directory_iterator(path))
{ {
@ -129,7 +118,7 @@ void GraphicPack2::LoadPatchFiles()
if (LoadCemuPatches()) if (LoadCemuPatches())
return; // exit if at least one Cemu style patch file was found return; // exit if at least one Cemu style patch file was found
// fall back to Cemuhook patches.txt to guarantee backward compatibility // fall back to Cemuhook patches.txt to guarantee backward compatibility
fs::path path(_utf8ToPath(m_filename)); fs::path path(m_rulesPath);
path.remove_filename(); path.remove_filename();
path.append("patches.txt"); path.append("patches.txt");
FileStream* patchFile = FileStream::openFile2(path); FileStream* patchFile = FileStream::openFile2(path);

View File

@ -25,7 +25,7 @@ sint32 GraphicPack2::GetLengthWithoutComment(const char* str, size_t length)
void GraphicPack2::LogPatchesSyntaxError(sint32 lineNumber, std::string_view errorMsg) void GraphicPack2::LogPatchesSyntaxError(sint32 lineNumber, std::string_view errorMsg)
{ {
cemuLog_log(LogType::Force, "Syntax error while parsing patch for graphic pack '{}':", this->GetFilename()); cemuLog_log(LogType::Force, "Syntax error while parsing patch for graphic pack '{}':", _pathToUtf8(this->GetRulesPath()));
if(lineNumber >= 0) if(lineNumber >= 0)
cemuLog_log(LogType::Force, fmt::format("Line {0}: {1}", lineNumber, errorMsg)); cemuLog_log(LogType::Force, fmt::format("Line {0}: {1}", lineNumber, errorMsg));
else else

View File

@ -64,7 +64,7 @@ void GraphicPacksWindow2::FillGraphicPackList() const
{ {
bool found = false; bool found = false;
if (boost::icontains(p->GetPath(), m_filter)) if (boost::icontains(p->GetVirtualPath(), m_filter))
found = true; found = true;
else else
{ {
@ -82,7 +82,7 @@ void GraphicPacksWindow2::FillGraphicPackList() const
continue; continue;
} }
const auto& path = p->GetPath(); const auto& path = p->GetVirtualPath();
auto tokens = TokenizeView(path, '/'); auto tokens = TokenizeView(path, '/');
auto node = root; auto node = root;
for(size_t i=0; i<tokens.size(); i++) for(size_t i=0; i<tokens.size(); i++)
@ -329,7 +329,7 @@ void GraphicPacksWindow2::SaveStateToConfig()
for (const auto& gp : GraphicPack2::GetGraphicPacks()) for (const auto& gp : GraphicPack2::GetGraphicPacks())
{ {
auto filename = MakeRelativePath(ActiveSettings::GetUserDataPath(), _utf8ToPath(gp->GetFilename())).lexically_normal(); auto filename = _utf8ToPath(gp->GetNormalizedPathString());
if (gp->IsEnabled()) if (gp->IsEnabled())
{ {
data.graphic_pack_entries.try_emplace(filename); data.graphic_pack_entries.try_emplace(filename);
@ -603,34 +603,29 @@ void GraphicPacksWindow2::OnCheckForUpdates(wxCommandEvent& event)
{ {
if (!CafeSystem::IsTitleRunning()) if (!CafeSystem::IsTitleRunning())
{ {
std::vector<GraphicPackPtr> old_packs = GraphicPack2::GetGraphicPacks(); // remember virtual paths of all the enabled packs
std::map<std::string, std::string> previouslyEnabledPacks;
for(auto& it : GraphicPack2::GetGraphicPacks())
{
if(it->IsEnabled())
previouslyEnabledPacks.emplace(it->GetNormalizedPathString(), it->GetVirtualPath());
}
// reload graphic packs
RefreshGraphicPacks(); RefreshGraphicPacks();
FillGraphicPackList(); FillGraphicPackList();
// remove packs which are still present
// check if enabled graphic packs are lost: for(auto& it : GraphicPack2::GetGraphicPacks())
const auto& new_packs = GraphicPack2::GetGraphicPacks(); previouslyEnabledPacks.erase(it->GetNormalizedPathString());
std::stringstream lost_packs; if(!previouslyEnabledPacks.empty())
for(const auto& p : old_packs)
{ {
if (!p->IsEnabled()) std::string lost_packs;
continue; for(auto& it : previouslyEnabledPacks)
const auto it = std::find_if(new_packs.cbegin(), new_packs.cend(), [&p](const auto& gp)
{
return gp->GetFilename() == p->GetFilename();
});
if(it == new_packs.cend())
{ {
lost_packs << p->GetPath() << "\n"; lost_packs.append(it.second);
lost_packs.push_back('\n');
} }
}
const auto lost_packs_str = lost_packs.str();
if (!lost_packs_str.empty())
{
wxString message = _("This update removed or renamed the following graphic packs:"); wxString message = _("This update removed or renamed the following graphic packs:");
message << "\n \n" << lost_packs_str << " \n" << _("You may need to set them up again."); message << "\n \n" << wxString::FromUTF8(lost_packs) << " \n" << _("You may need to set them up again.");
wxMessageBox(message, _("Warning"), wxOK | wxCENTRE | wxICON_INFORMATION, this); wxMessageBox(message, _("Warning"), wxOK | wxCENTRE | wxICON_INFORMATION, this);
} }
} }