diff --git a/Core/HLE/sceUmd.cpp b/Core/HLE/sceUmd.cpp index 01a9b5827b..eaf486c223 100644 --- a/Core/HLE/sceUmd.cpp +++ b/Core/HLE/sceUmd.cpp @@ -24,6 +24,9 @@ #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HLE/KernelWaitHelpers.h" +#include "Core/FileSystems/BlockDevices.h" +#include "Core/FileSystems/ISOFileSystem.h" +#include "Core/FileSystems/VirtualDiscFileSystem.h" const u64 MICRO_DELAY_ACTIVATE = 4000; @@ -36,6 +39,9 @@ static int umdStatChangeEvent = -1; static std::vector umdWaitingThreads; static std::map umdPausedWaits; +extern IFileSystem* currentUMD; +bool UMDReplacePermit = false; + struct PspUmdInfo { u32_le size; u32_le type; @@ -266,7 +272,6 @@ u32 sceUmdRegisterUMDCallBack(u32 cbId) // There's only ever one. driveCBId = cbId; } - DEBUG_LOG(SCEIO, "%d=sceUmdRegisterUMDCallback(id=%08x)", retVal, cbId); return retVal; } @@ -281,7 +286,6 @@ int sceUmdUnRegisterUMDCallBack(int cbId) retVal = cbId; driveCBId = -1; } - DEBUG_LOG(SCEIO, "%08x=sceUmdUnRegisterUMDCallBack(id=%08x)", retVal, cbId); return retVal; } @@ -436,14 +440,42 @@ u32 sceUmdGetErrorStat() return umdErrorStat; } +void __UmdReplace(std::string filename) { + pspFileSystem.Unmount("umd0:", currentUMD); + pspFileSystem.Unmount("umd1:", currentUMD); + pspFileSystem.Unmount("disc0:", currentUMD); + pspFileSystem.Unmount("umd:", currentUMD); + + IFileSystem* umd2; + PSPFileInfo info = pspFileSystem.GetFileInfo(filename); + if (info.type == FILETYPE_DIRECTORY) { + umd2 = new VirtualDiscFileSystem(&pspFileSystem, filename); + } else { + auto bd = constructBlockDevice(filename.c_str()); + if (!bd) + return; + umd2 = new ISOFileSystem(&pspFileSystem, bd); + pspFileSystem.Mount("umd0:", umd2); + pspFileSystem.Mount("umd1:", umd2); + pspFileSystem.Mount("disc0:", umd2); + pspFileSystem.Mount("umd:", umd2); + } + currentUMD = umd2; + u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE | PSP_UMD_CHANGED; + if (driveCBId != -1) + __KernelNotifyCallback(driveCBId, notifyArg); +} + u32 sceUmdReplaceProhibit() { + UMDReplacePermit = false; DEBUG_LOG(SCEIO,"sceUmdReplaceProhibit()"); return 0; } u32 sceUmdReplacePermit() { + UMDReplacePermit = true; DEBUG_LOG(SCEIO,"sceUmdReplacePermit()"); return 0; } diff --git a/Core/HLE/sceUmd.h b/Core/HLE/sceUmd.h index 3423c88f4c..a4f766eb49 100644 --- a/Core/HLE/sceUmd.h +++ b/Core/HLE/sceUmd.h @@ -41,4 +41,6 @@ enum pspUmdType { void __UmdInit(); void __UmdDoState(PointerWrap &p); +void __UmdReplace(std::string filename); + void Register_sceUmdUser(); diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index 15a0d86bd3..f69db2b2d3 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -42,6 +42,7 @@ #include "HLE/sceKernelMemory.h" #include "ELF/ParamSFO.h" +IFileSystem* currentUMD; // We gather the game info before actually loading/booting the ISO // to determine if the emulator should enable extra memory and // double-sized texture coordinates. @@ -72,6 +73,8 @@ void InitMemoryForGameISO(std::string fileToStart) { pspFileSystem.Mount("umd1:", umd2); pspFileSystem.Mount("disc0:", umd2); pspFileSystem.Mount("umd:", umd2); + currentUMD = umd2; + std::string gameID; std::string sfoPath("disc0:/PSP_GAME/PARAM.SFO"); @@ -205,6 +208,7 @@ bool Load_PSP_ELF_PBP(const char *filename, std::string *error_string) pspFileSystem.Mount("umd1:", umd2); pspFileSystem.Mount("disc0:", umd2); pspFileSystem.Mount("umd:", umd2); + currentUMD = umd2; } } diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 288c68130e..2dab018b9b 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -44,6 +44,8 @@ #include "GPU/GPUInterface.h" #include "i18n/i18n.h" +#include "Core/HLE/sceUmd.h" + #ifdef _WIN32 #include "Windows/W32Util/ShellUtil.h" #include "Windows/WndMainWindow.h" @@ -504,14 +506,14 @@ void MainScreen::CreateViews() { if (vertical) { root_ = new LinearLayout(ORIENT_VERTICAL); rightColumn->ReplaceLayoutParams(new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); - leftColumn->ReplaceLayoutParams(new LinearLayoutParams(1.0)); - root_->Add(rightColumn); + leftColumn->ReplaceLayoutParams(new LinearLayoutParams(1.0)); + root_->Add(rightColumn); root_->Add(leftColumn); } else { root_ = new LinearLayout(ORIENT_HORIZONTAL); leftColumn->ReplaceLayoutParams(new LinearLayoutParams(1.0)); rightColumn->ReplaceLayoutParams(new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins)); - root_->Add(leftColumn); + root_->Add(leftColumn); root_->Add(rightColumn); } @@ -703,6 +705,8 @@ GamePauseScreen::~GamePauseScreen() { } } +extern bool UMDReplacePermit; + void GamePauseScreen::CreateViews() { static const int NUM_SAVESLOTS = 5; @@ -753,6 +757,9 @@ void GamePauseScreen::CreateViews() { rightColumn->Add(rightColumnItems); rightColumnItems->SetSpacing(0.0f); + if (UMDReplacePermit) { + rightColumnItems->Add(new Choice(i->T("Switch UMD")))->OnClick.Handle(this, &GamePauseScreen::OnSwitchUMD); + } rightColumnItems->Add(new Choice(i->T("Continue")))->OnClick.Handle(this, &UIScreen::OnBack); rightColumnItems->Add(new Choice(i->T("Game Settings")))->OnClick.Handle(this, &GamePauseScreen::OnGameSettings); if (g_Config.bEnableCheats) { @@ -813,6 +820,11 @@ UI::EventReturn GamePauseScreen::OnCwCheat(UI::EventParams &e) { return UI::EVENT_DONE; } +UI::EventReturn GamePauseScreen::OnSwitchUMD(UI::EventParams &e) { + screenManager()->push(new UmdReplaceScreen()); + return UI::EVENT_DONE; +} + void GamePauseScreen::sendMessage(const char *message, const char *value) { // Since the language message isn't allowed to be in native, we have to have add this // to every screen which directly inherits from UIScreen(which are few right now, luckily). @@ -820,3 +832,58 @@ void GamePauseScreen::sendMessage(const char *message, const char *value) { screenManager()->RecreateAllViews(); } } + +void UmdReplaceScreen::CreateViews() { + I18NCategory *m = GetI18NCategory("MainMenu"); + + TabHolder *leftColumn = new TabHolder(ORIENT_HORIZONTAL, 64); + leftColumn->SetClip(true); + + ScrollView *scrollRecentGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); + ScrollView *scrollAllGames = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); + + GameBrowser *tabRecentGames = new GameBrowser( + "!RECENT", false, &g_Config.bGridView1, "", "", + new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); + GameBrowser *tabAllGames = new GameBrowser(g_Config.currentDirectory, true, &g_Config.bGridView2, + m->T("How to get games"), "http://www.ppsspp.org/getgames.html", + new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); + + scrollRecentGames->Add(tabRecentGames); + scrollAllGames->Add(tabAllGames); + + leftColumn->AddTab(m->T("Recent"), scrollRecentGames); + leftColumn->AddTab(m->T("Games"), scrollAllGames); + + tabRecentGames->OnChoice.Handle(this, &UmdReplaceScreen::OnGameSelectedInstant); + tabAllGames->OnChoice.Handle(this, &UmdReplaceScreen::OnGameSelectedInstant); + tabRecentGames->OnHoldChoice.Handle(this, &UmdReplaceScreen::OnGameSelected); + tabAllGames->OnHoldChoice.Handle(this, &UmdReplaceScreen::OnGameSelected); + + if (g_Config.recentIsos.size() > 0) { + leftColumn->SetCurrentTab(0); + }else{ + leftColumn->SetCurrentTab(1); + } + + root_ = new LinearLayout(ORIENT_HORIZONTAL); + leftColumn->ReplaceLayoutParams(new LinearLayoutParams(1.0)); + root_->Add(leftColumn); +} + +void UmdReplaceScreen::update(InputState &input) { + UpdateUIState(UISTATE_PAUSEMENU); + UIScreen::update(input); +} + +UI::EventReturn UmdReplaceScreen::OnGameSelected(UI::EventParams &e) { + __UmdReplace(e.s); + screenManager()->finishDialog(this, DR_OK); + return UI::EVENT_DONE; +} + +UI::EventReturn UmdReplaceScreen:: OnGameSelectedInstant(UI::EventParams &e) { + __UmdReplace(e.s); + screenManager()->finishDialog(this, DR_OK); + return UI::EVENT_DONE; +} diff --git a/UI/MainScreen.h b/UI/MainScreen.h index 308f86473c..0a7c432b7f 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -80,9 +80,25 @@ private: UI::EventReturn OnStateSelected(UI::EventParams &e); UI::EventReturn OnCwCheat(UI::EventParams &e); + UI::EventReturn OnSwitchUMD(UI::EventParams &e); + std::string gamePath_; UI::ChoiceStrip *saveSlots_; UI::Choice *saveStateButton_; UI::Choice *loadStateButton_; }; + +class UmdReplaceScreen : public UIDialogScreenWithBackground { +public: + UmdReplaceScreen() {} + +protected: + virtual void CreateViews(); + virtual void update(InputState &input); + //virtual void sendMessage(const char *message, const char *value); + +private: + UI::EventReturn OnGameSelected(UI::EventParams &e); + UI::EventReturn OnGameSelectedInstant(UI::EventParams &e); +};