extensions/sdkhooks/natives.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Fri Mar 21 22:09:15 2014 -0400 (2014-03-21)
changeset 4294 fa845b627daf
parent 4118 28b0497ef235
child 4297 c05238822c32
permissions -rw-r--r--
Improve logical entity support in SDKHooks natives (bug 6069, r=asherkin).
skamonkey@3767
     1
/**
skamonkey@3767
     2
 * vim: set ts=4 :
skamonkey@3767
     3
 * =============================================================================
skamonkey@3767
     4
 * Source SDK Hooks Extension
skamonkey@3767
     5
 * Copyright (C) 2010-2012 Nicholas Hastings
skamonkey@3767
     6
 * Copyright (C) 2009-2010 Erik Minekus
skamonkey@3767
     7
 * =============================================================================
skamonkey@3767
     8
 *
skamonkey@3767
     9
 * This program is free software; you can redistribute it and/or modify it under
skamonkey@3767
    10
 * the terms of the GNU General Public License, version 3.0, as published by the
skamonkey@3767
    11
 * Free Software Foundation.
skamonkey@3767
    12
 * 
skamonkey@3767
    13
 * This program is distributed in the hope that it will be useful, but WITHOUT
skamonkey@3767
    14
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
skamonkey@3767
    15
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
skamonkey@3767
    16
 * details.
skamonkey@3767
    17
 *
skamonkey@3767
    18
 * You should have received a copy of the GNU General Public License along with
skamonkey@3767
    19
 * this program.  If not, see <http://www.gnu.org/licenses/>.
skamonkey@3767
    20
 *
skamonkey@3767
    21
 * As a special exception, AlliedModders LLC gives you permission to link the
skamonkey@3767
    22
 * code of this program (as well as its derivative works) to "Half-Life 2," the
skamonkey@3767
    23
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
skamonkey@3767
    24
 * by the Valve Corporation.  You must obey the GNU General Public License in
skamonkey@3767
    25
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
skamonkey@3767
    26
 * this exception to all derivative works.  AlliedModders LLC defines further
skamonkey@3767
    27
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
skamonkey@3767
    28
 * or <http://www.sourcemod.net/license.php>.
skamonkey@3767
    29
 *
skamonkey@3767
    30
 * Version: $Id$
skamonkey@3767
    31
 */
skamonkey@3767
    32
skamonkey@3767
    33
#include "extension.h"
skamonkey@3767
    34
#include "natives.h"
skamonkey@3767
    35
#include <compat_wrappers.h>
skamonkey@3767
    36
skamonkey@3767
    37
#if defined SH_DECL_MANUALEXTERN1
skamonkey@3767
    38
SH_DECL_MANUALEXTERN1(OnTakeDamage, int, CTakeDamageInfoHack &);
skamonkey@3767
    39
SH_DECL_MANUALEXTERN3_void(Weapon_Drop, CBaseCombatWeapon *, const Vector *, const Vector *);
skamonkey@3767
    40
#endif
skamonkey@3767
    41
skamonkey@3767
    42
cell_t Native_Hook(IPluginContext *pContext, const cell_t *params)
skamonkey@3767
    43
{
skamonkey@3767
    44
	int entity = (int)params[1];
skamonkey@3767
    45
	SDKHookType type = (SDKHookType)params[2];
skamonkey@3767
    46
	IPluginFunction *callback = pContext->GetFunctionById(params[3]);
skamonkey@3767
    47
	HookReturn ret = g_Interface.Hook(entity, type, callback);
skamonkey@3767
    48
	switch (ret)
skamonkey@3767
    49
	{
skamonkey@3767
    50
		case HookRet_InvalidEntity:
skamonkey@3767
    51
			pContext->ThrowNativeError("Entity %d is invalid", entity);
skamonkey@3767
    52
			break;
skamonkey@3767
    53
		case HookRet_InvalidHookType:
skamonkey@3767
    54
			pContext->ThrowNativeError("Invalid hook type specified");
skamonkey@3767
    55
			break;
skamonkey@3767
    56
		case HookRet_NotSupported:
skamonkey@3767
    57
			pContext->ThrowNativeError("Hook type not supported on this game");
skamonkey@3767
    58
			break;
skamonkey@3767
    59
		case HookRet_BadEntForHookType:
kyle@3963
    60
		{
skamonkey@4294
    61
			CBaseEntity *pEnt = gamehelpers->ReferenceToEntity(params[1]);
skamonkey@4294
    62
			const char *pClassname = pEnt ? gamehelpers->GetEntityClassname(pEnt) : NULL;
skamonkey@4294
    63
			if (!pClassname)
skamonkey@4294
    64
			{
skamonkey@4294
    65
				pContext->ThrowNativeError("Hook type not valid for this type of entity (%i).", entity);
skamonkey@4294
    66
			}
skamonkey@4294
    67
			else
skamonkey@4294
    68
			{
skamonkey@4294
    69
				pContext->ThrowNativeError("Hook type not valid for this type of entity (%i/%s)", entity, pClassname);
kyle@3963
    70
			}
kyle@3963
    71
			
skamonkey@3767
    72
			break;
kyle@3963
    73
		}
skamonkey@3767
    74
	}
skamonkey@3767
    75
skamonkey@3767
    76
	return 0;
skamonkey@3767
    77
}
skamonkey@3767
    78
