Skip to content

Commit

Permalink
Implemented ResolvePath
Browse files Browse the repository at this point in the history
  • Loading branch information
MiranDMC committed Jun 8, 2024
1 parent bdf09fe commit 9575a5e
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 75 deletions.
132 changes: 95 additions & 37 deletions modloader_plugin/source/CLEO_ModLoader_Provider.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
#include "CLEO_ModLoader_Provider.h"
#include <filesystem>
#include <windows.h>
#include <algorithm>

using namespace std;
using namespace CLEO;
namespace FS = filesystem;

const char* const CLEO_ModLoader_Provider::Mod_Loader_Dir = "modloader\\";

bool CLEO_ModLoader_Provider::IsHandled(const modloader::file& file)

void CLEO_ModLoader_Provider::Init(const char* gamePath)
{
//return file.is_dir() && (_stricmp(file.filedir(), "cleo") == 0); // cleo directories
this->gamePath = gamePath;
NormalizePath(this->gamePath);

modLoaderPath = this->gamePath + Mod_Loader_Dir;
}

bool CLEO_ModLoader_Provider::IsHandled(const modloader::file& file) const
{
if (file.is_dir()) return false;

if (file.is_ext("cm") ||
Expand All @@ -35,7 +43,7 @@ void CLEO_ModLoader_Provider::RemoveFile(const modloader::file& file)
files.erase(&file);
}

set<string> CLEO_ModLoader_Provider::ListCleoFiles(const char* searchPattern)
set<string> CLEO_ModLoader_Provider::ListCleoFiles(const char* searchPattern) const
{
set<string> found;
if (files.empty()) return found;
Expand Down Expand Up @@ -87,48 +95,98 @@ set<string> CLEO_ModLoader_Provider::ListCleoFiles(const char* searchPattern)
return found;
}

void CLEO_ModLoader_Provider::NormalizePath(string& path)
string CLEO::CLEO_ModLoader_Provider::ResolvePath(const char* scriptPath, const char* path) const
{
replace(path.begin(), path.end(), '/', '\\');
transform(path.begin(), path.end(), path.begin(), [](unsigned char c) { return tolower(c); }); // to lower case
}
if (files.empty() ||
scriptPath == nullptr || strlen(scriptPath) <= modLoaderPath.length() ||
path == nullptr || strlen(path) <= gamePath.length())
{
return {};
}

/*string CLEO::CLEO_ModLoader_Provider::ResolvePath(CRunningScript* thread, const char* pathStr) const
{
if (!IsActive()) return {};
string script = scriptPath;
NormalizePath(script);

// is the script file in modloader directory?
auto scriptDir = FS::path(((CLEO::CCustomScript*)thread)->GetScriptFileDir());
auto [endLoader, _1] = mismatch(modloaderDir.begin(), modloaderDir.end(), scriptDir.begin());
if (endLoader != modloaderDir.end()) return {}; // the script is not modloader's mod
if (strncmp(script.c_str(), modLoaderPath.c_str(), modLoaderPath.length()) != 0)
{
return {}; // the script is not located inside 'modloader' directory
}

auto path = FS::weakly_canonical(FS::path(pathStr));
string p = path;
NormalizePath(p);

// do the path starts with game root?
auto [endGame, _2] = mismatch(gameDir.begin(), gameDir.end(), path.begin());
if (endGame != gameDir.end()) return {}; // the path target is not within the game root directory
if (strncmp(p.c_str(), gamePath.c_str(), gamePath.length()) != 0)
{
return {}; // the path is not within game directory
}

auto modName = *(FS::proximate(scriptDir, modloaderDir).begin());
if (!HasMod(modName.string().c_str())) return {}; // this mod is disabled/not present in modloader (but runs anyway?)
if (strncmp(p.c_str(), modLoaderPath.c_str(), modLoaderPath.length()) == 0)
{
return {}; // the path is already pointing inside 'modloader' directory, no need for resolving
}

auto relative = FS::proximate(path, gameDir);
// is the script part of any currently loaded mods?
script.resize(script.length() - gamePath.length()); // cut game directory path
auto scriptModFile = files.begin();
while (true)
{
if (scriptModFile == files.end())
{
return {}; // the script is not from ModLoader
}

auto modedPath = modloaderDir;
modedPath /= modName;
modedPath /= relative;
if (script == (*scriptModFile)->filebuffer())
{
break; // found
}

auto oriStatus = FS::status(path);
bool oriExists = FS::is_regular_file(oriStatus) || FS::is_directory(oriStatus);
scriptModFile++;
}

auto modedStatus = FS::status(modedPath);
bool modedExists = FS::is_regular_file(modedStatus) || FS::is_directory(modedStatus);
// build moded path relative to that mod's directory
string modded = modLoaderPath;
modded += GetModName(**scriptModFile);

if (!modedExists && oriExists) return {}; // file/dir not present in that mod, but exists in the game itself. Keep original path
auto relative = p.c_str() + gamePath.length();
if (strlen(relative) > 0)
{
modded += "\\";
modded += relative;
}

if (GetFileAttributesA(modded.c_str()) != INVALID_FILE_ATTRIBUTES)
{
return modded;
}

if (GetFileAttributesA(p.c_str()) == INVALID_FILE_ATTRIBUTES)
{
return modded; // both paths do not exists, so the mod perhaps tries to create new file
}

auto result = modedPath.string();
// TODO: check if original path ended with path separator and add it then
return {};
}

return result;
}*/
void CLEO_ModLoader_Provider::NormalizePath(string& path)
{
replace(path.begin(), path.end(), '/', '\\');
transform(path.begin(), path.end(), path.begin(), [](unsigned char c) { return tolower(c); }); // to lower case
}

string_view CLEO_ModLoader_Provider::GetModName(const modloader::file& file)
{
auto start = file.buffer + strlen(Mod_Loader_Dir);

size_t length;
auto separator = strchr(start, '\\');
if (separator != nullptr)
{
length = (size_t)separator - (size_t)start; // distance
}
else
{
length = strlen(start);
}

return std::string_view(start, length);
}
20 changes: 13 additions & 7 deletions modloader_plugin/source/CLEO_ModLoader_Provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,27 @@ namespace CLEO

class CLEO_ModLoader_Provider
{
std::set<const modloader::file*> files;

public:
CLEO_ModLoader_Provider() = default;
~CLEO_ModLoader_Provider() = default;

bool IsHandled(const modloader::file&); // is this file interesting to the provider
void Init(const char* gamePath);

bool IsHandled(const modloader::file&) const; // is this file interesting to the provider
void AddFile(const modloader::file&);
void RemoveFile(const modloader::file&);

std::set<std::string> ListCleoFiles(const char* searchPattern);

//std::string ResolvePath(CRunningScript* thread, const char* path) const;
std::set<std::string> ListCleoFiles(const char* searchPattern) const;
std::string ResolvePath(const char* scriptPath, const char* path) const;

private:
void NormalizePath(std::string& path);
static const char* const Mod_Loader_Dir;

std::string gamePath;
std::string modLoaderPath;
std::set<const modloader::file*> files;

static void NormalizePath(std::string& path);
static std::string_view GetModName(const modloader::file&);
};
}
19 changes: 18 additions & 1 deletion modloader_plugin/source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class ModLoaderPlugin : public modloader::basic_plugin
} plugin;
REGISTER_ML_PLUGIN(::plugin);


