bool CHalfLife2::GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax)
{
	SMFindMapResult result = FindMap(pMapName, pDisplayname, nMapNameMax);

	if (result == SMFindMapResult::NotFound)
	{
		return false;
	}

#if SOURCE_ENGINE == SE_CSGO
	// In CSGO, the path separator is used in workshop maps.
	char workshop[10];
	ke::SafeSprintf(workshop, SM_ARRAYSIZE(workshop), "%s%c", "workshop", PLATFORM_SEP_CHAR);

	char *lastSlashPos;
	// In CSGO, workshop maps show up as workshop/123456789/mapname or workshop\123456789\mapname depending on OS
	if (strncmp(pDisplayname, workshop, 9) == 0 && (lastSlashPos = strrchr(pDisplayname, PLATFORM_SEP_CHAR)) != NULL)
	{
		ke::SafeStrcpy(pDisplayname, nMapNameMax, &lastSlashPos[1]);
		return true;
	}
#elif SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_BMS
	char *ugcPos;
	// In TF2 and BMS, workshop maps show up as workshop/mapname.ugc123456789 regardless of OS
	if (strncmp(pDisplayname, "workshop/", 9) == 0 && (ugcPos = strstr(pDisplayname, ".ugc")) != NULL)
	{
		// Overwrite the . with a null and SafeStrcpy will handle the rest
		ugcPos[0] = '\0';
		ke::SafeStrcpy(pDisplayname, nMapNameMax, &pDisplayname[9]);
		return true;
	}
#endif

	return true;
}
Exemple #2
0
void SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSample, 
							 float flVolume, float flAttenuation, int iFlags, int iPitch, const Vector *pOrigin, 
							 const Vector *pDirection, CUtlVector<Vector> *pUtlVecOrigins, bool bUpdatePositions, 
							 float soundtime, int speakerentity)
#endif
{
	SoundHookIter iter;
	IPluginFunction *pFunc;
	cell_t res = static_cast<ResultType>(Pl_Continue);
	cell_t sndlevel = static_cast<cell_t>(ATTN_TO_SNDLVL(flAttenuation));
	char buffer[PLATFORM_MAX_PATH];
	strcpy(buffer, pSample);

	char soundEntry[PLATFORM_MAX_PATH] = "";
#if SOURCE_ENGINE >= SE_PORTAL2
	Q_strncpy(soundEntry, pSoundEntry, sizeof(soundEntry));
#endif

#if SOURCE_ENGINE < SE_PORTAL2
	int nSeed = 0;
#endif

	for (iter=m_NormalFuncs.begin(); iter!=m_NormalFuncs.end(); iter++)
	{
		int players[SM_MAXPLAYERS], size;
		size = _FillInPlayers(players, &filter);
		pFunc = (*iter);

		pFunc->PushArray(players, SM_ARRAYSIZE(players), SM_PARAM_COPYBACK);
		pFunc->PushCellByRef(&size);
		pFunc->PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
		pFunc->PushCellByRef(&iEntIndex);
		pFunc->PushCellByRef(&iChannel);
		pFunc->PushFloatByRef(&flVolume);
		pFunc->PushCellByRef(&sndlevel);
		pFunc->PushCellByRef(&iPitch);
		pFunc->PushCellByRef(&iFlags);
		pFunc->PushStringEx(soundEntry, sizeof(soundEntry), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
		pFunc->PushCellByRef(&nSeed);
		g_InSoundHook = true;
		pFunc->Execute(&res);
		g_InSoundHook = false;

		switch (res)
		{
		case Pl_Handled:
		case Pl_Stop:
			{
#if SOURCE_ENGINE >= SE_PORTAL2
				RETURN_META_VALUE(MRES_SUPERCEDE, -1);
#else
				RETURN_META(MRES_SUPERCEDE);
#endif
			}
		case Pl_Changed:
			{
				/* Client validation */
				for (int i = 0; i < size; i++)
				{
					int client = players[i];
					IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);

					if (!pPlayer)
					{
						pFunc->GetParentContext()->BlamePluginError(pFunc, "Client index %d is invalid", client);
					} else if (!pPlayer->IsInGame()) {
						pFunc->GetParentContext()->BlamePluginError(pFunc, "Client %d is not connected", client);
					} else {
						continue;
					}

#if SOURCE_ENGINE >= SE_PORTAL2
					RETURN_META_VALUE(MRES_IGNORED, -1 );
#else
					return;
#endif
				}

#if SOURCE_ENGINE >= SE_PORTAL2
				if (strcmp(pSoundEntry, soundEntry) != 0 || strcmp(pSample, buffer) != 0)
				{
					if (strcmp(soundEntry, buffer) == 0)
						nSoundEntryHash = -1;
					else if (strcmp(soundEntry, "") != 0)
						nSoundEntryHash = GenerateSoundEntryHash(soundEntry);
				}
#endif

				CellRecipientFilter crf;
				crf.Initialize(players, size);
#if SOURCE_ENGINE >= SE_PORTAL2
				RETURN_META_VALUE_NEWPARAMS(
					MRES_IGNORED,
					-1,
					static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char *, unsigned int, const char *, float, float, 
					int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
					(crf, iEntIndex, iChannel, soundEntry, nSoundEntryHash, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)),
					nSeed, iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
					);
#elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 \
	|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2
RETURN_META_NEWPARAMS(
					MRES_IGNORED,
					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char *, float, float, 
					int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
					(crf, iEntIndex, iChannel, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)), 
					iFlags, iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
					);
#else
				RETURN_META_NEWPARAMS(
					MRES_IGNORED,
					static_cast<void (IEngineSound::*)(IRecipientFilter &, int, int, const char *, float, float, 
					int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound), 
					(crf, iEntIndex, iChannel, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)), 
					iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
					);
#endif
			}
		}
	}

