load.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. auto Program::identify(const string& filename) -> shared_pointer<Emulator> {
  2. if(auto system = mia::identify(filename)) {
  3. for(auto& emulator : emulators) {
  4. if(emulator->name == system) return emulator;
  5. }
  6. }
  7. MessageDialog().setTitle("lucia").setText({
  8. "Filename: ", Location::file(filename), "\n\n"
  9. "Unable to determine what type of game this file is.\n"
  10. "Please use the load menu to choose the appropriate game system instead."
  11. }).setAlignment(presentation).error();
  12. return {};
  13. }
  14. auto Program::load(shared_pointer<Emulator> emulator, string filename) -> bool {
  15. if(!filename) {
  16. string location = emulator->configuration.game;
  17. if(!location) location = Path::desktop();
  18. BrowserDialog dialog;
  19. dialog.setTitle({"Load ", emulator->name, " Game"});
  20. dialog.setPath(location);
  21. dialog.setAlignment(presentation);
  22. string filters{"*.zip:"};
  23. for(auto& extension : emulator->medium->extensions()) {
  24. filters.append("*.", extension, ":");
  25. }
  26. //support both uppercase and lowercase extensions
  27. filters.append(string{filters}.upcase());
  28. filters.trimRight(":", 1L);
  29. filters.prepend(emulator->name, " Games|");
  30. dialog.setFilters({filters, "All Files|*"});
  31. filename = openFile(dialog);
  32. }
  33. if(!file::exists(filename)) return false;
  34. vector<uint8_t> filedata;
  35. if(filename.iendsWith(".zip")) {
  36. Decode::ZIP archive;
  37. if(archive.open(filename)) {
  38. for(auto& file : archive.file) {
  39. auto extension = Location::suffix(file.name).trimLeft(".", 1L).downcase();
  40. if(emulator->medium->extensions().find(extension)) {
  41. filedata = archive.extract(file);
  42. break;
  43. }
  44. }
  45. }
  46. } else {
  47. filedata = file::read(filename);
  48. }
  49. if(!filedata) return false;
  50. //apply patch (if one exists)
  51. bool patchApplied = false;
  52. if(auto patch = file::read(emulator->locate(filename, ".bps", settings.paths.patches))) {
  53. if(auto output = Beat::Single::apply(filedata, patch)) {
  54. filedata = output();
  55. patchApplied = true;
  56. }
  57. }
  58. unload();
  59. ::emulator = emulator;
  60. if(!emulator->load(filename, filedata)) {
  61. ::emulator.reset();
  62. if(settings.video.adaptiveSizing) presentation.resizeWindow();
  63. presentation.showIcon(true);
  64. return false;
  65. }
  66. //this is a safeguard warning in case the user loads their games from a read-only location:
  67. string savesPath = settings.paths.saves;
  68. if(!savesPath) savesPath = Location::path(filename);
  69. if(!directory::writable(savesPath)) {
  70. MessageDialog().setTitle("lucia").setText({
  71. "The current save path is read-only; please choose a writable save path now.\n"
  72. "Otherwise, any in-game progress will be lost once this game is unloaded!\n\n"
  73. "Current save location: ", savesPath
  74. }).warning();
  75. }
  76. paletteUpdate();
  77. runAheadUpdate();
  78. presentation.loadEmulator();
  79. presentation.showIcon(false);
  80. if(settings.video.adaptiveSizing) presentation.resizeWindow();
  81. manifestViewer.reload();
  82. memoryEditor.reload();
  83. graphicsViewer.reload();
  84. streamManager.reload();
  85. propertiesViewer.reload();
  86. traceLogger.reload();
  87. state = {}; //reset hotkey state slot to 1
  88. if(settings.general.autoDebug) {
  89. pause(true);
  90. toolsWindow.show("Tracer");
  91. presentation.setFocused();
  92. } else {
  93. pause(false);
  94. }
  95. showMessage({"Loaded ", Location::prefix(emulator->game.location), patchApplied ? ", and patch applied" : ""});
  96. //update recent games list
  97. for(int index = 7; index >= 0; index--) {
  98. settings.recent.game[index + 1] = settings.recent.game[index];
  99. }
  100. settings.recent.game[0] = {emulator->name, ";", filename};
  101. presentation.loadEmulators();
  102. return true;
  103. }
  104. auto Program::unload() -> void {
  105. if(!emulator) return;
  106. settings.save();
  107. showMessage({"Unloaded ", Location::prefix(emulator->game.location)});
  108. emulator->unload();
  109. emulator.reset();
  110. rewindReset();
  111. presentation.unloadEmulator();
  112. toolsWindow.setVisible(false);
  113. manifestViewer.unload();
  114. memoryEditor.unload();
  115. graphicsViewer.unload();
  116. streamManager.unload();
  117. propertiesViewer.unload();
  118. traceLogger.unload();
  119. message.text = "";
  120. ruby::video.clear();
  121. ruby::audio.clear();
  122. }