skamonkey@3767
    79
cell_t Native_HookEx(IPluginContext *pContext, const cell_t *params)
skamonkey@3767
    80
{
skamonkey@3767
    81
	int entity = (int)params[1];
skamonkey@3767
    82
	SDKHookType type = (SDKHookType)params[2];
skamonkey@3767
    83
	IPluginFunction *callback = pContext->GetFunctionById(params[3]);
skamonkey@3767
    84
	HookReturn ret = g_Interface.Hook(entity, type, callback);
skamonkey@3767
    85
	if (ret == HookRet_Successful)
skamonkey@3767
    86
		return true;
skamonkey@3767
    87
skamonkey@3767
    88
	return false;
skamonkey@3767
    89
}
skamonkey@3767
    90
skamonkey@3767
    91
cell_t Native_Unhook(IPluginContext *pContext, const cell_t *params)
skamonkey@3767
    92
{
skamonkey@3767
    93
	int entity = (int)params[1];
skamonkey@3767
    94
	SDKHookType type = (SDKHookType)params[2];
skamonkey@3767
    95
	IPluginFunction *callback = pContext->GetFunctionById(params[3]);
skamonkey@3767
    96
skamonkey@3767
    97
	for(int i = g_HookList.Count() - 1; i >= 0; i--)
skamonkey@3767
    98
	{
skamonkey@3767
    99
		if(g_HookList[i].entity == entity && g_HookList[i].type == type && g_HookList[i].callback == callback)
skamonkey@3767
   100
			g_Interface.Unhook(i);
skamonkey@3767
   101
	}
skamonkey@3767
   102
skamonkey@3767
   103
	return 0;
skamonkey@3767
   104
}
skamonkey@3767
   105
skamonkey@3767
   106
