extensions/sdktools/hooks.cpp
author Asher Baker <asherkin@gmail.com>
Fri May 17 21:46:43 2013 +0100 (2013-05-17)
changeset 3921 96e96debb70d
parent 3848 7d02e32ac0ae
child 4141 8ff66ae5ffcc
permissions -rw-r--r--
Force rebuild.
     1 /**
     2 * vim: set ts=4 :
     3 * =============================================================================
     4 * SourceMod SDKTools Extension
     5 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6 * =============================================================================
     7 *
     8 * This program is free software; you can redistribute it and/or modify it under
     9 * the terms of the GNU General Public License, version 3.0, as published by the
    10 * Free Software Foundation.
    11 *
    12 * This program is distributed in the hope that it will be useful, but WITHOUT
    13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15 * details.
    16 *
    17 * You should have received a copy of the GNU General Public License along with
    18 * this program.  If not, see <http://www.gnu.org/licenses/>.
    19 *
    20 * As a special exception, AlliedModders LLC gives you permission to link the
    21 * code of this program (as well as its derivative works) to "Half-Life 2," the
    22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23 * by the Valve Corporation.  You must obey the GNU General Public License in
    24 * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25 * this exception to all derivative works.  AlliedModders LLC defines further
    26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27 * or <http://www.sourcemod.net/license.php>.
    28 *
    29 * Version: $Id$
    30 */
    31 
    32 #include "hooks.h"
    33 #include "extension.h"
    34 
    35 #define FEATURECAP_PLAYERRUNCMD_11PARAMS	"SDKTools PlayerRunCmd 11Params"
    36 
    37 CHookManager g_Hooks;
    38 static bool PRCH_enabled = false;
    39 static bool PRCH_used = false;
    40 
    41 SH_DECL_MANUALHOOK2_void(PlayerRunCmdHook, 0, 0, 0, CUserCmd *, IMoveHelper *);
    42 
    43 CHookManager::CHookManager()
    44 {
    45 	m_usercmdsFwd = NULL;
    46 }
    47 
    48 void CHookManager::Initialize()
    49 {
    50 	int offset;
    51 	if (g_pGameConf->GetOffset("PlayerRunCmd", &offset))
    52 	{
    53 		SH_MANUALHOOK_RECONFIGURE(PlayerRunCmdHook, offset, 0, 0);
    54 		PRCH_enabled = true;
    55 	}
    56 	else
    57 	{
    58 		g_pSM->LogError(myself, "Failed to find PlayerRunCmd offset - OnPlayerRunCmd forward disabled.");
    59 		PRCH_enabled = false;
    60 	}
    61 	
    62 	plsys->AddPluginsListener(this);
    63 	sharesys->AddCapabilityProvider(myself, this, FEATURECAP_PLAYERRUNCMD_11PARAMS);
    64 
    65 	m_usercmdsFwd = forwards->CreateForward("OnPlayerRunCmd", ET_Event, 11, NULL,
    66 		Param_Cell,			// client
    67 		Param_CellByRef,	// buttons
    68 		Param_CellByRef,	// impulse
    69 		Param_Array,		// Float:vel[3]
    70 		Param_Array,		// Float:angles[3]
    71 		Param_CellByRef,	// weapon
    72 		Param_CellByRef,	// subtype
    73 		Param_CellByRef,	// cmdnum
    74 		Param_CellByRef,	// tickcount
    75 		Param_CellByRef,	// seed
    76 		Param_Array);		// mouse[2]
    77 }
    78 
    79 void CHookManager::Shutdown()
    80 {
    81 	forwards->ReleaseForward(m_usercmdsFwd);
    82 
    83 	plsys->RemovePluginsListener(this);
    84 	sharesys->DropCapabilityProvider(myself, this, FEATURECAP_PLAYERRUNCMD_11PARAMS);
    85 }
    86 
    87 void CHookManager::OnClientPutInServer(int client)
    88 {
    89 	if (!PRCH_enabled)
    90 		return;
    91 
    92 	if (!PRCH_used)
    93 		return;
    94 
    95 	edict_t *pEdict = PEntityOfEntIndex(client);
    96 	if (!pEdict)
    97 	{
    98 		return;
    99 	}
   100 
   101 	IServerUnknown *pUnknown = pEdict->GetUnknown();
   102 	if (!pUnknown)
   103 	{
   104 		return;
   105 	}
   106 
   107 	CBaseEntity *pEntity = pUnknown->GetBaseEntity();
   108 	if (!pEntity)
   109 	{
   110 		return;
   111 	}
   112 
   113 	SH_ADD_MANUALHOOK(PlayerRunCmdHook, pEntity, SH_MEMBER(this, &CHookManager::PlayerRunCmd), false);
   114 }
   115 
   116 void CHookManager::OnClientDisconnecting(int client)
   117 {
   118 	if (!PRCH_enabled)
   119 		return;
   120 
   121 	if (!PRCH_used)
   122 		return;
   123 
   124 	edict_t *pEdict = PEntityOfEntIndex(client);
   125 	if (!pEdict)
   126 	{
   127 		return;
   128 	}
   129 
   130 	IServerUnknown *pUnknown = pEdict->GetUnknown();
   131 	if (!pUnknown)
   132 	{
   133 		return;
   134 	}
   135 
   136 	CBaseEntity *pEntity = pUnknown->GetBaseEntity();
   137 	if (!pEntity)
   138 	{
   139 		return;
   140 	}
   141 
   142 	SH_REMOVE_MANUALHOOK(PlayerRunCmdHook, pEntity, SH_MEMBER(this, &CHookManager::PlayerRunCmd), false);
   143 }
   144 
   145 void CHookManager::PlayerRunCmd(CUserCmd *ucmd, IMoveHelper *moveHelper)
   146 {
   147 	if (m_usercmdsFwd->GetFunctionCount() == 0)
   148 	{
   149 		RETURN_META(MRES_IGNORED);
   150 	}
   151 
   152 	CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
   153 
   154 	if (!pEntity)
   155 	{
   156 		RETURN_META(MRES_IGNORED);
   157 	}
   158 
   159 	edict_t *pEdict = gameents->BaseEntityToEdict(pEntity);
   160 
   161 	if (!pEdict)
   162 	{
   163 		RETURN_META(MRES_IGNORED);
   164 	}
   165 
   166 	int client = IndexOfEdict(pEdict);
   167 
   168 
   169 	cell_t result = 0;
   170 	/* Impulse is a byte so we copy it back manually */
   171 	cell_t impulse = ucmd->impulse;
   172 	cell_t vel[3] = {sp_ftoc(ucmd->forwardmove), sp_ftoc(ucmd->sidemove), sp_ftoc(ucmd->upmove)};
   173 	cell_t angles[3] = {sp_ftoc(ucmd->viewangles.x), sp_ftoc(ucmd->viewangles.y), sp_ftoc(ucmd->viewangles.z)};
   174 	cell_t mouse[2] = {ucmd->mousedx, ucmd->mousedy};
   175 
   176 	m_usercmdsFwd->PushCell(client);
   177 	m_usercmdsFwd->PushCellByRef(&ucmd->buttons);
   178 	m_usercmdsFwd->PushCellByRef(&impulse);
   179 	m_usercmdsFwd->PushArray(vel, 3, SM_PARAM_COPYBACK);
   180 	m_usercmdsFwd->PushArray(angles, 3, SM_PARAM_COPYBACK);
   181 	m_usercmdsFwd->PushCellByRef(&ucmd->weaponselect);
   182 	m_usercmdsFwd->PushCellByRef(&ucmd->weaponsubtype);
   183 	m_usercmdsFwd->PushCellByRef(&ucmd->command_number);
   184 	m_usercmdsFwd->PushCellByRef(&ucmd->tick_count);
   185 	m_usercmdsFwd->PushCellByRef(&ucmd->random_seed);
   186 	m_usercmdsFwd->PushArray(mouse, 2, SM_PARAM_COPYBACK);
   187 	m_usercmdsFwd->Execute(&result);
   188 
   189 	ucmd->impulse = impulse;
   190 	ucmd->forwardmove = sp_ctof(vel[0]);
   191 	ucmd->sidemove = sp_ctof(vel[1]);
   192 	ucmd->upmove = sp_ctof(vel[2]);
   193 	ucmd->viewangles.x = sp_ctof(angles[0]);
   194 	ucmd->viewangles.y = sp_ctof(angles[1]);
   195 	ucmd->viewangles.z = sp_ctof(angles[2]);
   196 	ucmd->mousedx = mouse[0];
   197 	ucmd->mousedy = mouse[1];
   198 
   199 
   200 	if (result == Pl_Handled)
   201 	{
   202 		RETURN_META(MRES_SUPERCEDE);
   203 	}
   204 
   205 	RETURN_META(MRES_IGNORED);
   206 }
   207 
   208 void CHookManager::OnPluginLoaded(IPlugin *plugin)
   209 {
   210 	if (!PRCH_enabled)
   211 		return;
   212 
   213 	if (PRCH_used)
   214 		return;
   215 
   216 	if (!m_usercmdsFwd->GetFunctionCount())
   217 		return;
   218 
   219 	PRCH_used = true;
   220 
   221 	int MaxClients = playerhelpers->GetMaxClients();
   222 	for (int i = 1; i <= MaxClients; i++)
   223 	{
   224 		if (playerhelpers->GetGamePlayer(i)->IsInGame())
   225 		{
   226 			OnClientPutInServer(i);
   227 		}
   228 	}
   229 }
   230 
   231 void CHookManager::OnPluginUnloaded(IPlugin *plugin)
   232 {
   233 	if (!PRCH_enabled)
   234 		return;
   235 
   236 	if (!PRCH_used)
   237 		return;
   238 
   239 	if (m_usercmdsFwd->GetFunctionCount())
   240 		return;
   241 
   242 	int MaxClients = playerhelpers->GetMaxClients();
   243 	for (int i = 1; i <= MaxClients; i++)
   244 	{
   245 		if (playerhelpers->GetGamePlayer(i)->IsInGame())
   246 		{
   247 			OnClientDisconnecting(i);
   248 		}
   249 	}
   250 
   251 	PRCH_used = false;
   252 }
   253 
   254 FeatureStatus CHookManager::GetFeatureStatus(FeatureType type, const char *name)
   255 {
   256 	return FeatureStatus_Available;
   257 }