diff --git a/IMPLEMENTATION_CHEAT_SHEET.md b/IMPLEMENTATION_CHEAT_SHEET.md index f2b6b98b..e27f53a1 100644 --- a/IMPLEMENTATION_CHEAT_SHEET.md +++ b/IMPLEMENTATION_CHEAT_SHEET.md @@ -190,8 +190,15 @@ They might be worth trying in very tricky cases, but they were usually seen as c ### String Literals -String literals are not resolved. Instead we use a big `string-literals.hpp` file. -Make always sure to use a reference from this file instead of a string literal. +String literals are not resolved. Instead we use tow big files, `string-macros.hpp` and `string-literals.hpp`. +`string-macros.hpp` is the ground truth. However, when ever possible, using the pointers from `string-literals.hpp` is preferred. + +There is one known case that requires using only the macros: +Only literals can by split up into multiple parts and be moved into registers to copy a string, for example via "strcpy". +In this case, use the macros for the strings and **DO NOT** include `string-literals.hpp`, since this might cause different behavior. +Should a mixture of pointers and macros be required, because the macro to not produce the fitting structure, still only use the macros from `string-macros.hpp`. Create a string pointer in the cpp file and use this for the pointer. + +Make always sure to use a reference from this files instead of a direct string literal. ### Blocks and Scopes @@ -291,3 +298,27 @@ A prominent example are `malloc` and `free`, where it is simply needed to use th since the memory management in the std library is rather complex. For other std functions, mostly the math functions, we decided to just use the std library directly. + +### Copy Elision and Return Value Optimization + +The compiler may use copy elision and return value optimization. + +The return value optimization may appear if a function returns an object, but instead of putting the whole object on the stack, the function receives a hidden pointer to memory from the caller. This memory is then initialized and the pointer to it is also return. +The actual function signature will only have the object as value return. + +Example in Ghidra: +```cpp +std::string* paths_getDocumentsFolderString(std::string* out, bool param_2); +``` + +Actual signature: +```cpp +std::string paths_getDocumentsFolderString(bool param_2); +``` + +This structure can be reproduced. However, this can not be said about the resulting Copy Elision. +If the value is assigned to another object, the compiler tries to avoid creating a copy. + +**This only works if the function is called directly. Any form of indirection via pointer or resolver will not optimize. This is a fundamental limitation of the MSVC2005 compiler.** + +As a result, such cases do not use the resolver. The limitation through this is accepted, although, it should be noted in the status entry for the caller. diff --git a/cmake/compiler-flags-gl.txt b/cmake/compiler-flags-gl.txt index 5c4c1fe8..848d70de 100644 --- a/cmake/compiler-flags-gl.txt +++ b/cmake/compiler-flags-gl.txt @@ -1,6 +1,9 @@ src/OpenSHC/IO/LowLevelMemory/copyData.cpp -src/OpenSHC/IO/LowLevelMemory/fillMemory_ByteValue.cpp +src/OpenSHC/IO/LowLevelMemory/fillMemory.cpp +src/OpenSHC/IO/LowLevelMemory/putFileNameAndAppendFileExtension.cpp src/OpenSHC/IO/DecoderState/encodeData.cpp src/OpenSHC/IO/DecoderState/decodeData.cpp -src/OpenSHC/IO/DecoderState/swapMapDataWithNextMap.cpp +src/OpenSHC/IO/ResourceManager/swapMapDataWithNextMap.cpp src/OpenSHC/UI/Rendering/WindowAndDirectDraw/takeScreenshot.cpp +src/OpenSHC/IO/ResourceManager/readFirstPartOfCurrentResourceIntoMemory.cpp +src/OpenSHC/IO/ResourceManager/readNextPartOfCurrentResourceIntoMemory.cpp diff --git a/src/OpenSHC/IO/ResourceManager/Constructor_ResourceManager.cpp b/src/OpenSHC/IO/ResourceManager/Constructor_ResourceManager.cpp new file mode 100644 index 00000000..d6ace3a8 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/Constructor_ResourceManager.cpp @@ -0,0 +1,22 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00471BE0 + ResourceManager* ResourceManager::Constructor_ResourceManager() + { + this->mapFileCounter = 0; + + // FIXME?: Assuming the loadedMapNames is [500][1001], then this fill does not null the entire array. + MACRO_CALL_MEMBER(LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 500000, 0, this->loadedMapNames); + return this; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/discoverMapFiles.cpp b/src/OpenSHC/IO/ResourceManager/discoverMapFiles.cpp new file mode 100644 index 00000000..74eae848 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/discoverMapFiles.cpp @@ -0,0 +1,204 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace IO { + + // helper copied from the std lib + typedef union { + unsigned long long ft_scalar; + FILETIME ft_struct; + } FILETIME_UNION; + + // FUNCTION: STRONGHOLDCRUSADER 0x00477EE0 + void ResourceManager::discoverMapFiles(char const* param_1) + { + BOOLEnum _hasSwapped = TRUE; + int _mapIndex = 0; + + FILETIME_UNION filetimeBias; + filetimeBias.ft_scalar = 0; + + BOOLEnum _missionMaps = FALSE; + BOOLEnum _originalMaps = FALSE; + int local_22c = 0; + + if (!MACRO_CALL(OS_Func::__stricmp)(param_1, s_maps_map_005a64b0)) { + _missionMaps = TRUE; + _originalMaps = TRUE; + } + if (!MACRO_CALL(OS_Func::__stricmp)(param_1, s_mapsExtreme_map_005a649c)) { + _missionMaps = TRUE; + _originalMaps = TRUE; + } + + // the whole time part appears like something that should be part of the std libray, but I found nothing + // FIXME?: According to the chatbot I used, this seems to lack proper handling for the general bias + + _TIME_ZONE_INFORMATION timeZoneInformation; + DWORD timeZoneResult = GetTimeZoneInformation(&timeZoneInformation); + if (timeZoneResult == TIME_ZONE_ID_STANDARD) { + filetimeBias.ft_scalar = -timeZoneInformation.StandardBias; + } else if (timeZoneResult == TIME_ZONE_ID_DAYLIGHT) { + filetimeBias.ft_scalar = -timeZoneInformation.DaylightBias; + } + filetimeBias.ft_scalar *= 600000000; // transform into filetime ticks + + this->mapFileCounter = 0; + MACRO_CALL_MEMBER(LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 500000, 0, this->loadedMapNames); + + HANDLE _handle; + + WIN32_FIND_DATAA _win32FindData; + _handle = FindFirstFileA(param_1, &_win32FindData); + if (_handle == INVALID_HANDLE_VALUE) { + return; + } + + while (this->mapFileCounter < 500) { + MACRO_CALL_MEMBER(LowLevelMemory_Func::copyStringUntilFirstDot, DAT_LowLevelMemory::ptr)( + _win32FindData.cFileName, this->loadedMapNames[this->mapFileCounter]); + + { + FILETIME_UNION currentFileTime; + currentFileTime.ft_struct = _win32FindData.ftLastWriteTime; + currentFileTime.ft_scalar += filetimeBias.ft_scalar; + + WORD fatDate; + WORD fatTime; + FileTimeToDosDateTime(¤tFileTime.ft_struct, &fatDate, &fatTime); + + // this might indicate that they used a struct here to handle the time + // although other usages use it like a number + this->mapFileTimes[this->mapFileCounter] = (fatDate << 16) + fatTime; + } + + // since all strings are of type ptr, I can not get the length of the string during runtime via sizeof + // "magic numbers" here consider the length of "mission" and in relation to that + + if (_missionMaps + && !MACRO_CALL(OS_Func::__strnicmp)(this->loadedMapNames[this->mapFileCounter], s_mission_005a6494, 7) + && this->loadedMapNames[this->mapFileCounter][7] >= '0' + && this->loadedMapNames[this->mapFileCounter][7] <= '9') { + + if (this->loadedMapNames[this->mapFileCounter][7] == '1') { + if (this->loadedMapNames[this->mapFileCounter][8] < '0' + || this->loadedMapNames[this->mapFileCounter][8] > '9' + || this->loadedMapNames[this->mapFileCounter][9] != '\0') { + if (this->loadedMapNames[this->mapFileCounter][8] != '\0') { + goto keepMap; + } + } + } else if (this->loadedMapNames[this->mapFileCounter][7] == '2') { + if (this->loadedMapNames[this->mapFileCounter][8] < '0' + || this->loadedMapNames[this->mapFileCounter][8] > '1' + || this->loadedMapNames[this->mapFileCounter][9] != '\0') { + if (this->loadedMapNames[this->mapFileCounter][8] != '\0') { + goto keepMap; + } + } + } else if (this->loadedMapNames[this->mapFileCounter][7] == '3') { + if (this->loadedMapNames[this->mapFileCounter][8] < '3' + || this->loadedMapNames[this->mapFileCounter][8] > '7' + || this->loadedMapNames[this->mapFileCounter][9] != '\0') { + if (this->loadedMapNames[this->mapFileCounter][8] != '\0') { + goto keepMap; + } + } + } else { + if (this->loadedMapNames[this->mapFileCounter][8] != '\0') { + goto keepMap; + } + } + + MACRO_CALL_MEMBER(LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 1000, '\0', this->loadedMapNames[this->mapFileCounter]); + --this->mapFileCounter; + + keepMap:; // best matching solution so far + } + + ++this->mapFileCounter; + if (FindNextFileA(_handle, &_win32FindData)) { + continue; + } + if (!_originalMaps || local_22c) { + break; + } + local_22c = 1; + + // required, otherwise copy elision will not work + std::string path(this->paths_getDocumentsMapsFolderString(TRUE)); + path.append(s__map_005a648c); + + // FIXME: Assuming it did not get lost in the recomp process, since the func does not perfectly match, then + // this is a resource leak here. The older handle does not get closed properly + + // does this truly overwrite? + _handle = FindFirstFileA(path.c_str(), &_win32FindData); + if (_handle == INVALID_HANDLE_VALUE) { + break; + } + } + + if (_originalMaps) { + do { + ++_mapIndex; + if (!_hasSwapped) { + break; + } + _hasSwapped = FALSE; + for (int _currentMapIndex = 0; _currentMapIndex < this->mapFileCounter - _mapIndex; + ++_currentMapIndex) { + if (this->loadedMapNames[_currentMapIndex][0] == '\0' + || this->loadedMapNames[_currentMapIndex + 1][0] == '\0') { + break; + } + + int receiver; + char* _Str2 = MACRO_CALL(Global_Func::GetStringBasedOnHardcodedMaps)( + this->loadedMapNames[_currentMapIndex + 1], &receiver); + char* _Str1 = MACRO_CALL(Global_Func::GetStringBasedOnHardcodedMaps)( + this->loadedMapNames[_currentMapIndex], &receiver); + if (MACRO_CALL(OS_Func::__stricmp)(_Str1, _Str2) > 0) { + MACRO_CALL_MEMBER(ResourceManager_Func::swapMapDataWithNextMap, this)(_currentMapIndex); + _hasSwapped = TRUE; + } + } + } while (_mapIndex < 500); + } else { + do { + ++_mapIndex; + if (!_hasSwapped) { + break; + } + _hasSwapped = FALSE; + + for (int _currentMapIndex = 0; _currentMapIndex < this->mapFileCounter - _mapIndex; + ++_currentMapIndex) { + if (this->loadedMapNames[_currentMapIndex][0] == '\0' + || this->loadedMapNames[_currentMapIndex + 1][0] == '\0') { + break; + } + + if (MACRO_CALL(OS_Func::__stricmp)( + this->loadedMapNames[_currentMapIndex], this->loadedMapNames[_currentMapIndex + 1]) + > 0) { + MACRO_CALL_MEMBER(ResourceManager_Func::swapMapDataWithNextMap, this)(_currentMapIndex); + _hasSwapped = TRUE; + } + } + } while (_mapIndex < 500); + } + FindClose(_handle); + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/doesFileExist.cpp b/src/OpenSHC/IO/ResourceManager/doesFileExist.cpp new file mode 100644 index 00000000..5420fc7a --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/doesFileExist.cpp @@ -0,0 +1,20 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x0046C420 + BOOLEnum ResourceManager::doesFileExist(char* filename) + { + int _fileHandle = MACRO_CALL(OS_Func::_ucrt_open)(filename, _O_BINARY, 0); + if (_fileHandle == -1) { + return FALSE; + } + MACRO_CALL(OS_Func::_ucrt_close)(_fileHandle); + return TRUE; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/doesFileOfActiveResourceExist.cpp b/src/OpenSHC/IO/ResourceManager/doesFileOfActiveResourceExist.cpp new file mode 100644 index 00000000..24fd1549 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/doesFileOfActiveResourceExist.cpp @@ -0,0 +1,21 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00471DC0 + BOOLEnum ResourceManager::doesFileOfActiveResourceExist() + { + char* _Filename = MACRO_CALL_MEMBER(ResourceManager_Func::getFileNameOfCurrentActiveResource, this)(); + int fileDescriptor = MACRO_CALL(OpenSHC::OS_Func::_ucrt_open)(_Filename, _O_BINARY, 0); + if (fileDescriptor == -1) { + return FALSE; + } + MACRO_CALL(OpenSHC::OS_Func::_ucrt_close)(fileDescriptor); + return TRUE; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/fileHashFunctionByteByByte.cpp b/src/OpenSHC/IO/ResourceManager/fileHashFunctionByteByByte.cpp new file mode 100644 index 00000000..1436445d --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/fileHashFunctionByteByByte.cpp @@ -0,0 +1,33 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00472180 + int ResourceManager::fileHashFunctionByteByByte() + { + int _total = 0; + + char* _fileName = MACRO_CALL_MEMBER(ResourceManager_Func::getFileNameOfCurrentActiveResource, this)(); + int _fileHandle = MACRO_CALL(OS_Func::_ucrt_open)(_fileName, _O_BINARY, 0); + if (_fileHandle == -1) { + return -1; + } + + char _first1024chars[1024]; + int _numReadUnk; + do { + _numReadUnk = MACRO_CALL(OS_Func::_ucrt_read)(_fileHandle, _first1024chars, sizeof(_first1024chars)); + + for (int i = 0; i < _numReadUnk; ++i) { + _total += _first1024chars[i]; + } + } while (_numReadUnk != 0); + MACRO_CALL(OS_Func::_ucrt_close)(_fileHandle); + return _total; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/getChecksumOfMapByName.cpp b/src/OpenSHC/IO/ResourceManager/getChecksumOfMapByName.cpp new file mode 100644 index 00000000..e6a24b24 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/getChecksumOfMapByName.cpp @@ -0,0 +1,20 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x0046C280 + dword ResourceManager::getChecksumOfMapByName(char* mapNameAddress) + { + for (int _mapIndex = 0; _mapIndex < this->loadedMapsCount; ++_mapIndex) { + if (!MACRO_CALL(OS_Func::__stricmp)(this->mapNames[_mapIndex], mapNameAddress)) { + return this->mapMetaInfoArray[_mapIndex].loadedMapsChecksumArray; + } + } + return 0; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/getCurrentResourceCoreNameUnk.cpp b/src/OpenSHC/IO/ResourceManager/getCurrentResourceCoreNameUnk.cpp new file mode 100644 index 00000000..353d3c90 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/getCurrentResourceCoreNameUnk.cpp @@ -0,0 +1,37 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/Globals/DAT_CurrentResourceCoreName.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00471D30 + char* ResourceManager::getCurrentResourceCoreNameUnk() + { + char const* _resourceName = MACRO_CALL_MEMBER(ResourceManager_Func::getFileNameOfCurrentActiveResource, this)(); + int basenameEnd = strlen(_resourceName); + DAT_CurrentResourceCoreName::instance[0] = '\0'; + + for (int basenameStart = basenameEnd + -1; basenameStart >= 0; --basenameStart) { + if (_resourceName[basenameStart] == '.') { + basenameEnd = basenameStart; + } + if (_resourceName[basenameStart] != '\\') { + continue; + } + ++basenameStart; + int basenameLength = 0; + if (basenameStart < basenameEnd) { + basenameLength = basenameEnd - basenameStart; + for (int i = basenameStart; i < basenameEnd; ++i) { + DAT_CurrentResourceCoreName::instance[i - basenameStart] = _resourceName[i]; + } + } + DAT_CurrentResourceCoreName::instance[basenameLength] = '\0'; + break; + } + return DAT_CurrentResourceCoreName::instance; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/getCurrentResourceSize.cpp b/src/OpenSHC/IO/ResourceManager/getCurrentResourceSize.cpp new file mode 100644 index 00000000..986b6d50 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/getCurrentResourceSize.cpp @@ -0,0 +1,24 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/Global.func.hpp" +#include "OpenSHC/OS.func.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00471EB0 + int ResourceManager::getCurrentResourceSize() + { + char* _filename = MACRO_CALL_MEMBER(ResourceManager_Func::getFileNameOfCurrentActiveResource, this)(); + this->fileHandle = MACRO_CALL(OS_Func::_ucrt_open)(_filename, _O_BINARY, 0); + if (this->fileHandle == -1) { + return 0; + } + MACRO_CALL(OS_Func::_ucrt_lseek)(this->fileHandle, 0, FILE_END); + int _fileSize = MACRO_CALL(OS_Func::_ucrt_tell)(this->fileHandle); + MACRO_CALL(OS_Func::_ucrt_close)(this->fileHandle); + return _fileSize; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/getFileNameOfCurrentActiveResource.cpp b/src/OpenSHC/IO/ResourceManager/getFileNameOfCurrentActiveResource.cpp new file mode 100644 index 00000000..acd34eaf --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/getFileNameOfCurrentActiveResource.cpp @@ -0,0 +1,13 @@ +#include "../ResourceManager.func.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x0046C300 + char* ResourceManager::getFileNameOfCurrentActiveResource() + { + return this->resourceFileNameArray[this->currentActiveResourceType]; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/getSimpleFirst1024ByteSumOfFile.cpp b/src/OpenSHC/IO/ResourceManager/getSimpleFirst1024ByteSumOfFile.cpp new file mode 100644 index 00000000..e06affb9 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/getSimpleFirst1024ByteSumOfFile.cpp @@ -0,0 +1,33 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x0046C4E0 + int ResourceManager::getSimpleFirst1024ByteSumOfFile(char* filename) + { + int _byteValueSumUnk = 0; + + int _fileHandle = MACRO_CALL(OS_Func::_ucrt_open)(filename, _O_BINARY, 0); + if (_fileHandle == -1) { + _byteValueSumUnk = -1; + } else { + char _buf[1024]; + + int _lengthUnk; + do { + _lengthUnk = MACRO_CALL(OS_Func::_ucrt_read)(_fileHandle, _buf, sizeof(_buf)); + for (int _counter = 0; _counter < _lengthUnk; ++_counter) { + _byteValueSumUnk += _buf[_counter]; + } + } while (_lengthUnk != 0); + + MACRO_CALL(OS_Func::_ucrt_close)(_fileHandle); + } + return _byteValueSumUnk; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/loadConfigPathTxt.cpp b/src/OpenSHC/IO/ResourceManager/loadConfigPathTxt.cpp new file mode 100644 index 00000000..e2188028 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/loadConfigPathTxt.cpp @@ -0,0 +1,51 @@ +// disable deprecation warnings for strcpy +#pragma warning(disable : 4996) + +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/string-literals.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x0046C320 + void ResourceManager::loadConfigPathTxt() + { + FILE* _File = MACRO_CALL(OS_Func::_fopen)(s_configpath_txt_005a5a0c, s_rb_005a4e18); + if (!_File) { + return; + } + + MACRO_CALL(OS_Func::_fseek)(_File, 0, FILE_END); + int _count = MACRO_CALL(OS_Func::_ftell)(_File); + MACRO_CALL(OS_Func::_fseek)(_File, 0, FILE_BEGIN); + + if (_count > 500) { + _count = 500; + } + + char _configPathBufferUnk[1000]; + MACRO_CALL(OS_Func::_fread)(_configPathBufferUnk, sizeof(char), _count, _File); + + _configPathBufferUnk[_count] = '\0'; + int index = 0; + for (; index < _count; ++index) { + if (_configPathBufferUnk[index] == '\r' || _configPathBufferUnk[index] == '\n') { + _configPathBufferUnk[index] = '\0'; + break; + } + } + if (index > 2) { + if (_configPathBufferUnk[index + -1] == '\\') { + _configPathBufferUnk[index + -1] = '\0'; + } + this->configPathLoadedUnk_0x7da = true; + strcpy(this->configPathUnk_0x7db, _configPathBufferUnk); + } + + MACRO_CALL(OS_Func::_fclose)(_File); + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/loadMapHeaders.cpp b/src/OpenSHC/IO/ResourceManager/loadMapHeaders.cpp new file mode 100644 index 00000000..c310a602 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/loadMapHeaders.cpp @@ -0,0 +1,58 @@ +// disable deprecation warnings for strcpy and strcat +#pragma warning(disable : 4996) + +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/IO/FilePackager.func.hpp" +#include "OpenSHC/UI/Rendering/TextureRenderCore.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_LoadingBarProgress.hpp" +#include "OpenSHC/Globals/DAT_MapPropertiesState.hpp" +#include "OpenSHC/Globals/DAT_ResourceManager.hpp" +#include "OpenSHC/Globals/DAT_TextureRenderCoreObject.hpp" +#include "OpenSHC/Globals/FilePackagerObj.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00478AE0 + void ResourceManager::loadMapHeaders(BOOLEnum drawLoadingBar) + { + MACRO_CALL_MEMBER(ResourceManager_Func::discoverMapFiles, this)(s_maps_map_005a64b0); + this->loadedMapsCount = this->mapFileCounter; + + for (int mapIndex = 0; mapIndex < this->mapFileCounter; ++mapIndex) { + char* mapName = MACRO_CALL_MEMBER(ResourceManager_Func::mapNames_getLoadedMapNameForIndex, this)(mapIndex); + strcpy(this->mapNames[mapIndex], mapName); + + char resourceFileName[1008]; + strcpy(resourceFileName, mapName); + strcat(resourceFileName, s__map_005a2294); + MACRO_CALL_MEMBER(ResourceManager_Func::resolveResourceFileName, DAT_ResourceManager::ptr)( + FRT_MAPS, resourceFileName); + MACRO_CALL_MEMBER(FilePackager_Func::readMapHeader, FilePackagerObj::ptr)(FALSE); + + this->mapMetaInfoArray[mapIndex].loadedMapsChecksumArray + = MACRO_CALL_MEMBER(ResourceManager_Func::fileHashFunctionByteByByte, DAT_ResourceManager::ptr)(); + this->mapMetaInfoArray[mapIndex].mapType = DAT_GameCore::instance.mapType; + this->mapMetaInfoArray[mapIndex].mapLocked = DAT_GameCore::instance.savedMapLocked; + this->mapMetaInfoArray[mapIndex].mapBalance = DAT_GameCore::instance.savedMapBalance; + this->mapMetaInfoArray[mapIndex].mapEndInt2 = DAT_GameCore::instance.savedMapEndInt2; + this->mapMetaInfoArray[mapIndex].mapPlayerCount = DAT_GameCore::instance.mapPlayerCount; + this->mapMetaInfoArray[mapIndex].int0 = DAT_MapPropertiesState::instance.scenarionMissionType; + this->mapMetaInfoArray[mapIndex].mapType2 = DAT_MapPropertiesState::instance.scenarioMissionSiegeOrInvasion; + + int _progress = mapIndex * 100; + if (drawLoadingBar == TRUE) { + MACRO_CALL_MEMBER( + UI::Rendering::TextureRenderCore_Func::drawLoadingBarUnk, DAT_TextureRenderCoreObject::ptr)( + (Graphics::GmID)((_progress / this->mapFileCounter) + 80 + DAT_LoadingBarProgress::instance), + DAT_LoadingBarProgress::instance + 180); + } + } + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/loadMapMetaByID.cpp b/src/OpenSHC/IO/ResourceManager/loadMapMetaByID.cpp new file mode 100644 index 00000000..cdad9fa6 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/loadMapMetaByID.cpp @@ -0,0 +1,23 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_MapPropertiesState.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x0046C200 + void ResourceManager::loadMapMetaByID(dword id) + { + DAT_GameCore::instance.mapType = this->mapMetaInfoArray[id].mapType; + DAT_GameCore::instance.savedMapLocked = this->mapMetaInfoArray[id].mapLocked; + DAT_GameCore::instance.savedMapBalance = this->mapMetaInfoArray[id].mapBalance; + DAT_GameCore::instance.savedMapEndInt2 = this->mapMetaInfoArray[id].mapEndInt2; + DAT_GameCore::instance.mapPlayerCount = this->mapMetaInfoArray[id].mapPlayerCount; + DAT_MapPropertiesState::instance.scenarionMissionType = this->mapMetaInfoArray[id].int0; + DAT_MapPropertiesState::instance.scenarioMissionSiegeOrInvasion = this->mapMetaInfoArray[id].mapType2; + DAT_GameCore::instance.mapU4Int0_2 = 0; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/mapNames.cpp b/src/OpenSHC/IO/ResourceManager/mapNames.cpp new file mode 100644 index 00000000..ad504e6d --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/mapNames.cpp @@ -0,0 +1,60 @@ +// disable deprecation warnings for strcpy and strcat +#pragma warning(disable : 4996) + +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/IO/FilePackager.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_ResourceManager.hpp" +#include "OpenSHC/Globals/FilePackagerObj.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x0046C2E0 + char* ResourceManager::mapNames_getLoadedMapNameForIndex(int mapIndex) + { + if (mapIndex >= 500) { + return NULL; + } + return this->loadedMapNames[mapIndex]; + } + + // FUNCTION: STRONGHOLDCRUSADER 0x00471C10 + void ResourceManager::mapNames_syncLoadedMapNames() + { + this->mapFileCounter = this->loadedMapsCount; + for (int mapIndex = 0; mapIndex < (int)this->mapFileCounter; ++mapIndex) { + strcpy(MACRO_CALL_MEMBER(ResourceManager_Func::mapNames_getLoadedMapNameForIndex, this)(mapIndex), + this->mapNames[mapIndex]); + } + } + + // FUNCTION: STRONGHOLDCRUSADER 0x00478C60 + void ResourceManager::mapNames_filterMapsIfMapLock() + { + int const currentFileNumber = DAT_ResourceManager::instance.mapFileCounter; + + int id2 = 0; + for (int id1 = 0; id1 < currentFileNumber; ++id1) { + char* mapName = MACRO_CALL_MEMBER( + ResourceManager_Func::mapNames_getLoadedMapNameForIndex, DAT_ResourceManager::ptr)(id1); + + char local_3f0[1008]; + strcpy(local_3f0, mapName); + strcat(local_3f0, s__map_005a2294); + MACRO_CALL_MEMBER(ResourceManager_Func::resolveResourceFileName, this)(FRT_MAPS, local_3f0); + MACRO_CALL_MEMBER(FilePackager_Func::readMapHeader, FilePackagerObj::ptr)(FALSE); + if (DAT_GameCore::instance.savedMapLocked == Map::MLS_EDITABLE) { + MACRO_CALL_MEMBER(ResourceManager_Func::replaceMapNameWith, this)(id1, id2); + ++id2; + } else { + --DAT_ResourceManager::instance.mapFileCounter; + } + } + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/paths.cpp b/src/OpenSHC/IO/ResourceManager/paths.cpp new file mode 100644 index 00000000..6b6604af --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/paths.cpp @@ -0,0 +1,93 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Util/WideCharMultiByteState.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_ResourceManager.hpp" +#include "OpenSHC/Globals/DAT_WideCharMultiByteState.hpp" + +#include "shlobj.h" + +namespace OpenSHC { +namespace IO { + + // NOTE: "string_prependUserPathToString" can likely not be resolved, since the call is optimized and ignores proper + // call conventions in the game. Trying it does not make much sense also, since the strings interact with the + // allocator of the game, causing memory issues if hooked anyway. + + // FUNCTION: STRONGHOLDCRUSADER 0x00477710 + static bool string_prependUserPathToString(std::string& out, char const* path, int csidl) + { + if (DAT_ResourceManager::instance.configPathLoadedUnk_0x7da) { + std::string localStr(DAT_ResourceManager::instance.configPathUnk_0x7db); + out = localStr; + out.append(path); + } else { + // apparently, SHGetFolderPathW only returns a maximum of MAX_PATH, which is 260, so they overdid it + WCHAR pszPath[2000]; + if (SHGetFolderPathW(NULL, csidl | CSIDL_FLAG_CREATE, NULL, NULL, pszPath) < S_OK) { + return false; + } + + WCHAR _wideCharStr[2000]; + GetShortPathNameW(pszPath, _wideCharStr, sizeof(_wideCharStr) / sizeof(WCHAR)); + + CHAR _multiByteStr[2000]; + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteWithSize, + DAT_WideCharMultiByteState::ptr)(_multiByteStr, _wideCharStr, sizeof(_multiByteStr) - 1); + + out.append(_multiByteStr); + out.append(path); + } + if (GetFileAttributesA(out.c_str()) == INVALID_FILE_ATTRIBUTES && !CreateDirectoryA(out.c_str(), NULL)) { + return false; + } + return true; + } + + // FUNCTION: STRONGHOLDCRUSADER 0x004778E0 + std::string ResourceManager::paths_getDocumentsFolderString(bool param_2) + { + std::string suffix(s__Stronghold_Crusader__005a6434); + std::string userPath; + string_prependUserPathToString(userPath, suffix.c_str(), CSIDL_PERSONAL); + if (param_2) { + return userPath; + } else { + return suffix; + } + } + + // Return Value Optimization is not compatible with the resolver, therefore, the call needs to be direct. + + // FUNCTION: STRONGHOLDCRUSADER 0x004779F0 + std::string ResourceManager::paths_getSavesPath(bool param_2) + { + std::string suffix(this->paths_getDocumentsFolderString(false)); + suffix.append(s_Saves__005a644c); + std::string userPath; + string_prependUserPathToString(userPath, suffix.c_str(), CSIDL_PERSONAL); + if (param_2) { + return userPath; + } else { + return suffix; + } + } + + // FUNCTION: STRONGHOLDCRUSADER 0x00477B00 + std::string ResourceManager::paths_getDocumentsMapsFolderString(bool prependUserPath) + { + std::string suffix(this->paths_getDocumentsFolderString(false)); + suffix.append(s_Maps__005a6454); + std::string userPath; + string_prependUserPathToString(userPath, suffix.c_str(), CSIDL_PERSONAL); + if (prependUserPath) { + return userPath; + } else { + return suffix; + } + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/readCurrentResourceIntoDestination.cpp b/src/OpenSHC/IO/ResourceManager/readCurrentResourceIntoDestination.cpp new file mode 100644 index 00000000..8b6d1350 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/readCurrentResourceIntoDestination.cpp @@ -0,0 +1,22 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/OS.func.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00471E50 + BOOLEnum ResourceManager::readCurrentResourceIntoDestination(void* destination, size_t size) + { + char* _Filename = MACRO_CALL_MEMBER(ResourceManager_Func::getFileNameOfCurrentActiveResource, this)(); + this->fileHandle = MACRO_CALL(OS_Func::_ucrt_open)(_Filename, _O_BINARY, 0); + if (this->fileHandle == -1) { + return FALSE; + } + this->loadPositionInCurrentResource = MACRO_CALL(OS_Func::_ucrt_read)(this->fileHandle, destination, size); + MACRO_CALL(OpenSHC::OS_Func::_ucrt_close)(this->fileHandle); + return TRUE; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/readFirstPartOfCurrentResourceIntoMemory.cpp b/src/OpenSHC/IO/ResourceManager/readFirstPartOfCurrentResourceIntoMemory.cpp new file mode 100644 index 00000000..f4e15f84 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/readFirstPartOfCurrentResourceIntoMemory.cpp @@ -0,0 +1,40 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/OS.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00471F10 + BOOLEnum ResourceManager::readFirstPartOfCurrentResourceIntoMemory( + void* destination, int partSize, char* fileExtension) + { + // Why do these not use the complete size? Or it the array not 1001 bytes? But what about the instructions that + // basically use this number? + MACRO_CALL_MEMBER(LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 1000, '\0', this->resourceFileNameArray[0]); + MACRO_CALL_MEMBER(LowLevelMemory_Func::putFileNameAndAppendFileExtension, DAT_LowLevelMemory::ptr)( + this->resourceFileNameArray[this->currentActiveResourceType], this->resourceFileNameArray[0], + fileExtension); + + FileResourceTypeInt tempActiveResource = this->currentActiveResourceType; + this->currentActiveResourceType = NULL; + + char* _Filename = MACRO_CALL_MEMBER(ResourceManager_Func::getFileNameOfCurrentActiveResource, this)(); + this->fileHandle = MACRO_CALL(OS_Func::_ucrt_open)(_Filename, _O_BINARY, 0); + + this->currentActiveResourceType = tempActiveResource; + + if (this->fileHandle == -1) { + return FALSE; + } + this->loadPositionInCurrentResource = MACRO_CALL(OS_Func::_ucrt_read)(this->fileHandle, destination, partSize); + MACRO_CALL(OS_Func::_ucrt_close)(this->fileHandle); + return TRUE; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/readNextPartOfCurrentResourceIntoMemory.cpp b/src/OpenSHC/IO/ResourceManager/readNextPartOfCurrentResourceIntoMemory.cpp new file mode 100644 index 00000000..92e14353 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/readNextPartOfCurrentResourceIntoMemory.cpp @@ -0,0 +1,39 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" +#include "OpenSHC/OS.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00471FC0 + BOOLEnum ResourceManager::readNextPartOfCurrentResourceIntoMemory( + void* destination, int partSize, char* fileExtension) + { + MACRO_CALL_MEMBER(LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + 1000, '\0', this->resourceFileNameArray[0]); + MACRO_CALL_MEMBER(LowLevelMemory_Func::putFileNameAndAppendFileExtension, DAT_LowLevelMemory::ptr)( + this->resourceFileNameArray[this->currentActiveResourceType], this->resourceFileNameArray[0], + fileExtension); + + FileResourceTypeInt tempActiveResource = this->currentActiveResourceType; + this->currentActiveResourceType = NULL; + + char* _Filename = MACRO_CALL_MEMBER(ResourceManager_Func::getFileNameOfCurrentActiveResource, this)(); + this->fileHandle = MACRO_CALL(OS_Func::_ucrt_open)(_Filename, _O_BINARY, 0); + + this->currentActiveResourceType = tempActiveResource; + + if (this->fileHandle == -1) { + return FALSE; + } + MACRO_CALL(OS_Func::_ucrt_lseek)(this->fileHandle, this->loadPositionInCurrentResource, FILE_BEGIN); + this->loadPositionInCurrentResource += MACRO_CALL(OS_Func::_ucrt_read)(this->fileHandle, destination, partSize); + MACRO_CALL(OS_Func::_ucrt_close)(this->fileHandle); + return TRUE; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/replaceMapNameWith.cpp b/src/OpenSHC/IO/ResourceManager/replaceMapNameWith.cpp new file mode 100644 index 00000000..50000914 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/replaceMapNameWith.cpp @@ -0,0 +1,22 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00471CD0 + void ResourceManager::replaceMapNameWith(dword id1, dword id2) + { + if (id1 == id2) { + return; + } + MACRO_CALL_MEMBER(LowLevelMemory_Func::copyData, DAT_LowLevelMemory::ptr)( + 1000, this->loadedMapNames[id1], this->loadedMapNames[id2]); + this->mapFileTimes[id2] = this->mapFileTimes[id1]; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/resetOpenFileNameStruct.cpp b/src/OpenSHC/IO/ResourceManager/resetOpenFileNameStruct.cpp new file mode 100644 index 00000000..21830fbe --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/resetOpenFileNameStruct.cpp @@ -0,0 +1,26 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" +#include "OpenSHC/Globals/DAT_WindowAndDirectDraw.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00471DF0 + void ResourceManager::resetOpenFileNameStruct() + { + MACRO_CALL_MEMBER(LowLevelMemory_Func::fillMemory_ByteValue, DAT_LowLevelMemory::ptr)( + sizeof(this->openFileNameA), '\0', &this->openFileNameA); + this->openFileNameA.lStructSize = sizeof(this->openFileNameA); + this->openFileNameA.hwndOwner = DAT_WindowAndDirectDraw::instance.windowHandle; + this->openFileNameA.lpstrFile = this->strFile; + this->openFileNameA.nMaxFile = 1000; + this->openFileNameA.lpstrFileTitle = this->strFileTitle; + this->openFileNameA.nMaxFileTitle = 1000; + this->openFileNameA.Flags = OFN_NOCHANGEDIR; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/resolveResourceFileName.cpp b/src/OpenSHC/IO/ResourceManager/resolveResourceFileName.cpp new file mode 100644 index 00000000..020fd73a --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/resolveResourceFileName.cpp @@ -0,0 +1,102 @@ +// disable deprecation warnings for strcpy and strcat +#pragma warning(disable : 4996) + +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/IO/FileResourceType.hpp" +#include "OpenSHC/string-macros.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00478360 + void ResourceManager::resolveResourceFileName(FileResourceType resourceType, char const* shortFileName) + { + this->currentActiveResourceType = resourceType; + switch (resourceType) { + case FRT_GM: + strcpy(this->resourceFileNameArray[resourceType], S_GM); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + case FRT_SCENARIOS: + strcpy(this->resourceFileNameArray[resourceType], S_SCENARIOS__005A64F4); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + case FRT_GFX: + strcpy(this->resourceFileNameArray[resourceType], S_GFX__005A5A1C); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + case FRT_GFX8: + strcpy(this->resourceFileNameArray[resourceType], S_GFX8__005A64EC); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + case FRT_CASTLES: + strcpy(this->resourceFileNameArray[resourceType], S_CASTLES__005A64E0); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + case FRT_UNKNOWN: { + // NOTE: Requires direct, non-resolved call due to copy elision. + std::string savePath(this->paths_getSavesPath(true)); + strcpy(this->resourceFileNameArray[resourceType], savePath.c_str()); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + } + + case FRT_HELP: + strcpy(this->resourceFileNameArray[resourceType], S_HELP__005A5A24); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + case FRT_BINKS: + strcpy(this->resourceFileNameArray[resourceType], S_BINKS__005A64D8); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + case FRT_FX: + strcpy(this->resourceFileNameArray[resourceType], S_FX__005A5A2C); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + case FRT_GFX_SPEECH: // FIXME: Wrong name? Should be FRT_FX_SPEECH, or not? + strcpy(this->resourceFileNameArray[resourceType], S_FX_SPEECH__005A64CC); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + case FRT_MAPS: { + strcpy(this->resourceFileNameArray[resourceType], S_MAPS__005A64C4); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + + if (MACRO_CALL_MEMBER(ResourceManager_Func::doesFileExist, this)( + this->resourceFileNameArray[resourceType])) { + return; + } + // NOTE: Requires direct, non-resolved calls due to copy elision. + std::string documentMapsFolder(this->paths_getDocumentsMapsFolderString(true)); + strcpy(this->resourceFileNameArray[resourceType], documentMapsFolder.c_str()); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + } + + case FRT_SCORES: + strcpy(this->resourceFileNameArray[resourceType], S_SCORES__005A64BC); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + case FRT_BMP: + strcpy(this->resourceFileNameArray[resourceType], ""); + strcat(this->resourceFileNameArray[resourceType], shortFileName); + return; + + default: + strcpy(this->resourceFileNameArray[resourceType], shortFileName); + return; + } + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/setGfxFileFilter.cpp b/src/OpenSHC/IO/ResourceManager/setGfxFileFilter.cpp new file mode 100644 index 00000000..997ff1da --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/setGfxFileFilter.cpp @@ -0,0 +1,20 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_TextInputDefinedData.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x0046C450 + void ResourceManager::setGfxFileFilter() + { + this->openFileNameA.lpstrFilter = DAT_TextInputDefinedData::instance.field19_0x710; + this->openFileNameA.nFilterIndex = 1; + this->openFileNameA.lpstrDefExt = DAT_TextInputDefinedData::instance.field19_0x710; + this->openFileNameA.lpstrInitialDir = s_gfx__005a5a1c; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/setHelpFileFilter.cpp b/src/OpenSHC/IO/ResourceManager/setHelpFileFilter.cpp new file mode 100644 index 00000000..c7f26bdc --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/setHelpFileFilter.cpp @@ -0,0 +1,20 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_TextInputDefinedData.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x0046C480 + void ResourceManager::setHelpFileFilter() + { + this->openFileNameA.lpstrFilter = DAT_TextInputDefinedData::instance.field23_0x71c; + this->openFileNameA.nFilterIndex = 1; + this->openFileNameA.lpstrDefExt = DAT_TextInputDefinedData::instance.field23_0x71c; + this->openFileNameA.lpstrInitialDir = s_help__005a5a24; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/setSoundFileFilter.cpp b/src/OpenSHC/IO/ResourceManager/setSoundFileFilter.cpp new file mode 100644 index 00000000..0f97fc51 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/setSoundFileFilter.cpp @@ -0,0 +1,21 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_TextInputDefinedData.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x0046C4B0 + void ResourceManager::setSoundFileFilter() + + { + this->openFileNameA.lpstrFilter = DAT_TextInputDefinedData::instance.field27_0x728; + this->openFileNameA.nFilterIndex = 1; + this->openFileNameA.lpstrDefExt = DAT_TextInputDefinedData::instance.field27_0x728; + this->openFileNameA.lpstrInitialDir = s_fx__005a5a2c; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/showOpenGfxFileDialog.cpp b/src/OpenSHC/IO/ResourceManager/showOpenGfxFileDialog.cpp new file mode 100644 index 00000000..0f677b5a --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/showOpenGfxFileDialog.cpp @@ -0,0 +1,22 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/Input/MouseState.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_MouseState.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00472080 + BOOLEnum ResourceManager::showOpenGfxFileDialog() + { + MACRO_CALL_MEMBER(ResourceManager_Func::resetOpenFileNameStruct, this)(); + MACRO_CALL_MEMBER(ResourceManager_Func::setGfxFileFilter, this)(); + this->openFileNameA.lpstrTitle = s_Select_TGX_file_to_import_005a6268; + MACRO_CALL_MEMBER(OpenSHC::Input::MouseState_Func::resetMouseState2, DAT_MouseState::ptr)(); + return GetOpenFileNameA((LPOPENFILENAMEA) & this->openFileNameA) != NULL; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/showOpenHelpFileDialog.cpp b/src/OpenSHC/IO/ResourceManager/showOpenHelpFileDialog.cpp new file mode 100644 index 00000000..7fef007a --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/showOpenHelpFileDialog.cpp @@ -0,0 +1,21 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/Input/MouseState.func.hpp" + +#include "OpenSHC/Globals/DAT_MouseState.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x004720C0 + BOOLEnum ResourceManager::showOpenHelpFileDialog(LPCSTR param_1) + { + MACRO_CALL_MEMBER(ResourceManager_Func::resetOpenFileNameStruct, this)(); + MACRO_CALL_MEMBER(ResourceManager_Func::setHelpFileFilter, this)(); + this->openFileNameA.lpstrTitle = param_1; + MACRO_CALL_MEMBER(Input::MouseState_Func::resetMouseState2, DAT_MouseState::ptr)(); + return GetOpenFileNameA((LPOPENFILENAMEA) & this->openFileNameA) != NULL; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/showOpenSoundFileDialog.cpp b/src/OpenSHC/IO/ResourceManager/showOpenSoundFileDialog.cpp new file mode 100644 index 00000000..006e9d9b --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/showOpenSoundFileDialog.cpp @@ -0,0 +1,22 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/Input/MouseState.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_MouseState.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00472140 + BOOLEnum ResourceManager::showOpenSoundFileDialog() + { + MACRO_CALL_MEMBER(ResourceManager_Func::resetOpenFileNameStruct, this)(); + MACRO_CALL_MEMBER(ResourceManager_Func::setSoundFileFilter, this)(); + this->openFileNameA.lpstrTitle = s_Select_sound_file_to_import_005a62a0; + MACRO_CALL_MEMBER(Input::MouseState_Func::resetMouseState2, DAT_MouseState::ptr)(); + return GetOpenFileNameA((LPOPENFILENAMEA) & this->openFileNameA) != NULL; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/showSaveHelpFileDialog.cpp b/src/OpenSHC/IO/ResourceManager/showSaveHelpFileDialog.cpp new file mode 100644 index 00000000..08ddde65 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/showSaveHelpFileDialog.cpp @@ -0,0 +1,22 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/Input/MouseState.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_MouseState.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00472100 + BOOLEnum ResourceManager::showSaveHelpFileDialog() + { + MACRO_CALL_MEMBER(OpenSHC::IO::ResourceManager_Func::resetOpenFileNameStruct, this)(); + MACRO_CALL_MEMBER(OpenSHC::IO::ResourceManager_Func::setHelpFileFilter, this)(); + this->openFileNameA.lpstrTitle = s_Select_help_file_to_save_005a6284; + MACRO_CALL_MEMBER(OpenSHC::Input::MouseState_Func::resetMouseState2, DAT_MouseState::ptr)(); + return GetSaveFileNameA((LPOPENFILENAMEA) & this->openFileNameA) != NULL; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/IO/ResourceManager/swapMapDataWithNextMap.cpp b/src/OpenSHC/IO/ResourceManager/swapMapDataWithNextMap.cpp new file mode 100644 index 00000000..078afce8 --- /dev/null +++ b/src/OpenSHC/IO/ResourceManager/swapMapDataWithNextMap.cpp @@ -0,0 +1,26 @@ +#include "../ResourceManager.func.hpp" + +#include "OpenSHC/IO/LowLevelMemory.func.hpp" + +#include "OpenSHC/Globals/DAT_LowLevelMemory.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00471C50 + void ResourceManager::swapMapDataWithNextMap(int _mapFileIndex) + { + MACRO_CALL_MEMBER(LowLevelMemory_Func::copyData, DAT_LowLevelMemory::ptr)( + 1000, this->loadedMapNames[_mapFileIndex], this->resourceFileNameArray); + MACRO_CALL_MEMBER(LowLevelMemory_Func::copyData, DAT_LowLevelMemory::ptr)( + 1000, this->loadedMapNames[_mapFileIndex + 1], this->loadedMapNames[_mapFileIndex]); + MACRO_CALL_MEMBER(LowLevelMemory_Func::copyData, DAT_LowLevelMemory::ptr)( + 1000, this->resourceFileNameArray, this->loadedMapNames[_mapFileIndex + 1]); + + dword const nextFileTime = this->mapFileTimes[_mapFileIndex]; + this->mapFileTimes[_mapFileIndex] = this->mapFileTimes[_mapFileIndex + 1]; + this->mapFileTimes[_mapFileIndex + 1] = nextFileTime; + } + +} // namespace IO +} // namespace OpenSHC diff --git a/src/OpenSHC/OS/OS.cpp b/src/OpenSHC/OS/OS.cpp index d38226ce..1200943c 100644 --- a/src/OpenSHC/OS/OS.cpp +++ b/src/OpenSHC/OS/OS.cpp @@ -128,6 +128,9 @@ namespace OS { // STUB: STRONGHOLDCRUSADER 0x005824CD int __cdecl __toupper(int _C) { return toupper(_C); } + // STUB: STRONGHOLDCRUSADER 0x005826FB + int __cdecl _ucrt_tell(int handle) { return _tell(handle); } + // STUB: STRONGHOLDCRUSADER 0x0058277E int _ucrt_lseek(int fileDescriptor, long lDistanceToMove, DWORD moveMethod) { @@ -135,7 +138,10 @@ namespace OS { } // STUB: STRONGHOLDCRUSADER 0x005835BB - int __strnicmp(char* _Str1, char* _Str2, size_t _MaxCount) { return _strnicmp(_Str1, _Str2, _MaxCount); } + int __strnicmp(char const* _Str1, char const* _Str2, size_t _MaxCount) + { + return _strnicmp(_Str1, _Str2, _MaxCount); + } // STUB: STRONGHOLDCRUSADER 0x00583D55 void _exit(int _Code) { exit(_Code); } diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index a31b91b1..c00bd8f3 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -20899,25 +20899,25 @@ SHC_3BB0A8C1_0x0046BD50 | 0.0% | Pending SHC_3BB0A8C1_0x0046BDB0 | 0.0% | Pending -SHC_3BB0A8C1_0x0046C200 | 0.0% | Pending +SHC_3BB0A8C1_0x0046C200 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0046C280 | 0.0% | Pending +SHC_3BB0A8C1_0x0046C280 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0046C2E0 | 0.0% | Pending +SHC_3BB0A8C1_0x0046C2E0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0046C300 | 0.0% | Pending +SHC_3BB0A8C1_0x0046C300 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0046C320 | 0.0% | Pending +SHC_3BB0A8C1_0x0046C320 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0046C420 | 0.0% | Pending +SHC_3BB0A8C1_0x0046C420 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0046C450 | 0.0% | Pending +SHC_3BB0A8C1_0x0046C450 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0046C480 | 0.0% | Pending +SHC_3BB0A8C1_0x0046C480 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0046C4B0 | 0.0% | Pending +SHC_3BB0A8C1_0x0046C4B0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x0046C4E0 | 0.0% | Pending +SHC_3BB0A8C1_0x0046C4E0 | 100.0% | Reimplemented SHC_3BB0A8C1_0x0046C520 | 0.0% | Pending @@ -21335,37 +21335,37 @@ SHC_3BB0A8C1_0x00471A80 | 0.0% | Pending SHC_3BB0A8C1_0x00471AA0 | 0.0% | Pending -SHC_3BB0A8C1_0x00471BE0 | 0.0% | Pending +SHC_3BB0A8C1_0x00471BE0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00471C10 | 0.0% | Pending +SHC_3BB0A8C1_0x00471C10 | 100.0% | Reimplemented, requires called function to be active -SHC_3BB0A8C1_0x00471C50 | 0.0% | Pending +SHC_3BB0A8C1_0x00471C50 | 100.0% | Reimplemented, requires called function and subfunction to be active -SHC_3BB0A8C1_0x00471CD0 | 0.0% | Pending +SHC_3BB0A8C1_0x00471CD0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00471D30 | 0.0% | Pending +SHC_3BB0A8C1_0x00471D30 | 81.1% | Reimplemented, but register diffs; logic is sound -SHC_3BB0A8C1_0x00471DC0 | 0.0% | Pending +SHC_3BB0A8C1_0x00471DC0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00471DF0 | 0.0% | Pending +SHC_3BB0A8C1_0x00471DF0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00471E50 | 0.0% | Pending +SHC_3BB0A8C1_0x00471E50 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00471EB0 | 0.0% | Pending +SHC_3BB0A8C1_0x00471EB0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00471F10 | 0.0% | Pending +SHC_3BB0A8C1_0x00471F10 | 100.0% | Reimplemented, needs LowLevelMemory functions active -SHC_3BB0A8C1_0x00471FC0 | 0.0% | Pending +SHC_3BB0A8C1_0x00471FC0 | 100.0% | Reimplemented, needs LowLevelMemory functions active -SHC_3BB0A8C1_0x00472080 | 0.0% | Pending +SHC_3BB0A8C1_0x00472080 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004720C0 | 0.0% | Pending +SHC_3BB0A8C1_0x004720C0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00472100 | 0.0% | Pending +SHC_3BB0A8C1_0x00472100 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00472140 | 0.0% | Pending +SHC_3BB0A8C1_0x00472140 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00472180 | 0.0% | Pending +SHC_3BB0A8C1_0x00472180 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004721D0 | 0.0% | Pending @@ -22009,13 +22009,13 @@ SHC_3BB0A8C1_0x00477670 | 0.0% | Pending SHC_3BB0A8C1_0x00477690 | 0.0% | Pending -SHC_3BB0A8C1_0x00477710 | 0.0% | Pending +SHC_3BB0A8C1_0x00477710 | 100.0% | Reimplemented; static helper, not resolver due to optimized call convention -SHC_3BB0A8C1_0x004778E0 | 0.0% | Pending +SHC_3BB0A8C1_0x004778E0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x004779F0 | 0.0% | Pending +SHC_3BB0A8C1_0x004779F0 | 100.0% | Reimplemented; Return value optimization, always needs SHC_3BB0A8C1_0x004778E0 active -SHC_3BB0A8C1_0x00477B00 | 0.0% | Pending +SHC_3BB0A8C1_0x00477B00 | 100.0% | Reimplemented; Return value optimization, always needs SHC_3BB0A8C1_0x004778E0 active SHC_3BB0A8C1_0x00477C10 | 0.0% | Pending @@ -22033,11 +22033,11 @@ SHC_3BB0A8C1_0x00477EA0 | 0.0% | Pending SHC_3BB0A8C1_0x00477EC0 | 0.0% | Pending -SHC_3BB0A8C1_0x00477EE0 | 0.0% | Pending +SHC_3BB0A8C1_0x00477EE0 | 86.0% | Reimplemented, heavy stack reorder mismatch, logic should be sound; Return value optimization, always needs SHC_3BB0A8C1_0x00477B00 active SHC_3BB0A8C1_0x00478010 | 0.0% | Pending -SHC_3BB0A8C1_0x00478360 | 0.0% | Pending +SHC_3BB0A8C1_0x00478360 | 100.0% | Reimplemented SHC_3BB0A8C1_0x00478500 | 0.0% | Pending @@ -22093,9 +22093,9 @@ SHC_3BB0A8C1_0x00478A50 | 0.0% | Pending SHC_3BB0A8C1_0x00478AC0 | 0.0% | Pending -SHC_3BB0A8C1_0x00478AE0 | 0.0% | Pending +SHC_3BB0A8C1_0x00478AE0 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00478C60 | 0.0% | Pending +SHC_3BB0A8C1_0x00478C60 | 100.0% | Reimplemented, needs SHC_3BB0A8C1_0x0046C2E0 active SHC_3BB0A8C1_0x00478D30 | 0.0% | Pending