extensions/sdktools/vcallbuilder.cpp
author Phong Dang <teame06@gmail.com>
Wed Aug 01 04:17:36 2007 +0000 (2007-08-01)
changeset 1235 88bb46f9731e
parent 1233 e9cfc03b9bb8
child 1240 79eebacc9d02
permissions -rw-r--r--
Implemented requested amb603. Added voice natives.
faluco@1031
     1
/**
faluco@1031
     2
 * vim: set ts=4 :
dvander@1233
     3
 * ================================================================
dvander@1233
     4
 * SourceMod SDKTools Extension
dvander@1233
     5
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
dvander@1233
     6
 * ================================================================
faluco@1031
     7
 *
dvander@1233
     8
 * This program is free software; you can redistribute it and/or 
dvander@1233
     9
 * modify it under the terms of the GNU General Public License, 
dvander@1233
    10
 * version 3.0, as published by the Free Software Foundation.
dvander@1233
    11
 * 
faluco@1031
    12
 * This program is distributed in the hope that it will be useful,
faluco@1031
    13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
faluco@1031
    14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
faluco@1031
    15
 * GNU General Public License for more details.
dvander@1233
    16
 *
faluco@1031
    17
 * You should have received a copy of the GNU General Public License
dvander@1233
    18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1233
    19
 *
dvander@1233
    20
 * As a special exception, AlliedModders LLC gives you permission to 
dvander@1233
    21
 * link the code of this program (as well as its derivative works) to 
dvander@1233
    22
 * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
dvander@1233
    23
 * Game MODs that run on software by the Valve Corporation.  You must 
dvander@1233
    24
 * obey the GNU General Public License in all respects for all other 
dvander@1233
    25
 * code used. Additionally, AlliedModders LLC grants this exception 
dvander@1233
    26
 * to all derivative works. AlliedModders LLC defines further 
dvander@1233
    27
 * exceptions, found in LICENSE.txt (as of this writing, version 
dvander@1233
    28
 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
faluco@1031
    29
 *
faluco@1031
    30
 * Version: $Id$
faluco@1031
    31
 */
faluco@1031
    32
dvander@950
    33
#include "vcallbuilder.h"
dvander@950
    34
#include "extension.h"
dvander@950
    35
dvander@974
    36
ValveCall::ValveCall()
dvander@974
    37
{
dvander@974
    38
	call = NULL;
dvander@974
    39
	vparams = NULL;
dvander@974
    40
	retinfo = NULL;
dvander@974
    41
	thisinfo = NULL;
dvander@974
    42
	retbuf = NULL;
dvander@974
    43
}
dvander@974
    44
dvander@950
    45
ValveCall::~ValveCall()
dvander@950
    46
{
dvander@950
    47
	while (!stk.empty())
dvander@950
    48
	{
dvander@950
    49
		unsigned char *ptr = stk.front();
dvander@950
    50
		delete [] ptr;
dvander@950
    51
		stk.pop();
dvander@950
    52
	}
dvander@975
    53
	if (call)
dvander@975
    54
	{
dvander@975
    55
		call->Destroy();
dvander@975
    56
	}
dvander@950
    57
	delete [] retbuf;
dvander@950
    58
	delete [] vparams;
dvander@950
    59
}
dvander@950
    60
dvander@950
    61
unsigned char *ValveCall::stk_get()
dvander@950
    62
{
dvander@950
    63
	unsigned char *ptr;
dvander@950
    64
	if (stk.empty())
dvander@950
    65
	{
dvander@950
    66
		ptr = new unsigned char[stackSize];
dvander@950
    67
	} else {
dvander@950
    68
		ptr = stk.front();
dvander@950
    69
		stk.pop();
dvander@950
    70
	}
dvander@950
    71
	return ptr;
dvander@950
    72
}
dvander@950
    73
dvander@950
    74
void ValveCall::stk_put(unsigned char *ptr)
dvander@950
    75
{
dvander@950
    76
	stk.push(ptr);
dvander@950
    77
}
dvander@950
    78
dvander@953
    79
ValveCall *CreateValveCall(void *addr,
dvander@953
    80
						   ValveCallType vcalltype,
dvander@953
    81
						   const ValvePassInfo *retInfo,
dvander@953
    82
						   const ValvePassInfo *params,
dvander@953
    83
						   unsigned int numParams)
