Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
LittlePlanetCD committed Jun 24, 2024
2 parents 8c70049 + 88e8aba commit f75be29
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 205 deletions.
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,16 @@ endif()
target_include_directories(RetroEngine PRIVATE
RSDKv4/
RSDKv4/NativeObjects/
dependencies/all/asio/asio/include/
dependencies/all/stb-image/
dependencies/all/tinyxml2/
)

if(RETRO_NETWORKING)
target_include_directories(RetroEngine PRIVATE
dependencies/all/asio/asio/include/
)
endif()

if(DEFINED DEP_PATH)
target_include_directories(RetroEngine PRIVATE
dependencies/${DEP_PATH}/
Expand Down
29 changes: 18 additions & 11 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
### Q: How do I set this up?
A: You can find a tutorial for setting up both the game and mods [here](https://gamebanana.com/tuts/14066). Alternatively, opening the decompilation without any game assets present will generate a TXT file containing a brief guide to setting them up.

### Q: Why is the DLC disabled in release builds and autobuilds?
A: Long story short, it's to minimize piracy and ensure an extra layer of legal protection for Sonic Origins Plus. Giving players paid content for free is not the goal of this project.

### Q: The screen is tearing, how do I fix it?
A: Try turning on VSync in settings.ini.

### Q: I'm on Windows and experiencing issues such as mods not appearing in the mod menu, what's wrong?
A: A likely reason for this is that you put the decomp in a directory that's managed by OneDrive (Desktop, Downloads, etc). These directories are known to cause issues, so move your decomp installation elsewhere, such as the root of the C drive or another drive. If it's still not working, try redownloading and reinstalling the decomp.
### Q: Why is my game is running faster than it's supposed to?
A: The Retro Engine has all of its engine and game logic tied to the framerate, meaning the faster your refresh rate is, the faster the game runs. You can fix this by turning off VSync in settings.ini or by changing your device's refresh rate.

### Q: I'm on Windows and experiencing issues such as crashes or mods not appearing in the mod menu, what's wrong?
A: A likely reason for this is that you put the decomp in a directory in your user folder (Desktop, Downloads, Documents, etc). These directories are known to cause issues, so move your decomp installation elsewhere, such as the root of the C drive or another drive. If it's still not working, try redownloading and reinstalling the decomp.

### Q: I found a bug!
A: Submit an issue in the issues tab and we _might_ fix it in the main branch. Don't expect any major future releases, however.
A: Submit an issue in the Issues tab and we might fix it. Keep in mind that this is a decompilation, so bugs that exist in official releases will most likely not be fixed here.


# Using Mobile RSDK Files
### Q: Why does pressing B pause the game during gameplay?
Expand All @@ -21,26 +22,32 @@ A: This is a known script issue with most Sega Forever versions of the games. Us
### Q: Why is the default life count 1 instead of 3?
A: This is due to a change made in recent Sega Forever versions of the games. Using the [decompiled scripts](https://github.com/Rubberduckycooly/Sonic-1-Sonic-2-2013-Script-Decompilation) should fix it in most instances.


# Using Origins RSDK Files
You can find a guide for fixing most of these issues [here](https://gamebanana.com/tuts/16686).

### Q: Why doesn't using the datafile work?
A: The RSDK files from Sonic Origins are encrypted in the RSDKv5 datapack format, not the RSDKv4 format. Repacking the files in the correct format or using Data Folder Mode will fix the issue.
A: The RSDK files from Sonic Origins are encrypted as RSDKv5 datapacks, not RSDKv4 ones. Using Data Folder Mode or repacking the files in the correct format will fix the issue.

### Q: Why is there no audio?
A: Sonic Origins doesn't have any music or sound effects contained in the games' data files, instead storing and handling all in-game audio itself through Hedgehog Engine 2. You can fix this by simply inserting the audio files from the mobile versions of the games. Sound effects added in Origins will have to be inserted manually.
A: Sonic Origins doesn't have any music or sound effects contained in the games' data files, instead storing and handling all in-game audio itself through Hedgehog Engine 2. You can fix this by simply inserting the audio files from the mobile versions of the games. Sound effects new to Origins will have to be inserted manually.

### Q: The game crashes when trying to load the main menu or pause screen, what's wrong?
A: Similar to above, Origins removes some of the assets for the original mobile versions' menus. Also similar to above, the fix is to insert those files from the mobile versions.

### Q: Why is the Drop Dash disabled by default? How do I turn it on?
A: By default, the game mode is set to Classic Mode, which disables the Drop Dash. The only way to change this is through a mod, either by changing the default value of the `game.playMode` global variable in `GameConfig.bin` or by setting the variable to another value via scripts.
A: By default, the game mode is set to Classic Mode, which disables the Drop Dash. The only way to change this is through a mod.

### Q: How do I play as Amy?
A: Sonic Team implemented Amy in a way where she isn't playable on the decomp out of the box. This can be fixed via mods. **Do not ask about this in an issue, as we will not be able to help you.**
There are also checks implemented in the engine to prevent playing as Amy on release builds and autobuilds.
A: Sonic Team implemented Amy in a way where she isn't playable on the decomp out of the box. This can be fixed via mods. There are also checks implemented in the engine to prevent playing as Amy on release builds and autobuilds.

### Q: Why is the DLC disabled in release builds and autobuilds?
A: Long story short, it's to minimize piracy and ensure an extra layer of legal protection for Sonic Origins Plus. Giving players paid content for free is not the goal of this project.

### Q: Why doesn't local 2P VS work in Sonic 2?
A: In the version of the Retro Engine that Origins uses (RSDKv5U), certain features that local multiplayer uses, such as splitscreen and multiple controller support, rely on tech found in RSDKv5. This is a decompilation of standalone RSDKv4, and recreating this tech is outside of the scope of the project.


# Miscellaneous
### Q: Will you do a decompilation for Sonic CD (2011)?
A: I already have! You can find it [here](https://github.com/Rubberduckycooly/Sonic-CD-11-Decompilation).
Expand Down
2 changes: 1 addition & 1 deletion RSDKv4/Drawing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,7 @@ void DrawStageGFX()
#if RETRO_REV03
#if !RETRO_USE_ORIGINAL_CODE
// Hacky fix for Tails Object not working properly in special stages on non-Origins bytecode
if (forceUseScripts || GetGlobalVariableID("game.playMode") != 0xFF)
if (forceUseScripts || Engine.usingOrigins)
#endif
DrawObjectList(7);
#endif
Expand Down
4 changes: 0 additions & 4 deletions RSDKv4/Networking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ int dcError = 0;
float lastPing = 0;

bool waitingForPing = false;
bool waitForVerify = false;

uint64_t lastTime = 0;

Expand Down Expand Up @@ -204,7 +203,6 @@ class NetworkSession
return;
}
case SV_VERIFY_CLEAR: {
// waitForVerify = false;
repeat.header = 0x80;
return;
}
Expand Down Expand Up @@ -281,8 +279,6 @@ void SendData(bool verify)
send.header = CL_DATA + verify;
send.data.multiData = multiplayerDataOUT;
session->write(send, verify);
// if (verify)
// waitForVerify = true;
}

void DisconnectNetwork(bool finalClose)
Expand Down
1 change: 0 additions & 1 deletion RSDKv4/Networking.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ extern int networkPort;
extern float lastPing;
extern int dcError;
extern bool waitingForPing;
extern bool waitForVerify;

struct MultiplayerData {
int type;
Expand Down
51 changes: 31 additions & 20 deletions RSDKv4/Reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,19 @@ bool CheckRSDKFile(const char *filePath)

StrCopy(rsdkContainer.packNames[rsdkContainer.packCount], filePathBuffer);

ushort fileCount = 0;
fRead(&fileCount, 2, 1, cFileHandle);
byte b[4];
fRead(&b, 2, 1, cFileHandle);
ushort fileCount = (b[1] << 8) | (b[0] << 0);
for (int f = 0; f < fileCount; ++f) {
for (int y = 0; y < 16; y += 4) {
fRead(&rsdkContainer.files[f].hash[y + 3], 1, 1, cFileHandle);
fRead(&rsdkContainer.files[f].hash[y + 2], 1, 1, cFileHandle);
fRead(&rsdkContainer.files[f].hash[y + 1], 1, 1, cFileHandle);
fRead(&rsdkContainer.files[f].hash[y + 0], 1, 1, cFileHandle);
for (int y = 0; y < 4; ++y) {
fRead(b, 1, 4, cFileHandle);
rsdkContainer.files[f].hash[y] = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3] << 0);
}

fRead(&rsdkContainer.files[f].offset, 4, 1, cFileHandle);
fRead(&rsdkContainer.files[f].filesize, 4, 1, cFileHandle);
fRead(b, 4, 1, cFileHandle);
rsdkContainer.files[f].offset = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0] << 0);
fRead(b, 4, 1, cFileHandle);
rsdkContainer.files[f].filesize = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0] << 0);

