nn_pdm: Refactor code to use new module structure

This commit is contained in:
Exzap 2023-11-21 16:39:55 +01:00
parent 9398c0ca6b
commit 67f7ce815c
3 changed files with 117 additions and 32 deletions

View file

@ -530,7 +530,8 @@ namespace CafeSystem
{ {
// entries in this list are ordered by initialization order. Shutdown in reverse order // entries in this list are ordered by initialization order. Shutdown in reverse order
iosu::kernel::GetModule(), iosu::kernel::GetModule(),
iosu::fpd::GetModule() iosu::fpd::GetModule(),
iosu::pdm::GetModule(),
}; };
// initialize all subsystems which are persistent and don't depend on a game running // initialize all subsystems which are persistent and don't depend on a game running
@ -571,7 +572,6 @@ namespace CafeSystem
iosu::iosuAcp_init(); iosu::iosuAcp_init();
iosu::boss_init(); iosu::boss_init();
iosu::nim::Initialize(); iosu::nim::Initialize();
iosu::pdm::Initialize();
iosu::odm::Initialize(); iosu::odm::Initialize();
// init Cafe OS // init Cafe OS
avm::Initialize(); avm::Initialize();
@ -840,7 +840,6 @@ namespace CafeSystem
coreinit::OSSchedulerBegin(3); coreinit::OSSchedulerBegin(3);
else else
coreinit::OSSchedulerBegin(1); coreinit::OSSchedulerBegin(1);
iosu::pdm::StartTrackingTime(GetForegroundTitleId());
} }
void LaunchForegroundTitle() void LaunchForegroundTitle()
@ -970,8 +969,6 @@ namespace CafeSystem
RPLLoader_ResetState(); RPLLoader_ResetState();
for(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it) for(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it)
(*it)->TitleStop(); (*it)->TitleStop();
// stop time tracking
iosu::pdm::Stop();
// reset Cemu subsystems // reset Cemu subsystems
PPCRecompiler_Shutdown(); PPCRecompiler_Shutdown();
GraphicPack2::Reset(); GraphicPack2::Reset();

View file

