@@ -67,8 +67,55 @@ extern "C" {
6767bool prevAltAssets = false ;
6868}
6969
70+ typedef struct {
71+ uint16_t major;
72+ uint16_t minor;
73+ uint16_t patch;
74+ } OTRVersion;
75+
7076GameEngine* GameEngine::Instance;
7177
78+ // Read the port version from an OTR file
79+ OTRVersion ReadPortVersionFromOTR (std::string otrPath) {
80+ OTRVersion version = {};
81+
82+ // Use a temporary archive instance to load the otr and read the version file
83+ auto archive = std::make_shared<Ship::O2rArchive>(otrPath);
84+ if (archive->Open ()) {
85+ auto t = archive->LoadFile (" portVersion" );
86+ if (t != nullptr && t->IsLoaded ) {
87+ auto stream = std::make_shared<Ship::MemoryStream>(t->Buffer ->data (), t->Buffer ->size ());
88+ auto reader = std::make_shared<Ship::BinaryReader>(stream);
89+ Ship::Endianness endianness = (Ship::Endianness)reader->ReadUByte ();
90+ reader->SetEndianness (endianness);
91+ version.major = reader->ReadUInt16 ();
92+ version.minor = reader->ReadUInt16 ();
93+ version.patch = reader->ReadUInt16 ();
94+ }
95+ }
96+
97+ return version;
98+ }
99+
100+ // Checks the program version stored in the otr and compares the major value to soh
101+ // For Windows/Mac/Linux if the version doesn't match, offer to
102+ OTRVersion DetectOTRVersion (std::string fileName) {
103+ bool isOtrOld = false ;
104+ std::string otrPath = Ship::Context::LocateFileAcrossAppDirs (fileName, " sm64" );
105+
106+ // Doesn't exist so nothing to do here
107+ if (!std::filesystem::exists (otrPath)) {
108+ return { INT16_MAX , INT16_MAX , INT16_MAX };
109+ }
110+
111+ return ReadPortVersionFromOTR (otrPath);
112+ }
113+
114+ bool VerifyArchiveVersion (OTRVersion version) {
115+ return version.major != INT16_MAX && version.minor != INT16_MAX &&
116+ (version.major == gBuildVersionMajor || version.minor == gBuildVersionMinor );
117+ }
118+
72119GameEngine::GameEngine () : dictionary(nullptr ) {
73120 this ->context = Ship::Context::CreateUninitializedInstance (" Ghostship" , " sm64" , " ghostship.cfg.json" );
74121
@@ -81,16 +128,19 @@ GameEngine::GameEngine() : dictionary(nullptr) {
81128 const std::string main_path = Ship::Context::GetPathRelativeToAppDirectory (" sm64.o2r" );
82129 const std::string assets_path = Ship::Context::LocateFileAcrossAppDirs (" ghostship.o2r" );
83130
131+ bool shouldRegen = VerifyArchiveVersion (DetectOTRVersion (" sm64.o2r" ));
132+
84133#ifdef _WIN32
85134 AllocConsole ();
86135#endif
87136
88- if (std::filesystem::exists (main_path)) {
137+ if (std::filesystem::exists (main_path) && !shouldRegen ) {
89138 archiveFiles.push_back (main_path);
90139 } else {
91- if (ShowYesNoBox (" Ghostship - Asset Extraction" ,
92- " Please provide a Super Mario 64 ROM.\n\n Supported Versions:\n US\n JP\n\n Assets will be "
93- " extracted into an O2R file." ) == IDYES ) {
140+ std::string msg = (shouldRegen ? " Your ROM O2R is outdated, and needs to be re-extracted.\n\n " : " " ) +
141+ std::string (" Please provide a Super Mario 64 ROM.\n\n Supported Versions:\n US\n JP\n\n "
142+ " Assets will be extracted into an O2R file." );
143+ if (ShowYesNoBox (" Ghostship - Asset Extraction" , msg.c_str ()) == IDYES ) {
94144 if (!GenAssetFile ()) {
95145 ShowMessage (" Error" , " An error occured, no O2R file was generated.\n\n Exiting..." );
96146 exit (1 );
0 commit comments