Skip to content

Commit

Permalink
CLEO paths handling updates.
Browse files Browse the repository at this point in the history
Detection of multiple CLEO.asi loaded
  • Loading branch information
MiranDMC authored and x87 committed Nov 3, 2023
1 parent f606c18 commit c48d69e
Show file tree
Hide file tree
Showing 15 changed files with 96 additions and 74 deletions.
5 changes: 4 additions & 1 deletion CLEO5.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\plugin_sa\game_sa\RenderWare.cpp">
<Filter>plugin_sdk</Filter>
</ClCompile>
</ClCompile>
<ClCompile Include="source\crc32.cpp">
<Filter>source\utils</Filter>
</ClCompile>
Expand Down Expand Up @@ -158,6 +158,9 @@
<ClInclude Include="source\resource.h">
<Filter>source</Filter>
</ClInclude>
<ClInclude Include="source\Singleton.h">
<Filter>source\utils</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="source\cleo.def">
Expand Down
4 changes: 2 additions & 2 deletions source/CCustomOpcodeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2133,8 +2133,8 @@ namespace CLEO
}
scmFunc->moduleExportRef = scriptRef.base; // to be released on return

reinterpret_cast<CCustomScript*>(thread)->SetScriptFileDir(std::filesystem::path(modulePath).parent_path().string().c_str());
reinterpret_cast<CCustomScript*>(thread)->SetScriptFileName(std::filesystem::path(modulePath).filename().string().c_str());
reinterpret_cast<CCustomScript*>(thread)->SetScriptFileDir(FS::path(modulePath).parent_path().string().c_str());
reinterpret_cast<CCustomScript*>(thread)->SetScriptFileName(FS::path(modulePath).filename().string().c_str());
thread->SetBaseIp(scriptRef.base);
label = scriptRef.offset;
}
Expand Down
4 changes: 1 addition & 3 deletions source/CDebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
#define LOG_WARNING(a,...) {Debug.Trace(CLEO::eLogLevel::Error, a, __VA_ARGS__);}
#define SHOW_ERROR(a,...) {Debug.Error(a, __VA_ARGS__);}

const char szLogFileName[] = "cleo.log";

std::string stringPrintf(const char* format, ...);