dvander@953
    84
{
dvander@953
    85
	if (numParams > 32)
dvander@953
    86
	{
dvander@953
    87
		return NULL;
dvander@953
    88
	}
dvander@953
    89
dvander@953
    90
	ValveCall *vc = new ValveCall;
dvander@953
    91
ds@1065
    92
	vc->type = vcalltype;
ds@1065
    93
dvander@953
    94
	size_t size = 0;
dvander@953
    95
	vc->stackSize = 0;
dvander@953
    96
dvander@987
    97
	/* Get return information - encode only */
dvander@953
    98
	PassInfo retBuf;
dvander@953
    99
	size_t retBufSize = 0;
dvander@987
   100
	bool retbuf_needs_extra;
dvander@953
   101
	if (retInfo)
dvander@953
   102
	{
dvander@987
   103
		if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0)
dvander@953
   104
		{
dvander@953
   105
			delete vc;
dvander@953
   106
			return NULL;
dvander@953
   107
		}
dvander@987
   108
		retBufSize = retBuf.size;
dvander@953
   109
	}
dvander@953
   110
ds@1086
   111
	/* Get parameter info */
ds@1086
   112
	PassInfo paramBuf[32];
ds@1086
   113
	size_t sizes[32];
ds@1086
   114
	size_t normSize = 0;
ds@1086
   115
	size_t extraSize = 0;
ds@1086
   116
	for (unsigned int i=0; i<numParams; i++)
ds@1086
   117
	{
ds@1086
   118
		bool needs_extra;
ds@1086
   119
		if ((size = ValveParamToBinParam(params[i].vtype, 
ds@1086
   120
			params[i].type,
ds@1086
   121
			params[i].flags,
ds@1086
   122
			&paramBuf[i],
ds@1086
   123
			needs_extra)) == 0)
ds@1086
   124
		{
ds@1086
   125
			delete vc;
ds@1086
   126
			return NULL;
ds@1086
   127
		}
ds@1086
   128
		if (needs_extra)
ds@1086
   129
		{
ds@1086
   130
			sizes[i] = size;
ds@1086
   131
		} else {
ds@1086
   132
			sizes[i] = 0;
ds@1086
   133
		}
ds@1086
   134
		normSize += paramBuf[i].size;
ds@1086
   135
		extraSize += sizes[i];
ds@1086
   136
	}
ds@1086
   137
ds@1086
   138
dvander@953
   139
	/* Get thisinfo if needed */
dvander@953
   140
	ValvePassInfo thisbuf;
dvander@953
   141
	ValvePassInfo *thisinfo = NULL;
dvander@953
   142
	CallConvention cv = CallConv_Cdecl;
dvander@953
   143
	if (vcalltype != ValveCall_Static)
dvander@953
   144
	{
dvander@953
   145
		thisinfo = &thisbuf;
dvander@953
   146
		thisinfo->type = PassType_Basic;
ds@1065
   147
		switch (vcalltype)
dvander@953
   148
		{
ds@1065
   149
		case ValveCall_Entity:
dvander@953
   150
			thisinfo->vtype = Valve_CBaseEntity;
ds@1065
   151
			thisinfo->flags = PASSFLAG_BYVAL;
dvander@953
   152
			thisinfo->decflags |= VDECODE_FLAG_ALLOWWORLD;
ds@1065
   153
			break;
ds@1065
   154
		case ValveCall_Player:
dvander@953
   155
			thisinfo->vtype = Valve_CBasePlayer;
ds@1065
   156
			thisinfo->flags = PASSFLAG_BYVAL;
ds@1065
   157
			thisinfo->decflags = 0;
ds@1065
   158
			break;
ds@1065
   159
		case ValveCall_GameRules:
ds@1065
   160
			thisinfo->vtype = Valve_POD;
ds@1065
   161
			thisinfo->flags = PASSFLAG_ASPOINTER;
dvander@953
   162
			thisinfo->decflags = 0;
dvander@953
   163
		}
dvander@953
   164
		thisinfo->encflags = 0;
dvander@953
   165
		thisinfo->offset = 0;
ds@1086
   166
		normSize += sizeof(void *);
dvander@953
   167
		cv = CallConv_ThisCall;
dvander@953
   168
	}
dvander@953
   169
dvander@953
   170
	/* Now we can try creating the call */
dvander@953
   171
	if ((vc->call = g_pBinTools->CreateCall(addr,
dvander@953
   172
		cv,
dvander@953
   173
		(retInfo ? &retBuf : NULL),
dvander@953
   174
		paramBuf,
dvander@953
   175
		numParams))
dvander@953
   176
		== NULL)
dvander@953
   177
	{
dvander@953
   178
		if (!vc->call)
dvander@953
   179
		{
dvander@953
   180
			delete vc;
dvander@953
   181
			return NULL;
dvander@953
   182
		}
dvander@953
   183
	}
dvander@953
   184
dvander@953
   185
	/* Allocate extra space for thisptr AND ret buffer, even if we don't use it */
dvander@953
   186
	vc->vparams = new ValvePassInfo[numParams + 2];
dvander@953
   187
