core/smn_entities.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Aug 24 04:35:48 2008 +0000 (2008-08-24)
changeset 2237 4403a982ec91
parent 2051 568678a2e847
child 2289 44045ead61cd
permissions -rw-r--r--
Improved bot detection slightly. This was meant to go along with the fix for amb1801.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "sm_globals.h"
    33 #include "sourcemod.h"
    34 #include "sourcemm_api.h"
    35 #include "PlayerManager.h"
    36 #include "HalfLife2.h"
    37 #include "GameConfigs.h"
    38 #include "sm_stringutil.h"
    39 
    40 enum PropType
    41 {
    42 	Prop_Send = 0,
    43 	Prop_Data
    44 };
    45 
    46 enum PropFieldType
    47 {
    48 	PropField_Unsupported,		/**< The type is unsupported. */
    49 	PropField_Integer,			/**< Valid for SendProp and Data fields */
    50 	PropField_Float,			/**< Valid for SendProp and Data fields */
    51 	PropField_Entity,			/**< Valid for Data fields only (SendProp shows as int) */
    52 	PropField_Vector,			/**< Valid for SendProp and Data fields */
    53 	PropField_String,			/**< Valid for SendProp and Data fields */
    54 	PropField_String_T,			/**< Valid for Data fields.  Read only! */
    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_MODELNAME:
   799 		case FIELD_SOUNDNAME:
   800 		case FIELD_STRING:
   801 			{
   802 				*pSize = sizeof(string_t);
   803 				*pType = PropField_String_T;
   804 				break;
   805 			}
   806 		case FIELD_FLOAT:
   807 		case FIELD_TIME:
   808 			{
   809 				*pType = PropField_Float;
   810 				*pSize = 32;
   811 				break;
   812 			}
   813 		case FIELD_EHANDLE:
   814 			{
   815 				*pType = PropField_Entity;
   816 				*pSize = 32;
   817 				break;
   818 			}
   819 		default:
   820 			{
   821 				*pType = PropField_Unsupported;
   822 				*pSize = 0;
   823 			}
   824 		}
   825 	}
   826 
   827 	return td->fieldOffset[TD_OFFSET_NORMAL];
   828 }
   829 
   830 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
   831 {
   832 	CBaseEntity *pEntity;
   833 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   834 
   835 	if (!pEdict || !pEntity)
   836 	{
   837 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   838 	}
   839 
   840 	int offset = params[2];
   841 	if (offset < 0 || offset > 32768)
   842 	{
   843 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   844 	}
   845 
   846 	size_t len;
   847 	char *src = (char *)((uint8_t *)pEntity + offset);
   848 	pContext->StringToLocalUTF8(params[3], params[4], src, &len);
   849 
   850 	return len;
   851 }
   852 
   853 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
   854 {
   855 	CBaseEntity *pEntity;
   856 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   857 
   858 	if (!pEdict || !pEntity)
   859 	{
   860 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   861 	}
   862 
   863 	int offset = params[2];
   864 	if (offset < 0 || offset > 32768)
   865 	{
   866 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   867 	}
   868 
   869 	char *src;
   870 	char *dest = (char *)((uint8_t *)pEntity + offset);
   871 
   872 	pContext->LocalToString(params[3], &src);
   873 	size_t len = strncopy(dest, src, params[4]);
   874 
   875 	if (params[5])
   876 	{
   877 		g_HL2.SetEdictStateChanged(pEdict, offset);
   878 	}
   879 
   880 	return len;
   881 }
   882 
   883 #define FIND_PROP_DATA(td) \
   884 	datamap_t *pMap; \
   885 	if ((pMap = CBaseEntity_GetDataDescMap(pEntity)) == NULL) \
   886 	{ \
   887 		return pContext->ThrowNativeError("Could not retrieve datamap"); \
   888 	} \
   889 	if ((td = g_HL2.FindInDataMap(pMap, prop)) == NULL) \
   890 	{ \
   891 		return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
   892 			prop, \
   893 			params[1], \
   894 			class_name); \
   895 	}
   896 
   897 #define FIND_PROP_SEND(pProp) \
   898 	IServerNetworkable *pNet = pEdict->GetNetworkable(); \
   899 	if (!pNet) \
   900 	{ \
   901 		return pContext->ThrowNativeError("Edict %d is not networkable", params[1]); \
   902 	} \
   903 	if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, pProp)) \
   904 	{ \
   905 		return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
   906 			prop, \
   907 			params[1], \
   908 			class_name); \
   909 	}
   910 
   911 inline int MatchFieldAsInteger(int field_type)
   912 {
   913 	switch (field_type)
   914 	{
   915 	case FIELD_TICK:
   916 	case FIELD_MODELINDEX:
   917 	case FIELD_MATERIALINDEX:
   918 	case FIELD_INTEGER:
   919 	case FIELD_COLOR32:
   920 		return 32;
   921 	case FIELD_SHORT:
   922 		return 16;
   923 	case FIELD_CHARACTER:
   924 		return 8;
   925 	case FIELD_BOOLEAN:
   926 		return 1;
   927 	default:
   928 		return 0;
   929 	}
   930 
   931 	return 0;
   932 }
   933 
   934 static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
   935 {
   936 	CBaseEntity *pEntity;
   937 	char *prop;
   938 	int offset;
   939 	const char *class_name;
   940 	edict_t *pEdict;
   941 	int bit_count;
   942 
   943 	pEdict = GetEntity(params[1], &pEntity);
   944 
   945 	if (!pEdict || !pEntity)
   946 	{
   947 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   948 	}
   949 
   950 	if ((class_name = pEdict->GetClassName()) == NULL)
   951 	{
   952 		class_name = "";
   953 	}
   954 
   955 	pContext->LocalToString(params[3], &prop);
   956 
   957 	switch (params[2])
   958 	{
   959 	case Prop_Data:
   960 		{
   961 			typedescription_t *td;
   962 
   963 			FIND_PROP_DATA(td);
   964 
   965 			if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
   966 			{
   967 				return pContext->ThrowNativeError("Data field %s is not an integer (%d)", 
   968 					prop,
   969 					td->fieldType);
   970 			}
   971 
   972 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
   973 			break;
   974 		}
   975 	case Prop_Send:
   976 		{
   977 			sm_sendprop_info_t info;
   978 
   979 			FIND_PROP_SEND(&info);
   980 
   981 			if (info.prop->GetType() != DPT_Int)
   982 			{
   983 				return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
   984 					prop,
   985 					info.prop->GetType(),
   986 					info.prop->m_nBits,
   987 					DPT_Int);
   988 			}
   989 
   990 			bit_count = info.prop->m_nBits;
   991 			offset = info.actual_offset;
   992 			break;
   993 		}
   994 	default:
   995 		{
   996 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
   997 		}
   998 	}
   999 
  1000 	if (bit_count < 1)
  1001 	{
  1002 		bit_count = params[4] * 8;
  1003 	}
  1004 
  1005 	if (bit_count >= 17)
  1006 	{
  1007 		return *(int32_t *)((uint8_t *)pEntity + offset);
  1008 	}
  1009 	else if (bit_count >= 9)
  1010 	{
  1011 		return *(int16_t *)((uint8_t *)pEntity + offset);
  1012 	}
  1013 	else if (bit_count >= 2)
  1014 	{
  1015 		return *(int8_t *)((uint8_t *)pEntity + offset);
  1016 	}
  1017 	else
  1018 	{
  1019 		return *(bool *)((uint8_t *)pEntity + offset) ? 1 : 0;
  1020 	}
  1021 
  1022 	return 0;
  1023 }
  1024 
  1025 static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
  1026 {
  1027 	CBaseEntity *pEntity;
  1028 	char *prop;
  1029 	int offset;
  1030 	const char *class_name;
  1031 	edict_t *pEdict;
  1032 	int bit_count;
  1033 
  1034 	pEdict = GetEntity(params[1], &pEntity);
  1035 
  1036 	if (!pEdict || !pEntity)
  1037 	{
  1038 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1039 	}
  1040 
  1041 	if ((class_name = pEdict->GetClassName()) == NULL)
  1042 	{
  1043 		class_name = "";
  1044 	}
  1045 
  1046 	pContext->LocalToString(params[3], &prop);
  1047 
  1048 	switch (params[2])
  1049 	{
  1050 	case Prop_Data:
  1051 		{
  1052 			typedescription_t *td;
  1053 
  1054 			FIND_PROP_DATA(td);
  1055 
  1056 			if ((bit_count = MatchFieldAsInteger(td->fieldType)) == 0)
  1057 			{
  1058 				return pContext->ThrowNativeError("Data field %s is not an integer (%d)", 
  1059 					prop,
  1060 					td->fieldType);
  1061 			}
  1062 
  1063 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1064 			break;
  1065 		}
  1066 	case Prop_Send:
  1067 		{
  1068 			sm_sendprop_info_t info;
  1069 
  1070 			FIND_PROP_SEND(&info);
  1071 
  1072 			if (info.prop->GetType() != DPT_Int)
  1073 			{
  1074 				return pContext->ThrowNativeError("SendProp %s is not an integer ([%d,%d] != %d)",
  1075 					prop,
  1076 					info.prop->GetType(),
  1077 					info.prop->m_nBits,
  1078 					DPT_Int);
  1079 			}
  1080 
  1081 			bit_count = info.prop->m_nBits;
  1082 			offset = info.actual_offset;
  1083 			break;
  1084 		}
  1085 	default:
  1086 		{
  1087 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1088 		}
  1089 	}
  1090 
  1091 	if (bit_count < 1)
  1092 	{
  1093 		bit_count = params[5] * 8;
  1094 	}
  1095 
  1096 	if (bit_count >= 17)
  1097 	{
  1098 		*(int32_t *)((uint8_t *)pEntity + offset) = params[4];
  1099 	}
  1100 	else if (bit_count >= 9)
  1101 	{
  1102 		*(int16_t *)((uint8_t *)pEntity + offset) = (int16_t)params[4];
  1103 	}
  1104 	else if (bit_count >= 2)
  1105 	{
  1106 		*(int8_t *)((uint8_t *)pEntity + offset) = (int8_t)params[4];
  1107 	}
  1108 	else
  1109 	{
  1110 		*(bool *)((uint8_t *)pEntity + offset) = params[4] ? true : false;
  1111 	}
  1112 
  1113 	return 0;
  1114 }
  1115 
  1116 static cell_t GetEntPropFloat(IPluginContext *pContext, const cell_t *params)
  1117 {
  1118 	CBaseEntity *pEntity;
  1119 	char *prop;
  1120 	int offset;
  1121 	const char *class_name;
  1122 	edict_t *pEdict;
  1123 
  1124 	pEdict = GetEntity(params[1], &pEntity);
  1125 
  1126 	if (!pEdict || !pEntity)
  1127 	{
  1128 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1129 	}
  1130 
  1131 	if ((class_name = pEdict->GetClassName()) == NULL)
  1132 	{
  1133 		class_name = "";
  1134 	}
  1135 
  1136 	pContext->LocalToString(params[3], &prop);
  1137 
  1138 	switch (params[2])
  1139 	{
  1140 	case Prop_Data:
  1141 		{
  1142 			typedescription_t *td;
  1143 
  1144 			FIND_PROP_DATA(td);
  1145 
  1146 			if (td->fieldType != FIELD_FLOAT
  1147 				&& td->fieldType != FIELD_TIME)
  1148 			{
  1149 				return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])", 
  1150 					prop,
  1151 					td->fieldType,
  1152 					FIELD_FLOAT,
  1153 					FIELD_TIME);
  1154 			}
  1155 
  1156 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1157 			break;
  1158 		}
  1159 	case Prop_Send:
  1160 		{
  1161 			sm_sendprop_info_t info;
  1162 
  1163 			FIND_PROP_SEND(&info);
  1164 
  1165 			if (info.prop->GetType() != DPT_Float)
  1166 			{
  1167 				return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
  1168 					prop,
  1169 					info.prop->GetType(),
  1170 					DPT_Float);
  1171 			}
  1172 
  1173 			offset = info.actual_offset;
  1174 			break;
  1175 		}
  1176 	default:
  1177 		{
  1178 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1179 		}
  1180 	}
  1181 
  1182 	float val = *(float *)((uint8_t *)pEntity + offset);
  1183 
  1184 	return sp_ftoc(val);
  1185 }
  1186 
  1187 static cell_t SetEntPropFloat(IPluginContext *pContext, const cell_t *params)
  1188 {
  1189 	CBaseEntity *pEntity;
  1190 	char *prop;
  1191 	int offset;
  1192 	const char *class_name;
  1193 	edict_t *pEdict;
  1194 
  1195 	pEdict = GetEntity(params[1], &pEntity);
  1196 
  1197 	if (!pEdict || !pEntity)
  1198 	{
  1199 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1200 	}
  1201 
  1202 	if ((class_name = pEdict->GetClassName()) == NULL)
  1203 	{
  1204 		class_name = "";
  1205 	}
  1206 
  1207 	pContext->LocalToString(params[3], &prop);
  1208 
  1209 	switch (params[2])
  1210 	{
  1211 	case Prop_Data:
  1212 		{
  1213 			typedescription_t *td;
  1214 
  1215 			FIND_PROP_DATA(td);
  1216 
  1217 			if (td->fieldType != FIELD_FLOAT
  1218 				&& td->fieldType != FIELD_TIME)
  1219 			{
  1220 				return pContext->ThrowNativeError("Data field %s is not a float (%d != [%d,%d])", 
  1221 					prop,
  1222 					td->fieldType,
  1223 					FIELD_FLOAT,
  1224 					FIELD_TIME);
  1225 			}
  1226 
  1227 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1228 			break;
  1229 		}
  1230 	case Prop_Send:
  1231 		{
  1232 			sm_sendprop_info_t info;
  1233 
  1234 			FIND_PROP_SEND(&info);
  1235 
  1236 			if (info.prop->GetType() != DPT_Float)
  1237 			{
  1238 				return pContext->ThrowNativeError("SendProp %s is not a float (%d != %d)",
  1239 					prop,
  1240 					info.prop->GetType(),
  1241 					DPT_Float);
  1242 			}
  1243 
  1244 			offset = info.actual_offset;
  1245 			break;
  1246 		}
  1247 	default:
  1248 		{
  1249 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1250 		}
  1251 	}
  1252 
  1253 	*(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[4]);
  1254 
  1255 	if (params[2] == Prop_Send)
  1256 	{
  1257 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1258 	}
  1259 
  1260 	return 1;
  1261 }
  1262 
  1263 static cell_t GetEntPropEnt(IPluginContext *pContext, const cell_t *params)
  1264 {
  1265 	CBaseEntity *pEntity;
  1266 	char *prop;
  1267 	int offset;
  1268 	const char *class_name;
  1269 	edict_t *pEdict;
  1270 
  1271 	pEdict = GetEntity(params[1], &pEntity);
  1272 
  1273 	if (!pEdict || !pEntity)
  1274 	{
  1275 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1276 	}
  1277 
  1278 	if ((class_name = pEdict->GetClassName()) == NULL)
  1279 	{
  1280 		class_name = "";
  1281 	}
  1282 
  1283 	pContext->LocalToString(params[3], &prop);
  1284 
  1285 	switch (params[2])
  1286 	{
  1287 	case Prop_Data:
  1288 		{
  1289 			typedescription_t *td;
  1290 
  1291 			FIND_PROP_DATA(td);
  1292 
  1293 			if (td->fieldType != FIELD_EHANDLE)
  1294 			{
  1295 				return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)", 
  1296 					prop,
  1297 					td->fieldType,
  1298 					FIELD_EHANDLE);
  1299 			}
  1300 
  1301 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1302 			break;
  1303 		}
  1304 	case Prop_Send:
  1305 		{
  1306 			sm_sendprop_info_t info;
  1307 
  1308 			FIND_PROP_SEND(&info);
  1309 
  1310 			if (info.prop->GetType() != DPT_Int)
  1311 			{
  1312 				return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
  1313 					prop,
  1314 					info.prop->GetType(),
  1315 					DPT_Int);
  1316 			}
  1317 
  1318 			offset = info.actual_offset;
  1319 			break;
  1320 		}
  1321 	default:
  1322 		{
  1323 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1324 		}
  1325 	}
  1326 
  1327 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
  1328 
  1329 	return CheckBaseHandle(hndl);
  1330 }
  1331 
  1332 static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
  1333 {
  1334 	CBaseEntity *pEntity;
  1335 	char *prop;
  1336 	int offset;
  1337 	const char *class_name;
  1338 	edict_t *pEdict;
  1339 
  1340 	pEdict = GetEntity(params[1], &pEntity);
  1341 
  1342 	if (!pEdict || !pEntity)
  1343 	{
  1344 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1345 	}
  1346 
  1347 	if ((class_name = pEdict->GetClassName()) == NULL)
  1348 	{
  1349 		class_name = "";
  1350 	}
  1351 
  1352 	pContext->LocalToString(params[3], &prop);
  1353 
  1354 	switch (params[2])
  1355 	{
  1356 	case Prop_Data:
  1357 		{
  1358 			typedescription_t *td;
  1359 
  1360 			FIND_PROP_DATA(td);
  1361 
  1362 			if (td->fieldType != FIELD_EHANDLE)
  1363 			{
  1364 				return pContext->ThrowNativeError("Data field %s is not an entity (%d != %d)", 
  1365 					prop,
  1366 					td->fieldType,
  1367 					FIELD_EHANDLE);
  1368 			}
  1369 
  1370 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1371 			break;
  1372 		}
  1373 	case Prop_Send:
  1374 		{
  1375 			sm_sendprop_info_t info;
  1376 
  1377 			FIND_PROP_SEND(&info);
  1378 
  1379 			if (info.prop->GetType() != DPT_Int)
  1380 			{
  1381 				return pContext->ThrowNativeError("SendProp %s is not an integer (%d != %d)",
  1382 					prop,
  1383 					info.prop->GetType(),
  1384 					DPT_Int);
  1385 			}
  1386 
  1387 			offset = info.actual_offset;
  1388 			break;
  1389 		}
  1390 	default:
  1391 		{
  1392 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1393 		}
  1394 	}
  1395 
  1396 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
  1397 
  1398 	if (params[4] == -1)
  1399 	{
  1400 		hndl.Set(NULL);
  1401 	}
  1402 	else
  1403 	{
  1404 		edict_t *pOther;
  1405 		CBaseEntity *pOtherEnt;
  1406 
  1407 		if ((pOther = GetEntity(params[4], &pOtherEnt)) == NULL)
  1408 		{
  1409 			return pContext->ThrowNativeError("Invalid entity %d", params[4]);
  1410 		}
  1411 
  1412 		hndl.Set(pOther->GetIServerEntity());
  1413 	}
  1414 
  1415 	if (params[2] == Prop_Send)
  1416 	{
  1417 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1418 	}
  1419 
  1420 	return 1;
  1421 }
  1422 
  1423 static cell_t GetEntPropVector(IPluginContext *pContext, const cell_t *params)
  1424 {
  1425 	CBaseEntity *pEntity;
  1426 	char *prop;
  1427 	int offset;
  1428 	const char *class_name;
  1429 	edict_t *pEdict;
  1430 	
  1431 	pEdict = GetEntity(params[1], &pEntity);
  1432 
  1433 	if (!pEdict || !pEntity)
  1434 	{
  1435 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1436 	}
  1437 
  1438 	if ((class_name = pEdict->GetClassName()) == NULL)
  1439 	{
  1440 		class_name = "";
  1441 	}
  1442 
  1443 	pContext->LocalToString(params[3], &prop);
  1444 
  1445 	switch (params[2])
  1446 	{
  1447 	case Prop_Data:
  1448 		{
  1449 			typedescription_t *td;
  1450 			
  1451 			FIND_PROP_DATA(td);
  1452 
  1453 			if (td->fieldType != FIELD_VECTOR
  1454 				&& td->fieldType != FIELD_POSITION_VECTOR)
  1455 			{
  1456 				return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])", 
  1457 					prop,
  1458 					td->fieldType,
  1459 					FIELD_VECTOR,
  1460 					FIELD_POSITION_VECTOR);
  1461 			}
  1462 
  1463 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1464 			break;
  1465 		}
  1466 	case Prop_Send:
  1467 		{
  1468 			sm_sendprop_info_t info;
  1469 
  1470 			FIND_PROP_SEND(&info);
  1471 
  1472 			if (info.prop->GetType() != DPT_Vector)
  1473 			{
  1474 				return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
  1475 					prop,
  1476 					info.prop->GetType(),
  1477 					DPT_Vector);
  1478 			}
  1479 
  1480 			offset = info.actual_offset;
  1481 			break;
  1482 		}
  1483 	default:
  1484 		{
  1485 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1486 		}
  1487 	}
  1488 
  1489 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
  1490 
  1491 	cell_t *vec;
  1492 	pContext->LocalToPhysAddr(params[4], &vec);
  1493 
  1494 	vec[0] = sp_ftoc(v->x);
  1495 	vec[1] = sp_ftoc(v->y);
  1496 	vec[2] = sp_ftoc(v->z);
  1497 
  1498 	return 1;
  1499 }
  1500 
  1501 static cell_t SetEntPropVector(IPluginContext *pContext, const cell_t *params)
  1502 {
  1503 	CBaseEntity *pEntity;
  1504 	char *prop;
  1505 	int offset;
  1506 	const char *class_name;
  1507 	edict_t *pEdict;
  1508 	
  1509 	pEdict = GetEntity(params[1], &pEntity);
  1510 
  1511 	if (!pEdict || !pEntity)
  1512 	{
  1513 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1514 	}
  1515 
  1516 	if ((class_name = pEdict->GetClassName()) == NULL)
  1517 	{
  1518 		class_name = "";
  1519 	}
  1520 
  1521 	pContext->LocalToString(params[3], &prop);
  1522 
  1523 	switch (params[2])
  1524 	{
  1525 	case Prop_Data:
  1526 		{
  1527 			typedescription_t *td;
  1528 			
  1529 			FIND_PROP_DATA(td);
  1530 
  1531 			if (td->fieldType != FIELD_VECTOR
  1532 				&& td->fieldType != FIELD_POSITION_VECTOR)
  1533 			{
  1534 				return pContext->ThrowNativeError("Data field %s is not a vector (%d != [%d,%d])", 
  1535 					prop,
  1536 					td->fieldType,
  1537 					FIELD_VECTOR,
  1538 					FIELD_POSITION_VECTOR);
  1539 			}
  1540 
  1541 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1542 			break;
  1543 		}
  1544 	case Prop_Send:
  1545 		{
  1546 			sm_sendprop_info_t info;
  1547 
  1548 			FIND_PROP_SEND(&info);
  1549 
  1550 			if (info.prop->GetType() != DPT_Vector)
  1551 			{
  1552 				return pContext->ThrowNativeError("SendProp %s is not a vector (%d != %d)",
  1553 					prop,
  1554 					info.prop->GetType(),
  1555 					DPT_Vector);
  1556 			}
  1557 
  1558 			offset = info.actual_offset;
  1559 			break;
  1560 		}
  1561 	default:
  1562 		{
  1563 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1564 		}
  1565 	}
  1566 
  1567 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
  1568 
  1569 	cell_t *vec;
  1570 	pContext->LocalToPhysAddr(params[4], &vec);
  1571 
  1572 	v->x = sp_ctof(vec[0]);
  1573 	v->y = sp_ctof(vec[1]);
  1574 	v->z = sp_ctof(vec[2]);
  1575 
  1576 	if (params[2] == Prop_Send)
  1577 	{
  1578 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1579 	}
  1580 
  1581 	return 1;
  1582 }
  1583 
  1584 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
  1585 {
  1586 	CBaseEntity *pEntity;
  1587 	char *prop;
  1588 	int offset;
  1589 	const char *class_name;
  1590 	edict_t *pEdict;
  1591 	bool bIsStringIndex;
  1592 	
  1593 	pEdict = GetEntity(params[1], &pEntity);
  1594 
  1595 	if (!pEdict || !pEntity)
  1596 	{
  1597 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1598 	}
  1599 
  1600 	if ((class_name = pEdict->GetClassName()) == NULL)
  1601 	{
  1602 		class_name = "";
  1603 	}
  1604 
  1605 	pContext->LocalToString(params[3], &prop);
  1606 
  1607 	bIsStringIndex = false;
  1608 
  1609 	switch (params[2])
  1610 	{
  1611 	case Prop_Data:
  1612 		{
  1613 			typedescription_t *td;
  1614 			
  1615 			FIND_PROP_DATA(td);
  1616 
  1617 			if (td->fieldType != FIELD_CHARACTER
  1618 				&& td->fieldType != FIELD_STRING
  1619 				&& td->fieldType != FIELD_MODELNAME 
  1620 				&& td->fieldType != FIELD_SOUNDNAME)
  1621 			{
  1622 				return pContext->ThrowNativeError("Data field %s is not a string (%d != %d)", 
  1623 					prop,
  1624 					td->fieldType,
  1625 					FIELD_CHARACTER);
  1626 			}
  1627 
  1628 			bIsStringIndex = (td->fieldType != FIELD_CHARACTER);
  1629 
  1630 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1631 			break;
  1632 		}
  1633 	case Prop_Send:
  1634 		{
  1635 			sm_sendprop_info_t info;
  1636 
  1637 			FIND_PROP_SEND(&info);
  1638 
  1639 			if (info.prop->GetType() != DPT_String)
  1640 			{
  1641 				return pContext->ThrowNativeError("SendProp %s is not a string (%d != %d)",
  1642 					prop,
  1643 					info.prop->GetType(),
  1644 					DPT_String);
  1645 			}
  1646 
  1647 			offset = info.actual_offset;
  1648 			break;
  1649 			break;
  1650 		}
  1651 	default:
  1652 		{
  1653 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1654 		}
  1655 	}
  1656 
  1657 	size_t len;
  1658 	const char *src; 
  1659 	
  1660 	if (!bIsStringIndex)
  1661 	{
  1662 		src = (char *)((uint8_t *)pEntity + offset);
  1663 	}
  1664 	else
  1665 	{
  1666 		string_t idx;
  1667 
  1668 		idx = *(string_t *)((uint8_t *)pEntity + offset);
  1669 		src = (idx == NULL_STRING) ? "" : STRING(idx);
  1670 	}
  1671 
  1672 	pContext->StringToLocalUTF8(params[4], params[5], src, &len);
  1673 
  1674 	return len;
  1675 }
  1676 
  1677 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
  1678 {
  1679 	CBaseEntity *pEntity;
  1680 	char *prop;
  1681 	int offset;
  1682 	int maxlen;
  1683 	edict_t *pEdict = GetEntity(params[1], &pEntity);
  1684 
  1685 	if (!pEdict || !pEntity)
  1686 	{
  1687 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
  1688 	}
  1689 
  1690 	switch (params[2])
  1691 	{
  1692 	case Prop_Data:
  1693 		{
  1694 			datamap_t *pMap;
  1695 			typedescription_t *td;
  1696 			if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
  1697 			{
  1698 				return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
  1699 			}
  1700 			pContext->LocalToString(params[3], &prop);
  1701 			if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
  1702 			{
  1703 				return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
  1704 			}
  1705 			if (td->fieldType != FIELD_CHARACTER)
  1706 			{
  1707 				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
  1708 			}
  1709 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
  1710 			maxlen = td->fieldSize;
  1711 			break;
  1712 		}
  1713 	case Prop_Send:
  1714 		{
  1715 			char *prop;
  1716 			IServerNetworkable *pNet = pEdict->GetNetworkable();
  1717 			if (!pNet)
  1718 			{
  1719 				return pContext->ThrowNativeError("The edict is not networkable");
  1720 			}
  1721 			pContext->LocalToString(params[3], &prop);
  1722 			SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
  1723 			if (!pSend)
  1724 			{
  1725 				return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
  1726 			}
  1727 			if (pSend->GetType() != DPT_String)
  1728 			{
  1729 				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
  1730 			}
  1731 			offset = pSend->GetOffset();
  1732 			maxlen = DT_MAX_STRING_BUFFERSIZE;
  1733 			break;
  1734 		}
  1735 	default:
  1736 		{
  1737 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
  1738 		}
  1739 	}
  1740 
  1741 	char *src;
  1742 	char *dest = (char *)((uint8_t *)pEntity + offset);
  1743 
  1744 	pContext->LocalToString(params[4], &src);
  1745 	size_t len = strncopy(dest, src, maxlen);
  1746 
  1747 	if (params[2] == Prop_Send)
  1748 	{
  1749 		g_HL2.SetEdictStateChanged(pEdict, offset);
  1750 	}
  1751 
  1752 	return len;
  1753 }
  1754 
  1755 REGISTER_NATIVES(entityNatives)
  1756 {
  1757 	{"ChangeEdictState",		ChangeEdictState},
  1758 	{"CreateEdict",				CreateEdict},
  1759 	{"FindDataMapOffs",			FindDataMapOffs},
  1760 	{"FindSendPropInfo",		FindSendPropInfo},
  1761 	{"FindSendPropOffs",		FindSendPropOffs},
  1762 	{"GetEdictClassname",		GetEdictClassname},
  1763 	{"GetEdictFlags",			GetEdictFlags},
  1764 	{"GetEntData",				GetEntData},
  1765 	{"GetEntDataEnt",			GetEntDataEnt},		/** DEPRECATED */
  1766 	{"GetEntDataEnt2",			GetEntDataEnt2},
  1767 	{"GetEntDataFloat",			GetEntDataFloat},
  1768 	{"GetEntDataString",		GetEntDataString},
  1769 	{"GetEntDataVector",		GetEntDataVector},
  1770 	{"GetEntProp",				GetEntProp},
  1771 	{"GetEntPropEnt",			GetEntPropEnt},
  1772 	{"GetEntPropFloat",			GetEntPropFloat},
  1773 	{"GetEntPropString",		GetEntPropString},
  1774 	{"GetEntPropVector",		GetEntPropVector},
  1775 	{"GetEntityCount",			GetEntityCount},
  1776 	{"GetEntityNetClass",		GetEntityNetClass},
  1777 	{"GetMaxEntities",			GetMaxEntities},
  1778 	{"IsEntNetworkable",		IsEntNetworkable},
  1779 	{"IsValidEdict",			IsValidEdict},
  1780 	{"IsValidEntity",			IsValidEntity},
  1781 	{"RemoveEdict",				RemoveEdict},
  1782 	{"SetEdictFlags",			SetEdictFlags},
  1783 	{"SetEntData",				SetEntData},
  1784 	{"SetEntDataEnt",			SetEntDataEnt},		/** DEPRECATED */
  1785 	{"SetEntDataEnt2",			SetEntDataEnt2},
  1786 	{"SetEntDataFloat",			SetEntDataFloat},
  1787 	{"SetEntDataVector",		SetEntDataVector},
  1788 	{"SetEntDataString",		SetEntDataString},
  1789 	{"SetEntProp",				SetEntProp},
  1790 	{"SetEntPropEnt",			SetEntPropEnt},
  1791 	{"SetEntPropFloat",			SetEntPropFloat},
  1792 	{"SetEntPropString",		SetEntPropString},
  1793 	{"SetEntPropVector",		SetEntPropVector},
  1794 	{NULL,						NULL}
  1795 };