dvander@1738: /** dvander@1738: * vim: set ts=4 : dvander@1738: * ============================================================================= dvander@1738: * SourceMod dvander@1738: * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. dvander@1738: * ============================================================================= dvander@1738: * dvander@1738: * This program is free software; you can redistribute it and/or modify it under dvander@1738: * the terms of the GNU General Public License, version 3.0, as published by the dvander@1738: * Free Software Foundation. dvander@1738: * dvander@1738: * This program is distributed in the hope that it will be useful, but WITHOUT dvander@1738: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@1738: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more dvander@1738: * details. dvander@1738: * dvander@1738: * You should have received a copy of the GNU General Public License along with dvander@1738: * this program. If not, see . dvander@1738: * dvander@1738: * As a special exception, AlliedModders LLC gives you permission to link the dvander@1738: * code of this program (as well as its derivative works) to "Half-Life 2," the dvander@1738: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software dvander@1738: * by the Valve Corporation. You must obey the GNU General Public License in dvander@1738: * all respects for all other code used. Additionally, AlliedModders LLC grants dvander@1738: * this exception to all derivative works. AlliedModders LLC defines further dvander@1738: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), dvander@1738: * or . dvander@1738: * dvander@1738: * Version: $Id$ dvander@1738: */ dvander@1738: dvander@1738: #include dvander@1738: #include "sm_globals.h" dvander@1738: #include "sm_trie_tpl.h" dvander@1738: #include "CellArray.h" dvander@1738: #include "convar.h" dvander@1738: #include "sourcemm_api.h" dvander@1738: #include "LibrarySys.h" dvander@1738: #include "TextParsers.h" dvander@1738: #include "sm_stringutil.h" dvander@1738: #include "sourcemod.h" dvander@1738: #include "Logger.h" dvander@1738: #include "HandleSys.h" dvander@1738: dvander@1738: using namespace SourceHook; dvander@1738: dvander@1738: struct maplist_info_t dvander@1738: { dvander@1738: bool bIsCompat; dvander@1738: bool bIsPath; dvander@1738: char name[PLATFORM_MAX_PATH]; dvander@1738: char path[PLATFORM_MAX_PATH]; dvander@1738: time_t last_modified_time; dvander@1738: CellArray *pArray; dvander@1738: int serial; dvander@1738: }; dvander@1738: dvander@1738: #define MAPLIST_FLAG_MAPSFOLDER (1<<0) /**< On failure, use all maps in the maps folder. */ dvander@1738: #define MAPLIST_FLAG_CLEARARRAY (1<<1) /**< If an input array is specified, clear it before adding. */ dvander@1738: #define MAPLIST_FLAG_NO_DEFAULT (1<<2) /**< Do not read "default" or "mapcyclefile" on failure. */ dvander@1738: dvander@1738: class MapLists : public SMGlobalClass, public ITextListener_SMC dvander@1738: { dvander@1738: public: dvander@1738: enum MapListState dvander@1738: { dvander@1738: MPS_NONE, dvander@1738: MPS_GLOBAL, dvander@1738: MPS_MAPLIST, dvander@1738: }; dvander@1738: public: dvander@1738: MapLists() dvander@1738: { dvander@1738: m_pMapCycleFile = NULL; dvander@1738: m_ConfigLastChanged = 0; dvander@1738: m_nSerialChange = 0; dvander@1738: } dvander@1738: void OnSourceModAllInitialized() dvander@1738: { dvander@1738: g_SourceMod.BuildPath(Path_SM, m_ConfigFile, sizeof(m_ConfigFile), "configs/maplists.cfg"); dvander@1738: } dvander@1738: void OnSourceModShutdown() dvander@1738: { dvander@1738: DumpCache(NULL); dvander@1738: } dvander@1738: void AddOrUpdateDefault(const char *name, const char *file) dvander@1738: { dvander@1738: char path[PLATFORM_MAX_PATH]; dvander@1738: maplist_info_t *pMapList, **ppMapList; dvander@1738: dvander@1738: if ((ppMapList = m_ListLookup.retrieve(name)) == NULL) dvander@1738: { dvander@1738: pMapList = new maplist_info_t; dvander@1738: pMapList->bIsCompat = true; dvander@1738: pMapList->bIsPath = true; dvander@1738: pMapList->last_modified_time = 0; dvander@1738: strncopy(pMapList->name, name, sizeof(pMapList->name)); dvander@1738: pMapList->pArray = NULL; dvander@1738: g_SourceMod.BuildPath(Path_Game, dvander@1738: pMapList->path, dvander@1738: sizeof(pMapList->path), dvander@1738: "%s", dvander@1738: file); dvander@1738: pMapList->serial = 0; dvander@1738: m_ListLookup.insert(name, pMapList); dvander@1738: m_MapLists.push_back(pMapList); dvander@1738: return; dvander@1738: } dvander@1738: dvander@1738: pMapList = *ppMapList; dvander@1738: dvander@1738: /* Don't modify if it's from the config file */ dvander@1738: if (!pMapList->bIsCompat) dvander@1738: { dvander@1738: return; dvander@1738: } dvander@1738: dvander@1738: g_SourceMod.BuildPath(Path_Game, dvander@1738: path, dvander@1738: sizeof(path), dvander@1738: "%s", dvander@1738: file); dvander@1738: dvander@1738: /* If the path matches, don't reset the serial/time */ dvander@1738: if (strcmp(path, pMapList->path) == 0) dvander@1738: { dvander@1738: return; dvander@1738: } dvander@1738: dvander@1738: strncopy(pMapList->path, path, sizeof(pMapList->path)); dvander@1738: pMapList->bIsPath = true; dvander@1738: pMapList->last_modified_time = 0; dvander@1738: pMapList->serial = 0; dvander@1738: } dvander@1738: void UpdateCache() dvander@1738: { dvander@1738: bool fileFound; dvander@1738: SMCError error; dvander@1738: time_t fileTime; dvander@1738: SMCStates states = {0, 0}; dvander@1738: dvander@1738: fileFound = g_LibSys.FileTime(m_ConfigFile, FileTime_LastChange, &fileTime); dvander@1738: dvander@1738: /* If the file is found and hasn't changed, bail out now. */ dvander@1738: if (fileFound && fileTime == m_ConfigLastChanged) dvander@1738: { dvander@1738: return; dvander@1738: } dvander@1738: dvander@1738: /* If the file wasn't found, and we already have entries, we bail out too. dvander@1738: * This case lets us optimize when a user deletes the config file, so we dvander@1738: * don't reparse every single time the function is called. dvander@1738: */ dvander@1738: if (!fileFound && m_MapLists.size() > 0) dvander@1738: { dvander@1738: return; dvander@1738: } dvander@1738: dvander@1746: m_pMapCycleFile = icvar->FindVar("mapcyclefile"); dvander@1746: dvander@1738: /* Dump everything we know about. */ dvander@1738: List compat; dvander@1738: DumpCache(&compat); dvander@1738: dvander@1738: /* All this is to add the default entry back in. */ dvander@1738: maplist_info_t *pDefList = new maplist_info_t; dvander@1738: dvander@1738: pDefList->bIsPath = true; dvander@1738: strncopy(pDefList->name, "mapcyclefile", sizeof(pDefList->name)); dvander@1738: g_SourceMod.BuildPath(Path_Game, dvander@1738: pDefList->path, dvander@1738: sizeof(pDefList->path), dvander@1738: "%s", dvander@1738: m_pMapCycleFile ? m_pMapCycleFile->GetString() : "mapcycle.txt"); dvander@1738: pDefList->last_modified_time = 0; dvander@1738: pDefList->pArray = NULL; dvander@1738: pDefList->serial = 0; dvander@1738: dvander@1738: m_ListLookup.insert("mapcyclefile", pDefList); dvander@1738: m_MapLists.push_back(pDefList); dvander@1738: dvander@1738: /* Now parse the config file even if we don't know about it. dvander@1738: * This will give us a nice error message. dvander@1738: */ dvander@1738: if ((error = g_TextParser.ParseFile_SMC(m_ConfigFile, this, &states)) dvander@1738: != SMCError_Okay) dvander@1738: { dvander@1738: const char *errmsg = g_TextParser.GetSMCErrorString(error); dvander@1738: if (errmsg == NULL) dvander@1738: { dvander@1738: errmsg = "Unknown error"; dvander@1738: } dvander@1738: g_Logger.LogError("[SM] Could not parse file \"%s\"", m_ConfigFile); dvander@1738: g_Logger.LogError("[SM] Error on line %d (col %d): %s", dvander@1738: states.line, dvander@1738: states.col, dvander@1738: errmsg); dvander@1738: } dvander@1738: else dvander@1738: { dvander@1738: m_ConfigLastChanged = fileTime; dvander@1738: } dvander@1738: dvander@1738: /* Now, re-add compat stuff back in if we can. */ dvander@1738: List::iterator iter = compat.begin(); dvander@1738: while (iter != compat.end()) dvander@1738: { dvander@1738: if (m_ListLookup.retrieve((*iter)->name) != NULL) dvander@1738: { dvander@1738: /* The compatibility shim is no longer needed. */ dvander@1738: delete (*iter)->pArray; dvander@1738: delete (*iter); dvander@1738: } dvander@1738: else dvander@1738: { dvander@1738: m_ListLookup.insert((*iter)->name, (*iter)); dvander@1738: m_MapLists.push_back((*iter)); dvander@1738: } dvander@1738: iter = compat.erase(iter); dvander@1738: } dvander@1738: } dvander@1738: void ReadSMC_ParseStart() dvander@1738: { dvander@1738: m_CurState = MPS_NONE; dvander@1738: m_IgnoreLevel = 0; dvander@1738: m_pCurMapList = NULL; dvander@1738: } dvander@1738: SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name) dvander@1738: { dvander@1738: if (m_IgnoreLevel) dvander@1738: { dvander@1738: m_IgnoreLevel++; dvander@1738: return SMCResult_Continue; dvander@1738: } dvander@1738: dvander@1738: if (m_CurState == MPS_NONE) dvander@1738: { dvander@1738: if (strcmp(name, "MapLists") == 0) dvander@1738: { dvander@1738: m_CurState = MPS_GLOBAL; dvander@1738: } dvander@1738: else dvander@1738: { dvander@1738: m_IgnoreLevel = 1; dvander@1738: } dvander@1738: } dvander@1738: else if (m_CurState == MPS_GLOBAL) dvander@1738: { dvander@1738: m_pCurMapList = new maplist_info_t; dvander@1738: dvander@1738: memset(m_pCurMapList, 0, sizeof(maplist_info_t)); dvander@1738: strncopy(m_pCurMapList->name, name, sizeof(m_pCurMapList->name)); dvander@1738: dvander@1738: m_CurState = MPS_MAPLIST; dvander@1738: } dvander@1738: else if (m_CurState == MPS_MAPLIST) dvander@1738: { dvander@1738: m_IgnoreLevel++; dvander@1738: } dvander@1738: dvander@1738: return SMCResult_Continue; dvander@1738: } dvander@1738: SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value) dvander@1738: { dvander@1738: if (m_IgnoreLevel || m_pCurMapList == NULL) dvander@1738: { dvander@1738: return SMCResult_Continue; dvander@1738: } dvander@1738: dvander@1738: if (strcmp(key, "file") == 0) dvander@1738: { dvander@1738: g_SourceMod.BuildPath(Path_Game, dvander@1738: m_pCurMapList->path, dvander@1738: sizeof(m_pCurMapList->path), dvander@1738: "%s", dvander@1738: value); dvander@1738: m_pCurMapList->bIsPath = true; dvander@1738: } dvander@1738: else if (strcmp(key, "target") == 0) dvander@1738: { dvander@1738: strncopy(m_pCurMapList->path, value, sizeof(m_pCurMapList->path)); dvander@1738: m_pCurMapList->bIsPath = false; dvander@1738: } dvander@1738: dvander@1738: return SMCResult_Continue; dvander@1738: } dvander@1738: SMCResult ReadSMC_LeavingSection(const SMCStates *states) dvander@1738: { dvander@1738: if (m_IgnoreLevel) dvander@1738: { dvander@1738: m_IgnoreLevel--; dvander@1738: return SMCResult_Continue; dvander@1738: } dvander@1738: dvander@1738: if (m_CurState == MPS_MAPLIST) dvander@1738: { dvander@1738: if (m_pCurMapList != NULL dvander@1738: && m_pCurMapList->path[0] != '\0' dvander@1738: && m_ListLookup.retrieve(m_pCurMapList->name) == NULL) dvander@1738: { dvander@1738: m_ListLookup.insert(m_pCurMapList->name, m_pCurMapList); dvander@1738: m_MapLists.push_back(m_pCurMapList); dvander@1738: m_pCurMapList = NULL; dvander@1738: } dvander@1738: else dvander@1738: { dvander@1738: delete m_pCurMapList; dvander@1738: m_pCurMapList = NULL; dvander@1738: } dvander@1738: m_CurState = MPS_GLOBAL; dvander@1738: } dvander@1738: else if (m_CurState == MPS_GLOBAL) dvander@1738: { dvander@1738: m_CurState = MPS_NONE; dvander@1738: } dvander@1738: dvander@1738: return SMCResult_Continue; dvander@1738: } dvander@1738: void ReadSMC_ParseEnd(bool halted, bool failed) dvander@1738: { dvander@1738: delete m_pCurMapList; dvander@1738: m_pCurMapList = NULL; dvander@1738: } dvander@1738: static int sort_maps_in_adt_array(const void *str1, const void *str2) dvander@1738: { dvander@1738: return strcmp((char *)str1, (char *)str2); dvander@1738: } dvander@1738: CellArray *UpdateMapList(CellArray *pUseArray, const char *name, int *pSerial, unsigned int flags) dvander@1738: { dvander@1738: int change_serial; dvander@1747: CellArray *pNewArray = NULL; dvander@1738: bool success, free_new_array; dvander@1738: dvander@1738: free_new_array = false; dvander@1738: dvander@1738: if ((success = GetMapList(&pNewArray, name, &change_serial)) == false) dvander@1738: { dvander@1738: if ((flags & MAPLIST_FLAG_NO_DEFAULT) != MAPLIST_FLAG_NO_DEFAULT) dvander@1738: { dvander@1738: /* If this list failed, and it's not the default, try the default. dvander@1738: */ dvander@1738: if (strcmp(name, "default") != 0) dvander@1738: { dvander@1738: success = GetMapList(&pNewArray, name, &change_serial); dvander@1738: } dvander@1738: /* If either of the last two conditions failed, try again if we can. */ dvander@1746: if (!success && strcmp(name, "mapcyclefile") != 0) dvander@1738: { dvander@1738: success = GetMapList(&pNewArray, "mapcyclefile", &change_serial); dvander@1738: } dvander@1738: } dvander@1738: } dvander@1738: dvander@1738: /* If there was a success, and the serial has not changed, bail out. */ dvander@1897: if (success && *pSerial == change_serial) dvander@1738: { dvander@1738: return NULL; dvander@1738: } dvander@1738: dvander@1738: /** dvander@1738: * If there was a success but no map list, we need to look in the maps folder. dvander@1738: * If there was a failure and the flag is specified, we need to look in the maps folder. dvander@1738: */ dvander@1738: if ((success && pNewArray == NULL) dvander@1738: || (!success && ((flags & MAPLIST_FLAG_MAPSFOLDER) == MAPLIST_FLAG_MAPSFOLDER))) dvander@1738: { dvander@1738: char path[255]; dvander@1738: IDirectory *pDir; dvander@1738: dvander@1738: pNewArray = new CellArray(64); dvander@1738: free_new_array = true; dvander@1738: g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "maps"); dvander@1738: dvander@1738: if ((pDir = g_LibSys.OpenDirectory(path)) != NULL) dvander@1738: { dvander@1738: char *ptr; dvander@1738: cell_t *blk; dvander@1738: char buffer[PLATFORM_MAX_PATH]; dvander@1738: dvander@1738: while (pDir->MoreFiles()) dvander@1738: { dvander@1738: if (!pDir->IsEntryFile() dvander@1738: || strcmp(pDir->GetEntryName(), ".") == 0 dvander@1738: || strcmp(pDir->GetEntryName(), "..") == 0) dvander@1738: { dvander@1738: pDir->NextEntry(); dvander@1738: continue; dvander@1738: } dvander@1738: strncopy(buffer, pDir->GetEntryName(), sizeof(buffer)); dvander@1738: if ((ptr = strstr(buffer, ".bsp")) == NULL) dvander@1738: { dvander@1738: pDir->NextEntry(); dvander@1738: continue; dvander@1738: } dvander@1738: *ptr = '\0'; dvander@1738: if (!engine->IsMapValid(buffer)) dvander@1738: { dvander@1738: pDir->NextEntry(); dvander@1738: continue; dvander@1738: } dvander@1738: if ((blk = pNewArray->push()) == NULL) dvander@1738: { dvander@1738: pDir->NextEntry(); dvander@1738: continue; dvander@1738: } dvander@1738: strncopy((char *)blk, buffer, 255); dvander@1738: pDir->NextEntry(); dvander@1738: } dvander@1738: g_LibSys.CloseDirectory(pDir); dvander@1738: } dvander@1738: dvander@1738: /* Remove the array if there were no items. */ dvander@1738: if (pNewArray->size() == 0) dvander@1738: { dvander@1738: delete pNewArray; dvander@1738: pNewArray = NULL; dvander@1738: } dvander@1738: else dvander@1738: { dvander@1738: qsort(pNewArray->base(), dvander@1738: pNewArray->size(), dvander@1738: pNewArray->blocksize() * sizeof(cell_t), dvander@1738: sort_maps_in_adt_array); dvander@1738: } dvander@1738: dvander@1738: change_serial = -1; dvander@1738: } dvander@1738: dvander@1738: /* If there is still no array by this point, bail out. */ dvander@1738: if (pNewArray == NULL) dvander@1738: { dvander@1738: *pSerial = -1; dvander@1738: return NULL; dvander@1738: } dvander@1738: dvander@1738: *pSerial = change_serial; dvander@1738: dvander@1738: /* If there is no input array, return something temporary. */ dvander@1738: if (pUseArray == NULL) dvander@1738: { dvander@1738: if (free_new_array) dvander@1738: { dvander@1738: return pNewArray; dvander@1738: } dvander@1738: else dvander@1738: { dvander@1738: return pNewArray->clone(); dvander@1738: } dvander@1738: } dvander@1738: dvander@1738: /* Clear the input array if necessary. */ dvander@1738: if ((flags & MAPLIST_FLAG_CLEARARRAY) == MAPLIST_FLAG_CLEARARRAY) dvander@1738: { dvander@1738: pUseArray->clear(); dvander@1738: } dvander@1738: dvander@1738: /* Copy. */ dvander@1738: cell_t *blk_dst; dvander@1738: cell_t *blk_src; dvander@1738: for (size_t i = 0; i < pNewArray->size(); i++) dvander@1738: { dvander@1738: blk_dst = pUseArray->push(); dvander@1738: blk_src = pNewArray->at(i); dvander@1738: strncopy((char *)blk_dst, (char *)blk_src, pUseArray->blocksize() * sizeof(cell_t)); dvander@1738: } dvander@1738: dvander@1738: /* Free resources if necessary. */ dvander@1738: if (free_new_array) dvander@1738: { dvander@1738: delete pNewArray; dvander@1738: } dvander@1738: dvander@1738: /* Return the array we were given. */ dvander@1738: return pUseArray; dvander@1738: } dvander@1738: private: dvander@1738: bool GetMapList(CellArray **ppArray, const char *name, int *pSerial) dvander@1738: { dvander@1738: time_t last_time; dvander@1738: maplist_info_t *pMapList, **ppMapList; dvander@1738: dvander@1738: if ((ppMapList = m_ListLookup.retrieve(name)) == NULL) dvander@1738: { dvander@1738: return false; dvander@1738: } dvander@1738: dvander@1738: pMapList = *ppMapList; dvander@1738: dvander@1738: if (!pMapList->bIsPath) dvander@1738: { dvander@1738: return GetMapList(ppArray, pMapList->path, pSerial); dvander@1738: } dvander@1738: dvander@1738: /* If it is a path, and the path is "*", assume all files must be used. */ dvander@1738: if (strcmp(pMapList->path, "*") == 0) dvander@1738: { dvander@1738: *ppArray = NULL; dvander@1738: return true; dvander@1738: } dvander@1738: dvander@1738: if (m_pMapCycleFile != NULL && strcmp(name, "mapcyclefile") == 0) dvander@1738: { dvander@1749: char path[PLATFORM_MAX_PATH]; dvander@1749: g_SourceMod.BuildPath(Path_Game, dvander@1749: path, dvander@1749: sizeof(path), dvander@1749: "%s", dvander@1749: m_pMapCycleFile ? m_pMapCycleFile->GetString() : "mapcycle.txt"); dvander@1749: dvander@1749: if (strcmp(path, pMapList->path) != 0) dvander@1738: { dvander@1749: strncopy(pMapList->path, path, sizeof(pMapList->path)); dvander@1738: pMapList->last_modified_time = 0; dvander@1738: } dvander@1738: } dvander@1738: dvander@1738: if (!g_LibSys.FileTime(pMapList->path, FileTime_LastChange, &last_time) dvander@1738: || last_time > pMapList->last_modified_time) dvander@1738: { dvander@1738: /* Reparse */ dvander@1738: FILE *fp; dvander@1738: cell_t *blk; dvander@1738: char buffer[255]; dvander@1738: dvander@1738: if ((fp = fopen(pMapList->path, "rt")) == NULL) dvander@1738: { dvander@1738: return false; dvander@1738: } dvander@1738: dvander@1738: delete pMapList->pArray; dvander@1738: pMapList->pArray = new CellArray(64); dvander@1738: dvander@1738: while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL) dvander@1738: { dvander@1738: size_t len = strlen(buffer); dvander@1738: char *ptr = UTIL_TrimWhitespace(buffer, len); dvander@1738: if (*ptr == '\0' dvander@1738: || *ptr == ';' dvander@1738: || strncmp(ptr, "//", 2) == 0) dvander@1738: { dvander@1738: continue; dvander@1738: } dvander@1738: if (!engine->IsMapValid(ptr)) dvander@1738: { dvander@1738: continue; dvander@1738: } dvander@1738: if ((blk = pMapList->pArray->push()) != NULL) dvander@1738: { dvander@1738: strncopy((char *)blk, ptr, 255); dvander@1738: } dvander@1738: } dvander@1738: dvander@1738: fclose(fp); dvander@1738: dvander@1738: pMapList->last_modified_time = last_time; dvander@1738: pMapList->serial = ++m_nSerialChange; dvander@1738: } dvander@1738: dvander@1738: if (pMapList->pArray == NULL || pMapList->pArray->size() == 0) dvander@1738: { dvander@1738: return false; dvander@1738: } dvander@1738: dvander@1738: *pSerial = pMapList->serial; dvander@1738: *ppArray = pMapList->pArray; dvander@1738: dvander@1738: return true; dvander@1738: } dvander@1738: void DumpCache(List *compat_list) dvander@1738: { dvander@1738: m_ListLookup.clear(); dvander@1738: dvander@1738: List::iterator iter = m_MapLists.begin(); dvander@1738: while (iter != m_MapLists.end()) dvander@1738: { dvander@1738: if (compat_list != NULL && (*iter)->bIsCompat) dvander@1738: { dvander@1738: compat_list->push_back((*iter)); dvander@1738: } dvander@1738: else dvander@1738: { dvander@1738: delete (*iter)->pArray; dvander@1738: delete (*iter); dvander@1738: } dvander@1738: iter = m_MapLists.erase(iter); dvander@1738: } dvander@1738: } dvander@1738: private: dvander@1738: char m_ConfigFile[PLATFORM_MAX_PATH]; dvander@1738: time_t m_ConfigLastChanged; dvander@1738: ConVar *m_pMapCycleFile; dvander@1738: KTrie m_ListLookup; dvander@1738: List m_MapLists; dvander@1738: MapListState m_CurState; dvander@1738: unsigned int m_IgnoreLevel; dvander@1738: maplist_info_t *m_pCurMapList; dvander@1738: int m_nSerialChange; dvander@1738: } s_MapLists; dvander@1738: dvander@1738: static cell_t LoadMapList(IPluginContext *pContext, const cell_t *params) dvander@1738: { dvander@1738: char *str; dvander@1738: Handle_t hndl; dvander@1738: cell_t *addr, flags; dvander@1738: CellArray *pArray, *pNewArray; dvander@1738: dvander@1738: hndl = params[1]; dvander@1738: pContext->LocalToPhysAddr(params[2], &addr); dvander@1738: pContext->LocalToString(params[3], &str); dvander@1738: flags = params[4]; dvander@1738: dvander@1738: /* Make sure the input Handle is valid */ dvander@1738: pArray = NULL; dvander@1738: if (hndl != BAD_HANDLE) dvander@1738: { dvander@1738: HandleError err; dvander@1738: HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); dvander@1738: dvander@1738: if ((err = g_HandleSys.ReadHandle(hndl, htCellArray, &sec, (void **)&pArray)) dvander@1738: != HandleError_None) dvander@1738: { dvander@1738: return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err); dvander@1738: } dvander@1738: } dvander@1738: dvander@1738: /* Make sure the map list cache is up to date at the root */ dvander@1738: s_MapLists.UpdateCache(); dvander@1738: dvander@1738: /* Try to get the map list. */ dvander@1738: if ((pNewArray = s_MapLists.UpdateMapList(pArray, str, addr, flags)) == NULL) dvander@1738: { dvander@1738: return BAD_HANDLE; dvander@1738: } dvander@1738: dvander@1738: /* If the user wanted a new array, create it now. */ dvander@1738: if (hndl == BAD_HANDLE) dvander@1738: { dvander@1738: if ((hndl = g_HandleSys.CreateHandle(htCellArray, pNewArray, pContext->GetIdentity(), g_pCoreIdent, NULL)) dvander@1738: == BAD_HANDLE) dvander@1738: { dvander@1738: *addr = -1; dvander@1738: delete pNewArray; dvander@1738: return BAD_HANDLE; dvander@1738: } dvander@1738: } dvander@1738: dvander@1738: return hndl; dvander@1738: } dvander@1738: dvander@1738: static cell_t SetMapListCompatBind(IPluginContext *pContext, const cell_t *params) dvander@1738: { dvander@1738: char *name, *file; dvander@1738: dvander@1738: pContext->LocalToString(params[1], &name); dvander@1738: pContext->LocalToString(params[2], &file); dvander@1738: dvander@1783: s_MapLists.UpdateCache(); dvander@1738: s_MapLists.AddOrUpdateDefault(name, file); dvander@1738: dvander@1738: return 1; dvander@1738: } dvander@1738: dvander@1738: REGISTER_NATIVES(mapListNatives) dvander@1738: { dvander@1738: {"ReadMapList", LoadMapList}, dvander@1738: {"SetMapListCompatBind", SetMapListCompatBind}, dvander@1738: {NULL, NULL}, dvander@1738: };