cell_t Native_TakeDamage(IPluginContext *pContext, const cell_t *params)
skamonkey@3767
   107
{
skamonkey@3767
   108
// todo: fix code to not require this >.<
skamonkey@3767
   109
#if !defined SH_DECL_MANUALEXTERN1
skamonkey@3767
   110
	pContext->ThrowNativeError("SDKHooks_TakeDamage is not supported on this engine.");
skamonkey@3767
   111
#else
skamonkey@4294
   112
	CBaseEntity *pVictim = gamehelpers->ReferenceToEntity(params[1]);
skamonkey@3767
   113
	if (!pVictim)
skamonkey@3767
   114
		return pContext->ThrowNativeError("Invalid entity index %d for victim", params[1]);
skamonkey@3767
   115
	
skamonkey@4294
   116
	CBaseEntity *pInflictor = gamehelpers->ReferenceToEntity(params[2]);
skamonkey@3767
   117
	if (!pInflictor)
skamonkey@3767
   118
		return pContext->ThrowNativeError("Invalid entity index %d for inflictor", params[2]);
skamonkey@3767
   119
kyle@4118
   120
	CBaseEntity *pAttacker;
skamonkey@3767
   121
	if (params[3] != -1)
skamonkey@3767
   122
	{
skamonkey@4294
   123
		pAttacker = gamehelpers->ReferenceToEntity(params[3]);
skamonkey@3767
   124
		if (!pAttacker)
skamonkey@3767
   125
		{
skamonkey@3767
   126
			return pContext->ThrowNativeError("Invalid entity index %d for attackerr", params[3]);
skamonkey@3767
   127
		}
skamonkey@3767
   128
	}
kyle@4118
   129
	else
kyle@4118
   130
	{
kyle@4118
   131
		pAttacker = NULL;
kyle@4118
   132
	}
skamonkey@3767
   133
skamonkey@3767
   134
	float flDamage = sp_ctof(params[4]);
skamonkey@3767
   135
	int iDamageType = params[5];
skamonkey@3767
   136
kyle@4118
   137
	CBaseEntity *pWeapon;
skamonkey@3767
   138
	if (params[6] != -1)
skamonkey@3767
   139
	{
skamonkey@4294
   140
		pWeapon = gamehelpers->ReferenceToEntity(params[6]);
kyle@4118
   141
		if (!pWeapon)
skamonkey@3767
   142
		{
skamonkey@3767
   143
			return pContext->ThrowNativeError("Invalid entity index %d for weapon", params[6]);
skamonkey@3767
   144
		}
skamonkey@3767
   145
	}
kyle@4118
   146
	else
kyle@4118
   147
	{
kyle@4118
   148
		pWeapon = NULL;
kyle@4118
   149
	}
skamonkey@3767
   150
skamonkey@3767
   151
	cell_t *addr;
skamonkey@3767
   152
	int err;
skamonkey@3767
   153
	if ((err = pContext->LocalToPhysAddr(params[7], &addr)) != SP_ERROR_NONE)
skamonkey@3767
   154
	{
skamonkey@3767
   155
		return pContext->ThrowNativeError("Could not read damageForce vector");
skamonkey@3767
   156
	}
skamonkey@3767
   157
kyle@4118
   158
	Vector vecDamageForce;
skamonkey@3767
   159
	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
skamonkey@3767
   160
	{
kyle@4118
   161
		vecDamageForce.Init(sp_ctof(addr[0]), sp_ctof(addr[1]), sp_ctof(addr[2]));
kyle@4118
   162
	}
kyle@4118
   163
	else
kyle@4118
   164
	{
kyle@4118
   165
		vecDamageForce.Init();
skamonkey@3767
   166
	}
skamonkey@3767
   167
skamonkey@3767
   168
	if ((err = pContext->LocalToPhysAddr(params[8], &addr)) != SP_ERROR_NONE)
skamonkey@3767
   169
	{
skamonkey@3767
   170
		return pContext->ThrowNativeError("Could not read damagePosition vector");
skamonkey@3767
   171
	}
skamonkey@3767
   172
kyle@4118
   173
	Vector vecDamagePosition;
skamonkey@3767
   174
	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
skamonkey@3767
   175
	{
kyle@4118
   176
		vecDamagePosition.Init(sp_ctof(addr[0]), sp_ctof(addr[1]), sp_ctof(addr[2]));
kyle@4118
   177
	}
kyle@4118
   178
	else
kyle@4118
   179
	{
kyle@4118
   180
		 vecDamagePosition = vec3_origin;
skamonkey@3767
   181
	}
skamonkey@3767
   182
skamonkey@3767
   183
	CTakeDamageInfoHack info(pInflictor, pAttacker, flDamage, iDamageType, pWeapon, vecDamageForce, vecDamagePosition);
skamonkey@3767
   184
	SH_MCALL(pVictim, OnTakeDamage)((CTakeDamageInfoHack &)info);
skamonkey@3767
   185
#endif
skamonkey@3767
   186
skamonkey@3767
   187
	return 0;
skamonkey@3767
   188
}
skamonkey@3767
   189
skamonkey@3767
   190