@ -1,4 +1,5 @@
#include "iosu_pdm.h" #include "iosu_pdm.h"
#include "Cafe/CafeSystem.h"
#include "config/ActiveSettings.h" #include "config/ActiveSettings.h"
#include "Common/FileStream.h" #include "Common/FileStream.h"
#include "util/helpers/Semaphore.h" #include "util/helpers/Semaphore.h"
@ -17,7 +18,8 @@ namespace iosu
{ {
namespace pdm namespace pdm
{ {
std::mutex sDiaryLock; std::recursive_mutex sPlaystatsLock;
std::recursive_mutex sDiaryLock;
fs::path GetPDFile(const char* filename) fs::path GetPDFile(const char* filename)
{ {
@ -80,14 +82,16 @@ namespace iosu
static_assert((NUM_PLAY_STATS_ENTRIES * sizeof(PlayStatsEntry)) == 0x1400); static_assert((NUM_PLAY_STATS_ENTRIES * sizeof(PlayStatsEntry)) == 0x1400);
} }
void LoadPlaystats() void OpenPlaystats()
{ {
std::unique_lock _l(sPlaystatsLock);
PlayStats.numEntries = 0; PlayStats.numEntries = 0;
for (size_t i = 0; i < NUM_PLAY_STATS_ENTRIES; i++) for (size_t i = 0; i < NUM_PLAY_STATS_ENTRIES; i++)
{ {
auto& e = PlayStats.entry[i]; auto& e = PlayStats.entry[i];
memset(&e, 0, sizeof(PlayStatsEntry)); memset(&e, 0, sizeof(PlayStatsEntry));
} }
cemu_assert_debug(!PlayStats.fs);
PlayStats.fs = FileStream::openFile2(GetPDFile("PlayStats.dat"), true); PlayStats.fs = FileStream::openFile2(GetPDFile("PlayStats.dat"), true);
if (!PlayStats.fs) if (!PlayStats.fs)
{ {
@ -98,18 +102,39 @@ namespace iosu
{ {
delete PlayStats.fs; delete PlayStats.fs;
PlayStats.fs = nullptr; PlayStats.fs = nullptr;
cemuLog_log(LogType::Force, "PlayStats.dat malformed"); cemuLog_log(LogType::Force, "PlayStats.dat malformed. Time tracking wont be used");
// dont delete the existing file in case it could still be salvaged (todo) and instead just dont track play time // dont delete the existing file in case it could still be salvaged (todo) and instead just dont track play time
return; return;
} }
PlayStats.numEntries = 0;
PlayStats.fs->readData(&PlayStats.numEntries, sizeof(uint32be)); PlayStats.fs->readData(&PlayStats.numEntries, sizeof(uint32be));
if (PlayStats.numEntries > NUM_PLAY_STATS_ENTRIES) if (PlayStats.numEntries > NUM_PLAY_STATS_ENTRIES)
PlayStats.numEntries = NUM_PLAY_STATS_ENTRIES; PlayStats.numEntries = NUM_PLAY_STATS_ENTRIES;
PlayStats.fs->readData(PlayStats.entry, NUM_PLAY_STATS_ENTRIES * 20); PlayStats.fs->readData(PlayStats.entry, NUM_PLAY_STATS_ENTRIES * 20);
} }
void ClosePlaystats()
{
std::unique_lock _l(sPlaystatsLock);
if (PlayStats.fs)
{
delete PlayStats.fs;
PlayStats.fs = nullptr;
}
}
void UnloadPlaystats()
{
std::unique_lock _l(sPlaystatsLock);
cemu_assert_debug(!PlayStats.fs); // unloading expects that file is closed
PlayStats.numEntries = 0;
for(auto& it : PlayStats.entry)
it = PlayStatsEntry{};
}
PlayStatsEntry* PlayStats_GetEntry(uint64 titleId) PlayStatsEntry* PlayStats_GetEntry(uint64 titleId)
{ {
std::unique_lock _l(sPlaystatsLock);
uint32be titleIdHigh = (uint32)(titleId>>32); uint32be titleIdHigh = (uint32)(titleId>>32);
uint32be titleIdLow = (uint32)(titleId & 0xFFFFFFFF); uint32be titleIdLow = (uint32)(titleId & 0xFFFFFFFF);
size_t numEntries = PlayStats.numEntries; size_t numEntries = PlayStats.numEntries;
@ -121,7 +146,7 @@ namespace iosu
return nullptr; return nullptr;
} }
void PlayStats_WriteEntry(PlayStatsEntry* entry, bool writeEntryCount = false) void PlayStats_WriteEntryNoLock(PlayStatsEntry* entry, bool writeEntryCount = false)
{ {
if (!PlayStats.fs) if (!PlayStats.fs)
return; return;
@ -141,8 +166,15 @@ namespace iosu
} }
} }
void PlayStats_WriteEntry(PlayStatsEntry* entry, bool writeEntryCount = false)
{
std::unique_lock _l(sPlaystatsLock);
PlayStats_WriteEntryNoLock(entry, writeEntryCount);
}
PlayStatsEntry* PlayStats_CreateEntry(uint64 titleId) PlayStatsEntry* PlayStats_CreateEntry(uint64 titleId)
{ {
std::unique_lock _l(sPlaystatsLock);
bool entryCountChanged = false; bool entryCountChanged = false;
PlayStatsEntry* newEntry; PlayStatsEntry* newEntry;
if(PlayStats.numEntries < NUM_PLAY_STATS_ENTRIES) if(PlayStats.numEntries < NUM_PLAY_STATS_ENTRIES)
@ -168,7 +200,7 @@ namespace iosu
newEntry->numTimesLaunched = 1; newEntry->numTimesLaunched = 1;
newEntry->totalMinutesPlayed = 0; newEntry->totalMinutesPlayed = 0;
newEntry->ukn12 = 0; newEntry->ukn12 = 0;
PlayStats_WriteEntry(newEntry, entryCountChanged); PlayStats_WriteEntryNoLock(newEntry, entryCountChanged);
return newEntry; return newEntry;
} }
@ -176,6 +208,7 @@ namespace iosu
// if it does not exist it creates a new entry with first and last played set to today // if it does not exist it creates a new entry with first and last played set to today
PlayStatsEntry* PlayStats_BeginNewTracking(uint64 titleId) PlayStatsEntry* PlayStats_BeginNewTracking(uint64 titleId)
{ {
std::unique_lock _l(sPlaystatsLock);
PlayStatsEntry* entry = PlayStats_GetEntry(titleId); PlayStatsEntry* entry = PlayStats_GetEntry(titleId);
if (entry) if (entry)
{ {
@ -189,11 +222,12 @@ namespace iosu
void PlayStats_CountAdditionalMinutes(PlayStatsEntry* entry, uint32 additionalMinutes) void PlayStats_CountAdditionalMinutes(PlayStatsEntry* entry, uint32 additionalMinutes)
{ {
std::unique_lock _l(sPlaystatsLock);
if (additionalMinutes == 0) if (additionalMinutes == 0)
return; return;
entry->totalMinutesPlayed += additionalMinutes; entry->totalMinutesPlayed += additionalMinutes;
entry->mostRecentDayIndex = GetTodaysDayIndex(); entry->mostRecentDayIndex = GetTodaysDayIndex();
PlayStats_WriteEntry(entry); PlayStats_WriteEntryNoLock(entry);
} }
struct PlayDiaryHeader struct PlayDiaryHeader
@ -218,6 +252,7 @@ namespace iosu
void CreatePlayDiary() void CreatePlayDiary()
{ {
MakeDirectory(); MakeDirectory();
cemu_assert_debug(!PlayDiaryData.fs);
PlayDiaryData.fs = FileStream::createFile2(GetPDFile("PlayDiary.dat")); PlayDiaryData.fs = FileStream::createFile2(GetPDFile("PlayDiary.dat"));
if (!PlayDiaryData.fs) if (!PlayDiaryData.fs)
{ {
@ -230,7 +265,7 @@ namespace iosu
PlayDiaryData.fs->writeData(&PlayDiaryData.header, sizeof(PlayDiaryHeader)); PlayDiaryData.fs->writeData(&PlayDiaryData.header, sizeof(PlayDiaryHeader));
} }
void LoadPlayDiary() void OpenPlayDiary()
{ {
std::unique_lock _lock(sDiaryLock); std::unique_lock _lock(sDiaryLock);
cemu_assert_debug(!PlayDiaryData.fs); cemu_assert_debug(!PlayDiaryData.fs);
@ -268,6 +303,26 @@ namespace iosu
} }
} }
void ClosePlayDiary()
{
std::unique_lock _lock(sDiaryLock);
if (PlayDiaryData.fs)
{
delete PlayDiaryData.fs;
PlayDiaryData.fs = nullptr;
}
}
void UnloadDiaryData()
{
std::unique_lock _lock(sDiaryLock);
cemu_assert_debug(!PlayDiaryData.fs); // unloading expects that file is closed
PlayDiaryData.header.readIndex = 0;
PlayDiaryData.header.writeIndex = 0;
for (auto& it : PlayDiaryData.entry)
it = PlayDiaryEntry{};
}
uint32 GetDiaryEntries(uint8 accountSlot, PlayDiaryEntry* diaryEntries, uint32 maxEntries) uint32 GetDiaryEntries(uint8 accountSlot, PlayDiaryEntry* diaryEntries, uint32 maxEntries)
{ {
std::unique_lock _lock(sDiaryLock); std::unique_lock _lock(sDiaryLock);
@ -352,25 +407,59 @@ namespace iosu
} }
} }
void Initialize() class : public ::IOSUModule
{ {
// todo - add support for per-account handling void PDMLoadAll()
LoadPlaystats(); {
LoadPlayDiary(); OpenPlaystats();
} OpenPlayDiary();
}
void StartTrackingTime(uint64 titleId)
{
sPDMRequestExitThread = false;
sPDMTimeTrackingThread = std::thread(TimeTrackingThread, titleId);
}
void Stop() void PDMUnloadAll()
{
UnloadPlaystats();
UnloadDiaryData();
}
void PDMCloseAll()
{
ClosePlaystats();
ClosePlayDiary();
}
void SystemLaunch() override
{
// todo - add support for per-account handling
PDMLoadAll();
PDMCloseAll(); // close the files again, user may mess with MLC files or change MLC path while no game is running
}
void SystemExit() override
{
PDMCloseAll();
PDMUnloadAll();
}
void TitleStart() override
{
// reload data and keep files open
PDMUnloadAll();
PDMLoadAll();
auto titleId = CafeSystem::GetForegroundTitleId();
sPDMRequestExitThread = false;
sPDMTimeTrackingThread = std::thread(TimeTrackingThread, titleId);
}
void TitleStop() override
{
sPDMRequestExitThread.store(true);
sPDMSem.increment();
if(sPDMTimeTrackingThread.joinable())
sPDMTimeTrackingThread.join();
PDMCloseAll();
}
}sIOSUModuleNNPDM;
IOSUModule* GetModule()
{ {
sPDMRequestExitThread.store(true); return static_cast<IOSUModule*>(&sIOSUModuleNNPDM);
sPDMSem.increment();
if(sPDMTimeTrackingThread.joinable())
sPDMTimeTrackingThread.join();
} }
}; };

View file

@ -1,13 +1,10 @@
#pragma once #pragma once
#include "Cafe/IOSU/iosu_types_common.h"
namespace iosu namespace iosu
{ {
namespace pdm namespace pdm
{ {
void Initialize();
void StartTrackingTime(uint64 titleId);
void Stop();
inline constexpr size_t NUM_PLAY_STATS_ENTRIES = 256; inline constexpr size_t NUM_PLAY_STATS_ENTRIES = 256;
inline constexpr size_t NUM_PLAY_DIARY_ENTRIES_MAX = 18250; // 0x474A inline constexpr size_t NUM_PLAY_DIARY_ENTRIES_MAX = 18250; // 0x474A
@ -34,5 +31,7 @@ namespace iosu
}; };
bool GetStatForGamelist(uint64 titleId, GameListStat& stat); bool GetStatForGamelist(uint64 titleId, GameListStat& stat);
IOSUModule* GetModule();
}; };
}; };