dvander@953
   188
	/* We've got the call and everything is encoded.
dvander@953
   189
	 * It's time to save the valve specific information and helper variables.
dvander@953
   190
	 */
dvander@953
   191
	if (retInfo)
dvander@953
   192
	{
dvander@953
   193
		/* Allocate and copy */
dvander@953
   194
		vc->retinfo = &(vc->vparams[numParams]);
dvander@953
   195
		*vc->retinfo = *retInfo;
dvander@953
   196
		vc->retinfo->offset = 0;
dvander@987
   197
		vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0;
dvander@953
   198
		/* Allocate stack space */
dvander@953
   199
		vc->retbuf = new unsigned char[retBufSize];
dvander@953
   200
	} else {
dvander@953
   201
		vc->retinfo = NULL;
dvander@953
   202
		vc->retbuf = NULL;
dvander@953
   203
	}
dvander@953
   204
dvander@953
   205
	if (thisinfo)
dvander@953
   206
	{
dvander@953
   207
		/* Allocate and copy */
dvander@953
   208
		vc->thisinfo = &(vc->vparams[numParams + 1]);
dvander@953
   209
		*vc->thisinfo = *thisinfo;
dvander@953
   210
		vc->thisinfo->offset = 0;
dvander@987
   211
		vc->thisinfo->obj_offset = 0;
dvander@953
   212
	} else {
dvander@953
   213
		vc->thisinfo = NULL;
dvander@953
   214
	}
dvander@953
   215
dvander@953
   216
	/* Now, save info about each parameter. */
dvander@987
   217
	size_t last_extra_offset = 0;
dvander@953
   218
	for (unsigned int i=0; i<numParams; i++)
dvander@953
   219
	{
dvander@953
   220
		/* Copy */
dvander@953
   221
		vc->vparams[i] = params[i];
dvander@953
   222
		vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
dvander@987
   223
		vc->vparams[i].obj_offset = last_extra_offset;
dvander@987
   224
		last_extra_offset += sizes[i];
dvander@953
   225
	}
dvander@953
   226
dvander@987
   227
	vc->stackSize = normSize + extraSize;
dvander@987
   228
	vc->stackEnd = normSize;
dvander@987
   229
dvander@953
   230
	return vc;
dvander@953
   231
}
dvander@953
   232
dvander@950
   233
ValveCall *CreateValveVCall(unsigned int vtableIdx,
dvander@950
   234
							ValveCallType vcalltype,
dvander@950
   235
							const ValvePassInfo *retInfo,
dvander@950
   236
							const ValvePassInfo *params,
dvander@950
   237
							unsigned int numParams)
dvander@950
   238
{
dvander@950
   239
	if (numParams > 32)
dvander@950
   240
	{
dvander@950
   241
		return NULL;
dvander@950
   242
	}
dvander@950
   243
dvander@950
   244
	ValveCall *vc = new ValveCall;
dvander@950
   245
ds@1065
   246
	vc->type = vcalltype;
ds@1065
   247
dvander@950
   248
	size_t size = 0;
dvander@950
   249
	vc->stackSize = 0;
dvander@950
   250
dvander@987
   251
	/* Get return information - encode only */
dvander@950
   252
	PassInfo retBuf;
dvander@950
   253
	size_t retBufSize = 0;
dvander@987
   254
	bool retbuf_needs_extra;
dvander@950
   255
	if (retInfo)
dvander@950
   256
	{
dvander@987
   257
		if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0)
dvander@950
   258
		{
dvander@950
   259
			delete vc;
dvander@950
   260
			return NULL;
dvander@950
   261
		}
dvander@987
   262
		retBufSize = retBuf.size;
dvander@950
   263
	}
dvander@950
   264
dvander@950
   265
	/* Get parameter info */
dvander@950
   266
	PassInfo paramBuf[32];
dvander@987
   267
	size_t sizes[32];
dvander@987
   268
	size_t normSize = 0;
dvander@987
   269
	size_t extraSize = 0;
dvander@950
   270
	for (unsigned int i=0; i<numParams; i++)
dvander@950
   271
	{
dvander@987
   272
		bool needs_extra;
dvander@987
   273
		if ((size = ValveParamToBinParam(params[i].vtype, 
dvander@987
   274
										params[i].type,
dvander@987
   275
										params[i].flags,
dvander@987
   276
										&paramBuf[i],
dvander@987
   277
										needs_extra)) == 0)
dvander@950
   278
		{
dvander@950
   279
			delete vc;
dvander@950
   280
			return NULL;
dvander@950
   281
		}
dvander@987
   282
		if (needs_extra)
dvander@987
   283
		{
dvander@987
   284
			sizes[i] = size;
dvander@987
   285
		} else {
dvander@987
   286
			sizes[i] = 0;
dvander@987
   287
		}
dvander@987
   288
		normSize += paramBuf[i].size;
dvander@987
   289
		extraSize += sizes[i];
dvander@950
   290
	}
