diff --git a/CMakeLists.txt b/CMakeLists.txt index 35830147c..f64e2b0b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ set(EXECUTABLE re3) +set(STEAMID 12100) cmake_minimum_required(VERSION 3.8) project(${EXECUTABLE} C CXX) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b4660a6d..2104153f7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,7 +39,14 @@ target_compile_definitions(${EXECUTABLE} $,DEBUG,NDEBUG> LIBRW RE3_NO_AUTOLINK + RELOCATABLE ) +if(STEAMID) + target_compile_definitions(${EXECUTABLE} + PRIVATE + STEAMID=${STEAMID} + ) +endif() if(LIBRW_PLATFORM_D3D9) target_compile_definitions(${EXECUTABLE} @@ -109,6 +116,9 @@ set_target_properties(${EXECUTABLE} CXX_STANDARD 11 CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON + VS_DEBUGGER_ENVIRONMENT "GTA3DIR=$" + VS_DEBUGGER_COMMAND_ARGUMENTS "-console" + VS_JUST_MY_CODE_DEBUGGING ON ) if(RE3_INSTALL) diff --git a/src/audio/AudioSamples.h b/src/audio/AudioSamples.h index df64521c7..b36b4de8c 100644 --- a/src/audio/AudioSamples.h +++ b/src/audio/AudioSamples.h @@ -1,7 +1,5 @@ #pragma once -#include "common.h" - enum eSfxSample { SFX_CAR_HORN_JEEP = 0, diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index 74ed86f46..bf7151813 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -1,9 +1,11 @@ +#ifdef AUDIO_OAL #include "common.h" -#ifdef AUDIO_OAL #include "stream.h" #include "sampman.h" +#include "relocatable.h" + #if defined _MSC_VER && !defined RE3_NO_AUTOLINK #ifdef AUDIO_OAL_USE_SNDFILE #pragma comment( lib, "libsndfile-1.lib" ) @@ -213,7 +215,7 @@ class CWavFile : public IDecoder public: CWavFile(const char* path) : m_bIsOpen(false), m_DataStartOffset(0), m_nSampleCount(0), m_nSamplesPerBlock(0), m_pAdpcmBuffer(nil), m_ppPcmBuffers(nil), m_pAdpcmDecoders(nil) { - m_pFile = fopen(path, "rb"); + m_pFile = reloc_fopen(path, "rb"); if (!m_pFile) return; #define CLOSE_ON_ERROR(op)\ @@ -402,7 +404,7 @@ class CSndFile : public IDecoder m_pfSound(nil) { memset(&m_soundInfo, 0, sizeof(m_soundInfo)); - m_pfSound = sf_open(path, SFM_READ, &m_soundInfo); + m_pfSound = sf_open(reloc_realpath(path), SFM_READ, &m_soundInfo); } ~CSndFile() @@ -489,8 +491,8 @@ class CMP3File : public IDecoder long rate = 0; int channels = 0; int encoding = 0; - - m_bOpened = mpg123_open(m_pMH, path) == MPG123_OK + + m_bOpened = mpg123_open(m_pMH, reloc_realpath(path)) == MPG123_OK && mpg123_getformat(m_pMH, &rate, &channels, &encoding) == MPG123_OK; m_nRate = rate; m_nChannels = channels; @@ -669,7 +671,7 @@ class CVbFile : public IDecoder CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels), m_pVagDecoders(nil), m_ppVagBuffers(nil), m_ppPcmBuffers(nil), m_FileSize(0), m_nNumberOfBlocks(0), m_bBlockRead(false), m_LineInBlock(0), m_CurrentBlock(0) { - m_pFile = fopen(path, "rb"); + m_pFile = reloc_fopen(path, "rb"); if (!m_pFile) return; fseek(m_pFile, 0, SEEK_END); @@ -819,7 +821,7 @@ class COpusFile : public IDecoder m_nChannels(0) { int ret; - m_FileH = op_open_file(path, &ret); + m_FileH = op_open_file(reloc_realpath(path), &ret); if (m_FileH) { m_nChannels = op_head(m_FileH, 0)->channel_count; @@ -915,7 +917,7 @@ void CStream::Terminate() #endif } -CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate) : +CStream::CStream(const char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate) : m_pAlSources(sources), m_alBuffers(buffers), m_pBuffer(nil), @@ -930,7 +932,7 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU { // Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/) #if !defined(_WIN32) - char *real = casepath(filename); + char *real = reloc_casepath(filename); if (real) { strcpy(m_aFilename, real); free(real); @@ -940,7 +942,7 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU #endif strcpy(m_aFilename, filename); } - + DEV("Stream %s\n", m_aFilename); if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav")) diff --git a/src/audio/oal/stream.h b/src/audio/oal/stream.h index bcbc5e543..82d2b5d4c 100644 --- a/src/audio/oal/stream.h +++ b/src/audio/oal/stream.h @@ -86,7 +86,7 @@ class CStream static void Initialise(); static void Terminate(); - CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate = 32000); + CStream(const char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate = 32000); ~CStream(); void Delete(); diff --git a/src/audio/sampman_miles.cpp b/src/audio/sampman_miles.cpp index 82886c665..22a408131 100644 --- a/src/audio/sampman_miles.cpp +++ b/src/audio/sampman_miles.cpp @@ -14,6 +14,7 @@ #include "MusicManager.h" #include "Frontend.h" #include "Timer.h" +#include "relocatable.h" #pragma comment( lib, "mss32.lib" ) @@ -369,7 +370,7 @@ _ResolveLink(char const *path, char *out) { WCHAR wpath[MAX_PATH]; - MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, reloc_realpath(path), -1, wpath, MAX_PATH); if (SUCCEEDED(ppf->Load(wpath, STGM_READ))) { @@ -378,7 +379,7 @@ _ResolveLink(char const *path, char *out) { strcpy(filepath, path); - if (SUCCEEDED(psl->GetPath(filepath, MAX_PATH, &fd, SLGP_UNCPRIORITY))) + if (SUCCEEDED(psl->GetPath(reloc_realpath(filepath), MAX_PATH, &fd, SLGP_UNCPRIORITY))) { OutputDebugString(fd.cFileName); @@ -429,7 +430,7 @@ _FindMP3s(void) strcat(path, "*"); - hFind = FindFirstFile(path, &fd); + hFind = reloc_FindFirstFile(path, &fd); if ( hFind == INVALID_HANDLE_VALUE ) { @@ -444,7 +445,7 @@ _FindMP3s(void) if ( filepathlen <= 0) { - FindClose(hFind); + reloc_FindClose(hFind); return; } @@ -479,7 +480,7 @@ _FindMP3s(void) bShortcut = false; } - mp3Stream[0] = AIL_open_stream(DIG, filepath, 0); + mp3Stream[0] = AIL_open_stream(DIG, reloc_realpath(filepath), 0); if ( mp3Stream[0] ) { AIL_stream_ms_position(mp3Stream[0], &total_ms, NULL); @@ -493,7 +494,7 @@ _FindMP3s(void) if ( _pMP3List == NULL ) { - FindClose(hFind); + reloc_FindClose(hFind); if ( f ) fclose(f); @@ -538,7 +539,7 @@ _FindMP3s(void) while ( true ) { - if ( !FindNextFile(hFind, &fd) ) + if ( !reloc_FindNextFile(hFind, &fd) ) break; if ( bInitFirstEntry ) @@ -583,7 +584,7 @@ _FindMP3s(void) } } - mp3Stream[0] = AIL_open_stream(DIG, filepath, 0); + mp3Stream[0] = AIL_open_stream(DIG, reloc_realpath(filepath), 0); if ( mp3Stream[0] ) { AIL_stream_ms_position(mp3Stream[0], &total_ms, NULL); @@ -665,7 +666,7 @@ _FindMP3s(void) } } - mp3Stream[0] = AIL_open_stream(DIG, filepath, 0); + mp3Stream[0] = AIL_open_stream(DIG, reloc_realpath(filepath), 0); if ( mp3Stream[0] ) { AIL_stream_ms_position(mp3Stream[0], &total_ms, NULL); @@ -719,7 +720,7 @@ _FindMP3s(void) fclose(f); } - FindClose(hFind); + reloc_FindClose(hFind); } static void @@ -959,7 +960,7 @@ cSampleManager::Initialise(void) #ifdef AUDIO_CACHE TRACE("cache"); - FILE *cacheFile = fopen("audio\\sound.cache", "rb"); + FILE *cacheFile = reloc_fopen("audio\\sound.cache", "rb"); if (cacheFile) { fread(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); fclose(cacheFile); @@ -993,7 +994,7 @@ cSampleManager::Initialise(void) strcpy(filepath, m_szCDRomRootPath); strcat(filepath, StreamedNameTable[0]); - FILE *f = fopen(filepath, "rb"); + FILE *f = reloc_fopen(filepath, "rb"); if ( f ) { @@ -1006,7 +1007,7 @@ cSampleManager::Initialise(void) strcpy(filepath, m_szCDRomRootPath); strcat(filepath, StreamedNameTable[i]); - mp3Stream[0] = AIL_open_stream(DIG, filepath, 0); + mp3Stream[0] = AIL_open_stream(DIG, reloc_realpath(filepath), 0); if ( mp3Stream[0] ) { @@ -1076,7 +1077,7 @@ cSampleManager::Initialise(void) strcpy(_aHDDPath, m_szCDRomRootPath); rootpath[0] = '\0'; - FILE *f = fopen(StreamedNameTable[0], "rb"); + FILE *f = reloc_fopen(StreamedNameTable[0], "rb"); if ( f ) { @@ -1087,7 +1088,7 @@ cSampleManager::Initialise(void) strcpy(filepath, rootpath); strcat(filepath, StreamedNameTable[i]); - mp3Stream[0] = AIL_open_stream(DIG, filepath, 0); + mp3Stream[0] = AIL_open_stream(DIG, reloc_realpath(filepath), 0); if ( mp3Stream[0] ) { @@ -1123,7 +1124,7 @@ cSampleManager::Initialise(void) } #endif #ifdef AUDIO_CACHE - cacheFile = fopen("audio\\sound.cache", "wb"); + cacheFile = reloc_fopen("audio\\sound.cache", "wb"); fwrite(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); fclose(cacheFile); } @@ -1309,7 +1310,7 @@ cSampleManager::CheckForAnAudioFileOnCD(void) strcat(filepath, StreamedNameTable[AudioManager.GetRandomNumber(1) % TOTAL_STREAMED_SOUNDS]); - FILE *f = fopen(filepath, "rb"); + FILE *f = reloc_fopen(filepath, "rb"); if ( f ) { @@ -2009,7 +2010,7 @@ cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream) strcpy(filepath, m_szCDRomRootPath); strcat(filepath, StreamedNameTable[nFile]); - mp3Stream[nStream] = AIL_open_stream(DIG, filepath, 0); + mp3Stream[nStream] = AIL_open_stream(DIG, reloc_realpath(filepath), 0); if ( mp3Stream[nStream] ) { @@ -2289,11 +2290,11 @@ cSampleManager::InitialiseSampleBanks(void) { int32 nBank = SFX_BANK_0; - fpSampleDescHandle = fopen(SampleBankDescFilename, "rb"); + fpSampleDescHandle = reloc_fopen(SampleBankDescFilename, "rb"); if ( fpSampleDescHandle == NULL ) return false; - fpSampleDataHandle = fopen(SampleBankDataFilename, "rb"); + fpSampleDataHandle = reloc_fopen(SampleBankDataFilename, "rb"); if ( fpSampleDataHandle == NULL ) { fclose(fpSampleDescHandle); diff --git a/src/audio/sampman_oal.cpp b/src/audio/sampman_oal.cpp index 798ea2871..fd8974507 100644 --- a/src/audio/sampman_oal.cpp +++ b/src/audio/sampman_oal.cpp @@ -14,7 +14,9 @@ #include #include +#ifdef _MSC_VER #pragma comment(lib, "OpenAL32.lib") +#endif // for user MP3s #include @@ -24,8 +26,10 @@ #define _getcwd getcwd #endif +#define WITHWINDOWS #include "common.h" #include "crossplatform.h" +#include "relocatable.h" #include "sampman.h" @@ -562,7 +566,7 @@ _FindMP3s(void) strcat(path, "*"); - hFind = FindFirstFile(path, &fd); + hFind = reloc_FindFirstFile(path, &fd); if ( hFind == INVALID_HANDLE_VALUE ) { @@ -576,7 +580,7 @@ _FindMP3s(void) if ( filepathlen <= 0) { - FindClose(hFind); + reloc_FindClose(hFind); return; } @@ -964,7 +968,7 @@ cSampleManager::Initialise(void) add_providers(); #ifdef AUDIO_CACHE - FILE *cacheFile = fcaseopen("audio\\sound.cache", "rb"); + FILE *cacheFile = reloc_fcaseopen("audio\\sound.cache", "rb"); // FIXME: was fcaseopen if (cacheFile) { debug("Loadind audio cache (If game crashes around here, then your cache is corrupted, remove audio/sound.cache)\n"); fread(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); @@ -987,7 +991,13 @@ cSampleManager::Initialise(void) USERERROR("Can't open '%s'\n", StreamedNameTable[i]); } #ifdef AUDIO_CACHE - cacheFile = fcaseopen("audio\\sound.cache", "wb"); + // FIXME: cross platform mkdir!!! +#ifdef _MSC_VER + ::mkdir("audio"); +#else + ::mkdir("audio", S_IREAD | S_IWRITE | S_IEXEC | S_IXGRP | S_IXOTH); +#endif + cacheFile = reloc_fcaseopen("audio\\sound.cache", "wb"); if(cacheFile) { debug("Saving audio cache\n"); fwrite(nStreamLength, sizeof(uint32), TOTAL_STREAMED_SOUNDS, cacheFile); @@ -1970,11 +1980,11 @@ cSampleManager::InitialiseSampleBanks(void) { int32 nBank = SFX_BANK_0; - fpSampleDescHandle = fcaseopen(SampleBankDescFilename, "rb"); + fpSampleDescHandle = reloc_fcaseopen(SampleBankDescFilename, "rb"); if ( fpSampleDescHandle == NULL ) return false; #ifndef OPUS_SFX - fpSampleDataHandle = fcaseopen(SampleBankDataFilename, "rb"); + fpSampleDataHandle = reloc_fcaseopen(SampleBankDataFilename, "rb"); if ( fpSampleDataHandle == NULL ) { fclose(fpSampleDescHandle); diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp index 4bb31ea43..0c8434a75 100644 --- a/src/core/CdStream.cpp +++ b/src/core/CdStream.cpp @@ -6,9 +6,10 @@ #include "rwcore.h" #include "RwHelper.h" #include "MemoryMgr.h" +#include "relocatable.h" #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) -#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) +#define CDTRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, "cdvd_stream: " f "\n", ## __VA_ARGS__) struct CdReadInfo { @@ -472,18 +473,16 @@ CdStreamAddImage(char const *path) ASSERT(path != nil); ASSERT(gNumImages < MAX_CDIMAGES); - SetLastError(0); - - gImgFiles[gNumImages] = CreateFile(path, + gImgFiles[gNumImages] = CreateFile(reloc_realpath(path), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, _gdwCdStreamFlags | FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_READONLY, nil); - - ASSERT( gImgFiles[gNumImages] != nil ); - if ( gImgFiles[gNumImages] == NULL ) + + ASSERT( gImgFiles[gNumImages] != INVALID_HANDLE_VALUE ); + if ( gImgFiles[gNumImages] == INVALID_HANDLE_VALUE ) return false; strcpy(gCdImageNames[gNumImages], path); diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp index 0854d850f..a7ddce272 100644 --- a/src/core/CdStreamPosix.cpp +++ b/src/core/CdStreamPosix.cpp @@ -1,6 +1,7 @@ #ifndef _WIN32 #include "common.h" #include "crossplatform.h" +#include "relocatable.h" #include #include #include @@ -19,7 +20,7 @@ #include "MemoryMgr.h" #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) -#define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) +#define CDTRACE(f, ...) TRACE ("cddvd_stream: " f "\n", ## __VA_ARGS__) // #define ONE_THREAD_PER_CHANNEL // Don't use if you're not on SSD/Flash. (Also you may want to benefit from this via using all channels in Streaming.cpp) @@ -145,7 +146,7 @@ CdStreamInit(int32 numChannels) { struct statvfs fsInfo; - if((statvfs("models/gta3.img", &fsInfo)) < 0) + if((statvfs(reloc_realpath("models/gta3.img"), &fsInfo)) < 0) { CDTRACE("can't get filesystem info"); ASSERT(0); @@ -192,7 +193,7 @@ GetGTA3ImgSize(void) realpath(gImgNames[0], path); if (stat(path, &statbuf) == -1) { // Try case-insensitivity - char* real = casepath(gImgNames[0], false); + char* real = reloc_casepath(gImgNames[0], false); if (real) { realpath(real, path); @@ -483,11 +484,11 @@ CdStreamAddImage(char const *path) ASSERT(path != nil); ASSERT(gNumImages < MAX_CDIMAGES); - gImgFiles[gNumImages] = open(path, _gdwCdStreamFlags); + gImgFiles[gNumImages] = open(reloc_realpath(path), _gdwCdStreamFlags); // Fix case sensitivity and backslashes. if (gImgFiles[gNumImages] == -1) { - char* real = casepath(path, false); + char* real = reloc_casepath(path, false); if (real) { gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags); diff --git a/src/core/FileMgr.cpp b/src/core/FileMgr.cpp index 32aa40416..d532bfac0 100644 --- a/src/core/FileMgr.cpp +++ b/src/core/FileMgr.cpp @@ -5,6 +5,7 @@ #endif #include "common.h" #include "crossplatform.h" +#include "relocatable.h" #include "FileMgr.h" @@ -27,23 +28,21 @@ struct myFILE #define NUMFILES 20 static myFILE myfiles[NUMFILES]; - #if !defined(_WIN32) #include #include #include #define _getcwd getcwd - // Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen) void mychdir(char const *path) { - char* r = casepath(path, false); - if (r) { - chdir(r); + char *r = reloc_casepath(path, false); + if(r) { + chdir(r); free(r); - } else { - errno = ENOENT; - } + } else { + errno = ENOENT; + } } #else #define mychdir chdir @@ -70,9 +69,9 @@ myfopen(const char *filename, const char *mode) mode++; *p++ = 'b'; *p = '\0'; - - myfiles[fd].file = fcaseopen(filename, realmode); - if(myfiles[fd].file == nil) + + myfiles[fd].file = reloc_fcaseopen(filename, realmode); + if (myfiles[fd].file == nil) return 0; return fd; } @@ -200,24 +199,30 @@ char CFileMgr::ms_dirName[128]; void CFileMgr::Initialise(void) { + strcpy(ms_dirName, ""); +#ifdef RELOCATABLE + strcpy(ms_rootDirName, ""); +#else _getcwd(ms_rootDirName, 128); strcat(ms_rootDirName, "\\"); +#endif + reloc_initialize(); } void CFileMgr::ChangeDir(const char *dir) { - if(*dir == '\\'){ - strcpy(ms_dirName, ms_rootDirName); - dir++; - } - if(*dir != '\0'){ - strcat(ms_dirName, dir); + strcpy(ms_dirName, dir); + if (*dir != '\0'){ // BUG in the game it seems, it's off by one - if(dir[strlen(dir)-1] != '\\') + if (dir[strlen(dir)-1] != '\\') { strcat(ms_dirName, "\\"); + } } +#ifndef RELOCATABLE + mychdir(ms_rootDirName); mychdir(ms_dirName); +#endif } void @@ -230,14 +235,19 @@ CFileMgr::SetDir(const char *dir) if(dir[strlen(dir)-1] != '\\') strcat(ms_dirName, "\\"); } +#ifndef RELOCATABLE mychdir(ms_dirName); +#endif } void CFileMgr::SetDirMyDocuments(void) { SetDir(""); // better start at the root if user directory is relative + //FIXME: When using USE_MY_DOCUMENTS, the returned path is absolute. +#ifndef RELOCATABLE mychdir(_psGetUserFilesFolder()); +#endif } ssize_t diff --git a/src/core/FileMgr.h b/src/core/FileMgr.h index f70451b75..7a3ad5f43 100644 --- a/src/core/FileMgr.h +++ b/src/core/FileMgr.h @@ -1,5 +1,6 @@ #pragma once + class CFileMgr { static char ms_rootDirName[128]; @@ -20,4 +21,5 @@ class CFileMgr static int CloseFile(int fd); static int GetErrorReadWrite(int fd); static char *GetRootDirName() { return ms_rootDirName; } + static const char *GetWorkingDir() { return ms_dirName; } }; diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 65eab125f..580027c01 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -4,6 +4,7 @@ #include "common.h" #ifndef PS2_MENU #include "crossplatform.h" +#include "relocatable.h" #include "platform.h" #include "Frontend.h" #include "Font.h" @@ -3081,8 +3082,8 @@ CMenuManager::DrawPlayerSetupScreen() WIN32_FIND_DATA FindFileData; SYSTEMTIME SystemTime; - HANDLE handle = FindFirstFile("skins\\*.bmp", &FindFileData); - for (int i = 1; handle != INVALID_HANDLE_VALUE && i; i = FindNextFile(handle, &FindFileData)) { + HANDLE handle = reloc_FindFirstFile("skins\\*.bmp", &FindFileData); + for (int i = 1; handle != INVALID_HANDLE_VALUE && i; i = reloc_FindNextFile(handle, &FindFileData)) { if (strcmp(FindFileData.cFileName, DEFAULT_SKIN_NAME) != 0) { m_pSelectedSkin->nextSkin = new tSkinInfo; m_pSelectedSkin = m_pSelectedSkin->nextSkin; @@ -3095,7 +3096,7 @@ CMenuManager::DrawPlayerSetupScreen() m_pSelectedSkin->nextSkin = nil; } } - FindClose(handle); + reloc_FindClose(handle); m_nSkinsTotal = nextSkinId; char nameTemp[256]; for (m_pSelectedSkin = m_pSkinListHead.nextSkin; m_pSelectedSkin; m_pSelectedSkin = m_pSelectedSkin->nextSkin) { @@ -3686,7 +3687,7 @@ CMenuManager::LoadSettings() m_nPrefsWidth = 0; m_nPrefsHeight = 0; m_nPrefsDepth = 0; - m_nPrefsWindowed = 0; + m_nPrefsWindowed =0; m_nPrefsSubsystem = 0; } m_nSelectedScreenMode = m_nPrefsWindowed; @@ -3756,14 +3757,14 @@ CMenuManager::LoadSettings() WIN32_FIND_DATA FindFileData; char skinfile[256+16]; // Stack analysis shows 16 bits gap, but I don't trust it. It may very well be MAX_PATH(260). bool SkinFound = false; - HANDLE handle = FindFirstFile("skins\\*.bmp", &FindFileData); - for (int i = 1; handle != INVALID_HANDLE_VALUE && i; i = FindNextFile(handle, &FindFileData)) { + HANDLE handle = reloc_FindFirstFile("skins\\*.bmp", &FindFileData); + for (int i = 1; handle != INVALID_HANDLE_VALUE && i; i = reloc_FindNextFile(handle, &FindFileData)) { strcpy(skinfile, m_PrefsSkinFile); strcat(skinfile, ".bmp"); if (strcmp(FindFileData.cFileName, skinfile) == 0) SkinFound = true; } - FindClose(handle); + reloc_FindClose(handle); if (!SkinFound) { OutputDebugString("Default skin set as no other skins are available OR saved skin not found!"); diff --git a/src/core/common.h b/src/core/common.h index d7facfd10..ab0263a87 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -1,11 +1,13 @@ #pragma once +#ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS #define _USE_MATH_DEFINES #pragma warning(disable: 4244) // int to float #pragma warning(disable: 4800) // int to bool #pragma warning(disable: 4838) // narrowing conversion #pragma warning(disable: 4996) // POSIX names +#endif #include #include @@ -305,7 +307,7 @@ void re3_usererror(const char *format, ...); #endif #define debug(f, ...) re3_debug("[DBG]: " f, ## __VA_ARGS__) -#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f, ## __VA_ARGS__) +#define TRACE(f, ...) re3_trace(__FILE__, __LINE__, __FUNCTION__, f "\n", ## __VA_ARGS__) #define Error(f, ...) re3_debug("[ERROR]: " f, ## __VA_ARGS__) #define USERERROR(f, ...) re3_usererror(f, ## __VA_ARGS__) diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index c11509311..a5a7a461d 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -7,9 +7,9 @@ #include #include #include -#ifndef _WIN32 + #include "crossplatform.h" -#endif +#include "relocatable.h" using namespace rw; @@ -337,10 +337,6 @@ const RwTexDictionary *RwTexDictionaryStreamWrite(const RwTexDictionary *texDict return texDict; } - - - - RwStream *RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, const void *pData) { StreamFile *file; StreamMemory *mem; @@ -361,9 +357,9 @@ RwStream *RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, const v file = rwNewT(StreamFile, 1, 0); memcpy(file, &fakefile, sizeof(StreamFile)); #ifndef _WIN32 - char *r = casepath((char*)pData); + char *r = reloc_casepath((char*)pData); if (r) { - if (file->open((char*)r, mode)) { + if (file->open(r, mode)) { free(r); return file; } @@ -371,7 +367,7 @@ RwStream *RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, const v } else #endif { - if (file->open((char*)pData, mode)) + if (file->open((const char *)pData, mode)) return file; } rwFree(file); @@ -913,7 +909,7 @@ RwImage * RtBMPImageWrite(RwImage *image, const RwChar *imageName) { #ifndef _WIN32 - char *r = casepath(imageName); + char *r = reloc_casepath(imageName); if (r) { rw::writeBMP(image, r); free(r); @@ -931,7 +927,7 @@ RtBMPImageRead(const RwChar *imageName) { #ifndef _WIN32 RwImage *image; - char *r = casepath(imageName); + char *r = reloc_casepath(imageName); if (r) { image = rw::readBMP(r); free(r); diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index 6c643caf5..15fb0c9a1 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -233,11 +233,11 @@ TWEAKFUNC(CParticle::ReloadConfig); void CParticle::ReloadConfig() { - debug("Initialising CParticleMgr..."); + debug("Initialising CParticleMgr...\n"); mod_ParticleSystemManager.Initialise(); - debug("Initialising CParticle..."); + debug("Initialising CParticle...\n"); m_pUnusedListHead = gParticleArray; @@ -622,7 +622,7 @@ CEntity::AddSteamsFromGround(CVector *unused) void CParticle::Shutdown() { - debug("Shutting down CParticle..."); + debug("Shutting down CParticle...\n"); for ( int32 i = 0; i < MAX_SMOKE_FILES; i++ ) { diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h index d8807f2b8..a10739f71 100644 --- a/src/skel/crossplatform.h +++ b/src/skel/crossplatform.h @@ -1,3 +1,4 @@ +#pragma once #include // This is the common include for platform/renderer specific skeletons(glfw.cpp, win.cpp etc.) and using cross platform things (like Windows directories wrapper, platform specific global arrays etc.) diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 5f87d6000..87b189c58 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -33,6 +33,7 @@ long _dwOperatingSystemVersion; #include "skeleton.h" #include "platform.h" #include "crossplatform.h" +#include "relocatable.h" #include "main.h" #include "FileMgr.h" @@ -860,7 +861,7 @@ void _InputInitialiseJoys() // Load our gamepad mappings. #define SDL_GAMEPAD_DB_PATH "gamecontrollerdb.txt" - FILE *f = fopen(SDL_GAMEPAD_DB_PATH, "rb"); + FILE *f = reloc_fopen(SDL_GAMEPAD_DB_PATH, "rb"); if (f) { fseek(f, 0, SEEK_END); size_t fsize = ftell(f); @@ -936,7 +937,7 @@ void psPostRWinit(void) // Make sure all keys are released CPad::GetPad(0)->Clear(true); CPad::GetPad(1)->Clear(true); -} + } /* ***************************************************************************** @@ -1469,6 +1470,10 @@ WinMain(HINSTANCE instance, if (strstr(cmdLine, "-console")) { AllocConsole(); + SetConsoleTitle("GTA3 Debug Console"); + // Set default big history (to enable scrolling back) + CONSOLE_HISTORY_INFO historyInfo = {sizeof(CONSOLE_HISTORY_INFO), 9999, 4, 0}; + SetConsoleHistoryInfo(&historyInfo); freopen("CONIN$", "r", stdin); freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); diff --git a/src/skel/relocatable.cpp b/src/skel/relocatable.cpp new file mode 100644 index 000000000..a186a7bd0 --- /dev/null +++ b/src/skel/relocatable.cpp @@ -0,0 +1,492 @@ +#ifdef RELOCATABLE +#include "common.h" +#include "FileMgr.h" + +#include +#ifdef _MSC_VER +#include +#else +#include +#include +#endif + +#ifdef __APPLE__ +#include +#include +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#endif + +#define WITHWINDOWS +#include "crossplatform.h" +#include "relocatable.h" + + +#ifndef R_OK +#define R_OK 4 +#endif + +#ifdef _WIN32 +#define PATHJOIN '\\' +#define PATHJOIN_S "\\" +#define PATHSEP ';' +#else +#define PATHJOIN '/' +#define PATHJOIN_S "/" +#define PATHSEP ':' +#endif + +bool +FileExists(const char *path) +{ +#if _WIN32 + bool exists = PathFileExistsA(path); + struct stat status; + stat(path, &status); + return (status.st_mode & _S_IFREG) != 0; +#else + return access(path, R_OK) == 0; +#endif +} + + +bool +containsGta3Data(const std::string &dirPath) +{ + std::string path(dirPath); + path.append("models" PATHJOIN_S "gta3.img"); + return FileExists(path.c_str()); +} + +#ifdef _WIN32 +std::string +winReadRegistry(HKEY hParentKey, const char *keyName, const char *valueName) +{ + HKEY hKey; + if (RegOpenKeyExA(hParentKey, keyName, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + std::string res; + DWORD valueSize = 1024; + res.resize(valueSize); + DWORD keyType; + if (RegQueryValueEx(hKey, valueName, NULL, &keyType, (LPBYTE)res.data(), &valueSize) == ERROR_SUCCESS) { + RegCloseKey(hKey); + if(keyType == REG_SZ) { + res.resize(strlen(res.data())); + return res; + } + } + RegCloseKey(hKey); + } + return ""; +} + +std::string +psExePath() +{ + std::string buf; + buf.resize(MAX_PATH); + if (GetModuleFileName(NULL, (LPSTR)buf.c_str(), MAX_PATH) == 0) { + debug("GetModuleFileNameA failed: cannot get path of executable.\n"); + return ""; + } + buf.resize(strlen(buf.c_str())); + return buf; +} +#endif + +#ifdef __APPLE__ +std::string +psExePath() +{ + std::string buf; + uint32_t bufsize = 0; + _NSGetExecutablePath(NULL, &bufsize); + buf.resize(bufsize + 1); + if(_NSGetExecutablePath((char*)buf.c_str(), &bufsize) != 0) { + debug("_NSGetExecutablePath failed: cannot get path of executable.\n"); + return ""; + } + buf.resize(bufsize); + return buf; +} +#endif + +#ifdef __linux__ +std::string +psExePath() +{ + std::string buf; + buf.resize(MAX_PATH); + ssize_t nb = readlink("/proc/self/exe", (char*)buf.c_str(), MAX_PATH); + if (nb == -1) { + return ""; + } + buf.resize(strlen(buf.c_str())); + return buf; +} +#endif + +std::string +psExeDir() +{ + std::string exePath = psExePath(); + if (!exePath.size()) { + return ""; + } +#ifdef _MSC_VER + std::string::size_type lastSepPos = exePath.rfind(PATHJOIN); + if (lastSepPos >= 0) { + exePath.resize(lastSepPos); + return exePath; + } + return ""; +#else + return dirname((char*)exePath.c_str()); +#endif +} + +#ifdef _WIN32 +std::string +winGetGtaDataFolder() +{ + if (containsGta3Data("C:\\Program Files\\Rockstar Games\\GTAIII\\")) { + return "C:\\Program Files\\Rockstar Games\\GTAIII\\"; + } + std::string location; + location.resize(MAX_PATH); + BOOL success = SHGetSpecialFolderPathA(NULL, (LPSTR)location.c_str(), CSIDL_PROGRAM_FILESX86, FALSE); + if (success) { + location.resize(strlen(location.c_str())); + location.append("\\Rockstar Games\\GTAIII\\"); + if(containsGta3Data(location)) { + return location; + } + } +#if defined(STEAMID) + location = winReadRegistry(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App " STR(STEAMID), "InstallLocation"); + if (location.size()) { + location.push_back('\\'); + if (containsGta3Data(location)) { + return location; + } + } +#endif + return ""; +} +#endif + +void +normalizePathCorrectPathJoiner(std::string &s) +{ +#ifdef _WIN32 +#define PATHJOIN_BAD '/' +#else +#define PATHJOIN_BAD '\\' +#endif + std::string::size_type pos(0); + while((pos = s.find(PATHJOIN_BAD, pos)) != std::string::npos) { + s[pos] = PATHJOIN; + } +} + +void +ensureTrailingPathJoiner(std::string &s) +{ + if(s.size() && *s.rbegin() != PATHJOIN) { + s.push_back(PATHJOIN); + } +} + + +#include +std::vector searchPaths; + +void +reloc_initialize() +{ + // FIXME: is called twice + searchPaths.clear(); + std::string path; + // 1. add search paths from command line + // FIXME + // 2. `GTA_III_RE_DIR` environment variable + const char *pEnv = ::getenv("GTA3DIR"); + if (pEnv) { + std::string env = pEnv; + std::string::size_type start(0); + std::string::size_type end; + while ((end = env.find(PATHSEP, start)) != std::string::npos) { + searchPaths.push_back(env.substr(start, end - start)); + start = end + 1; + } + searchPaths.push_back(env.substr(start)); + } + // 3. add search paths from INI + // FIXME + // 4. add current working directory to search path + path.resize(MAX_PATH); + char *cwd = getcwd((char *)path.c_str(), path.size()); + if (cwd) { + path.resize(strlen(path.c_str())); + searchPaths.push_back(path); + } + // 5. add exe path to search path + path = psExeDir(); + if(path.size()) { + searchPaths.push_back(path); + } +#ifdef _WIN32 + // 6. add default installation paths + path = winGetGtaDataFolder(); + if(path.size()) { + searchPaths.push_back(path); + } +#endif + // 6. built-in path +#ifdef GTA_III_RE_DIR + searchPaths.push_back(GTA_III_RE_DIR); +#endif + + // Normalize paths + for(std::string &path : searchPaths) { + normalizePathCorrectPathJoiner(path); + ensureTrailingPathJoiner(path); + } + + debug("Full search path is:\n"); + for (const std::string &s: searchPaths) { + debug("- %s\n", s.c_str()); + } +} + +std::string +searchPathsFindData(const char *path) +{ + const char *cwd = CFileMgr::GetWorkingDir(); + std::string suffix; + if (cwd && *cwd != '\0') { + suffix.append(cwd); + std::string::size_type pos = 0; + while(suffix[pos] == PATHJOIN) { + ++pos; + } + suffix = suffix.substr(pos, suffix.size() - pos); + if (suffix[suffix.size() - 1] != PATHJOIN) { + suffix.push_back(PATHJOIN); + } + } + suffix.append(path); + normalizePathCorrectPathJoiner(suffix); + for (const auto &searchpath : searchPaths) { + std::string curPath = searchpath + suffix; + if (FileExists(curPath.c_str())) { + return curPath; + } + FILE *f = fopen(curPath.c_str(), "rb"); + if(f) { + fclose(f); + debug("FileExists failed, but fopen succeeded. huh?\n"); + } + } + TRACE("Could not find \"%s\" in search paths (cwd=\"%s\").\n", path, cwd); + std::string res; + if (cwd && *cwd != '\0') { + res.append(cwd); + res.push_back(PATHJOIN); + } + res.append(path); + normalizePathCorrectPathJoiner(res); + return res; +} + +#include "FileMgr.h" +#include "common.h" + +FILE * +reloc_fopen(const char *path, const char *mode) +{ + std::string fullPath = searchPathsFindData(path); + TRACE("reloc_fopen(%s, %s) -> fopen(%s, %s)", path, mode, fullPath.c_str(), mode); + return fopen(fullPath.c_str(), mode); +} + +const char* +reloc_realpath(const char *filename) +{ + static std::string fullPath; + fullPath = searchPathsFindData(filename); + TRACE("reloc_realpath(%s) -> %s", filename, fullPath.c_str()); + return fullPath.c_str(); +} + +struct reloc_HANDLE { + HANDLE hFind; + std::string fullPathName; + int searchPathIndex; +}; + +HANDLE +reloc_FindFirstFile(const char *pathName, WIN32_FIND_DATA *findFileData) +{ + std::string suffix = CFileMgr::GetWorkingDir(); + if (suffix.size()) { + std::string::size_type pos = 0; + while(suffix[pos] == PATHJOIN) { ++pos; } + suffix = suffix.substr(pos, suffix.size() - pos); + if (suffix[suffix.size() - 1] != PATHJOIN) { + suffix.push_back(PATHJOIN); + } + } + suffix.append(pathName); + + for (int i = 0; i < (int)searchPaths.size(); ++i) { + HANDLE hFind = FindFirstFile((searchPaths[i] + suffix).c_str(), findFileData); + if (hFind != INVALID_HANDLE_VALUE) { + return (HANDLE) new reloc_HANDLE {hFind, suffix, i}; + } + } + return INVALID_HANDLE_VALUE; +} + +bool +reloc_FindNextFile(HANDLE hFind, WIN32_FIND_DATA *findFileData) +{ + reloc_HANDLE *relocHandle = (reloc_HANDLE *) hFind; + if (FindNextFile(relocHandle->hFind, findFileData)) { + return true; + } + FindClose(relocHandle->hFind); + relocHandle->hFind = NULL; + + for (int i = relocHandle->searchPathIndex + 1; i < (int)searchPaths.size(); ++i) { + HANDLE newHFind = FindFirstFile((searchPaths[i] + relocHandle->fullPathName).c_str(), findFileData); + if (newHFind != INVALID_HANDLE_VALUE) { + relocHandle->hFind = newHFind; + relocHandle->searchPathIndex = i; + return true; + } + } + return false; +} + +bool +reloc_FindClose(HANDLE hFind) +{ + reloc_HANDLE *relocHandle = (reloc_HANDLE *)hFind; + bool res = true; + if (relocHandle->hFind != NULL) { + res = FindClose(relocHandle->hFind); + } + delete relocHandle; + return res; +} + +#ifndef _WIN32 +static bool +casepath_subpath(const std::string &basePath, const char *path, std::string &result) { + const char *curLevelStart; + size_t curLevelSize; + bool currentIsFile; + + if (path == NULL) { + return false; + } + + // Fail early when the base path does not exist. + DIR *d = opendir(basePath.c_str()); + if (d == NULL) { + return false; + } + + // Split path in parts, ignoring empty levels (e.g. '/a//b' --> {'a', 'b'}) + const char *nextCurLevelStart = path; + while (true) { + curLevelStart = nextCurLevelStart; + const char *delimPos = strpbrk(curLevelStart, "/\\"); + if (delimPos == NULL) { + curLevelSize = strlen(curLevelStart); + currentIsFile = true; + break; + } + curLevelSize = delimPos - curLevelStart; + nextCurLevelStart = delimPos + 1; + currentIsFile = false; + + if (curLevelSize > 0) { + break; + } + } + char *curLevel = (char*) alloca(curLevelSize + 1); + strncpy(curLevel, curLevelStart, curLevelSize); + curLevel[curLevelSize] = '\0'; + + struct dirent *e; + while ((e = readdir(d)) != NULL) { + if (strcasecmp(curLevel, e->d_name) == 0) { + if (currentIsFile) { + result = basePath + e->d_name; + closedir(d); + return true; + } + bool subres = casepath_subpath(basePath + e->d_name + PATHJOIN_S, nextCurLevelStart, result); + if (subres) { + return subres; + } + } + } + closedir(d); + return false; +} + + +char* +reloc_casepath(const char *path, bool checkPathFirst) +{ + std::string realPath; + realPath.reserve(PATH_MAX); + if (checkPathFirst) { + for (const std::string &searchPath : searchPaths) { + realPath = searchPath + CFileMgr::GetWorkingDir() + path; + if (access(realPath.c_str(), F_OK) != -1) { + // File path is correct + debug("reloc_casepath(%s, %d) -> %s\n", path, checkPathFirst, realPath.c_str()); + return strdup(realPath.c_str()); + } + } + } + + std::string suffixPath = std::string{CFileMgr::GetWorkingDir()} + path; + for (const std::string &searchPath : searchPaths) { + bool res = casepath_subpath(searchPath, suffixPath.c_str(), realPath); + if (res) { + debug("reloc_casepath(%s, %d) -> %s\n", path, checkPathFirst, realPath.c_str()); + return strdup(realPath.c_str()); + } + } + debug("reloc_casepath(%s, %d) failed (wd=%s)\n", path, checkPathFirst, CFileMgr::GetWorkingDir()); + return NULL; +} + +FILE * +reloc_fcaseopen(char const *filename, char const *mode) +{ + FILE *result; + char *real = reloc_casepath(filename); + if (real == NULL) { + result = fopen(filename, mode); + } else { + result = fopen(real, mode); + free(real); + } + return result; +} + +#endif +#endif + diff --git a/src/skel/relocatable.h b/src/skel/relocatable.h new file mode 100644 index 000000000..72e6840a2 --- /dev/null +++ b/src/skel/relocatable.h @@ -0,0 +1,45 @@ +#pragma once + +#if defined _WIN32 +#ifdef WITHWINDOWS +#include +#endif +#else +#include "crossplatform.h" +#endif + +#ifdef RELOCATABLE + +void reloc_initialize(void); + +FILE *reloc_fopen(const char *path, const char *mode); +const char *reloc_realpath(const char *filename); + +#ifdef _WIN32 +#define reloc_casepath(PATH, CHECKFIRST) reloc_realpath(PATH) +#define reloc_fcaseopen reloc_fopen +#else +char *reloc_casepath(char const *path, bool checkPathFirst = true); +FILE *reloc_fcaseopen(char const *filename, char const *mode); +#endif + +#if defined WITHWINDOWS +HANDLE reloc_FindFirstFile(const char *pathName, WIN32_FIND_DATA *findFileData); +bool reloc_FindNextFile(HANDLE hFind, WIN32_FIND_DATA *findFileData); +bool reloc_FindClose(HANDLE hFind); +#endif + +#else +#define reloc_initialize() + +#define reloc_fopen(path, mode) fopen(path, mode) +#define reloc_realpath(filename) (filename) + +#define reloc_casepath casepath +#define reloc_fcaseopen fcaseopen + +#define reloc_FindFirstFile FindFirstFile +#define reloc_FindNextFile FindNextFile +#define reloc_FindClose FindClose + +#endif diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp index 00aaa6829..22bb0558b 100644 --- a/src/vehicles/HandlingMgr.cpp +++ b/src/vehicles/HandlingMgr.cpp @@ -97,7 +97,10 @@ cHandlingDataMgr::LoadHandlingData(void) tHandlingData *handling; CFileMgr::SetDir("DATA"); - CFileMgr::LoadFile(HandlingFilename, work_buff, sizeof(work_buff), "r"); + ssize_t nbBytesRead = CFileMgr::LoadFile(HandlingFilename, work_buff, sizeof(work_buff), "r"); + if(nbBytesRead < 0) { + USERERROR("Cannot open %s\n", HandlingFilename); + } CFileMgr::SetDir(""); start = (char*)work_buff;