Merge pull request #351 from alliedmodders/expose-findmap

Expose FindMap/ResolveFuzzyMapName to plugins.
This commit is contained in:
Nicholas Hastings 2015-06-28 12:43:56 -04:00
commit f960c64dc6
5 changed files with 130 additions and 28 deletions

View File

@ -1208,53 +1208,72 @@ const char *CHalfLife2::GetEntityClassname(CBaseEntity *pEntity)
return *(const char **)(((unsigned char *)pEntity) + offset);
}
#if SOURCE_ENGINE >= SE_LEFT4DEAD
static bool ResolveFuzzyMapName(const char *fuzzyName, char *outFullname, int size)
SMFindMapResult CHalfLife2::FindMap(char *pMapName, int nMapNameMax)
{
#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");
// This shouldn't happen.
if (!pHelperCmd || !pHelperCmd->CanAutoComplete())
return false;
{
return engine->IsMapValid(pMapName) == 0 ? SMFindMapResult::NotFound : SMFindMapResult::Found;
}
static size_t helperCmdLen = strlen(pHelperCmd->GetName());
CUtlVector<CUtlString> results;
pHelperCmd->AutoCompleteSuggest(fuzzyName, results);
pHelperCmd->AutoCompleteSuggest(pMapName, results);
if (results.Count() == 0)
return false;
return SMFindMapResult::NotFound;
// Results come back as you'd see in autocomplete. (ie. "changelevel fullmapnamehere"),
// so skip ahead to start of map path/name
// Like the engine, we're only going to deal with the first match.
strncopy(outFullname, &results[0][helperCmdLen + 1], size);
return true;
}
bool bExactMatch = Q_strcmp(pMapName, &results[0][helperCmdLen + 1]) == 0;
if (bExactMatch)
{
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
}
bool CHalfLife2::IsMapValid(const char *map)
{
if (!map || !map[0])
return false;
bool ret;
#if SOURCE_ENGINE == SE_TF2
char szTmp[PLATFORM_MAX_PATH];
static char szTmp[PLATFORM_MAX_PATH];
strncopy(szTmp, map, sizeof(szTmp));
ret = engine->FindMap(szTmp, sizeof(szTmp)) != eFindMap_NotFound;
#else
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;
return FindMap(szTmp, sizeof(szTmp)) != SMFindMapResult::NotFound;
}

View File

@ -129,6 +129,16 @@ public:
#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 :
public SMGlobalClass,
public IGameHelpers
@ -174,6 +184,7 @@ public: //IGameHelpers
const char *GetEntityClassname(edict_t *pEdict);
const char *GetEntityClassname(CBaseEntity *pEntity);
bool IsMapValid(const char *map);
SMFindMapResult FindMap(char *pMapName, int nMapNameMax);
public:
void AddToFakeCliCmdQueue(int client, int userid, const char *cmd);
void ProcessFakeCliCmdQueue();

View File

@ -67,6 +67,16 @@ static cell_t IsMapValid(IPluginContext *pContext, const cell_t *params)
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)
{
return engine->IsDedicatedServer();
@ -626,6 +636,7 @@ REGISTER_NATIVES(halflifeNatives)
{"GetRandomInt", GetRandomInt},
{"IsDedicatedServer", IsDedicatedServer},
{"IsMapValid", IsMapValid},
{"FindMap", FindMap},
{"SetFakeClientConVar", SetFakeClientConVar},
{"SetRandomSeed", SetRandomSeed},
{"PrecacheModel", PrecacheModel},

View File

@ -91,6 +91,25 @@ enum EngineVersion
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
/**
@ -136,6 +155,17 @@ native GetRandomInt(nmin, nmax);
*/
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.
*

View 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;
}