Merge pull request #351 from alliedmodders/expose-findmap
Expose FindMap/ResolveFuzzyMapName to plugins.
This commit is contained in:
commit
f960c64dc6
@ -1208,53 +1208,72 @@ const char *CHalfLife2::GetEntityClassname(CBaseEntity *pEntity)
|
|||||||
return *(const char **)(((unsigned char *)pEntity) + offset);
|
return *(const char **)(((unsigned char *)pEntity) + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
SMFindMapResult CHalfLife2::FindMap(char *pMapName, int nMapNameMax)
|
||||||
static bool ResolveFuzzyMapName(const char *fuzzyName, char *outFullname, int size)
|
|
||||||
{
|
{
|
||||||
|
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
||||||
|
static char mapNameTmp[PLATFORM_MAX_PATH];
|
||||||
|
g_SourceMod.Format(mapNameTmp, sizeof(mapNameTmp), "maps%c%s.bsp", PLATFORM_SEP_CHAR, pMapName);
|
||||||
|
if (filesystem->FileExists(mapNameTmp, "GAME"))
|
||||||
|
{
|
||||||
|
// If this is already an exact match, don't attempt to autocomplete it further (de_dust -> de_dust2).
|
||||||
|
// ... but still check that map file is actually valid.
|
||||||
|
// We check FileExists first to avoid console message about IsMapValid with invalid map.
|
||||||
|
return engine->IsMapValid(pMapName) == 0 ? SMFindMapResult::NotFound : SMFindMapResult::Found;
|
||||||
|
}
|
||||||
|
|
||||||
static ConCommand *pHelperCmd = g_pCVar->FindCommand("changelevel");
|
static ConCommand *pHelperCmd = g_pCVar->FindCommand("changelevel");
|
||||||
|
|
||||||
|
// This shouldn't happen.
|
||||||
if (!pHelperCmd || !pHelperCmd->CanAutoComplete())
|
if (!pHelperCmd || !pHelperCmd->CanAutoComplete())
|
||||||
return false;
|
{
|
||||||
|
return engine->IsMapValid(pMapName) == 0 ? SMFindMapResult::NotFound : SMFindMapResult::Found;
|
||||||
|
}
|
||||||
|
|
||||||
static size_t helperCmdLen = strlen(pHelperCmd->GetName());
|
static size_t helperCmdLen = strlen(pHelperCmd->GetName());
|
||||||
|
|
||||||
CUtlVector<CUtlString> results;
|
CUtlVector<CUtlString> results;
|
||||||
pHelperCmd->AutoCompleteSuggest(fuzzyName, results);
|
pHelperCmd->AutoCompleteSuggest(pMapName, results);
|
||||||
if (results.Count() == 0)
|
if (results.Count() == 0)
|
||||||
return false;
|
return SMFindMapResult::NotFound;
|
||||||
|
|
||||||
// Results come back as you'd see in autocomplete. (ie. "changelevel fullmapnamehere"),
|
// Results come back as you'd see in autocomplete. (ie. "changelevel fullmapnamehere"),
|
||||||
// so skip ahead to start of map path/name
|
// so skip ahead to start of map path/name
|
||||||
|
|
||||||
// Like the engine, we're only going to deal with the first match.
|
// Like the engine, we're only going to deal with the first match.
|
||||||
|
|
||||||
strncopy(outFullname, &results[0][helperCmdLen + 1], size);
|
bool bExactMatch = Q_strcmp(pMapName, &results[0][helperCmdLen + 1]) == 0;
|
||||||
|
if (bExactMatch)
|
||||||
return true;
|
{
|
||||||
}
|
return SMFindMapResult::Found;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strncopy(pMapName, &results[0][helperCmdLen + 1], nMapNameMax);
|
||||||
|
return SMFindMapResult::FuzzyMatch;
|
||||||
|
}
|
||||||
|
#elif SOURCE_ENGINE == SE_TF2
|
||||||
|
// Save off name passed in so that we can compare to output.
|
||||||
|
// There is a bug where eFindMap_FuzzyMap is never returned, even for fuzzy matches.
|
||||||
|
char *pOriginal = sm_strdup(pMapName);
|
||||||
|
SMFindMapResult res = static_cast<SMFindMapResult>(engine->FindMap(pMapName, nMapNameMax));
|
||||||
|
bool bExactMatch = strcmp(pOriginal, pMapName) == 0;
|
||||||
|
delete [] pOriginal;
|
||||||
|
if (res == SMFindMapResult::Found && !bExactMatch)
|
||||||
|
return SMFindMapResult::FuzzyMatch;
|
||||||
|
else
|
||||||
|
return res;
|
||||||
|
#else
|
||||||
|
return engine->IsMapValid(pMapName) == 0 ? SMFindMapResult::NotFound : SMFindMapResult::Found;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool CHalfLife2::IsMapValid(const char *map)
|
bool CHalfLife2::IsMapValid(const char *map)
|
||||||
{
|
{
|
||||||
if (!map || !map[0])
|
if (!map || !map[0])
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool ret;
|
static char szTmp[PLATFORM_MAX_PATH];
|
||||||
#if SOURCE_ENGINE == SE_TF2
|
|
||||||
char szTmp[PLATFORM_MAX_PATH];
|
|
||||||
strncopy(szTmp, map, sizeof(szTmp));
|
strncopy(szTmp, map, sizeof(szTmp));
|
||||||
ret = engine->FindMap(szTmp, sizeof(szTmp)) != eFindMap_NotFound;
|
|
||||||
#else
|
return FindMap(szTmp, sizeof(szTmp)) != SMFindMapResult::NotFound;
|
||||||
ret = engine->IsMapValid(map);
|
|
||||||
#if SOURCE_ENGINE >= SE_LEFT4DEAD
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
static char szFuzzyName[PLATFORM_MAX_PATH];
|
|
||||||
if (ResolveFuzzyMapName(map, szFuzzyName, sizeof(szFuzzyName)))
|
|
||||||
{
|
|
||||||
ret = engine->IsMapValid(szFuzzyName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif // SE_TF2
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,16 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Corresponds to TF2's eFindMapResult in eiface.h
|
||||||
|
// Not yet in other games, but eventually in others on same branch.
|
||||||
|
enum class SMFindMapResult : cell_t {
|
||||||
|
Found,
|
||||||
|
NotFound,
|
||||||
|
FuzzyMatch,
|
||||||
|
NonCanonical,
|
||||||
|
PossiblyAvailable
|
||||||
|
};
|
||||||
|
|
||||||
class CHalfLife2 :
|
class CHalfLife2 :
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IGameHelpers
|
public IGameHelpers
|
||||||
@ -174,6 +184,7 @@ public: //IGameHelpers
|
|||||||
const char *GetEntityClassname(edict_t *pEdict);
|
const char *GetEntityClassname(edict_t *pEdict);
|
||||||
const char *GetEntityClassname(CBaseEntity *pEntity);
|
const char *GetEntityClassname(CBaseEntity *pEntity);
|
||||||
bool IsMapValid(const char *map);
|
bool IsMapValid(const char *map);
|
||||||
|
SMFindMapResult FindMap(char *pMapName, int nMapNameMax);
|
||||||
public:
|
public:
|
||||||
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
|
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
|
||||||
void ProcessFakeCliCmdQueue();
|
void ProcessFakeCliCmdQueue();
|
||||||
|
@ -67,6 +67,16 @@ static cell_t IsMapValid(IPluginContext *pContext, const cell_t *params)
|
|||||||
return g_HL2.IsMapValid(map);
|
return g_HL2.IsMapValid(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t FindMap(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
char *pMapname;
|
||||||
|
pContext->LocalToString(params[1], &pMapname);
|
||||||
|
|
||||||
|
cell_t size = params[2];
|
||||||
|
|
||||||
|
return static_cast<cell_t>(g_HL2.FindMap(pMapname, size));
|
||||||
|
}
|
||||||
|
|
||||||
static cell_t IsDedicatedServer(IPluginContext *pContext, const cell_t *params)
|
static cell_t IsDedicatedServer(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
return engine->IsDedicatedServer();
|
return engine->IsDedicatedServer();
|
||||||
@ -626,6 +636,7 @@ REGISTER_NATIVES(halflifeNatives)
|
|||||||
{"GetRandomInt", GetRandomInt},
|
{"GetRandomInt", GetRandomInt},
|
||||||
{"IsDedicatedServer", IsDedicatedServer},
|
{"IsDedicatedServer", IsDedicatedServer},
|
||||||
{"IsMapValid", IsMapValid},
|
{"IsMapValid", IsMapValid},
|
||||||
|
{"FindMap", FindMap},
|
||||||
{"SetFakeClientConVar", SetFakeClientConVar},
|
{"SetFakeClientConVar", SetFakeClientConVar},
|
||||||
{"SetRandomSeed", SetRandomSeed},
|
{"SetRandomSeed", SetRandomSeed},
|
||||||
{"PrecacheModel", PrecacheModel},
|
{"PrecacheModel", PrecacheModel},
|
||||||
|
@ -91,6 +91,25 @@ enum EngineVersion
|
|||||||
Engine_BlackMesa, /**< Black Mesa Multiplayer */
|
Engine_BlackMesa, /**< Black Mesa Multiplayer */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum FindMapResult
|
||||||
|
{
|
||||||
|
// A direct match for this name was found
|
||||||
|
FindMap_Found,
|
||||||
|
// No match for this map name could be found.
|
||||||
|
FindMap_NotFound,
|
||||||
|
// A fuzzy match for this map name was found.
|
||||||
|
// Ex: cp_dust -> cp_dustbowl, c1m1 -> c1m1_hotel
|
||||||
|
// Only supported for maps that the engine knows about. (This excludes workshop maps on Orangebox).
|
||||||
|
FindMap_FuzzyMatch,
|
||||||
|
// A non-canonical match for this map name was found.
|
||||||
|
// Ex: workshop/1234 -> workshop/cp_qualified_name.ugc1234
|
||||||
|
// Only supported on "Orangebox" games with workshop support.
|
||||||
|
FindMap_NonCanonical,
|
||||||
|
// No currently available match for this map name could be found, but it may be possible to load
|
||||||
|
// Only supported on "Orangebox" games with workshop support.
|
||||||
|
FindMap_PossiblyAvailable
|
||||||
|
};
|
||||||
|
|
||||||
#define INVALID_ENT_REFERENCE 0xFFFFFFFF
|
#define INVALID_ENT_REFERENCE 0xFFFFFFFF
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,6 +155,17 @@ native GetRandomInt(nmin, nmax);
|
|||||||
*/
|
*/
|
||||||
native bool:IsMapValid(const String:map[]);
|
native bool:IsMapValid(const String:map[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a full or partial map name is found or can be resolved
|
||||||
|
*
|
||||||
|
* @param map Map name (usually same as map path relative to maps/ dir,
|
||||||
|
* excluding .bsp extension). If result is FindMap_FuzzyMatch
|
||||||
|
* or FindMap_NonCanonical, this will be updated to the full path.
|
||||||
|
* @param maxlen Maximum length to write to map var.
|
||||||
|
* @return Result of the find operation. Not all result types are supported on all games.
|
||||||
|
*/
|
||||||
|
native FindMapResult FindMap(char[] map, int maxlen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the server is dedicated.
|
* Returns whether the server is dedicated.
|
||||||
*
|
*
|
||||||
|
31
plugins/testsuite/findmap.sp
Normal file
31
plugins/testsuite/findmap.sp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <sourcemod>
|
||||||
|
|
||||||
|
public void OnPluginStart()
|
||||||
|
{
|
||||||
|
RegServerCmd("test_findmap", test_findmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action test_findmap( int argc )
|
||||||
|
{
|
||||||
|
char mapName[PLATFORM_MAX_PATH];
|
||||||
|
GetCmdArg(1, mapName, sizeof(mapName));
|
||||||
|
|
||||||
|
char resultName[16];
|
||||||
|
switch (FindMap(mapName, sizeof(mapName)))
|
||||||
|
{
|
||||||
|
case FindMap_Found:
|
||||||
|
strcopy(resultName, sizeof(resultName), "Found");
|
||||||
|
case FindMap_NotFound:
|
||||||
|
strcopy(resultName, sizeof(resultName), "NotFound");
|
||||||
|
case FindMap_FuzzyMatch:
|
||||||
|
strcopy(resultName, sizeof(resultName), "FuzzyMatch");
|
||||||
|
case FindMap_NonCanonical:
|
||||||
|
strcopy(resultName, sizeof(resultName), "NonCanonical");
|
||||||
|
case FindMap_PossiblyAvailable:
|
||||||
|
strcopy(resultName, sizeof(resultName), "PossiblyAvailable");
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintToServer("FindMap says %s - \"%s\"", resultName, mapName);
|
||||||
|
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user