#if SOURCE_ENGINE >= SE_PORTAL2
	RETURN_META_VALUE(MRES_IGNORED, -1 );
#endif
}
SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_t nMapNameMax)
{
	ke::SafeStrcpy(pFoundMap, nMapNameMax, pMapName);

#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 engine->IsMapValid(pMapName) == 0 ? SMFindMapResult::NotFound : SMFindMapResult::Found;
	}

	static size_t helperCmdLen = strlen(pHelperCmd->GetName());

	CUtlVector<CUtlString> results;
	pHelperCmd->AutoCompleteSuggest(pMapName, results);
	if (results.Count() == 0)
		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.

	bool bExactMatch = Q_strcmp(pMapName, &results[0][helperCmdLen + 1]) == 0;
	if (bExactMatch)
	{
		return SMFindMapResult::Found;
	}
	else
	{
		ke::SafeStrcpy(pFoundMap, nMapNameMax, &results[0][helperCmdLen + 1]);
		return SMFindMapResult::FuzzyMatch;
	}

#elif SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_BMS
	static char szTemp[PLATFORM_MAX_PATH];
	if (pFoundMap == NULL)
	{
		ke::SafeStrcpy(szTemp, SM_ARRAYSIZE(szTemp), pMapName);
		pFoundMap = szTemp;
		nMapNameMax = 0;
	}

	return static_cast<SMFindMapResult>(engine->FindMap(pFoundMap, static_cast<int>(nMapNameMax)));
#elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_SDK2013
	static IVEngineServer *engine21 = (IVEngineServer *)(g_SMAPI->GetEngineFactory()("VEngineServer021", nullptr));
	return engine21->IsMapValid(pMapName) == 0 ? SMFindMapResult::NotFound : SMFindMapResult::Found;
#else
	return engine->IsMapValid(pMapName) == 0 ? SMFindMapResult::NotFound : SMFindMapResult::Found;
#endif
}