// MassBuilderSaveTool // Copyright (C) 2021 Guillaume Jacquemin // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include #include #include #include #include "Profile.h" #include "Locators.h" using namespace Corrade; Profile::Profile(const std::string& path) { auto map = Utility::Directory::mapRead(path); if(!map) { _lastError = "Couldn't memory-map " + Utility::Directory::filename(path); return; } _profileDirectory = Utility::Directory::path(path); _filename = Utility::Directory::filename(path); if(Utility::String::beginsWith(_filename, "Demo")) { _type = ProfileType::Demo; } else { _type = ProfileType::FullGame; } _steamId = Utility::String::ltrim(Utility::String::rtrim(_filename, ".sav"), (_type == ProfileType::Demo ? "Demo" : "") + std::string{"Profile"}); auto it = std::search(map.begin(), map.end(), &company_name_locator[0], &company_name_locator[27]); if(it == map.end()) { _lastError = "Couldn't find a company name in " + _filename; return; } _companyName = std::string{it + 41}; _valid = true; } auto Profile::valid() const -> bool { return _valid; } auto Profile::lastError() const -> std::string const& { return _lastError; } auto Profile::filename() const -> std::string const& { return _filename; } auto Profile::type() const -> ProfileType { return _type; } auto Profile::steamId() const -> std::string const& { return _steamId; } void Profile::refreshValues() { getCompanyName(); getActiveFrameSlot(); getCredits(); getStoryProgress(); getLastMissionId(); getVerseSteel(); getUndinium(); getNecriumAlloy(); getLunarite(); getAsterite(); getEdnil(); getNuflalt(); getAurelene(); getSoldus(); getSynthesizedN(); getAlcarbonite(); getKeriphene(); getNitinolCM(); getQuarkium(); getAlterene(); getMixedComposition(); getVoidResidue(); getMuscularConstruction(); getMineralExoskeletology(); getCarbonizedSkin(); getEngineUnlocks(); getOsUnlocks(); } auto Profile::companyName() const -> std::string const& { return _companyName; } auto Profile::getCompanyName() -> std::string const& { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto it = std::search(mmap.begin(), mmap.end(), &company_name_locator[0], &company_name_locator[27]); if(it == mmap.end()) { _lastError = "Couldn't find a company name in " + _filename; _companyName = ""; } else { _companyName = std::string{it + 41}; } return _companyName; } auto Profile::renameCompany(const std::string& new_name) -> bool { char length_difference = static_cast(_companyName.length() - new_name.length()); std::string profile_data = Utility::Directory::readString(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(profile_data.begin(), profile_data.end(), &company_name_locator[0], &company_name_locator[27]); if(iter != profile_data.end()) { *(iter + 0x1C) = *(iter + 0x1C) - length_difference; *(iter + 0x25) = *(iter + 0x25) - length_difference; while(*(iter + 0x29) != '\0') { profile_data.erase(iter + 0x29); } profile_data.insert(iter + 0x29, new_name.cbegin(), new_name.cend()); if(!Utility::Directory::writeString(Utility::Directory::join(_profileDirectory, _filename), profile_data)) { _lastError = "The file" + _filename + " couldn't be written to."; return false; } _companyName = new_name; return true; } else { _lastError = "Couldn't find the company name in " + _filename; return false; } } auto Profile::activeFrameSlot() const -> Int { return _activeFrameSlot; } auto Profile::getActiveFrameSlot() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &active_slot_locator[0], &active_slot_locator[31]); if(iter == mmap.end()) { if(std::search(mmap.begin(), mmap.end(), &credits_locator[0], &credits_locator[22]) != mmap.end()) { _activeFrameSlot = 0; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _activeFrameSlot = -1; } } else { _activeFrameSlot = *(iter + 41); } return _activeFrameSlot; } auto Profile::credits() const -> Int { return _credits; } auto Profile::getCredits() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &credits_locator[0], &credits_locator[22]); if(iter != mmap.end()) { _credits = *reinterpret_cast(iter + 0x20); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _credits = -1; } return _credits; } auto Profile::setCredits(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &credits_locator[0], &credits_locator[22]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x20) = amount; _credits = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::storyProgress() const -> Int { return _storyProgress; } auto Profile::getStoryProgress() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &story_progress_locator[0], &story_progress_locator[29]); if(iter != mmap.end()) { _storyProgress = *reinterpret_cast(iter + 0x27); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _storyProgress = -1; } return _storyProgress; } auto Profile::setStoryProgress(Int progress) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &story_progress_locator[0], &story_progress_locator[29]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x27) = progress; _storyProgress = progress; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::lastMissionId() const -> Int { return _lastMissionId; } auto Profile::getLastMissionId() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &last_mission_id_locator[0], &last_mission_id_locator[29]); if(iter != mmap.end()) { _lastMissionId = *reinterpret_cast(iter + 0x27); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _lastMissionId = -1; } return _lastMissionId; } auto Profile::verseSteel() const -> Int { return _verseSteel; } auto Profile::getVerseSteel() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &verse_steel_locator[0], &verse_steel_locator[129]); if(iter != mmap.end()) { _verseSteel = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _verseSteel = -1; } return _verseSteel; } auto Profile::setVerseSteel(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &verse_steel_locator[0], &verse_steel_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _verseSteel = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::undinium() const -> Int { return _undinium; } auto Profile::getUndinium() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &undinium_locator[0], &undinium_locator[129]); if(iter != mmap.end()) { _undinium = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _undinium = -1; } return _undinium; } auto Profile::setUndinium(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &undinium_locator[0], &undinium_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _undinium = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::necriumAlloy() const -> Int { return _necriumAlloy; } auto Profile::getNecriumAlloy() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &necrium_alloy_locator[0], &necrium_alloy_locator[129]); if(iter != mmap.end()) { _necriumAlloy = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _necriumAlloy = -1; } return _necriumAlloy; } auto Profile::setNecriumAlloy(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &necrium_alloy_locator[0], &necrium_alloy_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _necriumAlloy = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::lunarite() const -> Int { return _lunarite; } auto Profile::getLunarite() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &lunarite_locator[0], &lunarite_locator[129]); if(iter != mmap.end()) { _lunarite = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _lunarite = -1; } return _lunarite; } auto Profile::setLunarite(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &lunarite_locator[0], &lunarite_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _lunarite = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::asterite() const -> Int { return _asterite; } auto Profile::getAsterite() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &asterite_locator[0], &asterite_locator[129]); if(iter != mmap.end()) { _asterite = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _asterite = -1; } return _asterite; } auto Profile::setAsterite(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &asterite_locator[0], &asterite_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _asterite = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::ednil() const -> Int { return _ednil; } auto Profile::getEdnil() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &ednil_locator[0], &ednil_locator[129]); if(iter != mmap.end()) { _ednil = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _ednil = -1; } return _ednil; } auto Profile::setEdnil(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &ednil_locator[0], &ednil_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _ednil = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::nuflalt() const -> Int { return _nuflalt; } auto Profile::getNuflalt() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &nuflalt_locator[0], &nuflalt_locator[129]); if(iter != mmap.end()) { _nuflalt = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _nuflalt = -1; } return _nuflalt; } auto Profile::setNuflalt(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &nuflalt_locator[0], &nuflalt_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _nuflalt = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::aurelene() const -> Int { return _aurelene; } auto Profile::getAurelene() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &aurelene_locator[0], &aurelene_locator[129]); if(iter != mmap.end()) { _aurelene = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _aurelene = -1; } return _aurelene; } auto Profile::setAurelene(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &aurelene_locator[0], &aurelene_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _aurelene = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::soldus() const -> Int { return _soldus; } auto Profile::getSoldus() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &soldus_locator[0], &soldus_locator[129]); if(iter != mmap.end()) { _soldus = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _soldus = -1; } return _soldus; } auto Profile::setSoldus(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &soldus_locator[0], &soldus_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _soldus = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::synthesizedN() const -> Int { return _synthesizedN; } auto Profile::getSynthesizedN() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &synthesized_n_locator[0], &synthesized_n_locator[129]); if(iter != mmap.end()) { _synthesizedN = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _synthesizedN = -1; } return _synthesizedN; } auto Profile::setSynthesizedN(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &synthesized_n_locator[0], &synthesized_n_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _synthesizedN = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::alcarbonite() const -> Int { return _alcarbonite; } auto Profile::getAlcarbonite() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &alcarbonite_locator[0], &alcarbonite_locator[129]); if(iter != mmap.end()) { _alcarbonite = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _alcarbonite = -1; } return _alcarbonite; } auto Profile::setAlcarbonite(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &alcarbonite_locator[0], &alcarbonite_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _alcarbonite = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::keriphene() const -> Int { return _keriphene; } auto Profile::getKeriphene() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &keriphene_locator[0], &keriphene_locator[129]); if(iter != mmap.end()) { _keriphene = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _keriphene= -1; } return _keriphene; } auto Profile::setKeriphene(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &keriphene_locator[0], &keriphene_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _keriphene = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::nitinolCM() const -> Int { return _nitinolCM; } auto Profile::getNitinolCM() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &nitinol_cm_locator[0], &nitinol_cm_locator[129]); if(iter != mmap.end()) { _nitinolCM = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _nitinolCM = -1; } return _nitinolCM; } auto Profile::setNitinolCM(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &nitinol_cm_locator[0], &nitinol_cm_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _nitinolCM = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::quarkium() const -> Int { return _quarkium; } auto Profile::getQuarkium() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &quarkium_locator[0], &quarkium_locator[129]); if(iter != mmap.end()) { _quarkium = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _quarkium = -1; } return _quarkium; } auto Profile::setQuarkium(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &quarkium_locator[0], &quarkium_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _quarkium = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::alterene() const -> Int { return _alterene; } auto Profile::getAlterene() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &alterene_locator[0], &alterene_locator[129]); if(iter != mmap.end()) { _alterene = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _alterene = -1; } return _alterene; } auto Profile::setAlterene(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &alterene_locator[0], &alterene_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _alterene = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::mixedComposition() const -> Int { return _mixedComposition; } auto Profile::getMixedComposition() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &mixed_composition_locator[0], &mixed_composition_locator[129]); if(iter != mmap.end()) { _mixedComposition = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _mixedComposition = -1; } return _mixedComposition; } auto Profile::setMixedComposition(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &mixed_composition_locator[0], &mixed_composition_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _mixedComposition = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::voidResidue() const -> Int { return _voidResidue; } auto Profile::getVoidResidue() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &void_residue_locator[0], &void_residue_locator[129]); if(iter != mmap.end()) { _voidResidue = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _voidResidue = -1; } return _voidResidue; } auto Profile::setVoidResidue(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &void_residue_locator[0], &void_residue_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _voidResidue = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::muscularConstruction() const -> Int { return _muscularConstruction; } auto Profile::getMuscularConstruction() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &muscular_construction_locator[0], &muscular_construction_locator[129]); if(iter != mmap.end()) { _muscularConstruction = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _muscularConstruction = -1; } return _muscularConstruction; } auto Profile::setMuscularConstruction(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &muscular_construction_locator[0], &muscular_construction_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _muscularConstruction = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::mineralExoskeletology() const -> Int { return _mineralExoskeletology; } auto Profile::getMineralExoskeletology() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &mineral_exoskeletology_locator[0], &mineral_exoskeletology_locator[129]); if(iter != mmap.end()) { _mineralExoskeletology = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _mineralExoskeletology = -1; } return _mineralExoskeletology; } auto Profile::setMineralExoskeletology(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &mineral_exoskeletology_locator[0], &mineral_exoskeletology_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _mineralExoskeletology = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::carbonizedSkin() const -> Int { return _carbonizedSkin; } auto Profile::getCarbonizedSkin() -> Int { auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &carbonized_skin_locator[0], &carbonized_skin_locator[129]); if(iter != mmap.end()) { _carbonizedSkin = *reinterpret_cast(iter + 0x8C); } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; _carbonizedSkin = -1; } return _carbonizedSkin; } auto Profile::setCarbonizedSkin(Int amount) -> bool { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &carbonized_skin_locator[0], &carbonized_skin_locator[129]); if(iter != mmap.end()) { *reinterpret_cast(iter + 0x8C) = amount; _carbonizedSkin = amount; return true; } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; return false; } } auto Profile::engineInventory() -> Containers::ArrayView { return _engineInventory; } auto Profile::gearInventory() -> Containers::ArrayView { return _gearInventory; } void Profile::getEngineUnlocks() { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &engine_inventory_locator[0], &engine_inventory_locator[33]); if(iter != mmap.end()) { Int* int_iter = reinterpret_cast(iter + 0x3B); Int size = *(int_iter++); if(size > 0) { _engineInventory = Containers::Array{DefaultInit, std::size_t(size)}; std::copy_n(int_iter, size, _engineInventory.data()); Utility::Debug{} << "_engineInventory:" << _engineInventory; iter = std::search(mmap.begin(), mmap.end(), &gear_inventory_locator[0], &gear_inventory_locator[31]); if(iter == mmap.end()) { return; } int_iter = reinterpret_cast(iter + 0x39); size = *(int_iter++); if(size <= 0) { return; } _gearInventory = Containers::Array{DefaultInit, std::size_t(size)}; std::copy_n(int_iter, size, _gearInventory.data()); Utility::Debug{} << "_gearInventory:" << _gearInventory; } else { _lastError = "An array can't have a null or negative size."; Utility::Fatal{EXIT_FAILURE} << _lastError.c_str(); } } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; } } auto Profile::osInventory() -> Containers::ArrayView { return _osInventory; } auto Profile::moduleInventory() -> Containers::ArrayView { return _moduleInventory; } void Profile::getOsUnlocks() { auto mmap = Utility::Directory::map(Utility::Directory::join(_profileDirectory, _filename)); auto iter = std::search(mmap.begin(), mmap.end(), &os_inventory_locator[0], &os_inventory_locator[29]); if(iter != mmap.end()) { Int* int_iter = reinterpret_cast(iter + 0x37); Int size = *(int_iter++); if(size > 0) { _osInventory = Containers::Array{DefaultInit, std::size_t(size)}; std::copy_n(int_iter, size, _osInventory.data()); Utility::Debug{} << "_osInventory:" << _osInventory; iter = std::search(mmap.begin(), mmap.end(), &module_inventory_locator[0], &module_inventory_locator[33]); if(iter == mmap.end()) { return; } int_iter = reinterpret_cast(iter + 0x3B); size = *(int_iter++); if(size <= 0) { return; } _moduleInventory = Containers::Array{DefaultInit, std::size_t(size)}; std::copy_n(int_iter, size, _moduleInventory.data()); Utility::Debug{} << "_moduleInventory:" << _moduleInventory; } else { _lastError = "An array can't have a null or negative size."; Utility::Fatal{EXIT_FAILURE} << _lastError.c_str(); } } else { _lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file."; } }