static cell_t sm_RemoveFromForward(IPluginContext *pContext, const cell_t *params)
{
	Handle_t fwdHandle = static_cast<Handle_t>(params[1]);
	Handle_t plHandle = static_cast<Handle_t>(params[2]);
	HandleError err;
	IChangeableForward *pForward;
	IPlugin *pPlugin;

	if ((err=g_HandleSys.ReadHandle(fwdHandle, g_PrivateFwdType, NULL, (void **)&pForward))
		!= HandleError_None)
	{
		return pContext->ThrowNativeError("Invalid private forward handle %x (error %d)", fwdHandle, err);
	}

	if (plHandle == 0)
	{
		pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
	} else {
		pPlugin = g_PluginSys.PluginFromHandle(plHandle, &err);

		if (!pPlugin)
		{
			return pContext->ThrowNativeError("Plugin handle %x is invalid (error %d)", plHandle, err);
		}
	}

	IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);

	if (!pFunction)
	{
		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
	}

	return pForward->RemoveFunction(pFunction);
}
void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFunction)
{
	ConVarInfo *pInfo;
	IChangeableForward *pForward;
	IPluginContext *pContext = pFunction->GetParentContext();

	/* Find the convar in the lookup trie */
	if (convar_cache_lookup(pConVar->GetName(), &pInfo))
	{
		/* Get the forward */
		pForward = pInfo->pChangeForward;

		/* If the forward doesn't exist, we can't unhook anything */
		if (!pForward)
		{
			pContext->ThrowNativeError("Convar \"%s\" has no active hook", pConVar->GetName());
			return;
		}

		/* Remove the function from the forward's list */
		if (!pForward->RemoveFunction(pFunction))
		{
			pContext->ThrowNativeError("Invalid hook callback specified for convar \"%s\"", pConVar->GetName());
			return;
		}

		/* If the forward now has 0 functions in it... */
		if (pForward->GetFunctionCount() == 0 &&
			!ConVarReentrancyGuard::IsCvarInChain(pConVar))
		{
			/* Free this forward */
			forwardsys->ReleaseForward(pForward);
			pInfo->pChangeForward = NULL;
		}
	}
}