FreeShop.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include <sys/stat.h>
  2. #include "FreeShop.hpp"
  3. #include "States/TitleState.hpp"
  4. #include "Notification.hpp"
  5. #include "States/DialogState.hpp"
  6. #include "States/LoadingState.hpp"
  7. #include "States/SyncState.hpp"
  8. #include "States/BrowseState.hpp"
  9. #include "States/NewsState.hpp"
  10. #include "TitleKeys.hpp"
  11. #include "Util.hpp"
  12. #include "States/SleepState.hpp"
  13. #include "States/QrScannerState.hpp"
  14. #include "GUI/Settings.hpp"
  15. #ifndef EMULATION
  16. #include <3ds.h>
  17. #endif
  18. using namespace cpp3ds;
  19. using namespace TweenEngine;
  20. namespace FreeShop {
  21. cpp3ds::Uint64 g_requestJump = 0;
  22. bool g_requestShutdown = false;
  23. bool g_requestReboot = false;
  24. FreeShop::FreeShop()
  25. : Game(0x100000)
  26. {
  27. m_stateStack = new StateStack(State::Context(m_text, m_data));
  28. m_stateStack->registerState<TitleState>(States::Title);
  29. m_stateStack->registerState<LoadingState>(States::Loading);
  30. m_stateStack->registerState<SyncState>(States::Sync);
  31. m_stateStack->registerState<BrowseState>(States::Browse);
  32. m_stateStack->registerState<SleepState>(States::Sleep);
  33. m_stateStack->registerState<QrScannerState>(States::QrScanner);
  34. m_stateStack->registerState<DialogState>(States::Dialog);
  35. m_stateStack->registerState<NewsState>(States::News);
  36. #ifdef EMULATION
  37. m_stateStack->pushState(States::Browse);
  38. #else
  39. m_stateStack->pushState(States::Loading);
  40. m_stateStack->pushState(States::Sync);
  41. m_stateStack->pushState(States::Title);
  42. #endif
  43. textFPS.setFillColor(cpp3ds::Color::Red);
  44. textFPS.setCharacterSize(20);
  45. // Set up directory structure, if necessary
  46. std::string path = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR);
  47. if (!pathExists(path.c_str(), false))
  48. makeDirectory(path.c_str());
  49. path = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/tmp");
  50. if (pathExists(path.c_str(), false))
  51. removeDirectory(path.c_str());
  52. mkdir(path.c_str(), 0777);
  53. path = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/cache");
  54. if (!pathExists(path.c_str(), false))
  55. mkdir(path.c_str(), 0777);
  56. path = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/keys");
  57. if (!pathExists(path.c_str(), false))
  58. mkdir(path.c_str(), 0777);
  59. path = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/news");
  60. if (!pathExists(path.c_str(), false))
  61. mkdir(path.c_str(), 0777);
  62. path = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/music");
  63. if (!pathExists(path.c_str(), false))
  64. mkdir(path.c_str(), 0777);
  65. path = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/music/eshop");
  66. if (!pathExists(path.c_str(), false))
  67. mkdir(path.c_str(), 0777);
  68. #ifndef NDEBUG
  69. path = cpp3ds::FileSystem::getFilePath(FREESHOP_DIR "/debug/dev/");
  70. if (!pathExists(path.c_str(), false))
  71. mkdir(path.c_str(), 0777);
  72. #endif
  73. Config::loadFromFile();
  74. // Load chosen language, correct auto-detect with separate Spanish/Portuguese
  75. std::string langCode = Config::get(Config::Language).GetString();
  76. #ifdef _3DS
  77. u8 region;
  78. CFGU_SecureInfoGetRegion(&region);
  79. if (langCode == "auto")
  80. {
  81. if (cpp3ds::I18n::getLanguage() == cpp3ds::Language::Spanish)
  82. langCode = (region == CFG_REGION_USA) ? "es_US" : "es_ES";
  83. else if (cpp3ds::I18n::getLanguage() == cpp3ds::Language::Portuguese)
  84. langCode = (region == CFG_REGION_USA) ? "pt_BR" : "pt_PT";
  85. }
  86. #endif
  87. if (langCode != "auto")
  88. cpp3ds::I18n::loadLanguageFile(_("lang/%s.lang", langCode.c_str()));
  89. // If override.lang exists, use it instead of chosen language
  90. std::string testLangFilename(FREESHOP_DIR "/override.lang");
  91. if (pathExists(testLangFilename.c_str()))
  92. cpp3ds::I18n::loadLanguageFile(testLangFilename);
  93. // Used to theme the loading background
  94. if (pathExists(FREESHOP_DIR "/theme/images/topBG.png", true)) {
  95. m_rectTopBG.setTexture(&AssetManager<cpp3ds::Texture>::get(FREESHOP_DIR "/theme/images/topBG.png"));
  96. m_rectTopBG.setPosition(0.f, 0.f);
  97. m_topBG = true;
  98. } else if (Config::get(Config::DarkTheme).GetBool()) {
  99. m_rectTopBG.setTexture(&AssetManager<cpp3ds::Texture>::get("darkimages/topBG.png"));
  100. m_rectTopBG.setPosition(0.f, 0.f);
  101. m_topBG = true;
  102. }
  103. if (pathExists(FREESHOP_DIR "/theme/images/botBG.png", true)) {
  104. m_rectBotBG.setTexture(&AssetManager<cpp3ds::Texture>::get(FREESHOP_DIR "/theme/images/botBG.png"));
  105. m_rectBotBG.setPosition(0.f, 0.f);
  106. m_botBG = true;
  107. } else if (Config::get(Config::DarkTheme).GetBool()) {
  108. m_rectBotBG.setTexture(&AssetManager<cpp3ds::Texture>::get("darkimages/botBG.png"));
  109. m_rectBotBG.setPosition(0.f, 0.f);
  110. m_botBG = true;
  111. }
  112. }
  113. FreeShop::~FreeShop()
  114. {
  115. delete m_stateStack;
  116. }
  117. void FreeShop::update(float delta)
  118. {
  119. #ifndef EMULATION
  120. // 3DSX version need to do this here...
  121. if (g_requestJump != 0 || g_requestShutdown || g_requestReboot) {
  122. prepareToCloseApp();
  123. if (g_requestShutdown && envIsHomebrew()) {
  124. //Init the services and turn off the console
  125. ptmSysmInit();
  126. PTMSYSM_ShutdownAsync(0);
  127. ptmSysmExit();
  128. } else if (g_requestJump != 0) {
  129. //Var initialization
  130. Result res = 0;
  131. u8 hmac[0x20];
  132. memset(hmac, 0, sizeof(hmac));
  133. //Check on which media launch the title
  134. FS_MediaType mediaType = ((g_requestJump >> 32) == TitleKeys::DSiWare) ? MEDIATYPE_NAND : MEDIATYPE_SD;
  135. FS_CardType type;
  136. bool cardInserted;
  137. cardInserted = (R_SUCCEEDED(FSUSER_CardSlotIsInserted(&cardInserted)) && cardInserted && R_SUCCEEDED(FSUSER_GetCardType(&type)) && type == CARD_CTR);
  138. if (cardInserted)
  139. {
  140. // Retry a bunch of times. When the card is newly inserted,
  141. // it sometimes takes a short while before title can be read.
  142. int retryCount = 100;
  143. u64 cardTitleId;
  144. while (retryCount-- > 0)
  145. if (R_SUCCEEDED(AM_GetTitleList(nullptr, MEDIATYPE_GAME_CARD, 1, &cardTitleId)))
  146. {
  147. try
  148. {
  149. if (cardTitleId == g_requestJump)
  150. mediaType = MEDIATYPE_GAME_CARD;
  151. }
  152. catch (int e)
  153. {
  154. //
  155. }
  156. break;
  157. }
  158. else
  159. cpp3ds::sleep(cpp3ds::milliseconds(5));
  160. }
  161. //Do the application jump
  162. if (R_SUCCEEDED(res = APT_PrepareToDoApplicationJump(0, g_requestJump, mediaType)))
  163. res = APT_DoApplicationJump(0, 0, hmac);
  164. }
  165. }
  166. #endif
  167. // Need to update before checking if empty
  168. m_stateStack->update(delta);
  169. if (m_stateStack->isEmpty() || g_requestJump != 0 || g_requestShutdown || g_requestReboot) {
  170. prepareToCloseApp();
  171. exit();
  172. }
  173. Notification::update(delta);
  174. #ifndef NDEBUG
  175. static int i;
  176. if (i++ % 10 == 0) {
  177. textFPS.setString(_("%.1f fps", 1.f / delta));
  178. textFPS.setPosition(395 - textFPS.getGlobalBounds().width, 2.f);
  179. }
  180. #endif
  181. }
  182. void FreeShop::processEvent(Event& event)
  183. {
  184. m_stateStack->processEvent(event);
  185. }
  186. void FreeShop::renderTopScreen(Window& window)
  187. {
  188. if (m_topBG)
  189. window.draw(m_rectTopBG);
  190. else
  191. window.clear(Color::White);
  192. m_stateStack->renderTopScreen(window);
  193. for (auto& notification : Notification::notifications)
  194. window.draw(*notification);
  195. #ifndef NDEBUG
  196. window.draw(textFPS);
  197. #endif
  198. }
  199. void FreeShop::renderBottomScreen(Window& window)
  200. {
  201. if (m_botBG)
  202. window.draw(m_rectBotBG);
  203. else
  204. window.clear(Color::White);
  205. m_stateStack->renderBottomScreen(window);
  206. //window.draw(m_AP_Sprite);
  207. }
  208. void FreeShop::prepareToCloseApp()
  209. {
  210. DownloadQueue::getInstance().suspend();
  211. DownloadQueue::getInstance().save();
  212. if (g_browseState)
  213. g_browseState->settingsSaveToConfig();
  214. Config::set(Config::CleanExit, true);
  215. Config::saveToFile();
  216. }
  217. } // namespace FreeShop