dvander@592: /** dvander@4069: * vim: set ts=4 sw=4 tw=99 noet : ds@1330: * ============================================================================= dvander@1231: * SourceMod ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. ds@1330: * ============================================================================= dvander@592: * ds@1330: * This program is free software; you can redistribute it and/or modify it under ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the ds@1330: * Free Software Foundation. dvander@1231: * ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1330: * details. dvander@1231: * ds@1330: * You should have received a copy of the GNU General Public License along with ds@1330: * this program. If not, see . dvander@1231: * ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1330: * this exception to all derivative works. AlliedModders LLC defines further ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1330: * or . dvander@592: * dvander@592: * Version: $Id$ dvander@592: */ dvander@592: dvander@592: #include "HalfLife2.h" ds@696: #include "sourcemod.h" dvander@592: #include "sourcemm_api.h" ds@873: #include "UserMessages.h" dvander@1338: #include "PlayerManager.h" dvander@1547: #include "sm_stringutil.h" dvander@3010: #include dvander@1547: #include pred@2746: #include skamonkey@3460: #include "LibrarySys.h" dvander@3010: #include "logic_bridge.h" skamonkey@3669: #include dvander@592: skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: #include skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3743: #include skamonkey@3743: #endif skamonkey@3743: skamonkey@3462: skamonkey@3462: typedef ICommandLine *(*FakeGetCommandLine)(); skamonkey@3462: dvander@3872: #if defined _WIN32 dvander@3872: #define TIER0_NAME "tier0.dll" dvander@3872: #define VSTDLIB_NAME "vstdlib.dll" dvander@3872: #elif defined __APPLE__ dvander@3872: #define TIER0_NAME "libtier0.dylib" dvander@3872: #define VSTDLIB_NAME "libvstdlib.dylib" skamonkey@3462: #elif defined __linux__ skamonkey@4141: #if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_LEFT4DEAD2 skamonkey@3669: #define TIER0_NAME "libtier0_srv.so" skamonkey@3669: #define VSTDLIB_NAME "libvstdlib_srv.so" januk@3763: #elif SOURCE_ENGINE >= SE_LEFT4DEAD wazzled08@3491: #define TIER0_NAME "libtier0.so" wazzled08@3491: #define VSTDLIB_NAME "libvstdlib.so" wazzled08@3491: #else wazzled08@3491: #define TIER0_NAME "tier0_i486.so" skamonkey@3462: #define VSTDLIB_NAME "vstdlib_i486.so" dvander@3872: #endif skamonkey@3460: #endif skamonkey@3460: dvander@592: CHalfLife2 g_HL2; dvander@1423: ConVar *sv_lan = NULL; dvander@592: pred@2746: static void *g_EntList = NULL; skamonkey@4230: static void **g_pEntInfoList = NULL; pred@2746: static int entInfoOffset = -1; pred@2746: skamonkey@4230: static CEntInfo *EntInfoArray() skamonkey@4230: { skamonkey@4230: if (g_EntList != NULL) skamonkey@4230: { skamonkey@4230: return (CEntInfo *)((intp)g_EntList + entInfoOffset); skamonkey@4230: } skamonkey@4230: else if (g_pEntInfoList) skamonkey@4230: { skamonkey@4230: return *(CEntInfo **)g_pEntInfoList; skamonkey@4230: } skamonkey@4230: skamonkey@4230: return NULL; skamonkey@4230: } skamonkey@4230: dvander@592: CHalfLife2::CHalfLife2() dvander@592: { dvander@4084: m_Maps.init(); dvander@592: } dvander@592: dvander@592: CHalfLife2::~CHalfLife2() dvander@592: { dvander@4069: for (NameHashSet::iterator iter = m_Classes.iter(); !iter.empty(); iter.next()) dvander@4069: delete *iter; faluco@682: dvander@4069: for (DataTableMap::iterator iter = m_Maps.iter(); !iter.empty(); iter.next()) dvander@4069: delete iter->value; dvander@592: } dvander@592: ds@2583: #if SOURCE_ENGINE != SE_DARKMESSIAH dvander@677: CSharedEdictChangeInfo *g_pSharedChangeInfo = NULL; ds@2583: #endif ds@2583: dvander@2846: #if !defined METAMOD_PLAPI_VERSION || PLAPI_VERSION < 11 dvander@1581: bool is_original_engine = false; dvander@2846: #endif dvander@677: dvander@592: void CHalfLife2::OnSourceModStartup(bool late) dvander@592: { ds@2583: #if SOURCE_ENGINE != SE_DARKMESSIAH ds@2583: ds@696: /* The Ship currently is the only known game to use an older version of the engine */ dvander@2846: #if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11 dvander@1581: if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL) dvander@1581: #else ds@729: if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0) dvander@1581: #endif dvander@677: { dvander@1581: is_original_engine = true; dvander@1581: } dvander@1581: else if (g_pSharedChangeInfo == NULL) dvander@1581: { dvander@677: g_pSharedChangeInfo = engine->GetSharedEdictChangeInfo(); dvander@677: } ds@2583: #endif dvander@592: } dvander@592: ds@873: void CHalfLife2::OnSourceModAllInitialized() ds@873: { ds@873: m_MsgTextMsg = g_UserMsgs.GetMessageIndex("TextMsg"); faluco@1218: m_HinTextMsg = g_UserMsgs.GetMessageIndex("HintText"); ds@2583: m_SayTextMsg = g_UserMsgs.GetMessageIndex("SayText"); faluco@1218: m_VGUIMenu = g_UserMsgs.GetMessageIndex("VGUIMenu"); dvander@3872: sharesys->AddInterface(NULL, this); ds@873: } ds@873: pred@2746: void CHalfLife2::OnSourceModAllInitialized_Post() pred@2746: { skamonkey@3460: InitLogicalEntData(); skamonkey@3460: InitCommandLine(); skamonkey@3460: } skamonkey@3460: skamonkey@3460: void CHalfLife2::InitLogicalEntData() skamonkey@3460: { pred@2746: char *addr = NULL; pred@2746: skamonkey@3221: /* skamonkey@3221: * gEntList and/or g_pEntityList skamonkey@3221: * skamonkey@3221: * First try to lookup pointer directly for platforms with symbols. skamonkey@3221: * If symbols aren't present (Windows or stripped Linux/Mac), skamonkey@3221: * attempt find via LevelShutdown + offset skamonkey@3221: */ skamonkey@3221: if (g_pGameConf->GetMemSig("gEntList", (void **)&addr)) pred@2746: { skamonkey@3238: #if !defined PLATFORM_WINDOWS skamonkey@3221: if (!addr) skamonkey@3221: { skamonkey@3221: // Key exists so notify if lookup fails, but try other method. skamonkey@3221: g_Logger.LogError("Failed lookup of gEntList directly - Reverting to lookup via LevelShutdown"); skamonkey@3221: } skamonkey@3221: else skamonkey@3221: { skamonkey@3238: #endif skamonkey@3221: g_EntList = reinterpret_cast(addr); skamonkey@3238: #if !defined PLATFORM_WINDOWS skamonkey@3221: } skamonkey@3238: #endif pred@2746: } skamonkey@3221: skamonkey@3221: if (!g_EntList) pred@2746: { skamonkey@4230: if (g_pGameConf->GetMemSig("LevelShutdown", (void **) &addr) && addr) skamonkey@3221: { skamonkey@4230: int offset; skamonkey@4230: if (!g_pGameConf->GetOffset("gEntList", &offset)) skamonkey@4230: { skamonkey@4230: g_Logger.LogError("Logical Entities not supported by this mod (gEntList) - Reverting to networkable entities only"); skamonkey@4230: return; skamonkey@4230: } skamonkey@3221: skamonkey@4230: g_EntList = *reinterpret_cast(addr + offset); skamonkey@4230: skamonkey@3221: } skamonkey@4230: } skamonkey@3221: skamonkey@4230: // If we have g_EntList from either of the above methods, make sure we can get the offset from it to EntInfo as well skamonkey@4230: if (g_EntList && !g_pGameConf->GetOffset("EntInfo", &entInfoOffset)) pred@2746: { skamonkey@4230: g_Logger.LogError("Logical Entities not supported by this mod (EntInfo) - Reverting to networkable entities only"); skamonkey@4230: g_EntList = NULL; pred@2746: return; pred@2746: } pred@2746: skamonkey@4230: // If we don't have g_EntList or have it but don't know where EntInfo is on it, use fallback. skamonkey@4230: if (!g_EntList || entInfoOffset == -1) pred@2746: { skamonkey@4230: g_pGameConf->GetAddress("EntInfosPtr", (void **)&g_pEntInfoList); skamonkey@4230: } skamonkey@4230: skamonkey@4230: if (!g_EntList && !g_pEntInfoList) skamonkey@4230: { skamonkey@4230: g_Logger.LogError("Failed lookup of gEntList - Reverting to networkable entities only"); pred@2746: return; pred@2746: } pred@2746: } pred@2746: skamonkey@3460: void CHalfLife2::InitCommandLine() skamonkey@3460: { skamonkey@3460: char error[256]; skamonkey@3460: skamonkey@4195: if (!is_original_engine) dvander@3872: { skamonkey@4195: ke::AutoPtr lib(g_LibSys.OpenLibrary(TIER0_NAME, error, sizeof(error))); skamonkey@4195: if (lib == NULL) dvander@3872: { skamonkey@4195: g_Logger.LogError("Could not load %s: %s", TIER0_NAME, error); dvander@3872: return; dvander@3872: } skamonkey@4195: skamonkey@4195: m_pGetCommandLine = lib->GetSymbolAddress("CommandLine_Tier0"); dvander@3872: skamonkey@4195: /* '_Tier0' dropped on Alien Swarm version */ skamonkey@4195: if (m_pGetCommandLine == NULL) dvander@3872: { skamonkey@4195: m_pGetCommandLine = lib->GetSymbolAddress("CommandLine"); skamonkey@4195: } skamonkey@4195: } skamonkey@4195: else skamonkey@4195: { skamonkey@4195: ke::AutoPtr lib(g_LibSys.OpenLibrary(VSTDLIB_NAME, error, sizeof(error))); skamonkey@4195: if (lib == NULL) skamonkey@4195: { skamonkey@4195: g_Logger.LogError("Could not load %s: %s", VSTDLIB_NAME, error); dvander@3872: return; dvander@3872: } dvander@3872: dvander@3872: m_pGetCommandLine = lib->GetSymbolAddress("CommandLine"); skamonkey@4195: } skamonkey@4195: skamonkey@4195: if (m_pGetCommandLine == NULL) skamonkey@4195: { skamonkey@4195: g_Logger.LogError("Could not locate any command line functionality"); skamonkey@3460: } skamonkey@3460: } skamonkey@3460: skamonkey@3460: ICommandLine *CHalfLife2::GetValveCommandLine() skamonkey@3460: { skamonkey@3460: if (!m_pGetCommandLine) skamonkey@3460: return NULL; skamonkey@3460: skamonkey@3462: return ((FakeGetCommandLine)((FakeGetCommandLine *)m_pGetCommandLine))(); skamonkey@3460: } skamonkey@3460: dvander@2846: #if !defined METAMOD_PLAPI_VERSION || PLAPI_VERSION < 11 dvander@1581: bool CHalfLife2::IsOriginalEngine() dvander@1581: { dvander@1581: return is_original_engine; dvander@1581: } dvander@1581: #endif dvander@1581: ds@2583: #if SOURCE_ENGINE != SE_DARKMESSIAH dvander@678: IChangeInfoAccessor *CBaseEdict::GetChangeAccessor() dvander@678: { skamonkey@3913: #if SOURCE_ENGINE == SE_DOTA skamonkey@3913: return engine->GetChangeAccessor( IndexOfEdict((const edict_t *)this) ); skamonkey@3913: #else dvander@678: return engine->GetChangeAccessor( (const edict_t *)this ); skamonkey@3913: #endif dvander@678: } ds@2583: #endif dvander@678: dvander@1847: bool UTIL_FindInSendTable(SendTable *pTable, dvander@1847: const char *name, dvander@1847: sm_sendprop_info_t *info, dvander@1847: unsigned int offset) dvander@592: { dvander@592: const char *pname; dvander@592: int props = pTable->GetNumProps(); dvander@592: SendProp *prop; dvander@592: dvander@592: for (int i=0; iGetProp(i); dvander@592: pname = prop->GetName(); dvander@592: if (pname && strcmp(name, pname) == 0) dvander@592: { dvander@1847: info->prop = prop; dvander@1847: info->actual_offset = offset + info->prop->GetOffset(); dvander@1847: return true; dvander@592: } dvander@592: if (prop->GetDataTable()) dvander@592: { dvander@1847: if (UTIL_FindInSendTable(prop->GetDataTable(), dvander@1847: name, dvander@1847: info, dvander@1847: offset + prop->GetOffset()) dvander@1847: ) dvander@592: { dvander@1847: return true; dvander@592: } dvander@592: } dvander@592: } dvander@592: dvander@1848: return false; dvander@592: } dvander@592: kyle@3997: bool UTIL_FindDataMapInfo(datamap_t *pMap, const char *name, sm_datatable_info_t *pDataTable) faluco@682: { faluco@682: while (pMap) faluco@682: { kyle@3997: for (int i = 0; i < pMap->dataNumFields; ++i) faluco@682: { dvander@709: if (pMap->dataDesc[i].fieldName == NULL) dvander@709: { dvander@709: continue; dvander@709: } faluco@682: if (strcmp(name, pMap->dataDesc[i].fieldName) == 0) faluco@682: { kyle@3997: pDataTable->prop = &(pMap->dataDesc[i]); kyle@3997: pDataTable->actual_offset = GetTypeDescOffs(pDataTable->prop); kyle@3997: return true; faluco@682: } kyle@3997: if (pMap->dataDesc[i].td == NULL || !UTIL_FindDataMapInfo(pMap->dataDesc[i].td, name, pDataTable)) faluco@682: { kyle@3997: continue; faluco@682: } kyle@3997: kyle@3997: pDataTable->actual_offset += GetTypeDescOffs(&(pMap->dataDesc[i])); kyle@3997: return true; faluco@682: } kyle@3997: faluco@682: pMap = pMap->baseMap; faluco@682: } faluco@682: kyle@3997: return false; faluco@682: } faluco@682: dvander@592: ServerClass *CHalfLife2::FindServerClass(const char *classname) dvander@592: { dvander@592: DataTableInfo *pInfo = _FindServerClass(classname); dvander@1847: dvander@592: if (!pInfo) dvander@592: return NULL; dvander@592: dvander@592: return pInfo->sc; dvander@592: } dvander@592: dvander@592: DataTableInfo *CHalfLife2::_FindServerClass(const char *classname) dvander@592: { dvander@4091: DataTableInfo *pInfo = NULL; dvander@4069: if (!m_Classes.retrieve(classname, &pInfo)) dvander@592: { dvander@592: ServerClass *sc = gamedll->GetAllServerClasses(); dvander@592: while (sc) dvander@592: { dvander@592: if (strcmp(classname, sc->GetName()) == 0) dvander@592: { dvander@4069: pInfo = new DataTableInfo(sc); dvander@4069: m_Classes.insert(classname, pInfo); dvander@592: break; dvander@592: } dvander@592: sc = sc->m_pNext; dvander@592: } dvander@592: if (!pInfo) dvander@592: return NULL; dvander@592: } dvander@592: dvander@592: return pInfo; dvander@592: } dvander@592: dvander@1847: bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info) dvander@1847: { dvander@1847: DataTableInfo *pInfo; dvander@1847: sm_sendprop_info_t *prop; dvander@1847: dvander@1847: if ((pInfo = _FindServerClass(classname)) == NULL) dvander@1847: { dvander@1847: return false; dvander@1847: } dvander@1847: dvander@4069: if (!pInfo->lookup.retrieve(offset, info)) dvander@1847: { dvander@1847: sm_sendprop_info_t temp_info; dvander@1847: dvander@1847: if (!UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp_info, 0)) dvander@1847: { dvander@1847: return false; dvander@1847: } dvander@1847: dvander@1847: pInfo->lookup.insert(offset, temp_info); dvander@1847: *info = temp_info; dvander@1847: } dvander@1847: dvander@1847: return true; dvander@1847: } dvander@1847: dvander@592: SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset) dvander@592: { dvander@1847: sm_sendprop_info_t info; dvander@592: dvander@1847: if (!FindSendPropInfo(classname, offset, &info)) dvander@592: { dvander@592: return NULL; dvander@592: } dvander@592: dvander@1847: return info.prop; dvander@592: } faluco@682: faluco@682: typedescription_t *CHalfLife2::FindInDataMap(datamap_t *pMap, const char *offset) faluco@682: { kyle@3997: sm_datatable_info_t dt_info; kyle@3997: kyle@3997: if (!(this->FindDataMapInfo(pMap, offset, &dt_info))) kyle@3997: { kyle@3997: return NULL; kyle@3997: } kyle@3997: kyle@3997: return dt_info.prop; asherkin@3806: } asherkin@3806: kyle@3997: bool CHalfLife2::FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable) asherkin@3806: { dvander@4069: DataTableMap::Insert i = m_Maps.findForAdd(pMap); dvander@4069: if (!i.found()) dvander@4069: m_Maps.add(i, pMap, new DataMapCache()); faluco@682: dvander@4069: DataMapCache *cache = i->value; dvander@4069: dvander@4069: sm_datatable_info_t *pNewTable; dvander@4069: if (!cache->retrieve(offset, pDataTable)) faluco@682: { dvander@4069: if (!UTIL_FindDataMapInfo(pMap, offset, pDataTable)) dvander@4069: return false; dvander@4069: cache->insert(offset, *pDataTable); kyle@3997: } faluco@682: dvander@4069: return true; faluco@682: } dvander@685: dvander@685: void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset) dvander@685: { ds@2583: #if SOURCE_ENGINE != SE_DARKMESSIAH dvander@1581: if (g_pSharedChangeInfo != NULL) dvander@685: { dvander@685: if (offset) dvander@685: { dvander@685: pEdict->StateChanged(offset); dvander@1847: } dvander@1847: else dvander@1847: { dvander@685: pEdict->StateChanged(); dvander@685: } dvander@1581: } dvander@1581: else ds@2583: #endif dvander@1581: { dvander@685: pEdict->m_fStateFlags |= FL_EDICT_CHANGED; dvander@685: } dvander@685: } ds@873: dvander@1132: bool CHalfLife2::TextMsg(int client, int dest, const char *msg) ds@873: { skamonkey@3855: #ifndef USE_PROTOBUF_USERMESSAGES ds@873: bf_write *pBitBuf = NULL; skamonkey@3743: #endif ds@873: cell_t players[] = {client}; ds@873: ds@2583: if (dest == HUD_PRINTTALK) ds@2583: { ds@2583: const char *chat_saytext = g_pGameConf->GetKeyValue("ChatSayText"); ds@2583: ds@2583: /* Use SayText user message instead */ ds@2583: if (chat_saytext != NULL && strcmp(chat_saytext, "yes") == 0) ds@2583: { ds@2583: char buffer[192]; ds@2583: UTIL_Format(buffer, sizeof(buffer), "%s\1\n", msg); ds@2583: skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: CUserMsg_SayText *pMsg; skamonkey@3855: if ((pMsg = (CUserMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) skamonkey@3855: { skamonkey@3855: return false; skamonkey@3855: } skamonkey@3855: skamonkey@3855: pMsg->set_client(0); skamonkey@3855: pMsg->set_text(buffer); skamonkey@3855: pMsg->set_chat(false); skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3743: CCSUsrMsg_SayText *pMsg; skamonkey@3743: if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) skamonkey@3743: { skamonkey@3743: return false; skamonkey@3743: } skamonkey@3743: skamonkey@3743: pMsg->set_ent_idx(0); skamonkey@3743: pMsg->set_text(buffer); skamonkey@3743: pMsg->set_chat(false); skamonkey@3743: #else skamonkey@3743: if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) ds@2583: { ds@2583: return false; ds@2583: } ds@2583: ds@2583: pBitBuf->WriteByte(0); ds@2583: pBitBuf->WriteString(buffer); ds@2583: pBitBuf->WriteByte(1); skamonkey@3743: #endif ds@2583: ds@2583: g_UserMsgs.EndMessage(); ds@2583: ds@2583: return true; ds@2583: } ds@2583: } ds@2583: skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: CUserMsg_TextMsg *pMsg; skamonkey@3855: if ((pMsg = (CUserMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) skamonkey@3855: { skamonkey@3855: return false; skamonkey@3855: } skamonkey@3855: skamonkey@3855: pMsg->set_dest(dest); skamonkey@3855: pMsg->add_param(msg); skamonkey@3855: pMsg->add_param(""); skamonkey@3855: pMsg->add_param(""); skamonkey@3855: pMsg->add_param(""); skamonkey@3855: pMsg->add_param(""); skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3743: CCSUsrMsg_TextMsg *pMsg; skamonkey@3743: if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) skamonkey@3743: { skamonkey@3743: return false; skamonkey@3743: } skamonkey@3743: skamonkey@3743: // Client tries to read all 5 'params' and will crash if less skamonkey@3743: pMsg->set_msg_dst(dest); skamonkey@3743: pMsg->add_params(msg); skamonkey@3743: pMsg->add_params(""); skamonkey@3743: pMsg->add_params(""); skamonkey@3743: pMsg->add_params(""); skamonkey@3743: pMsg->add_params(""); skamonkey@3743: #else skamonkey@3743: if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) dvander@1132: { dvander@1132: return false; dvander@1132: } dvander@1132: ds@873: pBitBuf->WriteByte(dest); ds@873: pBitBuf->WriteString(msg); skamonkey@3743: #endif ds@2583: ds@873: g_UserMsgs.EndMessage(); dvander@1132: dvander@1132: return true; ds@873: } faluco@1218: teame06@1264: bool CHalfLife2::HintTextMsg(int client, const char *msg) faluco@1218: { faluco@1218: cell_t players[] = {client}; faluco@1218: skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: CUserMsg_HintText *pMsg; skamonkey@3855: if ((pMsg = (CUserMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) skamonkey@3855: { skamonkey@3855: return false; skamonkey@3855: } skamonkey@3855: skamonkey@3855: pMsg->set_message(msg); skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3743: CCSUsrMsg_HintText *pMsg; skamonkey@3743: if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) skamonkey@3743: { skamonkey@3743: return false; skamonkey@3743: } skamonkey@3743: skamonkey@3743: pMsg->set_text(msg); skamonkey@3743: #else skamonkey@3743: bf_write *pBitBuf = NULL; skamonkey@3743: skamonkey@3743: if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL) faluco@1218: { faluco@1218: return false; faluco@1218: } faluco@1218: dvander@1690: const char *pre_byte = g_pGameConf->GetKeyValue("HintTextPreByte"); dvander@1690: if (pre_byte != NULL && strcmp(pre_byte, "yes") == 0) dvander@1690: { dvander@1690: pBitBuf->WriteByte(1); dvander@1690: } faluco@1218: pBitBuf->WriteString(msg); skamonkey@3743: #endif faluco@1218: g_UserMsgs.EndMessage(); faluco@1218: faluco@1218: return true; faluco@1218: } faluco@1218: pred@2801: bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg) pred@2801: { skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: CUserMsg_HintText *pMsg; skamonkey@3855: if ((pMsg = (CUserMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL) skamonkey@3855: { skamonkey@3855: return false; skamonkey@3855: } skamonkey@3855: skamonkey@3855: pMsg->set_message(msg); skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3743: CCSUsrMsg_HintText *pMsg; skamonkey@3743: if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL) skamonkey@3743: { skamonkey@3743: return false; skamonkey@3743: } skamonkey@3743: skamonkey@3743: pMsg->set_text(msg); skamonkey@3743: #else pred@2801: bf_write *pBitBuf = NULL; pred@2801: skamonkey@3743: if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL) pred@2801: { pred@2801: return false; pred@2801: } pred@2801: pred@2801: const char *pre_byte = g_pGameConf->GetKeyValue("HintTextPreByte"); pred@2801: if (pre_byte != NULL && strcmp(pre_byte, "yes") == 0) pred@2801: { pred@2801: pBitBuf->WriteByte(1); pred@2801: } pred@2801: pBitBuf->WriteString(msg); skamonkey@3743: #endif skamonkey@3743: pred@2801: g_UserMsgs.EndMessage(); pred@2801: pred@2801: return true; pred@2801: } pred@2801: faluco@1218: bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, bool show) faluco@1218: { faluco@1218: KeyValues *SubKey = NULL; faluco@1218: int count = 0; faluco@1218: cell_t players[] = {client}; faluco@1218: skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: CUserMsg_VGUIMenu *pMsg; skamonkey@3855: if ((pMsg = (CUserMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL) skamonkey@3855: { skamonkey@3855: return false; skamonkey@3855: } skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3743: CCSUsrMsg_VGUIMenu *pMsg; skamonkey@3743: if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL) faluco@1218: { faluco@1218: return false; faluco@1218: } skamonkey@3743: #else skamonkey@3743: bf_write *pBitBuf = NULL; skamonkey@3743: if ((pBitBuf = g_UserMsgs.StartBitBufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL) skamonkey@3743: { skamonkey@3743: return false; skamonkey@3743: } skamonkey@3743: #endif faluco@1218: faluco@1218: if (data) faluco@1218: { faluco@1218: SubKey = data->GetFirstSubKey(); faluco@1218: while (SubKey) faluco@1218: { faluco@1218: count++; faluco@1218: SubKey = SubKey->GetNextKey(); faluco@1218: } faluco@1218: SubKey = data->GetFirstSubKey(); faluco@1218: } faluco@1218: skamonkey@3855: #if SOURCE_ENGINE == SE_DOTA skamonkey@3855: pMsg->set_name(name); skamonkey@3855: pMsg->set_show(show); skamonkey@3855: skamonkey@3855: while (SubKey) skamonkey@3855: { skamonkey@3855: CUserMsg_VGUIMenu_Keys *key = pMsg->add_keys(); skamonkey@3855: key->set_name(SubKey->GetName()); skamonkey@3855: key->set_value(SubKey->GetString()); skamonkey@3855: SubKey = SubKey->GetNextKey(); skamonkey@3855: } skamonkey@3855: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3743: pMsg->set_name(name); skamonkey@3743: pMsg->set_show(show); skamonkey@3743: skamonkey@3743: while (SubKey) skamonkey@3743: { skamonkey@3743: CCSUsrMsg_VGUIMenu_Subkey *key = pMsg->add_subkeys(); skamonkey@3743: key->set_name(SubKey->GetName()); skamonkey@3743: key->set_str(SubKey->GetString()); skamonkey@3743: SubKey = SubKey->GetNextKey(); skamonkey@3743: } skamonkey@3743: #else faluco@1218: pBitBuf->WriteString(name); faluco@1218: pBitBuf->WriteByte((show) ? 1 : 0); faluco@1218: pBitBuf->WriteByte(count); faluco@1218: while (SubKey) faluco@1218: { faluco@1218: pBitBuf->WriteString(SubKey->GetName()); faluco@1218: pBitBuf->WriteString(SubKey->GetString()); faluco@1218: SubKey = SubKey->GetNextKey(); faluco@1218: } skamonkey@3743: #endif skamonkey@3743: faluco@1218: g_UserMsgs.EndMessage(); faluco@1218: faluco@1218: return true; faluco@1218: } dvander@1338: dvander@1338: void CHalfLife2::AddToFakeCliCmdQueue(int client, int userid, const char *cmd) dvander@1338: { dvander@1338: DelayedFakeCliCmd *pFake; dvander@1338: dvander@1338: if (m_FreeCmds.empty()) dvander@1338: { dvander@1338: pFake = new DelayedFakeCliCmd; dvander@1338: } else { dvander@1338: pFake = m_FreeCmds.front(); dvander@1338: m_FreeCmds.pop(); dvander@1338: } dvander@1338: dvander@1338: pFake->client = client; dvander@1338: pFake->userid = userid; dvander@1338: pFake->cmd.assign(cmd); dvander@1338: dvander@1338: m_CmdQueue.push(pFake); dvander@1338: } dvander@1338: dvander@1338: void CHalfLife2::ProcessFakeCliCmdQueue() dvander@1338: { dvander@1338: while (!m_CmdQueue.empty()) dvander@1338: { dvander@1338: DelayedFakeCliCmd *pFake = m_CmdQueue.first(); dvander@1338: dvander@1338: if (g_Players.GetClientOfUserId(pFake->userid) == pFake->client) dvander@1338: { dvander@1338: CPlayer *pPlayer = g_Players.GetPlayerByIndex(pFake->client); skamonkey@3854: #if SOURCE_ENGINE == SE_DOTA skamonkey@3913: engine->ClientCommand(pPlayer->GetIndex(), "%s", pFake->cmd.c_str()); skamonkey@3854: #else dvander@1338: serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), pFake->cmd.c_str()); skamonkey@3854: #endif dvander@1338: } dvander@1338: dvander@1338: m_CmdQueue.pop(); dvander@1338: } dvander@1338: } dvander@1423: dvander@1423: bool CHalfLife2::IsLANServer() dvander@1423: { dvander@1423: sv_lan = icvar->FindVar("sv_lan"); dvander@1423: dvander@1423: if (!sv_lan) dvander@1423: { dvander@1423: return false; dvander@1423: } dvander@1423: dvander@1423: return (sv_lan->GetInt() != 0); dvander@1423: } dvander@1544: ds@1944: bool CHalfLife2::KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID) ds@1944: { dvander@2846: #if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11 ds@1944: if (g_SMAPI->GetSourceEngineBuild() == SOURCE_ENGINE_ORIGINAL) ds@1944: #else ds@1944: if (strcasecmp(g_SourceMod.GetGameFolderName(), "ship") == 0) ds@1944: #endif ds@1944: { ds@1944: Assert(filesystem); ds@1944: #ifdef _MSC_VER ds@1944: Assert(_heapchk() == _HEAPOK); ds@1944: #endif ds@1944: ds@1944: FileHandle_t f = filesystem->Open(resourceName, "rb", pathID); ds@1944: if (!f) ds@1944: return false; ds@1944: ds@1944: // load file into a null-terminated buffer ds@1944: int fileSize = filesystem->Size(f); ds@1944: char *buffer = (char *)MemAllocScratch(fileSize + 1); ds@1944: ds@1944: Assert(buffer); ds@1944: ds@1944: filesystem->Read(buffer, fileSize, f); // read into local buffer ds@1944: ds@1944: buffer[fileSize] = 0; // null terminate file as EOF ds@1944: ds@1944: filesystem->Close( f ); // close file after reading ds@1944: ds@1944: bool retOK = kv->LoadFromBuffer( resourceName, buffer, filesystem ); ds@1944: ds@1944: MemFreeScratch(); ds@1944: ds@1944: return retOK; ds@1944: } ds@1944: else ds@1944: { ds@1944: return kv->LoadFromFile(filesystem, resourceName, pathID); ds@1944: } ds@1944: } ds@1944: dvander@1544: void CHalfLife2::PushCommandStack(const CCommand *cmd) dvander@1544: { dvander@1544: CachedCommandInfo info; dvander@1544: dvander@1544: info.args = cmd; ds@2583: #if SOURCE_ENGINE <= SE_DARKMESSIAH dvander@1544: strncopy(info.cmd, cmd->Arg(0), sizeof(info.cmd)); dvander@1544: #endif dvander@1544: dvander@1544: m_CommandStack.push(info); dvander@1544: } dvander@1544: dvander@1544: const CCommand *CHalfLife2::PeekCommandStack() dvander@1544: { dvander@1544: if (m_CommandStack.empty()) dvander@1544: { dvander@1544: return NULL; dvander@1544: } dvander@1544: dvander@1544: return m_CommandStack.front().args; dvander@1544: } dvander@1544: dvander@1544: void CHalfLife2::PopCommandStack() dvander@1544: { dvander@1544: m_CommandStack.pop(); dvander@1544: } dvander@1544: dvander@1544: const char *CHalfLife2::CurrentCommandName() dvander@1544: { ds@2400: #if SOURCE_ENGINE >= SE_ORANGEBOX dvander@1544: return m_CommandStack.front().args->Arg(0); dvander@1544: #else dvander@1544: return m_CommandStack.front().cmd; dvander@1544: #endif dvander@1544: } dvander@2162: dvander@2162: void CHalfLife2::AddDelayedKick(int client, int userid, const char *msg) dvander@2162: { systematicmania@3949: CPlayer *pPlayer = g_Players.GetPlayerByIndex(client); systematicmania@3949: if (!pPlayer || !pPlayer->IsConnected() || pPlayer->IsInKickQueue()) systematicmania@3949: { systematicmania@3949: return; systematicmania@3949: } systematicmania@3949: systematicmania@3949: pPlayer->MarkAsBeingKicked(); systematicmania@3949: dvander@2162: DelayedKickInfo kick; dvander@2162: dvander@2162: kick.client = client; dvander@2162: kick.userid = userid; dvander@2162: UTIL_Format(kick.buffer, sizeof(kick.buffer), "%s", msg); dvander@2162: dvander@2162: m_DelayedKicks.push(kick); dvander@2162: } dvander@2162: dvander@2162: void CHalfLife2::ProcessDelayedKicks() dvander@2162: { dvander@2162: while (!m_DelayedKicks.empty()) dvander@2162: { dvander@2162: DelayedKickInfo info = m_DelayedKicks.first(); dvander@2162: m_DelayedKicks.pop(); dvander@2162: dvander@2162: CPlayer *player = g_Players.GetPlayerByIndex(info.client); dvander@2162: if (player == NULL || player->GetUserId() != info.userid) dvander@2162: { dvander@2162: continue; dvander@2162: } dvander@2162: dvander@2162: player->Kick(info.buffer); dvander@2162: } dvander@2162: } pred@2596: pred@2596: edict_t *CHalfLife2::EdictOfIndex(int index) pred@2596: { pred@2596: return ::PEntityOfEntIndex(index); pred@2596: } pred@2596: pred@2596: int CHalfLife2::IndexOfEdict(edict_t *pEnt) pred@2596: { pred@2596: return ::IndexOfEdict(pEnt); pred@2596: } pred@2596: pred@2596: edict_t *CHalfLife2::GetHandleEntity(CBaseHandle &hndl) pred@2596: { pred@2596: if (!hndl.IsValid()) pred@2596: { pred@2596: return NULL; pred@2596: } pred@2596: pred@2596: int index = hndl.GetEntryIndex(); pred@2596: pred@2596: edict_t *pStoredEdict; pred@2596: CBaseEntity *pStoredEntity; pred@2596: fyrenmoo@2879: if (!IndexToAThings(index, &pStoredEntity, &pStoredEdict)) fyrenmoo@2879: { fyrenmoo@2879: return NULL; fyrenmoo@2879: } pred@2596: pred@2596: if (pStoredEdict == NULL || pStoredEntity == NULL) pred@2596: { pred@2596: return NULL; pred@2596: } pred@2596: pred@2596: IServerEntity *pSE = pStoredEdict->GetIServerEntity(); pred@2596: pred@2596: if (pSE == NULL) pred@2596: { pred@2596: return NULL; pred@2596: } pred@2596: pred@2596: if (pSE->GetRefEHandle() != hndl) pred@2596: { pred@2596: return NULL; pred@2596: } pred@2596: pred@2596: return pStoredEdict; pred@2596: } pred@2596: pred@2596: void CHalfLife2::SetHandleEntity(CBaseHandle &hndl, edict_t *pEnt) pred@2596: { pred@2596: IServerEntity *pEntOther = pEnt->GetIServerEntity(); pred@2596: pred@2596: if (pEntOther == NULL) pred@2596: { pred@2596: return; pred@2596: } pred@2596: pred@2596: hndl.Set(pEntOther); pred@2596: } dvander@2628: dvander@2628: const char *CHalfLife2::GetCurrentMap() dvander@2628: { dvander@2628: return STRING(gpGlobals->mapname); dvander@2628: } dvander@2628: dvander@2628: void CHalfLife2::ServerCommand(const char *buffer) dvander@2628: { dvander@2628: engine->ServerCommand(buffer); dvander@2628: } pred@2746: pred@2746: cell_t CHalfLife2::EntityToReference(CBaseEntity *pEntity) pred@2746: { pred@2746: IServerUnknown *pUnknown = (IServerUnknown *)pEntity; pred@2746: CBaseHandle hndl = pUnknown->GetRefEHandle(); pred@2746: return (hndl.ToInt() | (1<<31)); pred@2746: } pred@2746: pred@2746: CBaseEntity *CHalfLife2::ReferenceToEntity(cell_t entRef) pred@2746: { skamonkey@3547: if ((unsigned)entRef == INVALID_EHANDLE_INDEX) rgr_02@3546: { rgr_02@3546: return NULL; rgr_02@3546: } rgr_02@3546: pred@2746: CEntInfo *pInfo = NULL; pred@2746: pred@2746: if (entRef & (1<<31)) pred@2746: { pred@2746: /* Proper ent reference */ pred@2746: int hndlValue = entRef & ~(1<<31); pred@2746: CBaseHandle hndl(hndlValue); pred@2746: pred@2746: pInfo = LookupEntity(hndl.GetEntryIndex()); rgr_02@3546: if (!pInfo || pInfo->m_SerialNumber != hndl.GetSerialNumber()) pred@2746: { pred@2746: return NULL; pred@2746: } pred@2746: } pred@2746: else pred@2746: { pred@2746: /* Old style index only */ pred@2746: pInfo = LookupEntity(entRef); pred@2746: } pred@2746: pred@2746: if (!pInfo) pred@2746: { pred@2746: return NULL; pred@2746: } pred@2746: pred@2746: IServerUnknown *pUnk = static_cast(pInfo->m_pEntity); pred@2746: if (pUnk) pred@2746: { pred@2746: return pUnk->GetBaseEntity(); pred@2746: } pred@2746: pred@2746: return NULL; pred@2746: } pred@2746: pred@2746: /** pred@2746: * Retrieves the CEntInfo pointer from g_EntList for a given entity index pred@2746: */ pred@2746: CEntInfo *CHalfLife2::LookupEntity(int entIndex) pred@2746: { skamonkey@3387: // Make sure that our index is within the bounds of the global ent array skamonkey@3387: if (entIndex < 0 || entIndex >= NUM_ENT_ENTRIES) skamonkey@3387: { skamonkey@3387: return NULL; skamonkey@3387: } skamonkey@3387: skamonkey@4230: CEntInfo *entInfos = EntInfoArray(); skamonkey@4230: skamonkey@4230: if (!entInfos) pred@2746: { pred@2746: /* Attempt to use engine interface instead */ pred@2746: static CEntInfo tempInfo; pred@2746: tempInfo.m_pNext = NULL; pred@2746: tempInfo.m_pPrev = NULL; pred@2746: pred@2748: edict_t *pEdict = PEntityOfEntIndex(entIndex); pred@2746: pred@2746: if (!pEdict) pred@2746: { pred@2746: return NULL; pred@2746: } pred@2746: pred@2746: IServerUnknown *pUnk = pEdict->GetUnknown(); pred@2746: pred@2746: if (!pUnk) pred@2746: { pred@2746: return NULL; pred@2746: } pred@2746: pred@2746: tempInfo.m_pEntity = pUnk; pred@2746: tempInfo.m_SerialNumber = pUnk->GetRefEHandle().GetSerialNumber(); pred@2746: pred@2746: return &tempInfo; pred@2746: } pred@2746: skamonkey@4230: return &entInfos[entIndex]; pred@2746: } pred@2746: pred@2746: /** pred@2746: SERIAL_MASK = 0x7fff (15 bits) pred@2746: pred@2746: #define MAX_EDICT_BITS 11 pred@2746: #define NUM_ENT_ENTRY_BITS (MAX_EDICT_BITS + 1) pred@2746: m_Index = iEntry | (iSerialNumber << NUM_ENT_ENTRY_BITS); pred@2746: pred@2746: Top 5 bits of a handle are unused. pred@2746: Bit 31 - Our 'reference' flag indicator pred@2746: */ pred@2746: pred@2746: cell_t CHalfLife2::IndexToReference(int entIndex) pred@2746: { pred@2746: CBaseEntity *pEnt = ReferenceToEntity(entIndex); pred@2746: if (!pEnt) pred@2746: { pred@2746: return INVALID_EHANDLE_INDEX; pred@2746: } pred@2746: pred@2746: return EntityToReference(pEnt); pred@2746: } pred@2746: pred@2746: int CHalfLife2::ReferenceToIndex(cell_t entRef) pred@2746: { pred@2747: if ((unsigned)entRef == INVALID_EHANDLE_INDEX) pred@2746: { pred@2746: return INVALID_EHANDLE_INDEX; pred@2746: } pred@2746: pred@2746: if (entRef & (1<<31)) pred@2746: { pred@2746: /* Proper ent reference */ pred@2746: int hndlValue = entRef & ~(1<<31); pred@2746: CBaseHandle hndl(hndlValue); pred@2746: pred@2746: CEntInfo *pInfo = LookupEntity(hndl.GetEntryIndex()); pred@2746: pred@2746: if (pInfo->m_SerialNumber != hndl.GetSerialNumber()) pred@2746: { pred@2746: return INVALID_EHANDLE_INDEX; pred@2746: } pred@2746: pred@2746: return hndl.GetEntryIndex(); pred@2746: } pred@2746: pred@2746: return entRef; pred@2746: } pred@2746: pred@2746: cell_t CHalfLife2::EntityToBCompatRef(CBaseEntity *pEntity) pred@2746: { pred@2746: if (pEntity == NULL) pred@2746: { pred@2746: return INVALID_EHANDLE_INDEX; pred@2746: } pred@2746: pred@2746: IServerUnknown *pUnknown = (IServerUnknown *)pEntity; pred@2746: CBaseHandle hndl = pUnknown->GetRefEHandle(); pred@2746: kyle@3695: if (hndl == INVALID_EHANDLE_INDEX) kyle@3695: { kyle@3695: return INVALID_EHANDLE_INDEX; kyle@3695: } kyle@3695: pred@2746: if (hndl.GetEntryIndex() >= MAX_EDICTS) pred@2746: { pred@2746: return (hndl.ToInt() | (1<<31)); pred@2746: } pred@2746: else pred@2746: { pred@2746: return hndl.GetEntryIndex(); pred@2746: } pred@2746: } pred@2746: pred@2746: cell_t CHalfLife2::ReferenceToBCompatRef(cell_t entRef) pred@2746: { pred@2747: if ((unsigned)entRef == INVALID_EHANDLE_INDEX) pred@2746: { pred@2746: return INVALID_EHANDLE_INDEX; pred@2746: } pred@2746: pred@2746: int hndlValue = entRef & ~(1<<31); pred@2746: CBaseHandle hndl(hndlValue); pred@2746: pred@2746: if (hndl.GetEntryIndex() < MAX_EDICTS) pred@2746: { pred@2746: return hndl.GetEntryIndex(); pred@2746: } pred@2746: pred@2746: return entRef; pred@2746: } pred@2746: pred@2746: void *CHalfLife2::GetGlobalEntityList() pred@2746: { pred@2746: return g_EntList; pred@2747: } dvander@3010: dvander@3010: int CHalfLife2::GetSendPropOffset(SendProp *prop) dvander@3010: { dvander@3010: return prop->GetOffset(); dvander@3010: } dvander@3010: kyle@3638: const char *CHalfLife2::GetEntityClassname(edict_t * pEdict) kyle@3638: { kyle@3638: if (pEdict == NULL || pEdict->IsFree()) kyle@3638: { kyle@3638: return NULL; kyle@3638: } kyle@3638: kyle@3638: IServerUnknown *pUnk = pEdict->GetUnknown(); kyle@3638: if (pUnk == NULL) kyle@3638: { kyle@3638: return NULL; kyle@3638: } kyle@3638: kyle@3638: CBaseEntity * pEntity = pUnk->GetBaseEntity(); kyle@3638: kyle@3638: if (pEntity == NULL) kyle@3638: { kyle@3638: return NULL; kyle@3638: } kyle@3638: kyle@3638: return GetEntityClassname(pEntity); kyle@3638: } kyle@3638: kyle@3638: const char *CHalfLife2::GetEntityClassname(CBaseEntity *pEntity) kyle@3638: { kyle@3638: static int offset = -1; kyle@3638: if (offset == -1) kyle@3638: { skamonkey@3822: CBaseEntity *pGetterEnt = ReferenceToEntity(0); skamonkey@3822: datamap_t *pMap = GetDataMap(pGetterEnt); kyle@3997: kyle@3997: sm_datatable_info_t info; kyle@3997: if (!FindDataMapInfo(pMap, "m_iClassname", &info)) kyle@3997: { kyle@3997: return NULL; kyle@3997: } kyle@3997: kyle@3997: offset = info.actual_offset; kyle@3638: } kyle@3638: kyle@3638: return *(const char **)(((unsigned char *)pEntity) + offset); kyle@3638: } skamonkey@3789: skamonkey@3789: #if SOURCE_ENGINE >= SE_LEFT4DEAD skamonkey@3789: static bool ResolveFuzzyMapName(const char *fuzzyName, char *outFullname, int size) skamonkey@3789: { skamonkey@3789: static ConCommand *pHelperCmd = g_pCVar->FindCommand("changelevel"); skamonkey@3789: if (!pHelperCmd || !pHelperCmd->CanAutoComplete()) skamonkey@3789: return false; skamonkey@3789: skamonkey@3789: static size_t helperCmdLen = strlen(pHelperCmd->GetName()); skamonkey@3789: skamonkey@3789: CUtlVector results; skamonkey@3789: pHelperCmd->AutoCompleteSuggest(fuzzyName, results); skamonkey@3789: if (results.Count() == 0) skamonkey@3789: return false; skamonkey@3789: skamonkey@3789: // Results come back as you'd see in autocomplete. (ie. "changelevel fullmapnamehere"), skamonkey@3789: // so skip ahead to start of map path/name skamonkey@3789: skamonkey@3789: // Like the engine, we're only going to deal with the first match. skamonkey@3789: skamonkey@3789: strncopy(outFullname, &results[0][helperCmdLen + 1], size); skamonkey@3789: skamonkey@3789: return true; skamonkey@3789: } skamonkey@3789: #endif skamonkey@3789: skamonkey@3789: bool CHalfLife2::IsMapValid(const char *map) skamonkey@3789: { skamonkey@3864: if (!map || !map[0]) skamonkey@3864: return false; skamonkey@3864: skamonkey@3789: bool ret = engine->IsMapValid(map); skamonkey@3789: #if SOURCE_ENGINE >= SE_LEFT4DEAD skamonkey@3789: if (!ret) skamonkey@3789: { skamonkey@3789: static char szFuzzyName[PLATFORM_MAX_PATH]; skamonkey@3789: if (ResolveFuzzyMapName(map, szFuzzyName, sizeof(szFuzzyName))) skamonkey@3789: { skamonkey@3789: ret = engine->IsMapValid(szFuzzyName); skamonkey@3789: } skamonkey@3789: } skamonkey@3789: #endif skamonkey@3789: return ret; skamonkey@3789: }