dvander@950
   291
dvander@950
   292
	/* Now we can try creating the call */
dvander@950
   293
	if ((vc->call = g_pBinTools->CreateVCall(vtableIdx, 
dvander@950
   294
		0, 
dvander@950
   295
		0, 
dvander@950
   296
		(retInfo ? &retBuf : NULL),
dvander@950
   297
		paramBuf,
dvander@950
   298
		numParams))
dvander@950
   299
		== NULL)
dvander@950
   300
	{
dvander@950
   301
		if (!vc->call)
dvander@950
   302
		{
dvander@950
   303
			delete vc;
dvander@950
   304
			return NULL;
dvander@950
   305
		}
dvander@950
   306
	}
dvander@950
   307
dvander@950
   308
	/* Allocate extra space for thisptr AND ret buffer, even if we don't use it */
dvander@950
   309
	vc->vparams = new ValvePassInfo[numParams + 2];
dvander@950
   310
dvander@950
   311
	/* We've got the call and everything is encoded.
dvander@950
   312
	 * It's time to save the valve specific information and helper variables.
dvander@950
   313
	 */
dvander@950
   314
	if (retInfo)
dvander@950
   315
	{
dvander@950
   316
		/* Allocate and copy */
dvander@950
   317
		vc->retinfo = &(vc->vparams[numParams]);
dvander@950
   318
		*vc->retinfo = *retInfo;
dvander@950
   319
		vc->retinfo->offset = 0;
dvander@987
   320
		vc->retinfo->obj_offset = retbuf_needs_extra ? sizeof(void *) : 0;
dvander@950
   321
		/* Allocate stack space */
dvander@950
   322
		vc->retbuf = new unsigned char[retBufSize];
dvander@950
   323
	} else {
dvander@950
   324
		vc->retinfo = NULL;
dvander@950
   325
		vc->retbuf = NULL;
dvander@950
   326
	}
dvander@950
   327
dvander@950
   328
	/* Save the this info for the dynamic decoder */
dvander@950
   329
	vc->thisinfo = &(vc->vparams[numParams + 1]);
dvander@950
   330
	vc->thisinfo->type = PassType_Basic;
ds@1065
   331
	switch (vcalltype)
dvander@950
   332
	{
ds@1065
   333
	case ValveCall_Entity:
dvander@950
   334
		vc->thisinfo->vtype = Valve_CBaseEntity;
ds@1065
   335
		vc->thisinfo->flags = PASSFLAG_BYVAL;
dvander@986
   336
		vc->thisinfo->decflags = VDECODE_FLAG_ALLOWWORLD;
ds@1065
   337
		break;
ds@1065
   338
	case ValveCall_Player:
dvander@950
   339
		vc->thisinfo->vtype = Valve_CBasePlayer;
ds@1065
   340
		vc->thisinfo->flags = PASSFLAG_BYVAL;
dvander@950
   341
		vc->thisinfo->decflags = 0;
ds@1065
   342
		break;
ds@1065
   343
	case ValveCall_GameRules:
ds@1065
   344
		vc->thisinfo->vtype = Valve_POD;
ds@1065
   345
		vc->thisinfo->flags = PASSFLAG_ASPOINTER;
ds@1065
   346
		vc->thisinfo->decflags = 0;
ds@1065
   347
		break;
dvander@950
   348
	}
dvander@950
   349
	vc->thisinfo->encflags = 0;
dvander@950
   350
	vc->thisinfo->offset = 0;
dvander@987
   351
	vc->thisinfo->obj_offset = 0;
dvander@987
   352
	normSize += sizeof(void *);
dvander@950
   353
dvander@950
   354
	/* Now, save info about each parameter. */
dvander@987
   355
	size_t last_extra_offset = 0;
dvander@950
   356
	for (unsigned int i=0; i<numParams; i++)
dvander@950
   357
	{
dvander@950
   358
		/* Copy */
dvander@950
   359
		vc->vparams[i] = params[i];
dvander@950
   360
		vc->vparams[i].offset = vc->call->GetParamInfo(i)->offset;
dvander@987
   361
		vc->vparams[i].obj_offset = last_extra_offset;
dvander@987
   362
		last_extra_offset += sizes[i];
dvander@950
   363
	}
dvander@950
   364
dvander@987
   365
	vc->stackSize = normSize + extraSize;
dvander@987
   366
	vc->stackEnd = normSize;
dvander@987
   367
dvander@950
   368
	return vc;
dvander@950
   369
}