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
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
@ -571,7 +572,6 @@ namespace CafeSystem
iosu::iosuAcp_init();
iosu::boss_init();
iosu::nim::Initialize();
iosu::pdm::Initialize();
iosu::odm::Initialize();
// init Cafe OS
avm::Initialize();
@ -840,7 +840,6 @@ namespace CafeSystem
coreinit::OSSchedulerBegin(3);
else
coreinit::OSSchedulerBegin(1);
iosu::pdm::StartTrackingTime(GetForegroundTitleId());
}
void LaunchForegroundTitle()
@ -970,8 +969,6 @@ namespace CafeSystem
RPLLoader_ResetState();
for(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it)
(*it)->TitleStop();
// stop time tracking
iosu::pdm::Stop();
// reset Cemu subsystems
PPCRecompiler_Shutdown();
GraphicPack2::Reset();

View File

@ -1,4 +1,5 @@
#include "iosu_pdm.h"
#include "Cafe/CafeSystem.h"
#include "config/ActiveSettings.h"
#include "Common/FileStream.h"
#include "util/helpers/Semaphore.h"
@ -17,7 +18,8 @@ namespace iosu
{
namespace pdm
{
std::mutex sDiaryLock;
std::recursive_mutex sPlaystatsLock;
std::recursive_mutex sDiaryLock;
fs::path GetPDFile(const char* filename)
{
@ -80,14 +82,16 @@ namespace iosu
static_assert((NUM_PLAY_STATS_ENTRIES * sizeof(PlayStatsEntry)) == 0x1400);
}
void LoadPlaystats()
void OpenPlaystats()
{
std::unique_lock _l(sPlaystatsLock);
PlayStats.numEntries = 0;
for (size_t i = 0; i < NUM_PLAY_STATS_ENTRIES; i++)
{
auto& e = PlayStats.entry[i];
memset(&e, 0, sizeof(PlayStatsEntry));
}
cemu_assert_debug(!PlayStats.fs);
PlayStats.fs = FileStream::openFile2(GetPDFile("PlayStats.dat"), true);
if (!PlayStats.fs)
{
@ -98,18 +102,39 @@ namespace iosu
{
delete PlayStats.fs;
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
return;
}
PlayStats.numEntries = 0;
PlayStats.fs->readData(&PlayStats.numEntries, sizeof(uint32be));
if (PlayStats.numEntries > NUM_PLAY_STATS_ENTRIES)
PlayStats.numEntries = NUM_PLAY_STATS_ENTRIES;
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)
{
std::unique_lock _l(sPlaystatsLock);
uint32be titleIdHigh = (uint32)(titleId>>32);
uint32be titleIdLow = (uint32)(titleId & 0xFFFFFFFF);
size_t numEntries = PlayStats.numEntries;
@ -121,7 +146,7 @@ namespace iosu
return nullptr;
}
void PlayStats_WriteEntry(PlayStatsEntry* entry, bool writeEntryCount = false)
void PlayStats_WriteEntryNoLock(PlayStatsEntry* entry, bool writeEntryCount = false)
{
if (!PlayStats.fs)
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)
{
std::unique_lock _l(sPlaystatsLock);
bool entryCountChanged = false;
PlayStatsEntry* newEntry;
if(PlayStats.numEntries < NUM_PLAY_STATS_ENTRIES)
@ -168,7 +200,7 @@ namespace iosu
newEntry->numTimesLaunched = 1;
newEntry->totalMinutesPlayed = 0;
newEntry->ukn12 = 0;
PlayStats_WriteEntry(newEntry, entryCountChanged);
PlayStats_WriteEntryNoLock(newEntry, entryCountChanged);
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
PlayStatsEntry* PlayStats_BeginNewTracking(uint64 titleId)
{
std::unique_lock _l(sPlaystatsLock);
PlayStatsEntry* entry = PlayStats_GetEntry(titleId);
if (entry)
{
@ -189,11 +222,12 @@ namespace iosu
void PlayStats_CountAdditionalMinutes(PlayStatsEntry* entry, uint32 additionalMinutes)
{
std::unique_lock _l(sPlaystatsLock);
if (additionalMinutes == 0)
return;
entry->totalMinutesPlayed += additionalMinutes;
entry->mostRecentDayIndex = GetTodaysDayIndex();
PlayStats_WriteEntry(entry);
PlayStats_WriteEntryNoLock(entry);
}
struct PlayDiaryHeader
@ -218,6 +252,7 @@ namespace iosu
void CreatePlayDiary()
{
MakeDirectory();
cemu_assert_debug(!PlayDiaryData.fs);
PlayDiaryData.fs = FileStream::createFile2(GetPDFile("PlayDiary.dat"));
if (!PlayDiaryData.fs)
{
@ -230,7 +265,7 @@ namespace iosu
PlayDiaryData.fs->writeData(&PlayDiaryData.header, sizeof(PlayDiaryHeader));
}
void LoadPlayDiary()
void OpenPlayDiary()
{
std::unique_lock _lock(sDiaryLock);
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)
{
std::unique_lock _lock(sDiaryLock);
@ -352,25 +407,59 @@ namespace iosu
}
}
void Initialize()
class : public ::IOSUModule
{
// todo - add support for per-account handling
LoadPlaystats();
LoadPlayDiary();
}
void PDMLoadAll()
{
OpenPlaystats();
OpenPlayDiary();
}
void StartTrackingTime(uint64 titleId)
{
sPDMRequestExitThread = false;
sPDMTimeTrackingThread = std::thread(TimeTrackingThread, titleId);
}
void PDMUnloadAll()
{
UnloadPlaystats();
UnloadDiaryData();
}
void Stop()
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);
sPDMSem.increment();
if(sPDMTimeTrackingThread.joinable())
sPDMTimeTrackingThread.join();
return static_cast<IOSUModule*>(&sIOSUModuleNNPDM);
}
};

View File

@ -1,13 +1,10 @@
#pragma once
#include "Cafe/IOSU/iosu_types_common.h"
namespace iosu
{
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_DIARY_ENTRIES_MAX = 18250; // 0x474A
@ -34,5 +31,7 @@ namespace iosu
};
bool GetStatForGamelist(uint64 titleId, GameListStat& stat);
IOSUModule* GetModule();
};
};