class CDebug
{
public:
CDebug() : m_hFile(szLogFileName)
CDebug() : m_hFile(Filepath_Log)
{
Trace(CLEO::eLogLevel::Default, "Log started.");

Expand Down
14 changes: 5 additions & 9 deletions source/CModuleSystem.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#include "stdafx.h"
#include "CleoBase.h"
#include "CModuleSystem.h"
#include "CFileMgr.h"
#include "FileEnumerator.h"

#include <chrono>
#include <filesystem>
#include <fstream>

using namespace CLEO;
Expand Down Expand Up @@ -70,9 +68,7 @@ bool CModuleSystem::LoadDirectory(const char* path)

bool CModuleSystem::LoadCleoModules()
{
std::string path = CFileMgr::ms_rootDirName;
if (!path.empty() && path.back() != '\\') path.push_back('\\');
path += "cleo\\cleo_modules";
const auto path = FS::path(Filepath_Cleo).append("cleo_modules").string();
return LoadDirectory(path.c_str());
}

Expand Down Expand Up @@ -123,18 +119,18 @@ void CModuleSystem::CModule::Update()
{
if (!updateNeeded)
{
std::filesystem::file_time_type time;
FS::file_time_type time;
try
{
time = std::filesystem::last_write_time(filepath);
time = FS::last_write_time(filepath);
}
catch (...)
{
time = {};
}

// file not exists or up to date
if (time == std::filesystem::file_time_type{} || time == fileTime)
if (time == FS::file_time_type{} || time == fileTime)
{
// query files once a second
for(size_t i = 0; i < 100 && updateActive; i++)
Expand Down Expand Up @@ -201,7 +197,7 @@ bool CModuleSystem::CModule::LoadFromFile(const char* path)

try
{
fileTime = std::filesystem::last_write_time(path);
fileTime = FS::last_write_time(path);
}
catch(...)
{
Expand Down
3 changes: 1 addition & 2 deletions source/CModuleSystem.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#pragma once
#include <atomic>
#include <filesystem>
#include <map>
#include <mutex>
#include <thread>
Expand Down Expand Up @@ -58,7 +57,7 @@ namespace CLEO

// hot reloading when source file modified
std::atomic<int> refCount = 0;
std::filesystem::file_time_type fileTime; // last write time of source file
FS::file_time_type fileTime; // last write time of source file
void Update();
std::atomic<bool> updateActive = true;
std::atomic<bool> updateNeeded = false;
Expand Down
7 changes: 4 additions & 3 deletions source/CPluginSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ namespace CLEO

TRACE("Loading plugins...");

FilesWalk("cleo\\cleo_plugins", ".cleo", [&](const char* fullPath, const char* filename)
auto path = FS::path(Filepath_Cleo).append("cleo_plugins").string();
FilesWalk(path.c_str(), ".cleo", [&](const char* fullPath, const char* filename)
{
std::string name = filename;
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { return std::tolower(c); });
Expand All @@ -46,7 +47,7 @@ namespace CLEO
});

// load plugins from legacy location
FilesWalk("cleo", ".cleo", [&](const char* fullPath, const char* filename)
FilesWalk(Filepath_Cleo.c_str(), ".cleo", [&](const char* fullPath, const char* filename)
{
std::string name = filename;
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { return std::tolower(c); });
Expand All @@ -57,7 +58,7 @@ namespace CLEO
HMODULE hlib = LoadLibrary(fullPath);
if (!hlib)
{
LOG_WARNING("Error loading plugin '%s'", fullPath);
LOG_WARNING("Error while loading plugin '%s'", fullPath);
}
else
{
Expand Down
65 changes: 30 additions & 35 deletions source/CScriptEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "CFileMgr.h"
#include "CGame.h"

#include <filesystem>
#include <sstream>

namespace CLEO
Expand Down Expand Up @@ -652,10 +651,15 @@ namespace CLEO

void CCustomScript::SetWorkDir(const char* directory)
{
if(directory == nullptr || strlen(directory) == 0)
return; // Already done. Empty path is relative path starting at current work dir

auto resolved = ResolvePath(directory);

if (!bIsCustom)
GetInstance().ScriptEngine.MainScriptCurWorkDir = directory;
GetInstance().ScriptEngine.MainScriptCurWorkDir = resolved;
else
workDir = directory;
workDir = resolved;
}

std::string CCustomScript::ResolvePath(const char* path, const char* customWorkDir) const
Expand All @@ -667,7 +671,7 @@ namespace CLEO

try
{
auto fsPath = std::filesystem::path(path);
auto fsPath = FS::path(path);

// check for virtual path root
enum class VPref{ None, Game, User, Script, Cleo, Modules } virtualPrefix = VPref::None;
Expand All @@ -686,15 +690,14 @@ namespace CLEO
{
if(fsPath.is_relative())
{
auto workDir = ResolvePath(GetWorkDir());
fsPath = workDir / fsPath;
fsPath = GetWorkDir() / fsPath;
}

return std::filesystem::weakly_canonical(fsPath).string();
return FS::weakly_canonical(fsPath).string();
}

// expand virtual paths
std::filesystem::path resolved;
FS::path resolved;

if (virtualPrefix == VPref::User) // user files location
{
Expand All @@ -703,12 +706,12 @@ namespace CLEO
else
if (virtualPrefix == VPref::Script) // this script's source file location
{
resolved = ResolvePath(GetScriptFileDir());
resolved = GetScriptFileDir();
}
else
{
// all remaing variants starts with game root
resolved = std::filesystem::path(CFileMgr::ms_rootDirName);
resolved = Filepath_Root;

switch(virtualPrefix)
{
Expand All @@ -721,7 +724,7 @@ namespace CLEO
for(auto it = ++fsPath.begin(); it != fsPath.end(); it++)
resolved /= *it;

return std::filesystem::weakly_canonical(resolved).string(); // collapse "..\" uses
return FS::weakly_canonical(resolved).string(); // collapse "..\" uses
}
catch (const std::exception& ex)
{
Expand Down Expand Up @@ -924,29 +927,26 @@ namespace CLEO
{
if (CGame::bMissionPackGame == 0) // regular main game
{
MainScriptFileDir = std::string(DIR_GAME) + "\\data\\script";
MainScriptFileDir = FS::path(Filepath_Cleo).append("data\\script").string();
MainScriptFileName = "main.scm";
}
else // mission pack
{
MainScriptFileDir = std::string(DIR_USER) + "\\MPACK\\MPACK";
MainScriptFileDir += std::to_string(CGame::bMissionPackGame);
MainScriptFileDir = FS::path(GetUserDirectory()).append(stringPrintf("MPACK\\MPACK%d", CGame::bMissionPackGame)).string();
MainScriptFileName = "scr.scm";
}

NativeScriptsDebugMode = GetPrivateProfileInt("General", "DebugMode", 0, GetInstance().ConfigFilename.c_str()) != 0;
MainScriptCurWorkDir = DIR_GAME;
NativeScriptsDebugMode = GetPrivateProfileInt("General", "DebugMode", 0, Filepath_Config.c_str()) != 0;
MainScriptCurWorkDir = Filepath_Root;
}

void CScriptEngine::LoadCustomScripts(bool load_mode)
{
char safe_name[MAX_PATH];

// steam offset is different, so get it manually for now
CGameVersionManager& gvm = GetInstance().VersionManager;
int nSlot = gvm.GetGameVersion() != GV_STEAM ? *(BYTE*)&MenuManager->m_nSelectedSaveGame : *((BYTE*)MenuManager + 0x15B);

sprintf(safe_name, "./cleo/cleo_saves/cs%d.sav", nSlot);
auto saveFile = FS::path(Filepath_Cleo).append(stringPrintf("cleo_saves\\cs%d.sav", nSlot)).string();

safe_info = nullptr;
stopped_info = nullptr;
Expand All @@ -957,8 +957,8 @@ namespace CLEO
// load cleo saving file
try
{
TRACE("Loading cleo safe %s", safe_name);
std::ifstream ss(safe_name, std::ios::binary);
TRACE("Loading cleo safe %s", saveFile.c_str());
std::ifstream ss(saveFile.c_str(), std::ios::binary);
if (ss.is_open())
{
ss.exceptions(std::ios::eofbit | std::ios::badbit | std::ios::failbit);
Expand All @@ -984,7 +984,7 @@ namespace CLEO
}
catch (std::exception& ex)
{
TRACE("Loading of cleo safe %s failed: %s", safe_name, ex.what());
TRACE("Loading of cleo safe %s failed: %s", saveFile.c_str(), ex.what());
safe_header.n_saved_threads = safe_header.n_stopped_threads = 0;
memset(CleoVariables, 0, sizeof(CleoVariables));
}
Expand All @@ -994,23 +994,18 @@ namespace CLEO
memset(CleoVariables, 0, sizeof(CleoVariables));
}

// [game root]\cleo
/*std::string scriptsDir = CFileMgr::ms_rootDirName;
if (!scriptsDir.empty() && scriptsDir.back() != '\\') scriptsDir.push_back('\\');
scriptsDir += "cleo";*/
std::string scriptsDir = "cleo"; // TODO: restore to absolute path when ModLoader is updated to support CLEO5

TRACE("Searching for CLEO scripts");
std::string scriptsDir = "cleo"; // TODO: use Filepath_Cleo instead ModLoader is updated to support CLEO5

FilesWalk(scriptsDir.c_str(), cs_ext, [&](const char* fullPath, const char* filename)
{
if(auto cs = LoadScript(fullPath))
if (auto cs = LoadScript(fullPath))
{
cs->SetDebugMode(NativeScriptsDebugMode); // inherit from global state
}
});

FilesWalk(scriptsDir.c_str(), cs4_ext, [&](const char* fullPath, const char* filename)
FilesWalk(scriptsDir.c_str(), cs4_ext, [&](const char* fullPath, const char* filename)
{
if (auto cs = LoadScript(fullPath))
{
Expand All @@ -1019,7 +1014,7 @@ namespace CLEO
}
});

FilesWalk(scriptsDir.c_str(), cs3_ext, [&](const char* fullPath, const char* filename)
FilesWalk(scriptsDir.c_str(), cs3_ext, [&](const char* fullPath, const char* filename)
{
if (auto cs = LoadScript(fullPath))
{
Expand All @@ -1034,7 +1029,7 @@ namespace CLEO
((callback*)func)();
}

TRACE("Scripts search done.");
TRACE("Scripts search done");
}

CCustomScript * CScriptEngine::LoadScript(const char * szFilePath)
Expand Down Expand Up @@ -1318,12 +1313,12 @@ namespace CLEO
TRACE("Loading custom script %s...", szFileName);

// store script file directory and name
std::filesystem::path path = szFileName;
path = std::filesystem::weakly_canonical(path);
FS::path path = szFileName;
path = FS::weakly_canonical(path);
scriptFileDir = path.parent_path().string();
scriptFileName = path.filename().string();

workDir = DIR_GAME;
workDir = Filepath_Root;

try
{
Expand Down
3 changes: 3 additions & 0 deletions source/CSoundSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "bass.h"
#include "CDebug.h"
#include "CleoBase.h"
#include "Singleton.h"
#include <windows.h>

namespace CLEO
Expand All @@ -28,6 +29,8 @@ namespace CLEO

LRESULT __stdcall HOOK_DefWindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
CleoSingletonCheck(); // check once for CLEO.asi duplicates

if (GetInstance().SoundSystem.Initialized())
{
// pause streams if the window loses focus, or if SA found any other reason to pause
Expand Down
3 changes: 2 additions & 1 deletion source/CTextManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ namespace CLEO
CTextManager::CTextManager() : fxts(1, crc32FromUpcaseStdString)
{
// parse FXT files
FilesWalk("cleo\\cleo_text", ".fxt", [this](const char* fullPath, const char* filename)
auto path = FS::path(Filepath_Cleo).append("cleo_text").string();
FilesWalk(path.c_str(), ".fxt", [this](const char* fullPath, const char* filename)
{
TRACE("Parsing FXT file %s", fullPath);
try
Expand Down
17 changes: 11 additions & 6 deletions source/CleoBase.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "stdafx.h"
#include "CleoBase.h"
#include <filesystem>


namespace CLEO
Expand Down Expand Up @@ -31,12 +30,18 @@ namespace CLEO
{
if (m_bStarted) return; // already started

ConfigFilename = std::filesystem::current_path().append("cleo\\.cleo_config.ini").string();
/*if (FS::current_path() != Filepath_Root)
{
MessageBox(NULL, "CLEO.asi has to be placed in game's root directory!", "CLEO error", MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONERROR | MB_OK);
exit(1); // terminate the game
}*/

FS::create_directory(Filepath_Cleo);
FS::create_directory(FS::path(Filepath_Cleo).append("cleo_modules"));
FS::create_directory(FS::path(Filepath_Cleo).append("cleo_plugins"));
FS::create_directory(FS::path(Filepath_Cleo).append("cleo_saves"));
FS::create_directory(FS::path(Filepath_Cleo).append("cleo_text"));

CreateDirectory("cleo", NULL);
CreateDirectory("cleo/cleo_modules", NULL);
CreateDirectory("cleo/cleo_saves", NULL);
CreateDirectory("cleo/cleo_text", NULL);
CodeInjector.OpenReadWriteAccess(); // must do this earlier to ensure plugins write access on init
GameMenu.Inject(CodeInjector);
DmaFix.Inject(CodeInjector);
Expand Down
Loading

0 comments on commit c48d69e

Please sign in to comment.