Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0ccd22d
reimplement: SHC_3BB0A8C1_0x00471BE0 100%
TheRedDaemon Aug 15, 2026
d523720
reimplement: SHC_3BB0A8C1_0x0046C200 100%
TheRedDaemon Aug 15, 2026
c7032fa
reimplement: SHC_3BB0A8C1_0x0046C280 100%
TheRedDaemon Aug 15, 2026
4ed88b7
reimplement: SHC_3BB0A8C1_0x0046C2E0 100%
TheRedDaemon Aug 15, 2026
a64457c
reimplement: SHC_3BB0A8C1_0x0046C300 100%
TheRedDaemon Aug 15, 2026
e6c3226
reimplement: SHC_3BB0A8C1_0x0046C320 100%
TheRedDaemon Aug 15, 2026
f190aca
reimplement: SHC_3BB0A8C1_0x0046C420 100%
TheRedDaemon Aug 15, 2026
655134c
reimplement: SHC_3BB0A8C1_0x0046C450 100%
TheRedDaemon Aug 15, 2026
0a4bde4
reimplement: SHC_3BB0A8C1_0x0046C480 100%
TheRedDaemon Aug 15, 2026
089d30b
reimplement: SHC_3BB0A8C1_0x0046C4B0 100%
TheRedDaemon Aug 15, 2026
d0bfaff
reimplement: SHC_3BB0A8C1_0x0046C4E0 100%
TheRedDaemon Aug 15, 2026
10777e3
reimplement: SHC_3BB0A8C1_0x00471C10 100%
TheRedDaemon Aug 15, 2026
40b59b5
reimplement: SHC_3BB0A8C1_0x00471C50 100%
TheRedDaemon Aug 16, 2026
83ad6ec
reimplement: SHC_3BB0A8C1_0x00471CD0 100%
TheRedDaemon Aug 16, 2026
5816702
reimplement: SHC_3BB0A8C1_0x00471D30 81.1%
TheRedDaemon Aug 16, 2026
c3fc436
reimplement: SHC_3BB0A8C1_0x00471DC0 100%
TheRedDaemon Aug 16, 2026
69144a1
reimplement: SHC_3BB0A8C1_0x00471DF0 100%
TheRedDaemon Aug 16, 2026
2a6c575
reimplement: SHC_3BB0A8C1_0x00471E50 100%
TheRedDaemon Aug 16, 2026
198ed81
reimplement: SHC_3BB0A8C1_0x00471EB0 100%
TheRedDaemon Aug 16, 2026
f1ea714
reimplement: SHC_3BB0A8C1_0x00471F10 100%
TheRedDaemon Aug 16, 2026
1d97fa3
reimplement: SHC_3BB0A8C1_0x00471FC0 100%
TheRedDaemon Aug 16, 2026
cabd478
reimplement: SHC_3BB0A8C1_0x00472080 100%
TheRedDaemon Aug 16, 2026
7b92699
reimplement: SHC_3BB0A8C1_0x004720C0 100%
TheRedDaemon Aug 16, 2026
d726f50
reimplement: SHC_3BB0A8C1_0x00472100 100%
TheRedDaemon Aug 16, 2026
c34f3a0
reimplement: SHC_3BB0A8C1_0x00472140 100%
TheRedDaemon Aug 16, 2026
2d3cd62
reimplement: SHC_3BB0A8C1_0x00472180 100%
TheRedDaemon Aug 16, 2026
9f10697
reimplement: SHC_3BB0A8C1_0x00477710 and SHC_3BB0A8C1_0x004778E0 100%
TheRedDaemon Aug 17, 2026
8aaa352
reimplement: SHC_3BB0A8C1_0x004779F0 100%
TheRedDaemon Aug 17, 2026
794edf6
reimplement: SHC_3BB0A8C1_0x00477B00 100%
TheRedDaemon Aug 17, 2026
d8193f3
reimplement: SHC_3BB0A8C1_0x00477EE0 still issues
TheRedDaemon Aug 17, 2026
9a778b4
reimplement: SHC_3BB0A8C1_0x00477EE0 86.0%
TheRedDaemon Aug 18, 2026
4b35d8a
reimplement: SHC_3BB0A8C1_0x00478C60 100%
TheRedDaemon Aug 18, 2026
f83869a
reimplement: SHC_3BB0A8C1_0x00477EE0 add small fixme comment
TheRedDaemon Aug 19, 2026
8847a9e
reimplement: SHC_3BB0A8C1_0x00478AE0 100%
TheRedDaemon Aug 19, 2026
e33dc2f
reimplement: SHC_3BB0A8C1_0x00478360 100%, but literals still in file
TheRedDaemon Aug 20, 2026
fb415ba
reimplement: SHC_3BB0A8C1_0x00478360 now using macros
TheRedDaemon Aug 21, 2026
2cd80a2
feat(docs): extended cheat sheet regarding strings
TheRedDaemon Aug 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions IMPLEMENTATION_CHEAT_SHEET.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
7 changes: 5 additions & 2 deletions cmake/compiler-flags-gl.txt
Original file line number Diff line number Diff line change
@@ -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
22 changes: 22 additions & 0 deletions src/OpenSHC/IO/ResourceManager/Constructor_ResourceManager.cpp
Original file line number Diff line number Diff line change
@@ -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
204 changes: 204 additions & 0 deletions src/OpenSHC/IO/ResourceManager/discoverMapFiles.cpp
Original file line number Diff line number Diff line change
@@ -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(&currentFileTime.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
20 changes: 20 additions & 0 deletions src/OpenSHC/IO/ResourceManager/doesFileExist.cpp
Original file line number Diff line number Diff line change
@@ -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
21 changes: 21 additions & 0 deletions src/OpenSHC/IO/ResourceManager/doesFileOfActiveResourceExist.cpp
Original file line number Diff line number Diff line change
@@ -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
33 changes: 33 additions & 0 deletions src/OpenSHC/IO/ResourceManager/fileHashFunctionByteByByte.cpp
Original file line number Diff line number Diff line change
@@ -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
20 changes: 20 additions & 0 deletions src/OpenSHC/IO/ResourceManager/getChecksumOfMapByName.cpp
Original file line number Diff line number Diff line change
@@ -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
Loading