const ModLoaderPlugin::info& ModLoaderPlugin::GetInfo()
{
static const char* extable[] = { "cleo", "cleo5", "cm", "cs", "cs3", "cs4", 0 };
Expand All @@ -30,6 +29,7 @@ const ModLoaderPlugin::info& ModLoaderPlugin::GetInfo()

bool ModLoaderPlugin::OnStartup()
{
cleoML.Init(loader->gamepath);
return true;
}

Expand Down Expand Up @@ -98,3 +98,20 @@ extern "C" __declspec(dllexport) void StringListFree(CLEO::StringList list)
free(list.strings);
}
}

extern "C" __declspec(dllexport) BOOL ResolvePath(const char* scriptPath, char* path, DWORD pathMaxSize)
{
auto resolved = plugin.cleoML.ResolvePath(scriptPath, path);

if (!resolved.empty())
{
if (resolved.length() >= pathMaxSize)
resolved.resize(pathMaxSize - 1); // and terminator character

std::memcpy(path, resolved.c_str(), resolved.length() + 1); // with terminator

return true;
}

return false;
}
19 changes: 18 additions & 1 deletion source/CCustomOpcodeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1933,7 +1933,24 @@ extern "C"
return; // invalid param
}

auto resolved = reinterpret_cast<CCustomScript*>(thread)->ResolvePath(inOutPath);
auto cs = reinterpret_cast<CCustomScript*>(thread);

