core/smn_entities.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jan 13 08:10:25 2008 +0000 (2008-01-13)
changeset 1847 5336a438763f
parent 1471 dac1c6d68abd
child 1884 9ca6aacb1400
permissions -rw-r--r--
fixed amb1379 with sweeping changes to the entity stuff. all prop stocks are now natives so they can properly compute everything quickly, as well as do type checks. Get/SetEntDataEnt are deprecated for being sucky, the new 2 versions do more checking and uses better values. lastly, there are functions/parameters for finding types and sizes of property.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 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 "sm_globals.h"
    33 #include "sourcemod.h"
    34 #include "sourcemm_api.h"
    35 #include "server_class.h"
    36 #include "PlayerManager.h"
    37 #include "HalfLife2.h"
    38 #include "GameConfigs.h"
    39 #include "sm_stringutil.h"
    40 
    41 enum PropType
    42 {
    43 	Prop_Send = 0,
    44 	Prop_Data
    45 };
    46 
    47 enum PropFieldType
    48 {
    49 	PropField_Unsupported,		/**< The type is unsupported. */
    50 	PropField_Integer,			/**< Valid for SendProp and Data fields */
    51 	PropField_Float,			/**< Valid for SendProp and Data fields */
    52 	PropField_Entity,			/**< Valid for Data fields only (SendProp shows as int) */
    53 	PropField_Vector,			/**< Valid for SendProp and Data fields */
    54 	PropField_String,			/**< Valid for SendProp and Data fields */
    55 };
    56 
    57 inline edict_t *GetEdict(cell_t num)
    58 {
    59 	edict_t *pEdict = engine->PEntityOfEntIndex(num);
    60 	if (!pEdict || pEdict->IsFree())
    61 	{
    62 		return NULL;
    63 	}
    64 	if (num > 0 && num <= g_Players.GetMaxClients())
    65 	{
    66 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
    67 		if (!pPlayer || !pPlayer->IsConnected())
    68 		{
    69 			return NULL;
    70 		}
    71 	}
    72 	return pEdict;
    73 }
    74 
    75 inline edict_t *GetEntity(cell_t num, CBaseEntity **pData)
    76 {
    77 	edict_t *pEdict = engine->PEntityOfEntIndex(num);
    78 	if (!pEdict || pEdict->IsFree())
    79 	{
    80 		return NULL;
    81 	}
    82 	if (num > 0 && num <= g_Players.GetMaxClients())
    83 	{
    84 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
    85 		if (!pPlayer || !pPlayer->IsConnected())
    86 		{
    87 			return NULL;
    88 		}
    89 	}
    90 	IServerUnknown *pUnk;
    91 	if ((pUnk=pEdict->GetUnknown()) == NULL)
    92 	{
    93 		return NULL;
    94 	}
    95 	*pData = pUnk->GetBaseEntity();
    96 	return pEdict;
    97 }
    98 
    99 class VEmptyClass {};
   100 datamap_t *VGetDataDescMap(CBaseEntity *pThisPtr, int offset)
   101 {
   102 	void **this_ptr = *reinterpret_cast<void ***>(&pThisPtr);
   103 	void **vtable = *reinterpret_cast<void ***>(pThisPtr);
   104 	void *vfunc = vtable[offset];
   105 
   106 	union
   107 	{
   108 		datamap_t *(VEmptyClass::*mfpnew)();
   109 #ifndef PLATFORM_POSIX
   110 		void *addr;
   111 	} u;
   112 	u.addr = vfunc;
   113 #else
   114 		struct  
   115 		{
   116 			void *addr;
   117 			intptr_t adjustor;
   118 		} s;
   119 	} u;
   120 	u.s.addr = vfunc;
   121 	u.s.adjustor = 0;
   122 #endif
   123 
   124 	return (datamap_t *)(reinterpret_cast<VEmptyClass *>(this_ptr)->*u.mfpnew)();
   125 }
   126 
   127 inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity)
   128 {
   129 	int offset;
   130 
   131 	if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset)
   132 	{
   133 		return NULL;
   134 	}
   135 
   136 	return VGetDataDescMap(pEntity, offset);
   137 }
   138 
   139 /* :TODO: Move this! */
   140 datamap_t *CHalfLife2::GetDataMap(CBaseEntity *pEntity)
   141 {
   142 	return CBaseEntity_GetDataDescMap(pEntity);
   143 }
   144 
   145 static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params)
   146 {
   147 	return gpGlobals->maxEntities;
   148 }
   149 
   150 static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params)
   151 {
   152 	edict_t *pEdict = engine->CreateEdict();
   153 
   154 	if (!pEdict)
   155 	{
   156 		return 0;
   157 	}
   158 
   159 	return engine->IndexOfEdict(pEdict);
   160 }
   161 
   162 static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
   163 {
   164 	edict_t *pEdict = engine->PEntityOfEntIndex(params[1]);
   165 
   166 	if (!pEdict)
   167 	{
   168 		return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]);
   169 	}
   170 
   171 	engine->RemoveEdict(pEdict);
   172 
   173 	return 1;
   174 }
   175 
   176 static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params)
   177 {
   178 	edict_t *pEdict = GetEdict(params[1]);
   179 
   180 	if (!pEdict)
   181 	{
   182 		return 0;
   183 	}
   184 
   185 	/* Shouldn't be necessary... not sure though */
   186 	return pEdict->IsFree() ? 0 : 1;
   187 }
   188 
   189 static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
   190 {
   191 	edict_t *pEdict = GetEdict(params[1]);
   192 
   193 	if (!pEdict)
   194 	{
   195 		return 0;
   196 	}
   197 
   198 	IServerUnknown *pUnknown = pEdict->GetUnknown();
   199 	if (!pUnknown)
   200 	{
   201 		return 0;
   202 	}
   203 
   204 	CBaseEntity *pEntity = pUnknown->GetBaseEntity();
   205 	return (pEntity != NULL) ? 1 : 0;
   206 }
   207 
   208 static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
   209 {
   210 	edict_t *pEdict = GetEdict(params[1]);
   211 
   212 	if (!pEdict)
   213 	{
   214 		return 0;
   215 	}
   216 
   217 	return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
   218 }
   219 
   220 static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
   221 {
   222 	return engine->GetEntityCount();
   223 }
   224 
   225 static cell_t GetEdictFlags(IPluginContext *pContext, const cell_t *params)
   226 {
   227 	edict_t *pEdict = GetEdict(params[1]);
   228 
   229 	if (!pEdict)
   230 	{
   231 		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   232 	}
   233 
   234 	return pEdict->m_fStateFlags;
   235 }
   236 
   237 static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params)
   238 {
   239 	edict_t *pEdict = GetEdict(params[1]);
   240 
   241 	if (!pEdict)
   242 	{
   243 		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   244 	}
   245 
   246 	pEdict->m_fStateFlags = params[2];
   247 
   248 	return 1;
   249 }
   250 
   251 static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params)
   252 {
   253 	edict_t *pEdict = GetEdict(params[1]);
   254 
   255 	if (!pEdict)
   256 	{
   257 		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   258 	}
   259 
   260 	const char *cls = pEdict->GetClassName();
   261 
   262 	if (!cls || cls[0] == '\0')
   263 	{
   264 		return 0;
   265 	}
   266 
   267 	pContext->StringToLocal(params[2], params[3], cls);
   268 
   269 	return 1;
   270 }
   271 
   272 static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
   273 {
   274 	edict_t *pEdict = GetEdict(params[1]);
   275 
   276 	if (!pEdict)
   277 	{
   278 		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   279 	}
   280 
   281 	IServerNetworkable *pNet = pEdict->GetNetworkable();
   282 	if (!pNet)
   283 	{
   284 		return 0;
   285 	}
   286 
   287 	ServerClass *pClass = pNet->GetServerClass();
   288 
   289 	pContext->StringToLocal(params[2], params[3], pClass->GetName());
   290 
   291 	return 1;
   292 }
   293 
   294 static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
   295 {
   296 	CBaseEntity *pEntity;
   297 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   298 
   299 	if (!pEdict || !pEntity)
   300 	{
   301 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   302 	}
   303 
   304 	int offset = params[2];
   305 	if (offset <= 0 || offset > 32768)
   306 	{
   307 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   308 	}
   309 
   310 	switch (params[3])
   311 	{
   312 	case 4:
   313 		return *(int *)((uint8_t *)pEntity + offset);
   314 	case 2:
   315 		return *(short *)((uint8_t *)pEntity + offset);
   316 	case 1:
   317 		return *((uint8_t *)pEntity + offset);
   318 	default:
   319 		return pContext->ThrowNativeError("Integer size %d is invalid", params[3]);
   320 	}
   321 }
   322 
   323 static cell_t SetEntData(IPluginContext *pContext, const cell_t *params)
   324 {
   325 	CBaseEntity *pEntity;
   326 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   327 
   328 	if (!pEdict || !pEntity)
   329 	{
   330 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   331 	}
   332 
   333 	int offset = params[2];
   334 	if (offset <= 0 || offset > 32768)
   335 	{
   336 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   337 	}
   338 
   339 	if (params[5])
   340 	{
   341 		g_HL2.SetEdictStateChanged(pEdict, offset);
   342 	}
   343 
   344 	switch (params[4])
   345 	{
   346 	case 4:
   347 		{
   348 			*(int *)((uint8_t *)pEntity + offset) = params[3];
   349 			break;
   350 		}
   351 	case 2:
   352 		{
   353 			*(short *)((uint8_t *)pEntity + offset) = params[3];
   354 			break;
   355 		}
   356 	case 1:
   357 		{
   358 			*((uint8_t *)pEntity + offset) = params[3];
   359 			break;
   360 		}
   361 	default:
   362 		return pContext->ThrowNativeError("Integer size %d is invalid", params[4]);
   363 	}
   364 
   365 	return 1;
   366 }
   367 
   368 static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
   369 {
   370 	CBaseEntity *pEntity;
   371 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   372 
   373 	if (!pEdict || !pEntity)
   374 	{
   375 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   376 	}
   377 
   378 	int offset = params[2];
   379 	if (offset <= 0 || offset > 32768)
   380 	{
   381 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   382 	}
   383 
   384 	float f = *(float *)((uint8_t *)pEntity + offset);
   385 
   386 	return sp_ftoc(f);
   387 }
   388 
   389 static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params)
   390 {
   391 	CBaseEntity *pEntity;
   392 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   393 
   394 	if (!pEdict || !pEntity)
   395 	{
   396 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   397 	}
   398 
   399 	int offset = params[2];
   400 	if (offset <= 0 || offset > 32768)
   401 	{
   402 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   403 	}
   404 
   405 	*(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
   406 
   407 	if (params[4])
   408 	{
   409 		g_HL2.SetEdictStateChanged(pEdict, offset);
   410 	}
   411 
   412 	return 1;
   413 }
   414 
   415 static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
   416 {
   417 	CBaseEntity *pEntity;
   418 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   419 
   420 	if (!pEdict || !pEntity)
   421 	{
   422 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   423 	}
   424 
   425 	int offset = params[2];
   426 	if (offset <= 0 || offset > 32768)
   427 	{
   428 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   429 	}
   430 
   431 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
   432 
   433 	cell_t *vec;
   434 	pContext->LocalToPhysAddr(params[3], &vec);
   435 
   436 	vec[0] = sp_ftoc(v->x);
   437 	vec[1] = sp_ftoc(v->y);
   438 	vec[2] = sp_ftoc(v->z);
   439 
   440 	return 1;
   441 }
   442 
   443 static cell_t SetEntDataVector(IPluginContext *pContext, const cell_t *params)
   444 {
   445 	CBaseEntity *pEntity;
   446 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   447 
   448 	if (!pEdict || !pEntity)
   449 	{
   450 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   451 	}
   452 
   453 	int offset = params[2];
   454 	if (offset <= 0 || offset > 32768)
   455 	{
   456 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   457 	}
   458 
   459 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
   460 
   461 	cell_t *vec;
   462 	pContext->LocalToPhysAddr(params[3], &vec);
   463 
   464 	v->x = sp_ctof(vec[0]);
   465 	v->y = sp_ctof(vec[1]);
   466 	v->z = sp_ctof(vec[2]);
   467 
   468 	if (params[4])
   469 	{
   470 		g_HL2.SetEdictStateChanged(pEdict, offset);
   471 	}
   472 
   473 	return 1;
   474 }
   475 
   476 /* THIS GUY IS DEPRECATED. */
   477 static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
   478 {
   479 	CBaseEntity *pEntity;
   480 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   481 
   482 	if (!pEdict || !pEntity)
   483 	{
   484 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   485 	}
   486 
   487 	int offset = params[2];
   488 	if (offset <= 0 || offset > 32768)
   489 	{
   490 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   491 	}
   492 
   493 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   494 
   495 	if (!hndl.IsValid())
   496 	{
   497 		return 0;
   498 	}
   499 
   500 	return hndl.GetEntryIndex();
   501 }
   502 
   503 int CheckBaseHandle(CBaseHandle &hndl)
   504 {
   505 	if (!hndl.IsValid())
   506 	{
   507 		return -1;
   508 	}
   509 
   510 	int index = hndl.GetEntryIndex();
   511 
   512 	edict_t *pStoredEdict;
   513 	CBaseEntity *pStoredEntity;
   514 
   515 	pStoredEdict = GetEntity(index, &pStoredEntity);
   516 
   517 	if (pStoredEdict == NULL || pStoredEntity == NULL)
   518 	{
   519 		return -1;
   520 	}
   521 
   522 	IServerEntity *pSE = pStoredEdict->GetIServerEntity();
   523 
   524 	if (pSE == NULL)
   525 	{
   526 		return -1;
   527 	}
   528 
   529 	if (pSE->GetRefEHandle() != hndl)
   530 	{
   531 		return -1;
   532 	}
   533 
   534 	return index;
   535 }
   536 
   537 static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
   538 {
   539 	CBaseEntity *pEntity;
   540 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   541 
   542 	if (pEdict == NULL || pEntity == NULL)
   543 	{
   544 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   545 	}
   546 
   547 	int offset = params[2];
   548 	if (offset <= 0 || offset > 32768)
   549 	{
   550 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   551 	}
   552 
   553 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   554 
   555 	return CheckBaseHandle(hndl);
   556 }
   557 
   558 /* THIS GUY IS DEPRECATED. */
   559 static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
   560 {
   561 	CBaseEntity *pEntity;
   562 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   563 
   564 	if (!pEdict || !pEntity)
   565 	{
   566 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   567 	}
   568 
   569 	int offset = params[2];
   570 	if (offset <= 0 || offset > 32768)
   571 	{
   572 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   573 	}
   574 
   575 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   576 
   577 	if (params[3] == 0)
   578 	{
   579 		hndl.Set(NULL);
   580 	} else {
   581 		edict_t *pEdict = GetEdict(params[3]);
   582 		if (!pEdict)
   583 		{
   584 			return pContext->ThrowNativeError("Entity %d is invalid", params[3]);
   585 		}
   586 		IServerEntity *pEntOther = pEdict->GetIServerEntity();
   587 		hndl.Set(pEntOther);
   588 	}
   589 
   590 	if (params[4])
   591 	{
   592 		g_HL2.SetEdictStateChanged(pEdict, offset);
   593 	}
   594 
   595 	return 1;
   596 }
   597 
   598 static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
   599 {
   600 	CBaseEntity *pEntity;
   601 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   602 
   603 	if (!pEdict || !pEntity)
   604 	{
   605 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   606 	}
   607 
   608 	int offset = params[2];
   609 	if (offset <= 0 || offset > 32768)
   610 	{
   611 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   612 	}
   613 
   614 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   615 
   616 	if (params[3] == -1)
   617 	{
   618 		hndl.Set(NULL);
   619 	}
   620 	else
   621 	{
   622 		edict_t *pEdict = GetEdict(params[3]);
   623 		if (!pEdict)
   624 		{
   625 			return pContext->ThrowNativeError("Entity %d is invalid", params[3]);
   626 		}
   627 		IServerEntity *pEntOther = pEdict->GetIServerEntity();
   628 		hndl.Set(pEntOther);
   629 	}
   630 
   631 	if (params[4])
   632 	{
   633 		g_HL2.SetEdictStateChanged(pEdict, offset);
   634 	}
   635 
   636 	return 1;
   637 }
   638 
   639 static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
   640 {
   641 	edict_t *pEdict = GetEdict(params[1]);
   642 
   643 	if (!pEdict)
   644 	{
   645 		return pContext->ThrowNativeError("Edict %d is invalid", params[1]);
   646 	}
   647 
   648 	g_HL2.SetEdictStateChanged(pEdict, params[2]);
   649 
   650 	return 1;
   651 }
   652 
   653 static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
   654 {
   655 	char *cls, *prop;
   656 	pContext->LocalToString(params[1], &cls);
   657 	pContext->LocalToString(params[2], &prop);
   658 
   659 	SendProp *pSend = g_HL2.FindInSendTable(cls, prop);
   660 
   661 	if (!pSend)
   662 	{
   663 		return -1;
   664 	}
   665 
   666 	return pSend->GetOffset();
   667 }
   668 
   669 static cell_t FindSendPropInfo(IPluginContext *pContext, const cell_t *params)
   670 {
   671 	char *cls, *prop;
   672 	sm_sendprop_info_t info;
   673 	cell_t *pType, *pBits, *pLocal;
   674 
   675 	pContext->LocalToString(params[1], &cls);
   676 	pContext->LocalToString(params[2], &prop);
   677 
   678 	if (!g_HL2.FindSendPropInfo(cls, prop, &info))
   679 	{
   680 		return -1;
   681 	}
   682 
   683 	pContext->LocalToPhysAddr(params[3], &pType);
   684 	pContext->LocalToPhysAddr(params[4], &pBits);
   685 	pContext->LocalToPhysAddr(params[5], &pLocal);
   686 
   687 	switch (info.prop->GetType())
   688 	{
   689 	case DPT_Int:
   690 		{
   691 			*pType = PropField_Integer;
   692 			break;
   693 		}
   694 	case DPT_Float:
   695 		{
   696 			*pType = PropField_Float;
   697 			break;
   698 		}
   699 	case DPT_String:
   700 		{
   701 			*pType = PropField_String;
   702 			break;
   703 		}
   704 	case DPT_Vector:
   705 		{
   706 			*pType = PropField_Vector;
   707 			break;
   708 		}
   709 	default:
   710 		{
   711 			*pType = PropField_Unsupported;
   712 			break;
   713 		}
   714 	}
   715 
   716 	*pBits = info.prop->m_nBits;
   717 	*pLocal = info.prop->GetOffset();
   718 
   719 	return info.actual_offset;
   720 }
   721 
   722 static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
   723 {
   724 	CBaseEntity *pEntity;
   725 	datamap_t *pMap;
   726 	typedescription_t *td;
   727 	char *offset;
   728 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   729 
   730 	if (!pEdict || !pEntity)
   731 	{
   732 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   733 	}
   734 
   735 	if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
   736 	{
   737 		return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
   738 	}
   739 
   740 	pContext->LocalToString(params[2], &offset);
   741 	if ((td=g_HL2.FindInDataMap(pMap, offset)) == NULL)
   742 	{
   743 		return -1;
   744 	}
   745 
   746 	if (params[0] == 4)
   747 	{
   748 		cell_t *pType, *pSize;
   749 
   750 		pContext->LocalToPhysAddr(params[3], &pType);
   751 		pContext->LocalToPhysAddr(params[4], &pSize);
   752 
   753 		switch (td->fieldType)
   754 		{
   755 		case FIELD_TICK:
   756 		case FIELD_MODELINDEX:
   757 		case FIELD_MATERIALINDEX:
   758 		case FIELD_INTEGER:
   759 		case FIELD_COLOR32:
   760 			{
   761 				*pType = PropField_Integer;
   762 				*pSize = 32;
   763 				break;
   764 			}
   765 		case FIELD_VECTOR:
   766 		case FIELD_POSITION_VECTOR:
   767 			{
   768 				*pType = PropField_Vector;
   769 				*pSize = 12;
   770 				break;
   771 			}
   772 		case FIELD_SHORT:
   773 			{
   774 				*pType = PropField_Integer;
   775 				*pSize = 16;
   776 				break;
   777 			}
   778 		case FIELD_BOOLEAN:
   779 			{
   780 				*pType = PropField_Integer;
   781 				*pSize = 1;
   782 				break;
   783 			}
   784 		case FIELD_CHARACTER:
   785 			{
   786 				if (td->fieldSize == 1)
   787 				{
   788 					*pType = PropField_Integer;
   789 					*pSize = 8;
   790 				}
   791 				else
   792 				{
   793 					*pType = PropField_String;
   794 					*pSize = 8 * td->fieldSize;
   795 				}
   796 				break;
   797 			}
   798 		case FIELD_FLOAT:
   799 		case FIELD_TIME:
   800 			{
   801 				*pType = PropField_Float;
   802 				*pSize = 32;
   803 				break;
   804 			}
   805 		case FIELD_EHANDLE:
   806 			{
   807 				*pType = PropField_Entity;
   808 				*pSize = 32;
   809 				break;
   810 			}
   811 		default:
   812 			{
   813 				*pType = PropField_Unsupported;
   814 				*pSize = 0;
   815 			}
   816 		}
   817 	}
   818 
   819 	return td->fieldOffset[TD_OFFSET_NORMAL];
   820 }
   821 
   822 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
   823 {
   824 	CBaseEntity *pEntity;
   825 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   826 
   827 	if (!pEdict || !pEntity)
   828 	{
   829 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   830 	}
   831 
   832 	int offset = params[2];
   833 	if (offset < 0 || offset > 32768)
   834 	{
   835 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   836 	}
   837 
   838 	size_t len;
   839 	char *src = (char *)((uint8_t *)pEntity + offset);
   840 	pContext->StringToLocalUTF8(params[3], params[4], src, &len);
   841 
   842 	return len;
   843 }
   844 
   845 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
   846 {
   847 	CBaseEntity *pEntity;
   848 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   849 
   850 	if (!pEdict || !pEntity)
   851 	{
   852 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   853 	}
   854 
   855 	int offset = params[2];
   856 	if (offset < 0 || offset > 32768)
   857 	{
   858 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   859 	}
   860 
   861 	char *src;
   862 	char *dest = (char *)((uint8_t *)pEntity + offset);
   863 
   864 	pContext->LocalToString(params[3], &src);
   865 	size_t len = strncopy(dest, src, params[4]);
   866 
   867 	if (params[5])
   868 	{
   869 		g_HL2.SetEdictStateChanged(pEdict, offset);
   870 	}
   871 
   872 	return len;
   873 }
   874 
   875 #define FIND_PROP_DATA(td) \
   876 	datamap_t *pMap; \
   877 	if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL) \
   878 	{ \
   879 		return pContext->ThrowNativeError("Could not retrieve datamap"); \
   880 	} \
   881 	if ((td = g_HL2.FindInDataMap(pMap, prop)) == NULL) \
   882 	{ \
   883 		return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
   884 			prop, \
   885 			params[1], \
   886 			class_name); \
   887 	}
   888 
   889 #define FIND_PROP_SEND(pProp) \
   890 	IServerNetworkable *pNet = pEdict->GetNetworkable(); \
   891 	if (!pNet) \
   892 	{ \
   893 		return pContext->ThrowNativeError("Edict %d is not networkable", params[1]); \
   894 	} \
   895 	if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, pProp)) \
   896 	{ \
   897 		return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
   898 			prop, \
   899 			params[1], \
   900 			class_name); \
   901 	}
   902 
   903 inline int MatchFieldAsInteger(int field_type)
   904 {
   905 	switch (field_type)
   906 	{
   907 	case FIELD_TICK:
   908 	case FIELD_MODELINDEX:
   909 	case FIELD_MATERIALINDEX:
   910 	case FIELD_INTEGER:
   911 	case FIELD_COLOR32:
   912 		return 32;
   913 	case FIELD_SHORT:
   914 		return 16;
   915 	case FIELD_CHARACTER:
   916 		return 8;
   917 	case FIELD_BOOLEAN:
   918 		return 1;
   919 	default:
   920 		return 0;
   921 	}
   922 
   923 	return 0;
   924 }
   925 
   926 static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
   927 {
   928 	CBaseEntity *pEntity;
   929 	char *prop;
   930 	int offset;
   931 	const char *class_name;
   932 	edict_t *pEdict;
   933 	int bit_count;
   934 
   935 	pEdict = GetEntity(params[1], &pEntity);
   936 
   937 	if (!pEdict || !pEntity)
   938 	{
   939 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   940 	}
   941 
   942 	if ((class_name = pEdict->GetClassName()) == NULL)
   943 	{
   944 		class_name = "";
   945 	}
   946 
   947 	pContext->LocalToString(params[3], &prop);
   948 
   949 	switch (params[2])
   950 	{
   951 	case Prop_Data:
   952 		{
   953 			typedescription_t *td;
   954 
   955 			FIND_PROP_DATA(td);
   956 
   957 			if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
   958 			{
   959 				return pContext->ThrowNativeError("Data field %s is not an integer (%d)", 
   960 					prop,
   961 					td->fieldType);
   962 			}
   963 
   964 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
   965 			break;
   966 		}
   967 	case Prop_Send:
   968 		{
   969 			sm_sendprop_info_t info;
   970 
   971 			FIND_PROP_SEND(&info);
   972 
   973 			if (info.prop->GetType() != DPT_Int)
   974 			{
   975 				return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
   976 					prop,
   977 					info.prop->GetType(),
   978 					info.prop->m_nBits,
   979 					DPT_Int);
   980 			}
   981 
   982 			bit_count = info.prop->m_nBits;
   983 			offset = info.actual_offset;
   984 			break;
   985 		}
   986 	default:
   987 		{
   988 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
   989 		}
   990 	}
   991 
   992 	if (bit_count < 1)
   993 	{
   994 		bit_count = params[4] * 8;
   995 	}
   996 
   997 	if (bit_count >= 17)
   998 	{
   999 		return *(int32_t *)((uint8_t *)pEntity + offset);
  1000 	}
  1001 	else if (bit_count >= 9)
  1002 	{
  1003 		return *(int16_t *)((uint8_t *)pEntity + offset);
  1004 	}
  1005 	else if (bit_count >= 2)
  1006 	{
  1007 		return *(int8_t *)((uint8_t *)pEntity + offset);
  1008 	}
  1009 	else
  1010 	{
  1011 		return *(bool *)((uint8_t *)pEntity + offset) ? 1 : 0;
  1012 	}
  1013 
  1014 	return 0;
  1015 }
  1016 
  1017 static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
  1018 {
  1019 	CBaseEntity *pEntity;
  1020 	char *prop;
  1021 	int offset;
  1022 	const char *class_name;
  1023 	edict_t *pEdict;
  1024 	int bit_count;
  1025 
  1026 	pEdict = GetEntity(params[1], &pEntity);
  1027 
  1028 	if (!pEdict || !pEntity)
  1029 	{
  1030 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1031 	}
  1032 
  1033 	if ((class_name = pEdict->GetClassName()) == NULL)
  1034 	{
  1035 		class_name = "";
  1036 	}
  1037 
  1038 	pContext->LocalToString(params[3], &prop);
  1039 
  1040 	switch (params[2])
  1041 	{
  1042 	case Prop_Data:
  1043 		{
  1044 			typedescription_t *td;
  1045 
  1046 			FIND_PROP_DATA(td);
  1047 
  1048 			if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
  1049 			{
  1050 				return pContext->ThrowNativeError("Data field %s is not an integer (%d)", 
  1051 					prop,
  1052 					td->fieldType);
  1053 			}
  1054 
  1055 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1056 			break;
  1057 		}
  1058 	case Prop_Send:
  1059 		{
  1060 			sm_sendprop_info_t info;
  1061 
  1062 			FIND_PROP_SEND(&info);
  1063 
  1064 			if (info.prop->GetType() != DPT_Int)
  1065 			{
  1066 				return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
  1067 					prop,
  1068 					info.prop->GetType(),
  1069 					info.prop->m_nBits,
  1070 					DPT_Int);
  1071 			}
  1072 
  1073 			bit_count = info.prop->m_nBits;
  1074 			offset = info.actual_offset;
  1075 			break;
  1076 		}
  1077 	default:
  1078 		{
  1079 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1080 		}
  1081 	}
  1082 
  1083 	if (bit_count < 1)
  1084 	{
  1085 		bit_count = params[5] * 8;
  1086 	}
  1087 
  1088 	if (bit_count >= 17)
  1089 	{
  1090 		*(int32_t *)((uint8_t *)pEntity + offset) = params[4];
  1091 	}
  1092 	else if (bit_count >= 9)
  1093 	{
  1094 		*(int16_t *)((uint8_t *)pEntity + offset) = (int16_t)params[4];
  1095 	}
  1096 	else if (bit_count >= 2)
  1097 	{
  1098 		*(int8_t *)((uint8_t *)pEntity + offset) = (int8_t)params[4];
  1099 	}
  1100 	else
  1101 	{
  1102 		*(bool *)((uint8_t *)pEntity + offset) = params[4] ? true : false;
  1103 	}
  1104 
  1105 	return 0;
  1106 }
  1107 
  1108 static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params)
  1109 {
  1110 	CBaseEntity *pEntity;
  1111 	char *prop;
  1112 	int offset;
  1113 	const char *class_name;
  1114 	edict_t *pEdict;
  1115 
  1116 	pEdict = GetEntity(params[1], &pEntity);
  1117 
  1118 	if (!pEdict || !pEntity)
  1119 	{
  1120 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1121 	}
  1122 
  1123 	if ((class_name = pEdict->GetClassName()) == NULL)
  1124 	{
  1125 		class_name = "";
  1126 	}
  1127 
  1128 	pContext->LocalToString(params[3], &prop);
  1129 
  1130 	switch (params[2])
  1131 	{
  1132 	case Prop_Data:
  1133 		{
  1134 			typedescription_t *td;
  1135 
  1136 			FIND_PROP_DATA(td);
  1137 
  1138 			if (td->fieldType != FIELD_FLOAT
  1139 				&& td->fieldType != FIELD_TIME)
  1140 			{
  1141 				return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])", 
  1142 					prop,
  1143 					td->fieldType,
  1144 					FIELD_FLOAT,
  1145 					FIELD_TIME);
  1146 			}
  1147 
  1148 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1149 			break;
  1150 		}
  1151 	case Prop_Send:
  1152 		{
  1153 			sm_sendprop_info_t info;
  1154 
  1155 			FIND_PROP_SEND(&info);
  1156 
  1157 			if (info.prop->GetType() != DPT_Float)
  1158 			{
  1159 				return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
  1160 					prop,
  1161 					info.prop->GetType(),
  1162 					DPT_Float);
  1163 			}
  1164 
  1165 			offset = info.actual_offset;
  1166 			break;
  1167 		}
  1168 	default:
  1169 		{
  1170 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1171 		}
  1172 	}
  1173 
  1174 	float val = *(float *)((uint8_t *)pEntity + offset);
  1175 
  1176 	return sp_ftoc(val);
  1177 }
  1178 
  1179 static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params)
  1180 {
  1181 	CBaseEntity *pEntity;
  1182 	char *prop;
  1183 	int offset;
  1184 	const char *class_name;
  1185 	edict_t *pEdict;
  1186 
  1187 	pEdict = GetEntity(params[1], &pEntity);
  1188 
  1189 	if (!pEdict || !pEntity)
  1190 	{
  1191 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1192 	}
  1193 
  1194 	if ((class_name = pEdict->GetClassName()) == NULL)
  1195 	{
  1196 		class_name = "";
  1197 	}
  1198 
  1199 	pContext->LocalToString(params[3], &prop);
  1200 
  1201 	switch (params[2])
  1202 	{
  1203 	case Prop_Data:
  1204 		{
  1205 			typedescription_t *td;
  1206 
  1207 			FIND_PROP_DATA(td);
  1208 
  1209 			if (td->fieldType != FIELD_FLOAT
  1210 				&& td->fieldType != FIELD_TIME)
  1211 			{
  1212 				return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])", 
  1213 					prop,
  1214 					td->fieldType,
  1215 					FIELD_FLOAT,
  1216 					FIELD_TIME);
  1217 			}
  1218 
  1219 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1220 			break;
  1221 		}
  1222 	case Prop_Send:
  1223 		{
  1224 			sm_sendprop_info_t info;
  1225 
  1226 			FIND_PROP_SEND(&info);
  1227 
  1228 			if (info.prop->GetType() != DPT_Float)
  1229 			{
  1230 				return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
  1231 					prop,
  1232 					info.prop->GetType(),
  1233 					DPT_Float);
  1234 			}
  1235 
  1236 			offset = info.actual_offset;
  1237 			break;
  1238 		}
  1239 	default:
  1240 		{
  1241 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1242 		}
  1243 	}
  1244 
  1245 	*(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[4]);
  1246 
  1247 	if (params[2] == Prop_Send)
  1248 	{
  1249 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1250 	}
  1251 
  1252 	return 1;
  1253 }
  1254 
  1255 static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params)
  1256 {
  1257 	CBaseEntity *pEntity;
  1258 	char *prop;
  1259 	int offset;
  1260 	const char *class_name;
  1261 	edict_t *pEdict;
  1262 
  1263 	pEdict = GetEntity(params[1], &pEntity);
  1264 
  1265 	if (!pEdict || !pEntity)
  1266 	{
  1267 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1268 	}
  1269 
  1270 	if ((class_name = pEdict->GetClassName()) == NULL)
  1271 	{
  1272 		class_name = "";
  1273 	}
  1274 
  1275 	pContext->LocalToString(params[3], &prop);
  1276 
  1277 	switch (params[2])
  1278 	{
  1279 	case Prop_Data:
  1280 		{
  1281 			typedescription_t *td;
  1282 
  1283 			FIND_PROP_DATA(td);
  1284 
  1285 			if (td->fieldType != FIELD_EHANDLE)
  1286 			{
  1287 				return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)", 
  1288 					prop,
  1289 					td->fieldType,
  1290 					FIELD_EHANDLE);
  1291 			}
  1292 
  1293 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1294 			break;
  1295 		}
  1296 	case Prop_Send:
  1297 		{
  1298 			sm_sendprop_info_t info;
  1299 
  1300 			FIND_PROP_SEND(&info);
  1301 
  1302 			if (info.prop->GetType() != DPT_Int)
  1303 			{
  1304 				return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
  1305 					prop,
  1306 					info.prop->GetType(),
  1307 					DPT_Int);
  1308 			}
  1309 
  1310 			offset = info.actual_offset;
  1311 			break;
  1312 		}
  1313 	default:
  1314 		{
  1315 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1316 		}
  1317 	}
  1318 
  1319 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
  1320 
  1321 	return CheckBaseHandle(hndl);
  1322 }
  1323 
  1324 static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
  1325 {
  1326 	CBaseEntity *pEntity;
  1327 	char *prop;
  1328 	int offset;
  1329 	const char *class_name;
  1330 	edict_t *pEdict;
  1331 
  1332 	pEdict = GetEntity(params[1], &pEntity);
  1333 
  1334 	if (!pEdict || !pEntity)
  1335 	{
  1336 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1337 	}
  1338 
  1339 	if ((class_name = pEdict->GetClassName()) == NULL)
  1340 	{
  1341 		class_name = "";
  1342 	}
  1343 
  1344 	pContext->LocalToString(params[3], &prop);
  1345 
  1346 	switch (params[2])
  1347 	{
  1348 	case Prop_Data:
  1349 		{
  1350 			typedescription_t *td;
  1351 
  1352 			FIND_PROP_DATA(td);
  1353 
  1354 			if (td->fieldType != FIELD_EHANDLE)
  1355 			{
  1356 				return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)", 
  1357 					prop,
  1358 					td->fieldType,
  1359 					FIELD_EHANDLE);
  1360 			}
  1361 
  1362 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1363 			break;
  1364 		}
  1365 	case Prop_Send:
  1366 		{
  1367 			sm_sendprop_info_t info;
  1368 
  1369 			FIND_PROP_SEND(&info);
  1370 
  1371 			if (info.prop->GetType() != DPT_Int)
  1372 			{
  1373 				return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
  1374 					prop,
  1375 					info.prop->GetType(),
  1376 					DPT_Int);
  1377 			}
  1378 
  1379 			offset = info.actual_offset;
  1380 			break;
  1381 		}
  1382 	default:
  1383 		{
  1384 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1385 		}
  1386 	}
  1387 
  1388 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
  1389 
  1390 	if (params[4] == -1)
  1391 	{
  1392 		hndl.Set(NULL);
  1393 	}
  1394 	else
  1395 	{
  1396 		edict_t *pOther;
  1397 		CBaseEntity *pOtherEnt;
  1398 
  1399 		if ((pOther = GetEntity(params[4], &pOtherEnt)) == NULL)
  1400 		{
  1401 			return pContext->ThrowNativeError("Invalid entity %d", params[4]);
  1402 		}
  1403 
  1404 		hndl.Set(pOther->GetIServerEntity());
  1405 	}
  1406 
  1407 	if (params[2] == Prop_Send)
  1408 	{
  1409 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1410 	}
  1411 
  1412 	return 1;
  1413 }
  1414 
  1415 static cell_t GetEntPropVector(IPluginContext *pContext, const cell_t *params)
  1416 {
  1417 	CBaseEntity *pEntity;
  1418 	char *prop;
  1419 	int offset;
  1420 	const char *class_name;
  1421 	edict_t *pEdict;
  1422 	
  1423 	pEdict = GetEntity(params[1], &pEntity);
  1424 
  1425 	if (!pEdict || !pEntity)
  1426 	{
  1427 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1428 	}
  1429 
  1430 	if ((class_name = pEdict->GetClassName()) == NULL)
  1431 	{
  1432 		class_name = "";
  1433 	}
  1434 
  1435 	pContext->LocalToString(params[3], &prop);
  1436 
  1437 	switch (params[2])
  1438 	{
  1439 	case Prop_Data:
  1440 		{
  1441 			typedescription_t *td;
  1442 			
  1443 			FIND_PROP_DATA(td);
  1444 
  1445 			if (td->fieldType != FIELD_VECTOR
  1446 				&& td->fieldType != FIELD_POSITION_VECTOR)
  1447 			{
  1448 				return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])", 
  1449 					prop,
  1450 					td->fieldType,
  1451 					FIELD_VECTOR,
  1452 					FIELD_POSITION_VECTOR);
  1453 			}
  1454 
  1455 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1456 			break;
  1457 		}
  1458 	case Prop_Send:
  1459 		{
  1460 			sm_sendprop_info_t info;
  1461 
  1462 			FIND_PROP_SEND(&info);
  1463 
  1464 			if (info.prop->GetType() != DPT_Vector)
  1465 			{
  1466 				return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
  1467 					prop,
  1468 					info.prop->GetType(),
  1469 					DPT_Vector);
  1470 			}
  1471 
  1472 			offset = info.actual_offset;
  1473 			break;
  1474 		}
  1475 	default:
  1476 		{
  1477 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1478 		}
  1479 	}
  1480 
  1481 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
  1482 
  1483 	cell_t *vec;
  1484 	pContext->LocalToPhysAddr(params[4], &vec);
  1485 
  1486 	vec[0] = sp_ftoc(v->x);
  1487 	vec[1] = sp_ftoc(v->y);
  1488 	vec[2] = sp_ftoc(v->z);
  1489 
  1490 	return 1;
  1491 }
  1492 
  1493 static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params)
  1494 {
  1495 	CBaseEntity *pEntity;
  1496 	char *prop;
  1497 	int offset;
  1498 	const char *class_name;
  1499 	edict_t *pEdict;
  1500 	
  1501 	pEdict = GetEntity(params[1], &pEntity);
  1502 
  1503 	if (!pEdict || !pEntity)
  1504 	{
  1505 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1506 	}
  1507 
  1508 	if ((class_name = pEdict->GetClassName()) == NULL)
  1509 	{
  1510 		class_name = "";
  1511 	}
  1512 
  1513 	pContext->LocalToString(params[3], &prop);
  1514 
  1515 	switch (params[2])
  1516 	{
  1517 	case Prop_Data:
  1518 		{
  1519 			typedescription_t *td;
  1520 			
  1521 			FIND_PROP_DATA(td);
  1522 
  1523 			if (td->fieldType != FIELD_VECTOR
  1524 				&& td->fieldType != FIELD_POSITION_VECTOR)
  1525 			{
  1526 				return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])", 
  1527 					prop,
  1528 					td->fieldType,
  1529 					FIELD_VECTOR,
  1530 					FIELD_POSITION_VECTOR);
  1531 			}
  1532 
  1533 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1534 			break;
  1535 		}
  1536 	case Prop_Send:
  1537 		{
  1538 			sm_sendprop_info_t info;
  1539 
  1540 			FIND_PROP_SEND(&info);
  1541 
  1542 			if (info.prop->GetType() != DPT_Vector)
  1543 			{
  1544 				return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
  1545 					prop,
  1546 					info.prop->GetType(),
  1547 					DPT_Vector);
  1548 			}
  1549 
  1550 			offset = info.actual_offset;
  1551 			break;
  1552 		}
  1553 	default:
  1554 		{
  1555 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1556 		}
  1557 	}
  1558 
  1559 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
  1560 
  1561 	cell_t *vec;
  1562 	pContext->LocalToPhysAddr(params[4], &vec);
  1563 
  1564 	v->x = sp_ctof(vec[0]);
  1565 	v->y = sp_ctof(vec[1]);
  1566 	v->z = sp_ctof(vec[2]);
  1567 
  1568 	if (params[2] == Prop_Send)
  1569 	{
  1570 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1571 	}
  1572 
  1573 	return 1;
  1574 }
  1575 
  1576 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
  1577 {
  1578 	CBaseEntity *pEntity;
  1579 	char *prop;
  1580 	int offset;
  1581 	const char *class_name;
  1582 	edict_t *pEdict;
  1583 	
  1584 	pEdict = GetEntity(params[1], &pEntity);
  1585 
  1586 	if (!pEdict || !pEntity)
  1587 	{
  1588 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1589 	}
  1590 
  1591 	if ((class_name = pEdict->GetClassName()) == NULL)
  1592 	{
  1593 		class_name = "";
  1594 	}
  1595 
  1596 	pContext->LocalToString(params[3], &prop);
  1597 
  1598 	switch (params[2])
  1599 	{
  1600 	case Prop_Data:
  1601 		{
  1602 			typedescription_t *td;
  1603 			
  1604 			FIND_PROP_DATA(td);
  1605 
  1606 			if (td->fieldType != FIELD_CHARACTER)
  1607 			{
  1608 				return pContext->ThrowNativeError("Data field %s is not a string (%d != %d)", 
  1609 					prop,
  1610 					td->fieldType,
  1611 					FIELD_CHARACTER);
  1612 			}
  1613 
  1614 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1615 			break;
  1616 		}
  1617 	case Prop_Send:
  1618 		{
  1619 			sm_sendprop_info_t info;
  1620 
  1621 			FIND_PROP_SEND(&info);
  1622 
  1623 			if (info.prop->GetType() != DPT_String)
  1624 			{
  1625 				return pContext->ThrowNativeError("SendProp %s is not a string (%d != %d)",
  1626 					prop,
  1627 					info.prop->GetType(),
  1628 					DPT_String);
  1629 			}
  1630 
  1631 			offset = info.actual_offset;
  1632 			break;
  1633 			break;
  1634 		}
  1635 	default:
  1636 		{
  1637 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1638 		}
  1639 	}
  1640 
  1641 	size_t len;
  1642 	char *src = (char *)((uint8_t *)pEntity + offset);
  1643 	pContext->StringToLocalUTF8(params[4], params[5], src, &len);
  1644 
  1645 	return len;
  1646 }
  1647 
  1648 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
  1649 {
  1650 	CBaseEntity *pEntity;
  1651 	char *prop;
  1652 	int offset;
  1653 	int maxlen;
  1654 	edict_t *pEdict = GetEntity(params[1], &pEntity);
  1655 
  1656 	if (!pEdict || !pEntity)
  1657 	{
  1658 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1659 	}
  1660 
  1661 	switch (params[2])
  1662 	{
  1663 	case Prop_Data:
  1664 		{
  1665 			datamap_t *pMap;
  1666 			typedescription_t *td;
  1667 			if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
  1668 			{
  1669 				return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
  1670 			}
  1671 			pContext->LocalToString(params[3], &prop);
  1672 			if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
  1673 			{
  1674 				return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
  1675 			}
  1676 			if (td->fieldType != FIELD_CHARACTER)
  1677 			{
  1678 				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
  1679 			}
  1680 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1681 			maxlen = td->fieldSize;
  1682 			break;
  1683 		}
  1684 	case Prop_Send:
  1685 		{
  1686 			char *prop;
  1687 			IServerNetworkable *pNet = pEdict->GetNetworkable();
  1688 			if (!pNet)
  1689 			{
  1690 				return pContext->ThrowNativeError("The edict is not networkable");
  1691 			}
  1692 			pContext->LocalToString(params[3], &prop);
  1693 			SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
  1694 			if (!pSend)
  1695 			{
  1696 				return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
  1697 			}
  1698 			if (pSend->GetType() != DPT_String)
  1699 			{
  1700 				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
  1701 			}
  1702 			offset = pSend->GetOffset();
  1703 			maxlen = DT_MAX_STRING_BUFFERSIZE;
  1704 			break;
  1705 		}
  1706 	default:
  1707 		{
  1708 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1709 		}
  1710 	}
  1711 
  1712 	char *src;
  1713 	char *dest = (char *)((uint8_t *)pEntity + offset);
  1714 
  1715 	pContext->LocalToString(params[4], &src);
  1716 	size_t len = strncopy(dest, src, maxlen);
  1717 
  1718 	if (params[2] == Prop_Send)
  1719 	{
  1720 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1721 	}
  1722 
  1723 	return len;
  1724 }
  1725 
  1726 REGISTER_NATIVES(entityNatives)
  1727 {
  1728 	{"ChangeEdictState",		ChangeEdictState},
  1729 	{"CreateEdict",				CreateEdict},
  1730 	{"FindDataMapOffs",			FindDataMapOffs},
  1731 	{"FindSendPropInfo",		FindSendPropInfo},
  1732 	{"FindSendPropOffs",		FindSendPropOffs},
  1733 	{"GetEdictClassname",		GetEdictClassname},
  1734 	{"GetEdictFlags",			GetEdictFlags},
  1735 	{"GetEntData",				GetEntData},
  1736 	{"GetEntDataEnt",			GetEntDataEnt},		/** DEPRECATED */
  1737 	{"GetEntDataEnt2",			GetEntDataEnt2},
  1738 	{"GetEntDataFloat",			GetEntDataFloat},
  1739 	{"GetEntDataString",		GetEntDataString},
  1740 	{"GetEntDataVector",		GetEntDataVector},
  1741 	{"GetEntProp",				GetEntProp},
  1742 	{"GetEntPropEnt",			GetEntPropEnt},
  1743 	{"GetEntPropFloat",			GetEntPropFloat},
  1744 	{"GetEntPropString",		GetEntPropString},
  1745 	{"GetEntPropVector",		GetEntPropVector},
  1746 	{"GetEntityCount",			GetEntityCount},
  1747 	{"GetEntityNetClass",		GetEntityNetClass},
  1748 	{"GetMaxEntities",			GetMaxEntities},
  1749 	{"IsEntNetworkable",		IsEntNetworkable},
  1750 	{"IsValidEdict",			IsValidEdict},
  1751 	{"IsValidEntity",			IsValidEntity},
  1752 	{"RemoveEdict",				RemoveEdict},
  1753 	{"SetEdictFlags",			SetEdictFlags},
  1754 	{"SetEntData",				SetEntData},
  1755 	{"SetEntDataEnt",			SetEntDataEnt},		/** DEPRECATED */
  1756 	{"SetEntDataEnt2",			SetEntDataEnt2},
  1757 	{"SetEntDataFloat",			SetEntDataFloat},
  1758 	{"SetEntDataVector",		SetEntDataVector},
  1759 	{"SetEntDataString",		SetEntDataString},
  1760 	{"SetEntProp",				SetEntProp},
  1761 	{"SetEntPropEnt",			SetEntPropEnt},
  1762 	{"SetEntPropFloat",			SetEntPropFloat},
  1763 	{"SetEntPropString",		SetEntPropString},
  1764 	{"SetEntPropVector",		SetEntPropVector},
  1765 	{NULL,						NULL}
  1766 };