From 4f1721e9e4179270c293f394674b48b07f283be2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 20 Sep 2021 21:05:21 -0700 Subject: [PATCH] Add support for hl2sdk-mock. This also fixes UTIL_Relatize basically being completely bogus. For backwards compat it's wrapped in a helper though. --- AMBuildScript | 24 +++++-- core/ISmmPluginExt.h | 1 + core/metamod_util.cpp | 117 +++++++++++++++++++++++++++++++-- core/metamod_util.h | 10 +-- core/provider/provider_ep2.cpp | 4 ++ loader/loader.cpp | 5 ++ loader/loader.h | 1 + loader/serverplugin.cpp | 2 + 8 files changed, 151 insertions(+), 13 deletions(-) diff --git a/AMBuildScript b/AMBuildScript index 95893da..8225ac2 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -46,6 +46,11 @@ Blade = { 'windows': ['x86', 'x86_64'], 'linux': ['x86_64'] } +Mock = { + 'windows': ['x86', 'x86_64'], + 'linux': ['x86', 'x86_64'], + 'mac': ['x86_64'] +} PossibleSDKs = { 'episode1': SDK('HL2SDK', '2.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'), @@ -70,6 +75,7 @@ PossibleSDKs = { 'doi': SDK('HL2SDKDOI', '2.doi', '20', 'DOI', WinLinuxMac, 'doi'), 'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'), 'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'), + 'mock': SDK('HL2SDK-MOCK', '2.mock', '999', 'MOCK', Mock, 'mock'), } def ResolveEnvPath(env, folder): @@ -200,7 +206,10 @@ class MMSConfig(object): '-fPIC', ] - cxx.cxxflags += [ '-std=c++11' ] + if cxx.version == 'apple-clang-6.0' or cxx.version == 'clang-3.4': + cxx.cxxflags += ['-std=c++1y'] + else: + cxx.cxxflags += ['-std=c++14'] if (cxx.version >= 'gcc-4.0') or cxx.family == 'clang': cxx.cflags += ['-fvisibility=hidden'] cxx.cxxflags += ['-fvisibility-inlines-hidden'] @@ -450,10 +459,13 @@ class MMSConfig(object): lib_folder = os.path.join(sdk.path, 'lib', 'mac') if compiler.target.platform in ['linux', 'mac']: - if sdk.name in ['sdk2013', 'bms'] or compiler.target.arch == 'x86_64': - compiler.postlink += [os.path.join(lib_folder, 'tier1.a')] + if sdk.name in ['sdk2013', 'bms', 'mock'] or compiler.target.arch == 'x86_64': + tier1 = os.path.join(lib_folder, 'tier1.a') else: - compiler.postlink += [os.path.join(lib_folder, 'tier1_i486.a')] + tier1 = os.path.join(lib_folder, 'tier1_i486.a') + if sdk.name == 'mock' and compiler.target.platform == 'linux': + compiler.linkflags += ['-Wl,-z,origin'] + compiler.postlink += [tier1] if sdk.name in ['blade', 'insurgency', 'doi', 'csgo', 'dota']: if compiler.target.arch == 'x86_64': @@ -472,12 +484,14 @@ class MMSConfig(object): compiler.linkflags[0:0] = ['-lm'] if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']: dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so'] - elif compiler.target.arch == 'x86_64' and sdk.name in ['csgo', 'blade']: + elif compiler.target.arch == 'x86_64' and sdk.name in ['csgo', 'blade', 'mock']: dynamic_libs = ['libtier0_client.so', 'libvstdlib_client.so'] elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo', 'dota']: dynamic_libs = ['libtier0.so', 'libvstdlib.so'] else: dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so'] + if sdk.name in ['csgo', 'blade']: + compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0'] elif compiler.target.platform == 'mac': binary.compiler.linkflags.append('-liconv') dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib'] diff --git a/core/ISmmPluginExt.h b/core/ISmmPluginExt.h index 9cb4b8c..0c64f46 100644 --- a/core/ISmmPluginExt.h +++ b/core/ISmmPluginExt.h @@ -60,6 +60,7 @@ #define SOURCE_ENGINE_CONTAGION 22 /**< Contagion */ #define SOURCE_ENGINE_BMS 23 /**< Black Mesa Multiplayer */ #define SOURCE_ENGINE_DOI 24 /**< Day of Infamy */ +#define SOURCE_ENGINE_MOCK 25 /**< Mock source engine */ #define METAMOD_PLAPI_VERSION 16 /**< Version of this header file */ #define METAMOD_PLAPI_NAME "ISmmPlugin" /**< Name of the plugin interface */ diff --git a/core/metamod_util.cpp b/core/metamod_util.cpp index 8bbb14d..c20b208 100644 --- a/core/metamod_util.cpp +++ b/core/metamod_util.cpp @@ -28,9 +28,20 @@ #include #include #include +#include +#include #include "metamod_util.h" #include "metamod_oslink.h" +#ifdef _WIN32 +# include +#else +# include +# include +#endif + +using namespace std::string_literals; + /** * @brief Utility functions * @file util.cpp @@ -239,10 +250,10 @@ inline bool pathchar_cmp(char a, char b) * @param relFrom Source file or folder to use as a target. * @return True on success, false on failure. */ -bool UTIL_Relatize(char buffer[], - size_t maxlength, - const char *relTo, - const char *relFrom) +bool UTIL_BadRelatize(char buffer[], + size_t maxlength, + const char *relTo, + const char *relFrom) { /* We don't allow relative paths in here, force * the user to resolve these himself! @@ -357,3 +368,101 @@ bool UTIL_VerifySignature(const void *addr, const char *sig, size_t len) return true; } + +static bool ComparePathComponent(const std::string& a, const std::string& b) { +#ifdef _WIN32 + if (a.size() != b.size()) + return false; + for (size_t i = 0; i < a.size(); i++) { + if (!pathchar_cmp(a[i], b[i])) + return false; + } + return true; +#else + return a == b; +#endif +} + +static std::vector SplitPath(const char* path) { + std::vector parts; + + const char* iter = path; + +#ifdef _WIN32 + if (isalpha(path[0]) && path[1] == ':' && pathchar_sep(path[2])) { + // Append drive only (eg C:) + parts.emplace_back(path, 2); + iter += 2; + while (pathchar_sep(*iter)) + iter++; + } +#endif + + if (pathchar_sep(*iter)) { + parts.emplace_back(PATH_SEP_STR); + while (pathchar_sep(*iter)) + iter++; + } + + while (*iter) { + const char* start = iter; + while (*iter && !pathchar_sep(*iter)) + iter++; + if (iter != start) + parts.emplace_back(start, iter - start); + while (pathchar_sep(*iter)) + iter++; + } + return parts; +} + +bool UTIL_Relatize2(char* buffer, size_t maxlen, const char* path1, const char* path2) +{ + auto parts1 = SplitPath(path1); + auto parts2 = SplitPath(path2); + + // If this fails, paths were not relative or have different drives. + if (parts1[0] != parts2[0]) + return false; + + // Skip past identical paths. + size_t cursor = 1; + while (true) { + if (cursor >= parts1.size() || cursor >= parts2.size()) + break; + if (!ComparePathComponent(parts1[cursor], parts2[cursor])) + break; + cursor++; + } + + std::string new_path; + for (size_t i = cursor; i < parts1.size(); i++) + new_path += ".."s + PATH_SEP_STR; + for (size_t i = cursor; i < parts2.size(); i++) { + new_path += parts2[i]; + if (i != parts2.size() - 1) + new_path += PATH_SEP_STR; + } + if (pathchar_sep(path2[strlen(path2) - 1])) + new_path += PATH_SEP_STR; + + snprintf(buffer, maxlen, "%s", new_path.c_str()); + return true; +} + +static inline bool PathExists(const char* path) { +#ifdef _WIN32 + return _access(path, 0) == 0 || errno != ENOENT; +#else + return access(path, F_OK) == 0 || errno != ENOENT; +#endif +} + +bool UTIL_Relatize(char buffer[], size_t maxlength, const char *relTo, const char *relFrom) +{ + if (UTIL_BadRelatize(buffer, maxlength, relTo, relFrom)) { + if (PathExists(buffer)) + return true; + } + return UTIL_Relatize2(buffer, maxlength, relTo, relFrom); +} diff --git a/core/metamod_util.h b/core/metamod_util.h index fa20138..cf946e0 100644 --- a/core/metamod_util.h +++ b/core/metamod_util.h @@ -80,10 +80,12 @@ size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list * @param relFrom Source file or folder to use as a target. * @return True on success, false on failure. */ -bool UTIL_Relatize(char buffer[], - size_t maxlength, - const char *relTo, - const char *relFrom); +bool UTIL_Relatize(char buffer[], size_t maxlength, const char *relTo, const char *relFrom); + +// The previous version of Relatize is broken. Do not use it. We include it for +// backwards compatibility in old engines only, in case there are weird path +// scenarios going on. +bool UTIL_Relatize2(char buffer[], size_t maxlength, const char *relTo, const char *relFrom); /** * @brief Compares memory address against a signature. diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index ec67f3e..b2a3684 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -540,6 +540,8 @@ int BaseProvider::DetermineSourceEngine() return SOURCE_ENGINE_BMS; #elif SOURCE_ENGINE == SE_EPISODEONE return g_bOriginalEngine ? SOURCE_ENGINE_ORIGINAL : SOURCE_ENGINE_EPISODEONE; +#elif SOURCE_ENGINE == SE_MOCK + return SOURCE_ENGINE_MOCK; #else #error "SOURCE_ENGINE not defined to a known value" #endif @@ -671,6 +673,8 @@ const char *BaseProvider::GetEngineDescription() const { return "Episode 1 (2004)"; } +#elif SOURCE_ENGINE == SE_MOCK + return "Mock"; #else #error "SOURCE_ENGINE not defined to a known value" #endif diff --git a/loader/loader.cpp b/loader/loader.cpp index 9f277da..4918709 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -91,6 +91,7 @@ static const char *backend_names[] = "2.contagion", "2.bms", "2.doi", + "2.mock", }; #if defined _WIN32 @@ -425,6 +426,10 @@ mm_DetermineBackend(QueryValveInterface engineFactory, QueryValveInterface serve { return MMBackend_HL2DM; } + else if (strcmp(game_name, ".") == 0 && engineFactory("MOCK_ENGINE", NULL)) + { + return MMBackend_Mock; + } else { return MMBackend_SDK2013; diff --git a/loader/loader.h b/loader/loader.h index ca2e01d..5e7b99e 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -104,6 +104,7 @@ enum MetamodBackend MMBackend_BMS, MMBackend_DOI, + MMBackend_Mock, MMBackend_UNKNOWN }; diff --git a/loader/serverplugin.cpp b/loader/serverplugin.cpp index 9daff26..4d5cba2 100644 --- a/loader/serverplugin.cpp +++ b/loader/serverplugin.cpp @@ -91,6 +91,8 @@ public: mm_GetGameName(game_name, sizeof(game_name)); mm_backend = mm_DetermineBackend(engineFactory, gsFactory, game_name); + if (mm_backend == MMBackend_Mock) + strcpy(game_name, "mock"); } if (mm_backend == MMBackend_UNKNOWN)