auto resolved = cs->ResolvePath(inOutPath);

auto modLoader = GetInstance().ModLoaderSystem;
if (modLoader.IsActive())
{
if (resolved.length() < (pathMaxLen - 1))
{
resolved.resize(pathMaxLen);
}

std::string scriptFilePath = cs->GetScriptFileDir();
scriptFilePath += '\\';
scriptFilePath += cs->GetScriptFileName();

modLoader.ResolvePath(scriptFilePath.c_str(), resolved.data(), resolved.length() + 1); // including terminator character
}

if (resolved.length() >= pathMaxLen)
resolved.resize(pathMaxLen - 1); // and terminator character
Expand Down
28 changes: 18 additions & 10 deletions source/CModLoaderSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,41 @@ using namespace CLEO;

extern const StringList (__cdecl* ListCleoFiles)(const char* directory, const char* filePattern);
extern const void (__cdecl* StringListFree)(StringList);
extern const BOOL (__cdecl* ResolvePath)(const char* scriptPath, char* path, DWORD pathMaxSize);

void CModLoaderSystem::Init()
{
if (initialized) return;
auto provider = GetModuleHandleA("CLEO5_Provider.dll"); // CLEO's Mod Loader plugin
initialized = true;

if (GetModuleHandleA("modloader.asi") == NULL)
{
return;
}
TRACE("ModLoader detected");

auto provider = GetModuleHandleA("CLEO5_Provider.dll"); // CLEO's Mod Loader plugin
if (provider == NULL)
{
active = false;
SHOW_ERROR("CLEO's ModLoader plugin was not detected!\nPlease make sure CLEO5_Provider.dll is present.");
return;
}

TRACE("ModLoader detetected! Support activated.");

ListCleoFiles = memory_pointer(GetProcAddress(provider, "ListCleoFiles"));
StringListFree = memory_pointer(GetProcAddress(provider, "StringListFree"));
ResolvePath = memory_pointer(GetProcAddress(provider, "ResolvePath"));

if (ListCleoFiles == nullptr || StringListFree == nullptr || ResolvePath == nullptr)
{
SHOW_ERROR("CLEO's ModLoader plugin error!");
return;
}

TRACE("ModLoader support activate");
active = true;
initialized = true;
}

bool CModLoaderSystem::IsActive() const
{
return active;
}

void CModLoaderSystem::ResolvePath(CRunningScript* thread, char* inOutPath) const
{
if (!IsActive()) return;
}
2 changes: 1 addition & 1 deletion source/CModLoaderSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ namespace CLEO
const void (__cdecl* StringListFree)(CLEO::StringList) = nullptr;

const CLEO::StringList (__cdecl* ListCleoFiles)(const char* searchPattern) = nullptr;
void ResolvePath(CRunningScript* thread, char* inOutPath) const;
const BOOL (__cdecl* ResolvePath)(const char* scriptPath, char* path, DWORD pathMaxSize) = nullptr;
};
}
Loading

0 comments on commit 9575a5e

Please sign in to comment.