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