core/smn_entities.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jun 17 07:32:31 2007 +0000 (2007-06-17)
changeset 969 0cd7fc27e054
parent 965 327edbb1357a
child 1231 17badaf66ce4
permissions -rw-r--r--
fixed a state bug in the gameconf parser that would break parsing after a signature section was done
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "sm_globals.h"
    16 #include "sourcemod.h"
    17 #include "sourcemm_api.h"
    18 #include "server_class.h"
    19 #include "PlayerManager.h"
    20 #include "HalfLife2.h"
    21 #include "GameConfigs.h"
    22 #include "sm_stringutil.h"
    23 
    24 enum PropType
    25 {
    26 	Prop_Send = 0,
    27 	Prop_Data
    28 };
    29 
    30 inline edict_t *GetEdict(cell_t num)
    31 {
    32 	edict_t *pEdict = engine->PEntityOfEntIndex(num);
    33 	if (!pEdict || pEdict->IsFree())
    34 	{
    35 		return NULL;
    36 	}
    37 	if (num > 0 && num < g_Players.GetMaxClients())
    38 	{
    39 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
    40 		if (!pPlayer || !pPlayer->IsConnected())
    41 		{
    42 			return NULL;
    43 		}
    44 	}
    45 	return pEdict;
    46 }
    47 
    48 inline edict_t *GetEntity(cell_t num, CBaseEntity **pData)
    49 {
    50 	edict_t *pEdict = engine->PEntityOfEntIndex(num);
    51 	if (!pEdict || pEdict->IsFree())
    52 	{
    53 		return NULL;
    54 	}
    55 	if (num > 0 && num < g_Players.GetMaxClients())
    56 	{
    57 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(num);
    58 		if (!pPlayer || !pPlayer->IsConnected())
    59 		{
    60 			return NULL;
    61 		}
    62 	}
    63 	IServerUnknown *pUnk;
    64 	if ((pUnk=pEdict->GetUnknown()) == NULL)
    65 	{
    66 		return NULL;
    67 	}
    68 	*pData = pUnk->GetBaseEntity();
    69 	return pEdict;
    70 }
    71 
    72 class VEmptyClass {};
    73 datamap_t *VGetDataDescMap(CBaseEntity *pThisPtr, int offset)
    74 {
    75 	void **this_ptr = *reinterpret_cast<void ***>(&pThisPtr);
    76 	void **vtable = *reinterpret_cast<void ***>(pThisPtr);
    77 	void *vfunc = vtable[offset];
    78 
    79 	union
    80 	{
    81 		datamap_t *(VEmptyClass::*mfpnew)();
    82 #ifndef PLATFORM_POSIX
    83 		void *addr;
    84 	} u;
    85 	u.addr = vfunc;
    86 #else
    87 		struct  
    88 		{
    89 			void *addr;
    90 			intptr_t adjustor;
    91 		} s;
    92 	} u;
    93 	u.s.addr = vfunc;
    94 	u.s.adjustor = 0;
    95 #endif
    96 
    97 	return (datamap_t *)(reinterpret_cast<VEmptyClass *>(this_ptr)->*u.mfpnew)();
    98 }
    99 
   100 inline datamap_t *CBaseEntity_GetDataDescMap(CBaseEntity *pEntity)
   101 {
   102 	int offset;
   103 
   104 	if (!g_pGameConf->GetOffset("GetDataDescMap", &offset) || !offset)
   105 	{
   106 		return NULL;
   107 	}
   108 
   109 	return VGetDataDescMap(pEntity, offset);
   110 }
   111 
   112 /* :TODO: Move this! */
   113 datamap_t *CHalfLife2::GetDataMap(CBaseEntity *pEntity)
   114 {
   115 	return CBaseEntity_GetDataDescMap(pEntity);
   116 }
   117 
   118 static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params)
   119 {
   120 	return gpGlobals->maxEntities;
   121 }
   122 
   123 static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params)
   124 {
   125 	edict_t *pEdict = engine->CreateEdict();
   126 
   127 	if (!pEdict)
   128 	{
   129 		return 0;
   130 	}
   131 
   132 	return engine->IndexOfEdict(pEdict);
   133 }
   134 
   135 static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
   136 {
   137 	edict_t *pEdict = engine->PEntityOfEntIndex(params[1]);
   138 
   139 	if (!pEdict)
   140 	{
   141 		return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]);
   142 	}
   143 
   144 	engine->RemoveEdict(pEdict);
   145 
   146 	return 1;
   147 }
   148 
   149 static cell_t IsValidEdict(IPluginContext *pContext, const cell_t *params)
   150 {
   151 	edict_t *pEdict = GetEdict(params[1]);
   152 
   153 	if (!pEdict)
   154 	{
   155 		return 0;
   156 	}
   157 
   158 	/* Shouldn't be necessary... not sure though */
   159 	return pEdict->IsFree() ? 0 : 1;
   160 }
   161 
   162 static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
   163 {
   164 	edict_t *pEdict = GetEdict(params[1]);
   165 
   166 	if (!pEdict)
   167 	{
   168 		return 0;
   169 	}
   170 
   171 	IServerUnknown *pUnknown = pEdict->GetUnknown();
   172 	if (!pUnknown)
   173 	{
   174 		return 0;
   175 	}
   176 
   177 	CBaseEntity *pEntity = pUnknown->GetBaseEntity();
   178 	return (pEntity != NULL) ? 1 : 0;
   179 }
   180 
   181 static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
   182 {
   183 	edict_t *pEdict = GetEdict(params[1]);
   184 
   185 	if (!pEdict)
   186 	{
   187 		return 0;
   188 	}
   189 
   190 	return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
   191 }
   192 
   193 static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
   194 {
   195 	return engine->GetEntityCount();
   196 }
   197 
   198 static cell_t GetEdictFlags(IPluginContext *pContext, const cell_t *params)
   199 {
   200 	edict_t *pEdict = GetEdict(params[1]);
   201 
   202 	if (!pEdict)
   203 	{
   204 		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   205 	}
   206 
   207 	return pEdict->m_fStateFlags;
   208 }
   209 
   210 static cell_t SetEdictFlags(IPluginContext *pContext, const cell_t *params)
   211 {
   212 	edict_t *pEdict = GetEdict(params[1]);
   213 
   214 	if (!pEdict)
   215 	{
   216 		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   217 	}
   218 
   219 	pEdict->m_fStateFlags = params[2];
   220 
   221 	return 1;
   222 }
   223 
   224 static cell_t GetEdictClassname(IPluginContext *pContext, const cell_t *params)
   225 {
   226 	edict_t *pEdict = GetEdict(params[1]);
   227 
   228 	if (!pEdict)
   229 	{
   230 		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   231 	}
   232 
   233 	const char *cls = pEdict->GetClassName();
   234 
   235 	if (!cls || cls[0] == '\0')
   236 	{
   237 		return 0;
   238 	}
   239 
   240 	pContext->StringToLocal(params[2], params[3], cls);
   241 
   242 	return 1;
   243 }
   244 
   245 static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
   246 {
   247 	edict_t *pEdict = GetEdict(params[1]);
   248 
   249 	if (!pEdict)
   250 	{
   251 		return pContext->ThrowNativeError("Invalid edict (%d)", params[1]);
   252 	}
   253 
   254 	IServerNetworkable *pNet = pEdict->GetNetworkable();
   255 	if (!pNet)
   256 	{
   257 		return 0;
   258 	}
   259 
   260 	ServerClass *pClass = pNet->GetServerClass();
   261 
   262 	pContext->StringToLocal(params[2], params[3], pClass->GetName());
   263 
   264 	return 1;
   265 }
   266 
   267 static cell_t GetEntData(IPluginContext *pContext, const cell_t *params)
   268 {
   269 	CBaseEntity *pEntity;
   270 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   271 
   272 	if (!pEdict || !pEntity)
   273 	{
   274 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   275 	}
   276 
   277 	int offset = params[2];
   278 	if (offset < 0 || offset > 32768)
   279 	{
   280 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   281 	}
   282 
   283 	switch (params[3])
   284 	{
   285 	case 4:
   286 		return *(int *)((uint8_t *)pEntity + offset);
   287 	case 2:
   288 		return *(short *)((uint8_t *)pEntity + offset);
   289 	case 1:
   290 		return *((uint8_t *)pEntity + offset);
   291 	default:
   292 		return pContext->ThrowNativeError("Integer size %d is invalid", params[3]);
   293 	}
   294 }
   295 
   296 static cell_t SetEntData(IPluginContext *pContext, const cell_t *params)
   297 {
   298 	CBaseEntity *pEntity;
   299 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   300 
   301 	if (!pEdict || !pEntity)
   302 	{
   303 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   304 	}
   305 
   306 	int offset = params[2];
   307 	if (offset < 0 || offset > 32768)
   308 	{
   309 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   310 	}
   311 
   312 	if (params[5])
   313 	{
   314 		g_HL2.SetEdictStateChanged(pEdict, offset);
   315 	}
   316 
   317 	switch (params[4])
   318 	{
   319 	case 4:
   320 		{
   321 			*(int *)((uint8_t *)pEntity + offset) = params[3];
   322 			break;
   323 		}
   324 	case 2:
   325 		{
   326 			*(short *)((uint8_t *)pEntity + offset) = params[3];
   327 			break;
   328 		}
   329 	case 1:
   330 		{
   331 			*((uint8_t *)pEntity + offset) = params[3];
   332 			break;
   333 		}
   334 	default:
   335 		return pContext->ThrowNativeError("Integer size %d is invalid", params[4]);
   336 	}
   337 
   338 	return 1;
   339 }
   340 
   341 static cell_t GetEntDataFloat(IPluginContext *pContext, const cell_t *params)
   342 {
   343 	CBaseEntity *pEntity;
   344 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   345 
   346 	if (!pEdict || !pEntity)
   347 	{
   348 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   349 	}
   350 
   351 	int offset = params[2];
   352 	if (offset < 0 || offset > 32768)
   353 	{
   354 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   355 	}
   356 
   357 	float f = *(float *)((uint8_t *)pEntity + offset);
   358 
   359 	return sp_ftoc(f);
   360 }
   361 
   362 static cell_t SetEntDataFloat(IPluginContext *pContext, const cell_t *params)
   363 {
   364 	CBaseEntity *pEntity;
   365 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   366 
   367 	if (!pEdict || !pEntity)
   368 	{
   369 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   370 	}
   371 
   372 	int offset = params[2];
   373 	if (offset < 0 || offset > 32768)
   374 	{
   375 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   376 	}
   377 
   378 	*(float *)((uint8_t *)pEntity + offset) = sp_ctof(params[3]);
   379 
   380 	if (params[4])
   381 	{
   382 		g_HL2.SetEdictStateChanged(pEdict, offset);
   383 	}
   384 
   385 	return 1;
   386 }
   387 
   388 static cell_t GetEntDataVector(IPluginContext *pContext, const cell_t *params)
   389 {
   390 	CBaseEntity *pEntity;
   391 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   392 
   393 	if (!pEdict || !pEntity)
   394 	{
   395 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   396 	}
   397 
   398 	int offset = params[2];
   399 	if (offset < 0 || offset > 32768)
   400 	{
   401 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   402 	}
   403 
   404 	Vector *v = (Vector *)((uint8_t *)pEntity + offset);
   405 
   406 	cell_t *vec;
   407 	pContext->LocalToPhysAddr(params[3], &vec);
   408 
   409 	vec[0] = sp_ftoc(v->x);
   410 	vec[1] = sp_ftoc(v->y);
   411 	vec[2] = sp_ftoc(v->z);
   412 
   413 	return 1;
   414 }
   415 
   416 static cell_t SetEntDataVector(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 	v->x = sp_ctof(vec[0]);
   438 	v->y = sp_ctof(vec[1]);
   439 	v->z = sp_ctof(vec[2]);
   440 
   441 	if (params[4])
   442 	{
   443 		g_HL2.SetEdictStateChanged(pEdict, offset);
   444 	}
   445 
   446 	return 1;
   447 }
   448 
   449 static cell_t GetEntDataEnt(IPluginContext *pContext, const cell_t *params)
   450 {
   451 	CBaseEntity *pEntity;
   452 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   453 
   454 	if (!pEdict || !pEntity)
   455 	{
   456 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   457 	}
   458 
   459 	int offset = params[2];
   460 	if (offset < 0 || offset > 32768)
   461 	{
   462 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   463 	}
   464 
   465 	CBaseHandle &hndl = *(CBaseHandle *)((uint8_t *)pEntity + offset);
   466 
   467 	if (!hndl.IsValid())
   468 	{
   469 		return 0;
   470 	}
   471 
   472 	/* :TODO: check serial no.? */
   473 
   474 	return hndl.GetEntryIndex();
   475 }
   476 
   477 static cell_t SetEntDataEnt(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 (params[3] == 0)
   496 	{
   497 		hndl.Set(NULL);
   498 	} else {
   499 		edict_t *pEdict = GetEdict(params[3]);
   500 		if (!pEdict)
   501 		{
   502 			return pContext->ThrowNativeError("Entity %d is invalid", params[3]);
   503 		}
   504 		IServerEntity *pEntOther = pEdict->GetIServerEntity();
   505 		hndl.Set(pEntOther);
   506 	}
   507 
   508 	if (params[4])
   509 	{
   510 		g_HL2.SetEdictStateChanged(pEdict, offset);
   511 	}
   512 
   513 	return 1;
   514 }
   515 
   516 static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
   517 {
   518 	edict_t *pEdict = GetEdict(params[1]);
   519 
   520 	if (!pEdict)
   521 	{
   522 		return pContext->ThrowNativeError("Edict %d is invalid", params[1]);
   523 	}
   524 
   525 	g_HL2.SetEdictStateChanged(pEdict, params[2]);
   526 
   527 	return 1;
   528 }
   529 
   530 static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
   531 {
   532 	char *cls, *prop;
   533 	pContext->LocalToString(params[1], &cls);
   534 	pContext->LocalToString(params[2], &prop);
   535 
   536 	SendProp *pSend = g_HL2.FindInSendTable(cls, prop);
   537 
   538 	if (!pSend)
   539 	{
   540 		return -1;
   541 	}
   542 
   543 	return pSend->GetOffset();
   544 }
   545 
   546 static cell_t FindDataMapOffs(IPluginContext *pContext, const cell_t *params)
   547 {
   548 	CBaseEntity *pEntity;
   549 	datamap_t *pMap;
   550 	typedescription_t *td;
   551 	char *offset;
   552 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   553 
   554 	if (!pEdict || !pEntity)
   555 	{
   556 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   557 	}
   558 
   559 	if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
   560 	{
   561 		return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
   562 	}
   563 
   564 	pContext->LocalToString(params[2], &offset);
   565 	if ((td=g_HL2.FindInDataMap(pMap, offset)) == NULL)
   566 	{
   567 		return -1;
   568 	}
   569 
   570 	return td->fieldOffset[TD_OFFSET_NORMAL];
   571 }
   572 
   573 static cell_t GetEntDataString(IPluginContext *pContext, const cell_t *params)
   574 {
   575 	CBaseEntity *pEntity;
   576 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   577 
   578 	if (!pEdict || !pEntity)
   579 	{
   580 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   581 	}
   582 
   583 	int offset = params[2];
   584 	if (offset < 0 || offset > 32768)
   585 	{
   586 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   587 	}
   588 
   589 	size_t len;
   590 	char *src = (char *)((uint8_t *)pEntity + offset);
   591 	pContext->StringToLocalUTF8(params[3], params[4], src, &len);
   592 
   593 	return len;
   594 }
   595 
   596 static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
   597 {
   598 	CBaseEntity *pEntity;
   599 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   600 
   601 	if (!pEdict || !pEntity)
   602 	{
   603 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   604 	}
   605 
   606 	int offset = params[2];
   607 	if (offset < 0 || offset > 32768)
   608 	{
   609 		return pContext->ThrowNativeError("Offset %d is invalid", offset);
   610 	}
   611 
   612 	char *src;
   613 	char *dest = (char *)((uint8_t *)pEntity + offset);
   614 
   615 	pContext->LocalToString(params[3], &src);
   616 	size_t len = strncopy(dest, src, params[4]);
   617 
   618 	if (params[5])
   619 	{
   620 		g_HL2.SetEdictStateChanged(pEdict, offset);
   621 	}
   622 
   623 	return len;
   624 }
   625 
   626 static cell_t GetEntPropString(IPluginContext *pContext, const cell_t *params)
   627 {
   628 	CBaseEntity *pEntity;
   629 	char *prop;
   630 	int offset;
   631 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   632 
   633 	if (!pEdict || !pEntity)
   634 	{
   635 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   636 	}
   637 
   638 	switch (params[2])
   639 	{
   640 	case Prop_Data:
   641 		{
   642 			datamap_t *pMap;
   643 			typedescription_t *td;
   644 			if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
   645 			{
   646 				return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
   647 			}
   648 			pContext->LocalToString(params[3], &prop);
   649 			if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
   650 			{
   651 				return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
   652 			}
   653 			if (td->fieldType != FIELD_CHARACTER)
   654 			{
   655 				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
   656 			}
   657 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
   658 			break;
   659 		}
   660 	case Prop_Send:
   661 		{
   662 			char *prop;
   663 			IServerNetworkable *pNet = pEdict->GetNetworkable();
   664 			if (!pNet)
   665 			{
   666 				return pContext->ThrowNativeError("The edict is not networkable");
   667 			}
   668 			pContext->LocalToString(params[3], &prop);
   669 			SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
   670 			if (!pSend)
   671 			{
   672 				return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
   673 			}
   674 			if (pSend->GetType() != DPT_String)
   675 			{
   676 				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
   677 			}
   678 			offset = pSend->GetOffset();
   679 			break;
   680 		}
   681 	default:
   682 		{
   683 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
   684 		}
   685 	}
   686 
   687 	size_t len;
   688 	char *src = (char *)((uint8_t *)pEntity + offset);
   689 	pContext->StringToLocalUTF8(params[4], params[5], src, &len);
   690 
   691 	return len;
   692 }
   693 
   694 static cell_t SetEntPropString(IPluginContext *pContext, const cell_t *params)
   695 {
   696 	CBaseEntity *pEntity;
   697 	char *prop;
   698 	int offset;
   699 	int maxlen;
   700 	bool is_sendprop = false;
   701 	edict_t *pEdict = GetEntity(params[1], &pEntity);
   702 
   703 	if (!pEdict || !pEntity)
   704 	{
   705 		return pContext->ThrowNativeError("Entity %d is invalid", params[1]);
   706 	}
   707 
   708 	switch (params[2])
   709 	{
   710 	case Prop_Data:
   711 		{
   712 			datamap_t *pMap;
   713 			typedescription_t *td;
   714 			if ((pMap=CBaseEntity_GetDataDescMap(pEntity)) == NULL)
   715 			{
   716 				return pContext->ThrowNativeError("Unable to retrieve GetDataDescMap offset");
   717 			}
   718 			pContext->LocalToString(params[3], &prop);
   719 			if ((td=g_HL2.FindInDataMap(pMap, prop)) == NULL)
   720 			{
   721 				return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
   722 			}
   723 			if (td->fieldType != FIELD_CHARACTER)
   724 			{
   725 				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
   726 			}
   727 			offset = td->fieldOffset[TD_OFFSET_NORMAL];
   728 			maxlen = td->fieldSize;
   729 			break;
   730 		}
   731 	case Prop_Send:
   732 		{
   733 			char *prop;
   734 			IServerNetworkable *pNet = pEdict->GetNetworkable();
   735 			if (!pNet)
   736 			{
   737 				return pContext->ThrowNativeError("The edict is not networkable");
   738 			}
   739 			pContext->LocalToString(params[3], &prop);
   740 			SendProp *pSend = g_HL2.FindInSendTable(pNet->GetServerClass()->GetName(), prop);
   741 			if (!pSend)
   742 			{
   743 				return pContext->ThrowNativeError("Property \"%s\" not found for entity %d", prop, params[1]);
   744 			}
   745 			if (pSend->GetType() != DPT_String)
   746 			{
   747 				return pContext->ThrowNativeError("Property \"%s\" is not a valid string", prop);
   748 			}
   749 			offset = pSend->GetOffset();
   750 			maxlen = DT_MAX_STRING_BUFFERSIZE;
   751 			is_sendprop = true;
   752 			break;
   753 		}
   754 	default:
   755 		{
   756 			return pContext->ThrowNativeError("Invalid Property type %d", params[2]);
   757 		}
   758 	}
   759 
   760 	char *src;
   761 	char *dest = (char *)((uint8_t *)pEntity + offset);
   762 
   763 	pContext->LocalToString(params[4], &src);
   764 	size_t len = strncopy(dest, src, maxlen);
   765 
   766 	if (is_sendprop)
   767 	{
   768 		g_HL2.SetEdictStateChanged(pEdict, offset);
   769 	}
   770 
   771 	return len;
   772 }
   773 
   774 REGISTER_NATIVES(entityNatives)
   775 {
   776 	{"ChangeEdictState",		ChangeEdictState},
   777 	{"CreateEdict",				CreateEdict},
   778 	{"FindSendPropOffs",		FindSendPropOffs},
   779 	{"GetEdictClassname",		GetEdictClassname},
   780 	{"GetEdictFlags",			GetEdictFlags},
   781 	{"GetEntData",				GetEntData},
   782 	{"GetEntDataEnt",			GetEntDataEnt},
   783 	{"GetEntDataFloat",			GetEntDataFloat},
   784 	{"GetEntDataVector",		GetEntDataVector},
   785 	{"GetEntityCount",			GetEntityCount},
   786 	{"GetEntityNetClass",		GetEntityNetClass},
   787 	{"GetMaxEntities",			GetMaxEntities},
   788 	{"IsEntNetworkable",		IsEntNetworkable},
   789 	{"IsValidEdict",			IsValidEdict},
   790 	{"IsValidEntity",			IsValidEntity},
   791 	{"RemoveEdict",				RemoveEdict},
   792 	{"SetEdictFlags",			SetEdictFlags},
   793 	{"SetEntData",				SetEntData},
   794 	{"SetEntDataEnt",			SetEntDataEnt},
   795 	{"SetEntDataFloat",			SetEntDataFloat},
   796 	{"SetEntDataVector",		SetEntDataVector},
   797 	{"FindDataMapOffs",			FindDataMapOffs},
   798 	{"GetEntDataString",		GetEntDataString},
   799 	{"SetEntDataString",		SetEntDataString},
   800 	{"GetEntPropString",		GetEntPropString},
   801 	{"SetEntPropString",		SetEntPropString},
   802 	{NULL,						NULL}
   803 };