cell_t Native_DropWeapon(IPluginContext *pContext, const cell_t *params)
skamonkey@3767
   191
{
skamonkey@3767
   192
// todo: fix code to not require this >.<
skamonkey@3767
   193
#if !defined SH_DECL_MANUALEXTERN1
skamonkey@3767
   194
	pContext->ThrowNativeError("SDKHooks_DropWeapon is not supported on this engine.");
skamonkey@3767
   195
#else
skamonkey@4294
   196
	CBaseEntity *pPlayer = gamehelpers->ReferenceToEntity(params[1]);
skamonkey@3767
   197
	if (!pPlayer)
skamonkey@3767
   198
		return pContext->ThrowNativeError("Invalid client index %d", params[1]);
skamonkey@4294
   199
skamonkey@4294
   200
	IGamePlayer *pGamePlayer = playerhelpers->GetGamePlayer(gamehelpers->ReferenceToIndex(params[1]));
skamonkey@4294
   201
	if (!pGamePlayer || !pGamePlayer->IsInGame())
skamonkey@4294
   202
		return pContext->ThrowNativeError("Client index %d not in game", params[1]);
skamonkey@3767
   203
	
skamonkey@4294
   204
	CBaseEntity *pWeapon = gamehelpers->ReferenceToEntity(params[2]);
skamonkey@3767
   205
	if (!pWeapon)
skamonkey@3767
   206
		return pContext->ThrowNativeError("Invalid entity index %d for weapon", params[2]);
skamonkey@3767
   207
skamonkey@3767
   208
	IServerUnknown *pUnk = (IServerUnknown *)pWeapon;
skamonkey@3767
   209
	IServerNetworkable *pNet = pUnk->GetNetworkable();
skamonkey@3767
   210
skamonkey@4054
   211
	if (!UTIL_ContainsDataTable(pNet->GetServerClass()->m_pTable, "DT_BaseCombatWeapon"))
skamonkey@3767
   212
		return pContext->ThrowNativeError("Entity index %d is not a weapon", params[2]);
skamonkey@3767
   213
skamonkey@4054
   214
	sm_sendprop_info_t spi;
skamonkey@3767
   215
	if (!gamehelpers->FindSendPropInfo("CBaseCombatWeapon", "m_hOwnerEntity", &spi))
skamonkey@3767
   216
		return pContext->ThrowNativeError("Invalid entity index %d for weapon", params[2]);
skamonkey@3767
   217
skamonkey@3767
   218
	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pWeapon + spi.actual_offset);
skamonkey@3767
   219
	if (params[1] != hndl.GetEntryIndex())
skamonkey@3767
   220
		return pContext->ThrowNativeError("Weapon %d is not owned by client %d", params[2], params[1]);
skamonkey@3767
   221
skamonkey@3767
   222
	Vector vecTarget;
skamonkey@3767
   223
	cell_t *addr;
skamonkey@3767
   224
	int err;
skamonkey@3767
   225
	if ((err = pContext->LocalToPhysAddr(params[3], &addr)) != SP_ERROR_NONE)
skamonkey@3767
   226
	{
skamonkey@3767
   227
		return pContext->ThrowNativeError("Could not read vecTarget vector");
skamonkey@3767
   228
	}
skamonkey@3767
   229
skamonkey@3767
   230
	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
skamonkey@3767
   231
	{
skamonkey@3767
   232
		vecTarget = Vector(
skamonkey@3767
   233
			sp_ctof(addr[0]),
skamonkey@3767
   234
			sp_ctof(addr[1]),
skamonkey@3767
   235
			sp_ctof(addr[2]));
skamonkey@3767
   236
	}
skamonkey@3767
   237
	else
skamonkey@3767
   238
	{
skamonkey@3767
   239
		SH_MCALL(pPlayer, Weapon_Drop)((CBaseCombatWeapon *)pWeapon, NULL, NULL);
skamonkey@3767
   240
		return 0;
skamonkey@3767
   241
	}
skamonkey@3767
   242
skamonkey@3767
   243
	Vector vecVelocity;
skamonkey@3767
   244
	if ((err = pContext->LocalToPhysAddr(params[8], &addr)) != SP_ERROR_NONE)
skamonkey@3767
   245
	{
skamonkey@3767
   246
		return pContext->ThrowNativeError("Could not read vecVelocity vector");
skamonkey@3767
   247
	}
skamonkey@3767
   248
skamonkey@3767
   249
	if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
skamonkey@3767
   250
	{
skamonkey@3767
   251
		vecVelocity = Vector(
skamonkey@3767
   252
			sp_ctof(addr[0]),
skamonkey@3767
   253
			sp_ctof(addr[1]),
skamonkey@3767
   254
			sp_ctof(addr[2]));
skamonkey@3767
   255
	}
skamonkey@3767
   256
	else
skamonkey@3767
   257
	{
skamonkey@3767
   258
		SH_MCALL(pPlayer, Weapon_Drop)((CBaseCombatWeapon *)pWeapon, &vecTarget, NULL);
skamonkey@3767
   259
		return 0;
skamonkey@3767
   260
	}
skamonkey@3767
   261
skamonkey@3767
   262
	SH_MCALL(pPlayer, Weapon_Drop)((CBaseCombatWeapon *)pWeapon, &vecTarget, &vecVelocity);
skamonkey@3767
   263
#endif
skamonkey@3767
   264
skamonkey@3767
   265
	return 0;
skamonkey@3767
   266
}