rsdkContainer.files[f].encrypted = (rsdkContainer.files[f].filesize & 0x80000000);
rsdkContainer.files[f].filesize &= 0x7FFFFFFF;
Expand Down Expand Up @@ -105,16 +106,16 @@ int CheckFileInfo(const char *filepath)
{
char pathBuf[0x100];
StrCopy(pathBuf, filepath);
byte buffer[0x10];
uint hash[4];
int len = StrLength(pathBuf);
GenerateMD5FromString(pathBuf, len, buffer);
GenerateMD5FromString(pathBuf, len, &hash[0], &hash[1], &hash[2], &hash[3]);

for (int f = 0; f < rsdkContainer.fileCount; ++f) {
RSDKFileInfo *file = &rsdkContainer.files[f];

bool match = true;
for (int h = 0; h < 0x10; ++h) {
if (buffer[h] != file->hash[h]) {
for (int h = 0; h < 4; ++h) {
if (hash[h] != file->hash[h]) {
match = false;
break;
}
Expand Down Expand Up @@ -250,16 +251,16 @@ bool LoadFile(const char *filePath, FileInfo *fileInfo)
if (Engine.usingDataFile) {
StringLowerCase(fileInfo->fileName, filePath);
StrCopy(fileName, fileInfo->fileName);
byte buffer[0x10];
uint hash[4];
int len = StrLength(fileInfo->fileName);
GenerateMD5FromString(fileInfo->fileName, len, buffer);
GenerateMD5FromString(fileInfo->fileName, len, &hash[0], &hash[1], &hash[2], &hash[3]);

for (int f = 0; f < rsdkContainer.fileCount; ++f) {
RSDKFileInfo *file = &rsdkContainer.files[f];

bool match = true;
for (int h = 0; h < 0x10; ++h) {
if (buffer[h] != file->hash[h]) {
for (int h = 0; h < 4; ++h) {
if (hash[h] != file->hash[h]) {
match = false;
break;
}
Expand Down Expand Up @@ -351,31 +352,41 @@ bool LoadFile(const char *filePath, FileInfo *fileInfo)
void GenerateELoadKeys(uint key1, uint key2)
{
char buffer[0x20];
byte hash[0x10];
uint hash[0x4];

// StringA
ConvertIntegerToString(buffer, key1);
int len = StrLength(buffer);
GenerateMD5FromString(buffer, len, hash);
GenerateMD5FromString(buffer, len, &hash[0], &hash[1], &hash[2], &hash[3]);

#if !RETRO_USE_ORIGINAL_CODE
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j) encryptionStringA[i * 4 + j] = (hash[i] >> (8 * (j ^ 3))) & 0xFF;
#else
for (int y = 0; y < 0x10; y += 4) {
encryptionStringA[y + 3] = hash[y + 0];
encryptionStringA[y + 2] = hash[y + 1];
encryptionStringA[y + 1] = hash[y + 2];
encryptionStringA[y + 0] = hash[y + 3];
}
#endif

// StringB
ConvertIntegerToString(buffer, key2);
len = StrLength(buffer);
GenerateMD5FromString(buffer, len, hash);
GenerateMD5FromString(buffer, len, &hash[0], &hash[1], &hash[2], &hash[3]);

#if !RETRO_USE_ORIGINAL_CODE
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j) encryptionStringB[i * 4 + j] = (hash[i] >> (8 * (j ^ 3))) & 0xFF;
#else
for (int y = 0; y < 0x10; y += 4) {
encryptionStringB[y + 3] = hash[y + 0];
encryptionStringB[y + 2] = hash[y + 1];
encryptionStringB[y + 1] = hash[y + 2];
encryptionStringB[y + 0] = hash[y + 3];
}
#endif
}

const uint ENC_KEY_2 = 0x24924925;
Expand Down
2 changes: 1 addition & 1 deletion RSDKv4/Reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ struct FileInfo {
};

struct RSDKFileInfo {
byte hash[0x10];
uint hash[4];
int offset;
int filesize;
bool encrypted;
Expand Down
4 changes: 4 additions & 0 deletions RSDKv4/RetroEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,10 @@ bool RetroEngine::LoadGameConfig(const char *filePath)
startList_Game = STAGELIST_BONUS;
startStage_Game = 0xFE;
}

#if RETRO_REV03
Engine.usingOrigins = GetGlobalVariableID("game.playMode") != 0xFF;
#endif
#endif

return loaded;
Expand Down
5 changes: 4 additions & 1 deletion RSDKv4/RetroEngine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ typedef unsigned int uint;
#define RETRO_DEVICETYPE (RETRO_STANDARD)
#else
//#error "No Platform was defined"
#define RETRO_PLATFORM (RETRO_WIN)
#define RETRO_PLATFORM (RETRO_LINUX)
#define RETRO_DEVICETYPE (RETRO_STANDARD)
#endif

Expand Down Expand Up @@ -366,6 +366,9 @@ class RetroEngine
#endif
bool usingDataFile = false;
bool usingBytecode = false;
#if RETRO_REV03 && !RETRO_USE_ORIGINAL_CODE
bool usingOrigins = false;
#endif

char dataFile[RETRO_PACKFILE_COUNT][0x80];

Expand Down
58 changes: 28 additions & 30 deletions RSDKv4/Scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ void ProcessStage(void)
#if RETRO_REV03
#if !RETRO_USE_ORIGINAL_CODE
// Hacky fix for Tails Object not working properly in special stages on non-Origins bytecode
if (forceUseScripts || GetGlobalVariableID("game.playMode") != 0xFF)
if (forceUseScripts || Engine.usingOrigins)
#endif
DrawObjectList(7);
#endif
Expand Down Expand Up @@ -359,40 +359,38 @@ void ProcessStage(void)
PauseSound();
}

if (!waitForVerify) {
if (timeEnabled) {
if (++frameCounter == 60) {
frameCounter = 0;
if (++stageSeconds > 59) {
stageSeconds = 0;
if (++stageMinutes > 59)
stageMinutes = 0;
}
if (timeEnabled) {
if (++frameCounter == 60) {
frameCounter = 0;
if (++stageSeconds > 59) {
stageSeconds = 0;
if (++stageMinutes > 59)
stageMinutes = 0;
}
stageMilliseconds = 100 * frameCounter / 60;
}
else {
frameCounter = 60 * stageMilliseconds / 100;
}
stageMilliseconds = 100 * frameCounter / 60;
}
else {
frameCounter = 60 * stageMilliseconds / 100;
}

// Update
Process2PObjects();
// Update
Process2PObjects();

if (cameraTarget > -1) {
if (cameraEnabled == 1) {
switch (cameraStyle) {
case CAMERASTYLE_FOLLOW: SetPlayerScreenPosition(&objectEntityList[cameraTarget]); break;
case CAMERASTYLE_EXTENDED:
case CAMERASTYLE_EXTENDED_OFFSET_L:
case CAMERASTYLE_EXTENDED_OFFSET_R: SetPlayerScreenPositionCDStyle(&objectEntityList[cameraTarget]); break;
case CAMERASTYLE_HLOCKED: SetPlayerHLockedScreenPosition(&objectEntityList[cameraTarget]); break;
default: break;
}
}
else {
SetPlayerLockedScreenPosition(&objectEntityList[cameraTarget]);
if (cameraTarget > -1) {
if (cameraEnabled == 1) {
switch (cameraStyle) {
case CAMERASTYLE_FOLLOW: SetPlayerScreenPosition(&objectEntityList[cameraTarget]); break;
case CAMERASTYLE_EXTENDED:
case CAMERASTYLE_EXTENDED_OFFSET_L:
case CAMERASTYLE_EXTENDED_OFFSET_R: SetPlayerScreenPositionCDStyle(&objectEntityList[cameraTarget]); break;
case CAMERASTYLE_HLOCKED: SetPlayerHLockedScreenPosition(&objectEntityList[cameraTarget]); break;
default: break;
}
}
else {
SetPlayerLockedScreenPosition(&objectEntityList[cameraTarget]);
}
}

ProcessParallaxAutoScroll();
Expand Down Expand Up @@ -484,7 +482,7 @@ void ProcessStage(void)
#if RETRO_REV03
#if !RETRO_USE_ORIGINAL_CODE
// Hacky fix for Tails Object not working properly in special stages on non-Origins bytecode
if (forceUseScripts || GetGlobalVariableID("game.playMode") != 0xFF)
if (forceUseScripts || Engine.usingOrigins)
#endif
DrawObjectList(7);
#endif
Expand Down
4 changes: 2 additions & 2 deletions RSDKv4/Script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3392,7 +3392,7 @@ void ProcessScript(int scriptCodeStart, int jumpTableStart, byte scriptEvent)
#if RETRO_REV03 && !RETRO_USE_ORIGINAL_CODE
bool inputCheck = true; // Default to true for mobile bytecode
// If we're using the scripts or an Origins datafile, check the array value
if (forceUseScripts || GetGlobalVariableID("game.playMode") != 0xFF)
if (forceUseScripts || Engine.usingOrigins)
inputCheck = arrayVal <= 1;
#endif

Expand Down Expand Up @@ -5677,7 +5677,7 @@ void ProcessScript(int scriptCodeStart, int jumpTableStart, byte scriptEvent)
#if RETRO_REV03 && !RETRO_USE_ORIGINAL_CODE
bool inputCheck = true; // Default to true for mobile bytecode
// If we're using the scripts or an Origins datafile, check the array value
if (forceUseScripts || GetGlobalVariableID("game.playMode") != 0xFF)
if (forceUseScripts || Engine.usingOrigins)
inputCheck = arrayVal <= 1;
#endif

Expand Down
Loading

0 comments on commit f75be29

Please sign in to comment.