From 4c8103a4e1946ad1f66f6e6abc8599b3fe73fc14 Mon Sep 17 00:00:00 2001 From: Nick Hastings Date: Thu, 25 Jun 2020 21:20:56 -0400 Subject: [PATCH] Add string_t SetEntPropString support for ep1 (fixes #1287) --- core/HalfLife2.cpp | 72 +++++++++++++++++++++++++++--- core/HalfLife2.h | 2 - core/smn_entities.cpp | 4 -- gamedata/core.games/engine.ep1.txt | 6 +++ 4 files changed, 71 insertions(+), 13 deletions(-) diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index d9106d04..f9e60f37 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -1367,8 +1367,36 @@ bool CHalfLife2::IsMapValid(const char *map) return FindMap(map) != SMFindMapResult::NotFound; } -// TODO: Add ep1 support for this. (No IServerTools available there) -#if SOURCE_ENGINE >= SE_ORANGEBOX +#if SOURCE_ENGINE == SE_EPISODEONE +class VKeyValuesSS_Helper {}; +static bool VKeyValuesSS(CBaseEntity* pThisPtr, const char *pszKey, const char *pszValue, int offset) +{ + void** this_ptr = *reinterpret_cast(&pThisPtr); + void** vtable = *reinterpret_cast(pThisPtr); + void* vfunc = vtable[offset]; + + union + { + bool (VKeyValuesSS_Helper::* mfpnew)(const char *, const char *); +#ifndef PLATFORM_POSIX + void* addr; + } u; + u.addr = vfunc; +#else + struct + { + void* addr; + intptr_t adjustor; + } s; +} u; + u.s.addr = vfunc; + u.s.adjustor = 0; +#endif + + return (bool)(reinterpret_cast(this_ptr)->*u.mfpnew)(pszKey, pszValue); +} +#endif + string_t CHalfLife2::AllocPooledString(const char *pszValue) { // This is admittedly a giant hack, but it's a relatively safe method for @@ -1378,28 +1406,58 @@ string_t CHalfLife2::AllocPooledString(const char *pszValue) // current targetname string_t, set it to our string to insert via SetKeyValue, // read back the new targetname value, restore the old value, and return the new one. +#if SOURCE_ENGINE == SE_EPISODEONE + CBaseEntity* pEntity = nullptr; + for (int i = 0; i < gpGlobals->maxEntities; ++i) + { + pEntity = ReferenceToEntity(i); + if (pEntity) + { + break; + } + } + + if (!pEntity) + { + logger->LogError("Failed to locate a valid entity for AllocPooledString."); + return NULL_STRING; + } + +#else CBaseEntity *pEntity = ((IServerUnknown *) servertools->FirstEntity())->GetBaseEntity(); +#endif auto *pDataMap = GetDataMap(pEntity); assert(pDataMap); - static int offset = -1; - if (offset == -1) + static int iNameOffset = -1; + if (iNameOffset == -1) { sm_datatable_info_t info; bool found = FindDataMapInfo(pDataMap, "m_iName", &info); assert(found); - offset = info.actual_offset; + iNameOffset = info.actual_offset; } - string_t *pProp = (string_t *) ((intp) pEntity + offset); + string_t* pProp = (string_t*)((intp)pEntity + iNameOffset); string_t backup = *pProp; + +#if SOURCE_ENGINE == SE_EPISODEONE + static int iFuncOffset; + if (!g_pGameConf->GetOffset("DispatchKeyValue", &iFuncOffset) || !iFuncOffset) + { + logger->LogError("Failed to locate DispatchKeyValue in core gamedata. AllocPooledString unsupported."); + return NULL_STRING; + } + VKeyValuesSS(pEntity, "targetname", pszValue, iFuncOffset); +#else servertools->SetKeyValue(pEntity, "targetname", pszValue); +#endif + string_t newString = *pProp; *pProp = backup; return newString; } -#endif bool CHalfLife2::GetServerSteam3Id(char *pszOut, size_t len) const { diff --git a/core/HalfLife2.h b/core/HalfLife2.h index 74dc9a85..86860468 100644 --- a/core/HalfLife2.h +++ b/core/HalfLife2.h @@ -239,9 +239,7 @@ public: //IGameHelpers void FreeUtlVectorUtlString(CUtlVector> &vec); #endif bool GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax); -#if SOURCE_ENGINE >= SE_ORANGEBOX string_t AllocPooledString(const char *pszValue); -#endif bool GetServerSteam3Id(char *pszOut, size_t len) const override; uint64_t GetServerSteamId64() const override; public: diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index a8495694..698743cf 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -2380,12 +2380,8 @@ static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params) if (bIsStringIndex) { -#if SOURCE_ENGINE < SE_ORANGEBOX - return pContext->ThrowNativeError("Cannot set %s. Setting string_t values not supported on this game.", prop); -#else *(string_t *) ((intptr_t) pEntity + offset) = g_HL2.AllocPooledString(src); len = strlen(src); -#endif } else { diff --git a/gamedata/core.games/engine.ep1.txt b/gamedata/core.games/engine.ep1.txt index 932f92ca..44f763e0 100644 --- a/gamedata/core.games/engine.ep1.txt +++ b/gamedata/core.games/engine.ep1.txt @@ -41,6 +41,12 @@ "windows" "4" "linux" "4" } + + /* For AllocPooledString. KeyValue(const char *, const char *) */ + "DispatchKeyValue" + { + "windows" "35" + } } "Keys"