Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3548 lines
88 KiB

  1. //========== Copyright (c) Valve Corporation, All rights reserved. ========
  2. //
  3. // Purpose:
  4. //
  5. //==========================================================================
  6. //-------------------------------------
  7. // Work around one of the headers below including crtdbg.h
  8. #include "memdbgon.h"
  9. #include "memdbgoff.h"
  10. //-------------------------------------
  11. #include <stdio.h>
  12. #if defined( _PS3 ) || defined( POSIX )
  13. #include <ctype.h>
  14. #include <wctype.h>
  15. #undef _STD_USING
  16. #elif defined( _WIN32 )
  17. #include <io.h>
  18. #include <conio.h>
  19. #include <direct.h>
  20. #endif // _PS3
  21. #ifdef _HAS_EXCEPTIONS
  22. #undef _HAS_EXCEPTIONS
  23. #endif
  24. #define _HAS_EXCEPTIONS 0
  25. #include <string>
  26. #include "platform.h"
  27. #include "tier1/utlmap.h"
  28. #include "datamap.h"
  29. #include "tier1/functors.h"
  30. #include "tier1/utlvector.h"
  31. #include "tier1/utlhash.h"
  32. #include "tier1/utlbuffer.h"
  33. #include "tier1/fmtstr.h"
  34. #include "tier1/convar.h"
  35. #include "mathlib/vector.h"
  36. #include "vstdlib/random.h"
  37. #pragma warning(push, 3)
  38. #include "squirrel.h"
  39. #include "sqstdaux.h"
  40. #include "sqstdstring.h"
  41. #include "sqstdmath.h"
  42. #include "sqplus.h"
  43. #include "sqrdbg.h"
  44. #include "../squirrel/sqstate.h"
  45. #include "../squirrel/sqvm.h"
  46. #include "../squirrel/sqobject.h"
  47. #include "../squirrel/sqstring.h"
  48. #include "../squirrel/sqarray.h"
  49. #include "../squirrel/sqtable.h"
  50. #include "../squirrel/squserdata.h"
  51. #include "../squirrel/sqfuncproto.h"
  52. #include "../squirrel/sqclass.h"
  53. #include "../squirrel/sqclosure.h"
  54. #include "sqdbgserver.h"
  55. #pragma warning(pop)
  56. #include "vscript/ivscript.h"
  57. #include "tier0/vprof.h"
  58. #include "init_nut.h"
  59. #include "memdbgon.h"
  60. #ifdef VSQUIRREL_DEBUG_SERIALIZATION
  61. static SQObjectType lastType;
  62. #endif
  63. #if defined( _PS3 ) || defined( POSIX )
  64. inline int64 max( int64 a, int64 b)
  65. {
  66. return a > b ? a : b;
  67. }
  68. #endif
  69. //-----------------------------------------------------------------------------
  70. // Stub out unwanted features
  71. //-----------------------------------------------------------------------------
  72. extern "C"
  73. {
  74. SQRESULT sqstd_register_iolib(HSQUIRRELVM)
  75. {
  76. return SQ_OK;
  77. }
  78. SQRESULT sqstd_loadfile(HSQUIRRELVM,const SQChar *,SQBool)
  79. {
  80. return SQ_ERROR;
  81. }
  82. }
  83. //-------------------------------------------------------------------------
  84. // Helpers
  85. //-------------------------------------------------------------------------
  86. const char *FieldTypeToString( int type )
  87. {
  88. switch( type )
  89. {
  90. case FIELD_VOID: return "void";
  91. case FIELD_FLOAT: return "float";
  92. case FIELD_CSTRING: return "string";
  93. case FIELD_VECTOR: return "Vector";
  94. case FIELD_INTEGER: return "int";
  95. case FIELD_BOOLEAN: return "bool";
  96. case FIELD_CHARACTER: return "char";
  97. case FIELD_HSCRIPT: return "handle";
  98. default: return "<unknown>";
  99. }
  100. }
  101. static const char *SQTypeToString( SQObjectType sqType )
  102. {
  103. switch( sqType )
  104. {
  105. case OT_FLOAT: return "FLOAT";
  106. case OT_INTEGER: return "INTEGER";
  107. case OT_BOOL: return "BOOL";
  108. case OT_STRING: return "STRING";
  109. case OT_NULL: return "NULL";
  110. case OT_TABLE: return "TABLE";
  111. case OT_ARRAY: return "ARRAY";
  112. case OT_CLOSURE: return "CLOSURE";
  113. case OT_NATIVECLOSURE: return "NATIVECLOSURE";
  114. case OT_USERDATA: return "USERDATA";
  115. case OT_GENERATOR: return "GENERATOR";
  116. case OT_THREAD: return "THREAD";
  117. case OT_USERPOINTER: return "USERPOINTER";
  118. case OT_CLASS: return "CLASS";
  119. case OT_INSTANCE: return "INSTANCE";
  120. case OT_WEAKREF: return "WEAKREF";
  121. }
  122. return "<unknown>";
  123. }
  124. //-------------------------------------------------------------------------
  125. // Vector
  126. //-------------------------------------------------------------------------
  127. #define TYPETAG_VECTOR ((SQUserPointer)1)
  128. SQInteger VectorRelease( SQUserPointer p, SQInteger size )
  129. {
  130. delete (Vector *)p;
  131. return 0;
  132. }
  133. SQInteger VectorConstruct( HSQUIRRELVM hVM )
  134. {
  135. StackHandler sa(hVM);
  136. Vector *pVector = new Vector;
  137. int i;
  138. for ( i = 0; i < 3 && i < sa.GetParamCount() - 1; i++ )
  139. {
  140. (*pVector)[i] = sa.GetFloat(i + 2);
  141. }
  142. for ( ; i < 3 ; i++ )
  143. {
  144. (*pVector)[i] = 0;
  145. }
  146. sq_setinstanceup(hVM, 1, pVector);
  147. sq_setreleasehook( hVM, 1, &VectorRelease );
  148. return 0;
  149. }
  150. SQInteger VectorGet( HSQUIRRELVM hVM )
  151. {
  152. StackHandler sa(hVM);
  153. Vector *pVector = (Vector *)sa.GetInstanceUp(1,0);
  154. if ( !pVector )
  155. {
  156. sq_throwerror( hVM, "null vector" );
  157. return SQ_ERROR;
  158. }
  159. const char *pszKey = sa.GetString( 2 );
  160. if ( pszKey && *pszKey && !*(pszKey + 1) )
  161. {
  162. int index = *pszKey - 'x';
  163. if ( index >=0 && index <= 2)
  164. {
  165. sq_pushfloat( hVM, (*pVector)[index] );
  166. return 1;
  167. }
  168. }
  169. return SQ_ERROR;
  170. }
  171. SQInteger VectorSet( HSQUIRRELVM hVM )
  172. {
  173. StackHandler sa(hVM);
  174. Vector *pVector = (Vector *)sa.GetInstanceUp(1,0);
  175. if ( !pVector )
  176. {
  177. sq_throwerror( hVM, "null vector" );
  178. return SQ_ERROR;
  179. }
  180. const char *pszKey = sa.GetString( 2 );
  181. if ( pszKey && *pszKey && !*(pszKey + 1) )
  182. {
  183. int index = *pszKey - 'x';
  184. if ( index >=0 && index <= 2)
  185. {
  186. (*pVector)[index] = sa.GetFloat(3);
  187. sq_pushfloat( hVM, (*pVector)[index] );
  188. return 0;
  189. }
  190. }
  191. return SQ_ERROR;
  192. }
  193. SQInteger VectorIterate( HSQUIRRELVM hVM )
  194. {
  195. StackHandler sa(hVM);
  196. static const char *results[] =
  197. {
  198. "x", "y", "z"
  199. };
  200. const char *pszKey = (sa.GetType( 2 ) == OT_NULL ) ? "w" : sa.GetString( 2 );
  201. if ( pszKey && *pszKey && !*(pszKey + 1) )
  202. {
  203. int index = (*pszKey - 'x' ) + 1;
  204. if ( index >=0 && index <= 2)
  205. {
  206. sa.Return( results[index] );
  207. return 1;
  208. }
  209. sq_pushnull( hVM );
  210. return 1;
  211. }
  212. return SQ_ERROR;
  213. }
  214. SQInteger VectorToString( HSQUIRRELVM hVM )
  215. {
  216. StackHandler sa(hVM);
  217. Vector *pVector = (Vector *)sa.GetInstanceUp(1,0);
  218. if ( !pVector )
  219. {
  220. sq_throwerror( hVM, "null vector" );
  221. return SQ_ERROR;
  222. }
  223. sa.Return( (static_cast<const char *>(CFmtStr("(vector : (%f, %f, %f))", pVector->x, pVector->y, pVector->z))) );
  224. return 1;
  225. }
  226. SQInteger VectorTypeOf( HSQUIRRELVM hVM )
  227. {
  228. StackHandler sa(hVM);
  229. sa.Return( "Vector" );
  230. return 1;
  231. }
  232. SQInteger VectorToKeyValueString( HSQUIRRELVM hVM )
  233. {
  234. StackHandler sa(hVM);
  235. Vector *pVector = (Vector *)sa.GetInstanceUp(1,0);
  236. if ( !pVector )
  237. {
  238. sq_throwerror( hVM, "null vector" );
  239. return SQ_ERROR;
  240. }
  241. sa.Return( (static_cast<const char *>(CFmtStr("%f %f %f))", pVector->x, pVector->y, pVector->z))) );
  242. return 1;
  243. }
  244. SQInteger VectorAdd( HSQUIRRELVM hVM )
  245. {
  246. StackHandler sa(hVM);
  247. Vector *pVectorSrc = (Vector *)sa.GetInstanceUp(1,0);
  248. Vector *pVectorAdd = (Vector *)sa.GetInstanceUp(2,0);
  249. if ( !pVectorSrc || !pVectorAdd )
  250. {
  251. sq_throwerror( hVM, "null vector" );
  252. return SQ_ERROR;
  253. }
  254. Vector *pResult = new Vector;
  255. *pResult = *pVectorSrc + *pVectorAdd;
  256. sq_getclass( hVM, -1 );
  257. sq_createinstance( hVM, -1 );
  258. sq_setinstanceup( hVM, -1, (SQUserPointer)pResult );
  259. sq_setreleasehook( hVM, -1, &VectorRelease );
  260. sq_remove( hVM, -2 );
  261. return 1;
  262. }
  263. SQInteger VectorSubtract( HSQUIRRELVM hVM )
  264. {
  265. StackHandler sa(hVM);
  266. Vector *pVectorSrc = (Vector *)sa.GetInstanceUp(1,0);
  267. Vector *pVectorAdd = (Vector *)sa.GetInstanceUp(2,0);
  268. if ( !pVectorSrc || !pVectorAdd )
  269. {
  270. sq_throwerror( hVM, "null vector" );
  271. return SQ_ERROR;
  272. }
  273. Vector *pResult = new Vector;
  274. *pResult = *pVectorSrc - *pVectorAdd;
  275. sq_getclass( hVM, -1 );
  276. sq_createinstance( hVM, -1 );
  277. sq_setinstanceup( hVM, -1, (SQUserPointer)pResult );
  278. sq_setreleasehook( hVM, -1, &VectorRelease );
  279. sq_remove( hVM, -2 );
  280. return 1;
  281. }
  282. SQInteger VectorScale( HSQUIRRELVM hVM )
  283. {
  284. StackHandler sa(hVM);
  285. Vector *pVectorSrc = (Vector *)sa.GetInstanceUp(1,0);
  286. if ( !pVectorSrc )
  287. {
  288. sq_throwerror( hVM, "null vector" );
  289. return SQ_ERROR;
  290. }
  291. float scale = sa.GetFloat( 2 );
  292. Vector *pResult = new Vector;
  293. *pResult = *pVectorSrc * scale;
  294. sq_getclass( hVM, -2 );
  295. sq_createinstance( hVM, -1 );
  296. sq_setinstanceup( hVM, -1, (SQUserPointer)pResult );
  297. sq_setreleasehook( hVM, -1, &VectorRelease );
  298. sq_remove( hVM, -2 );
  299. return 1;
  300. }
  301. SQInteger VectorLength( HSQUIRRELVM hVM )
  302. {
  303. StackHandler sa(hVM);
  304. Vector *pVector = (Vector *)sa.GetInstanceUp(1,0);
  305. if ( !pVector )
  306. {
  307. sq_throwerror( hVM, "null vector" );
  308. return SQ_ERROR;
  309. }
  310. float flLength = pVector->Length();
  311. sa.Return( flLength );
  312. return 1;
  313. }
  314. SQInteger VectorLengthSqr( HSQUIRRELVM hVM )
  315. {
  316. StackHandler sa(hVM);
  317. Vector *pVector = (Vector *)sa.GetInstanceUp(1,0);
  318. if ( !pVector )
  319. {
  320. sq_throwerror( hVM, "null vector" );
  321. return SQ_ERROR;
  322. }
  323. float flLength = pVector->LengthSqr();
  324. sa.Return( flLength );
  325. return 1;
  326. }
  327. SQInteger VectorLength2D( HSQUIRRELVM hVM )
  328. {
  329. StackHandler sa(hVM);
  330. Vector *pVector = (Vector *)sa.GetInstanceUp(1,0);
  331. if ( !pVector )
  332. {
  333. sq_throwerror( hVM, "null vector" );
  334. return SQ_ERROR;
  335. }
  336. float flLength = pVector->Length2D();
  337. sa.Return( flLength );
  338. return 1;
  339. }
  340. SQInteger VectorLength2DSqr( HSQUIRRELVM hVM )
  341. {
  342. StackHandler sa(hVM);
  343. Vector *pVector = (Vector *)sa.GetInstanceUp(1,0);
  344. if ( !pVector )
  345. {
  346. sq_throwerror( hVM, "null vector" );
  347. return SQ_ERROR;
  348. }
  349. float flLength = pVector->Length2DSqr();
  350. sa.Return( flLength );
  351. return 1;
  352. }
  353. SQInteger VectorCross( HSQUIRRELVM hVM )
  354. {
  355. StackHandler sa(hVM);
  356. Vector *pVectorSrc = (Vector *)sa.GetInstanceUp(1,0);
  357. Vector *pVectorAdd = (Vector *)sa.GetInstanceUp(2,0);
  358. if ( !pVectorSrc || !pVectorAdd )
  359. {
  360. sq_throwerror( hVM, "null vector" );
  361. return SQ_ERROR;
  362. }
  363. Vector *pResult = new Vector;
  364. *pResult = (*pVectorSrc).Cross( *pVectorAdd );
  365. sq_getclass( hVM, -1 );
  366. sq_createinstance( hVM, -1 );
  367. sq_setinstanceup( hVM, -1, (SQUserPointer)pResult );
  368. sq_setreleasehook( hVM, -1, &VectorRelease );
  369. sq_remove( hVM, -2 );
  370. return 1;
  371. }
  372. SQInteger VectorDot( HSQUIRRELVM hVM )
  373. {
  374. StackHandler sa(hVM);
  375. Vector *pVectorSrc = (Vector *)sa.GetInstanceUp(1,0);
  376. Vector *pVectorAdd = (Vector *)sa.GetInstanceUp(2,0);
  377. if ( !pVectorSrc || !pVectorAdd )
  378. {
  379. sq_throwerror( hVM, "null vector" );
  380. return SQ_ERROR;
  381. }
  382. float flResult = (*pVectorSrc).Dot( *pVectorAdd );
  383. sa.Return( flResult );
  384. return 1;
  385. }
  386. SQInteger VectorNorm( HSQUIRRELVM hVM )
  387. {
  388. StackHandler sa(hVM);
  389. Vector *pVector = (Vector *)sa.GetInstanceUp(1,0);
  390. if ( !pVector )
  391. {
  392. sq_throwerror( hVM, "null vector" );
  393. return SQ_ERROR;
  394. }
  395. float flLength = pVector->NormalizeInPlace();
  396. sa.Return( flLength );
  397. return 1;
  398. }
  399. SQRegFunction g_VectorFuncs[] =
  400. {
  401. { "constructor", VectorConstruct, 0, NULL },
  402. { "_get", VectorGet, 2, ".." },
  403. { "_set", VectorSet, 3, "..n" },
  404. { "_tostring", VectorToString, 0, NULL },
  405. { "_typeof", VectorTypeOf, 0, NULL },
  406. { "_nexti", VectorIterate, 0, NULL },
  407. { "_add", VectorAdd, 2, NULL },
  408. { "_sub", VectorSubtract, 2, NULL },
  409. { "_mul", VectorScale, 2, NULL },
  410. { "ToKVString", VectorToKeyValueString, 0, NULL },
  411. { "Length", VectorLength, 0, NULL },
  412. { "LengthSqr", VectorLengthSqr, 0, NULL },
  413. { "Length2D", VectorLength2D, 0, NULL },
  414. { "Length2DSqr", VectorLength2DSqr, 0, NULL },
  415. { "Length2DSqr", VectorLength2DSqr, 0, NULL },
  416. { "Dot", VectorDot, 2, NULL },
  417. { "Cross", VectorCross, 2, NULL },
  418. { "Norm", VectorNorm, 0, NULL },
  419. };
  420. bool RegisterVector( HSQUIRRELVM hVM )
  421. {
  422. int top = sq_gettop( hVM );
  423. sq_pushroottable(hVM);
  424. sq_pushstring(hVM,"Vector",-1);
  425. if (SQ_FAILED(sq_newclass(hVM,0)))
  426. {
  427. sq_settop(hVM,top);
  428. return false;
  429. }
  430. HSQOBJECT hClass;
  431. sq_getstackobj(hVM,-1, &hClass);
  432. sq_settypetag(hVM,-1,TYPETAG_VECTOR);
  433. sq_createslot(hVM,-3);
  434. sq_pushobject( hVM, hClass );
  435. for ( int i = 0; i < ARRAYSIZE(g_VectorFuncs); i++ )
  436. {
  437. sq_pushstring(hVM,g_VectorFuncs[i].name,-1);
  438. sq_newclosure(hVM,g_VectorFuncs[i].f,0);
  439. if ( g_VectorFuncs[i].nparamscheck )
  440. sq_setparamscheck(hVM,g_VectorFuncs[i].nparamscheck,g_VectorFuncs[i].typemask);
  441. sq_setnativeclosurename(hVM,-1,g_VectorFuncs[i].name);
  442. sq_createslot(hVM,-3);
  443. }
  444. sq_pop(hVM,1);
  445. sq_settop( hVM, top );
  446. return true;
  447. }
  448. //-----------------------------------------------------------------------------
  449. // Bridge code, some cribbed from SqPlus
  450. //-----------------------------------------------------------------------------
  451. const HSQOBJECT INVALID_HSQOBJECT = { (SQObjectType)-1, (SQTable *)-1 };
  452. inline bool operator==( const HSQOBJECT &lhs, const HSQOBJECT &rhs ) { COMPILE_TIME_ASSERT( sizeof(lhs._unVal) == sizeof(lhs._unVal.pTable) ); return ( lhs._type == rhs._type && lhs._unVal.pTable == rhs._unVal.pTable ); }
  453. inline bool operator!=( const HSQOBJECT &lhs, const HSQOBJECT &rhs ) { return !operator==( lhs, rhs ); }
  454. class CSquirrelVM : public IScriptVM
  455. {
  456. public:
  457. CSquirrelVM( HSQUIRRELVM hVM = NULL )
  458. : m_hVM( hVM ), m_hDbg( NULL ), m_PtrMap( DefLessFunc(void *) ), m_iUniqueIdSerialNumber( 0 )
  459. #ifndef VSQUIRREL_TEST
  460. , developer( "developer" )
  461. #else
  462. , developer( "developer", "1" )
  463. #endif
  464. {
  465. m_hOnCreateScopeFunc = _null_;
  466. m_hOnReleaseScopeFunc = _null_;
  467. m_hClassVector = _null_;
  468. m_ErrorString = _null_;
  469. }
  470. //-------------------------------------------------------------
  471. //
  472. //-------------------------------------------------------------
  473. virtual bool Init()
  474. {
  475. m_hVM = sq_open(1024);
  476. m_hVM->_sharedstate->m_pOwnerData = this;
  477. m_hVM->SetQuerySuspendFn( &QueryContinue );
  478. // Need to make this conditional on convar or commandline [2/11/2008 tom]
  479. //m_hDbg = sq_rdbg_init( m_hVM, 1234, SQTrue);
  480. sq_setprintfunc(m_hVM, &PrintFunc);
  481. sq_pushroottable(m_hVM);
  482. sqstd_register_mathlib(m_hVM);
  483. sqstd_register_stringlib(m_hVM);
  484. sqstd_seterrorhandlers(m_hVM);
  485. sq_pop(m_hVM,1);
  486. if ( IsDebug() || developer.GetInt() > 0 )
  487. {
  488. sq_enabledebuginfo( m_hVM, SQTrue );
  489. }
  490. sq_pushroottable( m_hVM);
  491. sq_pushstring( m_hVM, "developer", -1 );
  492. sq_newclosure( m_hVM, &GetDeveloper, 0 );
  493. sq_setnativeclosurename(m_hVM, -1, "developer" );
  494. sq_createslot( m_hVM, -3 );
  495. sq_pushstring( m_hVM, "GetFunctionSignature", -1 );
  496. sq_newclosure( m_hVM, &GetFunctionSignature, 0 );
  497. sq_setnativeclosurename(m_hVM, -1, "GetFunctionSignature" );
  498. sq_createslot( m_hVM, -3 );
  499. sq_pop( m_hVM, 1 );
  500. m_TypeMap.Init( 256 );
  501. RegisterVector( m_hVM );
  502. sq_pushroottable(m_hVM );
  503. sq_pushstring( m_hVM, "Vector", -1 );
  504. sq_get(m_hVM,-2); //get the function from the root table
  505. sq_getstackobj(m_hVM,-1,&m_hClassVector);
  506. sq_addref(m_hVM,&m_hClassVector);
  507. sq_pop(m_hVM, 2);
  508. // Initialization scripts & hookup
  509. Run( (const char *)g_Script_init, "init.nut" );
  510. m_hOnCreateScopeFunc = LookupObject( "VSquirrel_OnCreateScope" );
  511. m_hOnReleaseScopeFunc = LookupObject( "VSquirrel_OnReleaseScope" );
  512. return true;
  513. }
  514. //-------------------------------------------------------------
  515. //
  516. //-------------------------------------------------------------
  517. bool Frame( float simTime )
  518. {
  519. //
  520. // <sergiy> removed garbage collection that was called at least 2 times a frame (60 fps server tick / 30fps game = 2 calls a frame)
  521. // and took 1 ms on PS3 PPU. It's not necessary because our scripts are supposed to never create circular references
  522. // and everything else is handled with ref counting. For the case of bugs creating circular references, the plan is to add
  523. // diagnostics that detects such loops and warns the developer.
  524. //
  525. if ( m_hDbg )
  526. {
  527. sq_rdbg_update( m_hDbg );
  528. if ( !m_hDbg->IsConnected() )
  529. DisconnectDebugger();
  530. }
  531. return false;
  532. }
  533. //-------------------------------------------------------------
  534. //
  535. //-------------------------------------------------------------
  536. virtual void Shutdown()
  537. {
  538. if ( m_hVM )
  539. {
  540. sq_collectgarbage( m_hVM );
  541. sq_pushnull(m_hVM);
  542. sq_setroottable(m_hVM);
  543. DisconnectDebugger();
  544. sq_close( m_hVM );
  545. m_hVM = NULL;
  546. }
  547. m_TypeMap.Purge();
  548. }
  549. //-------------------------------------------------------------
  550. //
  551. //-------------------------------------------------------------
  552. ScriptLanguage_t GetLanguage()
  553. {
  554. return SL_SQUIRREL;
  555. }
  556. //-------------------------------------------------------------
  557. //
  558. //-------------------------------------------------------------
  559. virtual const char *GetLanguageName()
  560. {
  561. return "Squirrel";
  562. }
  563. virtual void AddSearchPath( const char *pszSearchPath )
  564. {
  565. }
  566. //-------------------------------------------------------------
  567. //
  568. //-------------------------------------------------------------
  569. HSQUIRRELVM GetVM()
  570. {
  571. return m_hVM;
  572. }
  573. //-------------------------------------------------------------
  574. //
  575. //-------------------------------------------------------------
  576. bool ConnectDebugger()
  577. {
  578. if ( developer.GetInt() > 0 )
  579. {
  580. if ( !m_hDbg )
  581. {
  582. m_hDbg = sq_rdbg_init( m_hVM, 1234, SQTrue);
  583. }
  584. if ( !m_hDbg )
  585. {
  586. return false;
  587. }
  588. //!! SUSPENDS THE APP UNTIL THE DEBUGGER CLIENT CONNECTS
  589. return SQ_SUCCEEDED(sq_rdbg_waitforconnections(m_hDbg));
  590. }
  591. return false;
  592. }
  593. //-------------------------------------------------------------
  594. //
  595. //-------------------------------------------------------------
  596. void DisconnectDebugger()
  597. {
  598. if ( m_hDbg )
  599. {
  600. sq_rdbg_shutdown( m_hDbg );
  601. m_hDbg = NULL;
  602. }
  603. }
  604. //-------------------------------------------------------------
  605. //
  606. //-------------------------------------------------------------
  607. ScriptStatus_t Run( const char *pszScript, bool bWait = true )
  608. {
  609. Assert( bWait );
  610. if(SQ_SUCCEEDED(sq_compilebuffer(m_hVM,pszScript,(int)V_strlen(pszScript)*sizeof(SQChar),"unnamed",1)))
  611. {
  612. HSQOBJECT hScript;
  613. sq_getstackobj(m_hVM,-1, &hScript);
  614. sq_addref(m_hVM, &hScript );
  615. sq_pop(m_hVM,1);
  616. ScriptStatus_t result = CSquirrelVM::ExecuteFunction( (HSCRIPT)(&hScript), NULL, 0, NULL, NULL, bWait );
  617. sq_release( m_hVM, &hScript );
  618. return result;
  619. }
  620. return SCRIPT_ERROR;
  621. }
  622. //-------------------------------------------------------------
  623. //
  624. //-------------------------------------------------------------
  625. HSCRIPT CompileScript( const char *pszScript, const char *pszId = NULL )
  626. {
  627. if ( !pszScript || !*pszScript )
  628. {
  629. return NULL;
  630. }
  631. if(SQ_SUCCEEDED(sq_compilebuffer(m_hVM,pszScript,(int)V_strlen(pszScript)*sizeof(SQChar),(pszId) ? pszId : "unnamed",1)))
  632. {
  633. HSQOBJECT *pRet = new HSQOBJECT;
  634. sq_getstackobj(m_hVM,-1,pRet);
  635. sq_addref(m_hVM, pRet);
  636. sq_pop(m_hVM,1);
  637. return (HSCRIPT)pRet;
  638. }
  639. return NULL;
  640. }
  641. //-------------------------------------------------------------
  642. //
  643. //-------------------------------------------------------------
  644. void ReleaseScript( HSCRIPT hScript )
  645. {
  646. ReleaseScriptObject( hScript );
  647. }
  648. //-------------------------------------------------------------
  649. //
  650. //-------------------------------------------------------------
  651. ScriptStatus_t Run( HSCRIPT hScript, HSCRIPT hScope = NULL, bool bWait = true )
  652. {
  653. return CSquirrelVM::ExecuteFunction( hScript, NULL, 0, NULL, hScope, bWait );
  654. }
  655. //-------------------------------------------------------------
  656. //
  657. //-------------------------------------------------------------
  658. ScriptStatus_t Run( HSCRIPT hScript, bool bWait )
  659. {
  660. Assert( bWait );
  661. return CSquirrelVM::Run( hScript, (HSCRIPT)NULL, bWait );
  662. }
  663. //-------------------------------------------------------------
  664. //
  665. //-------------------------------------------------------------
  666. HSCRIPT CreateScope( const char *pszScope, HSCRIPT hParent = NULL )
  667. {
  668. if ( !hParent )
  669. {
  670. hParent = (HSCRIPT)&m_hVM->_roottable;
  671. }
  672. HSQOBJECT result;
  673. sq_pushobject( m_hVM, m_hOnCreateScopeFunc );
  674. sq_pushroottable( m_hVM );
  675. sq_pushstring( m_hVM, pszScope, -1 );
  676. sq_pushobject( m_hVM, *((HSQOBJECT *)hParent) );
  677. if ( sq_call( m_hVM, 3, true, SQ_CALL_RAISE_ERROR ) == SQ_OK )
  678. {
  679. sq_getstackobj(m_hVM,-1,&result);
  680. sq_pop(m_hVM,2);
  681. }
  682. else
  683. {
  684. result = _null_;
  685. sq_pop(m_hVM,1);
  686. }
  687. if ( sq_isnull( result ) )
  688. {
  689. return NULL;
  690. }
  691. sq_addref(m_hVM, &result);
  692. HSQOBJECT *pRet = new HSQOBJECT;
  693. *pRet = result;
  694. return (HSCRIPT)pRet;
  695. }
  696. //-------------------------------------------------------------
  697. //
  698. //-------------------------------------------------------------
  699. void ReleaseScope( HSCRIPT hScript )
  700. {
  701. HSQOBJECT &o = *((HSQOBJECT *)hScript);
  702. sq_pushobject( m_hVM, m_hOnReleaseScopeFunc );
  703. sq_pushroottable( m_hVM );
  704. sq_pushobject(m_hVM, o );
  705. sq_call( m_hVM, 2, false, SQ_CALL_RAISE_ERROR );
  706. sq_pop(m_hVM,1);
  707. ReleaseScriptObject( hScript );
  708. }
  709. //-------------------------------------------------------------
  710. //
  711. //-------------------------------------------------------------
  712. HSQOBJECT LookupObject( const char *pszObject, HSCRIPT hScope = NULL, bool bAddRef = true )
  713. {
  714. HSQOBJECT result = { OT_NULL, NULL };
  715. if ( !hScope )
  716. {
  717. sq_pushroottable( m_hVM );
  718. }
  719. else
  720. {
  721. if ( hScope == INVALID_HSCRIPT || *((HSQOBJECT *)hScope) == INVALID_HSQOBJECT || !sq_istable( *((HSQOBJECT *)hScope) ) )
  722. {
  723. return _null_;
  724. }
  725. sq_pushobject( m_hVM, *((HSQOBJECT *)hScope) );
  726. }
  727. sq_pushstring( m_hVM, pszObject, -1 );
  728. if ( sq_get( m_hVM, -2 ) == SQ_OK )
  729. {
  730. sq_getstackobj(m_hVM,-1,&result);
  731. if ( bAddRef )
  732. sq_addref(m_hVM, &result);
  733. sq_pop(m_hVM,1);
  734. }
  735. sq_pop(m_hVM,1);
  736. return result;
  737. }
  738. //-------------------------------------------------------------
  739. //
  740. //-------------------------------------------------------------
  741. HSCRIPT LookupFunction( const char *pszFunction, HSCRIPT hScope = NULL )
  742. {
  743. HSQOBJECT result = LookupObject( pszFunction, hScope );
  744. if ( !sq_isnull( result ) )
  745. {
  746. if ( sq_isclosure(result) )
  747. {
  748. HSQOBJECT *pResult = new HSQOBJECT;
  749. *pResult = result;
  750. return (HSCRIPT)pResult;
  751. }
  752. sq_release( m_hVM, &result );
  753. }
  754. return NULL;
  755. }
  756. //-------------------------------------------------------------
  757. //
  758. //-------------------------------------------------------------
  759. void ReleaseFunction( HSCRIPT hScript )
  760. {
  761. ReleaseScriptObject( hScript );
  762. }
  763. //-------------------------------------------------------------
  764. //
  765. //-------------------------------------------------------------
  766. ScriptStatus_t ExecuteFunction( HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope = NULL, bool bWait = true )
  767. {
  768. if ( hScope == INVALID_HSCRIPT )
  769. {
  770. DevWarning( "Invalid scope handed to script VM\n" );
  771. return SCRIPT_ERROR;
  772. }
  773. if ( m_hDbg )
  774. {
  775. extern bool g_bSqDbgTerminateScript;
  776. if ( g_bSqDbgTerminateScript )
  777. {
  778. DisconnectDebugger();
  779. g_bSqDbgTerminateScript = false;
  780. }
  781. }
  782. Assert( bWait );
  783. if ( hFunction )
  784. {
  785. SQInteger initialTop = m_hVM->_top;
  786. HSQOBJECT &o = *((HSQOBJECT *)hFunction);
  787. Assert( bWait );
  788. sq_pushobject( m_hVM, o);
  789. if ( hScope )
  790. {
  791. if ( hScope == INVALID_HSCRIPT || *((HSQOBJECT *)hScope) == INVALID_HSQOBJECT || !sq_istable( *((HSQOBJECT *)hScope) ) )
  792. {
  793. sq_pop(m_hVM,1);
  794. return SCRIPT_ERROR;
  795. }
  796. sq_pushobject( m_hVM, *((HSQOBJECT *)hScope) );
  797. }
  798. else
  799. {
  800. sq_pushroottable( m_hVM );
  801. }
  802. for ( int i = 0; i < nArgs; i++ )
  803. {
  804. PushVariant( pArgs[i], true );
  805. }
  806. m_TimeStartExecute = Plat_FloatTime();
  807. if (SQ_SUCCEEDED(sq_call(m_hVM,1+nArgs, ( pReturn != NULL ),SQ_CALL_RAISE_ERROR)))
  808. {
  809. m_TimeStartExecute = 0.0f;
  810. if ( pReturn )
  811. {
  812. HSQOBJECT ret;
  813. sq_getstackobj(m_hVM,-1,&ret);
  814. if ( !ConvertToVariant( ret, pReturn ) )
  815. {
  816. DevMsg( "Script function returned unsupported type\n" );
  817. }
  818. sq_pop(m_hVM,2);
  819. }
  820. else
  821. {
  822. sq_pop(m_hVM,1);
  823. }
  824. if ( m_hVM->_top != initialTop )
  825. {
  826. Warning( "Callstack mismatch in VScript/Squirrel!\n" );
  827. Assert( m_hVM->_top == initialTop );
  828. }
  829. if ( !sq_isnull( m_ErrorString ) )
  830. {
  831. if ( sq_isstring( m_ErrorString ) )
  832. {
  833. sq_throwerror( m_hVM, m_ErrorString._unVal.pString->_val );
  834. }
  835. else
  836. {
  837. sq_throwerror( m_hVM, "Internal error" );
  838. }
  839. m_ErrorString = _null_;
  840. return SCRIPT_ERROR;
  841. }
  842. return SCRIPT_DONE;
  843. }
  844. m_TimeStartExecute = 0.0f;
  845. sq_pop(m_hVM,1);
  846. }
  847. if ( pReturn )
  848. {
  849. pReturn->m_type = FIELD_VOID;
  850. }
  851. return SCRIPT_ERROR;
  852. }
  853. //-------------------------------------------------------------
  854. //
  855. //-------------------------------------------------------------
  856. void RegisterFunction( ScriptFunctionBinding_t *pScriptFunction )
  857. {
  858. sq_pushroottable( m_hVM );
  859. RegisterFunctionGuts( pScriptFunction );
  860. sq_pop( m_hVM, 1 );
  861. }
  862. //-------------------------------------------------------------
  863. //
  864. //-------------------------------------------------------------
  865. virtual bool RegisterClass( ScriptClassDesc_t *pClassDesc )
  866. {
  867. COMPILE_TIME_ASSERT( sizeof(pClassDesc) == sizeof(intptr_t) );
  868. if ( m_TypeMap.Find( (intptr_t)pClassDesc ) != m_TypeMap.InvalidHandle() )
  869. {
  870. return true;
  871. }
  872. sq_pushroottable( m_hVM );
  873. sq_pushstring( m_hVM, pClassDesc->m_pszScriptName, -1 );
  874. if ( sq_get( m_hVM, -2 ) == SQ_OK )
  875. {
  876. sq_pop( m_hVM, 2 );
  877. return false;
  878. }
  879. sq_pop( m_hVM, 1 );
  880. if ( pClassDesc->m_pBaseDesc )
  881. {
  882. CSquirrelVM::RegisterClass( pClassDesc->m_pBaseDesc );
  883. }
  884. int top = sq_gettop(m_hVM);
  885. HSQOBJECT newClass;
  886. newClass = CreateClass( pClassDesc );
  887. if ( newClass != INVALID_HSQOBJECT )
  888. {
  889. sq_pushobject( m_hVM, newClass );
  890. if ( pClassDesc->m_pfnConstruct )
  891. {
  892. sq_pushstring( m_hVM, "constructor", -1 );
  893. void **pUserData = (void **)sq_newuserdata(m_hVM, sizeof(void *));
  894. *pUserData = pClassDesc;
  895. sq_newclosure( m_hVM, &CallConstructor, 1 );
  896. sq_createslot( m_hVM, -3 );
  897. }
  898. sq_pushstring( m_hVM, "_tostring", -1 );
  899. sq_newclosure( m_hVM, &InstanceToString, 0 );
  900. sq_createslot( m_hVM, -3 );
  901. sq_pushstring( m_hVM, "IsValid", -1 );
  902. sq_newclosure( m_hVM, &InstanceIsValid, 0 );
  903. sq_createslot( m_hVM, -3 );
  904. for ( int i = 0; i < pClassDesc->m_FunctionBindings.Count(); i++ )
  905. {
  906. RegisterFunctionGuts( &pClassDesc->m_FunctionBindings[i], pClassDesc );
  907. }
  908. sq_pop( m_hVM, 1 );
  909. // more setup required for inheritance?
  910. }
  911. sq_settop(m_hVM, top);
  912. m_TypeMap.Insert( (intptr_t)pClassDesc, newClass._unVal.pClass );
  913. return true;
  914. }
  915. //-------------------------------------------------------------
  916. //
  917. //-------------------------------------------------------------
  918. bool CreateNativeInstance( ScriptClassDesc_t *pDesc, SQUserPointer ud,SQRELEASEHOOK hook )
  919. {
  920. sq_pushobject( m_hVM, SQObjectPtr(m_TypeMap[m_TypeMap.Find((intptr_t)pDesc)]) );
  921. if(SQ_FAILED(sq_createinstance(m_hVM,-1)))
  922. {
  923. sq_pop( m_hVM, 1 );
  924. return false;
  925. }
  926. sq_remove(m_hVM,-2); //removes the class
  927. if(SQ_FAILED(sq_setinstanceup(m_hVM,-1,ud)))
  928. {
  929. return false;
  930. }
  931. sq_setreleasehook(m_hVM,-1,hook);
  932. return TRUE;
  933. }
  934. //-------------------------------------------------------------
  935. //
  936. //-------------------------------------------------------------
  937. HSCRIPT RegisterInstance( ScriptClassDesc_t *pDesc, void *pInstance )
  938. {
  939. if ( !CSquirrelVM::RegisterClass( pDesc ) )
  940. {
  941. return NULL;
  942. }
  943. InstanceContext_t *pInstanceContext = new InstanceContext_t;
  944. pInstanceContext->pInstance = pInstance;
  945. pInstanceContext->pClassDesc = pDesc;
  946. pInstanceContext->name = _null_;
  947. if ( !CreateNativeInstance( pDesc, pInstanceContext, &ExternalInstanceReleaseHook ) )
  948. {
  949. delete pInstanceContext;
  950. return NULL;
  951. }
  952. HSQOBJECT hObject;
  953. sq_getstackobj(m_hVM,-1,&hObject);
  954. sq_addref( m_hVM, &hObject );
  955. sq_pop( m_hVM, 1 );
  956. HSQOBJECT *pResult = new HSQOBJECT;
  957. *pResult = hObject;
  958. return (HSCRIPT)pResult;
  959. }
  960. //-------------------------------------------------------------
  961. //
  962. //-------------------------------------------------------------
  963. void SetInstanceUniqeId( HSCRIPT hInstance, const char *pszId )
  964. {
  965. if ( !hInstance )
  966. {
  967. ExecuteOnce( DevMsg( "NULL instance passed to vscript!\n" ) );
  968. return;
  969. }
  970. HSQOBJECT *pInstance = (HSQOBJECT *)hInstance;
  971. Assert( pInstance->_type == OT_INSTANCE );
  972. if ( pInstance->_type == OT_INSTANCE )
  973. ((InstanceContext_t *)(pInstance->_unVal.pInstance->_userpointer))->name = SQString::Create( _ss(m_hVM), pszId );
  974. }
  975. //-------------------------------------------------------------
  976. //
  977. //-------------------------------------------------------------
  978. void RemoveInstance( HSCRIPT hInstance )
  979. {
  980. if ( !hInstance )
  981. {
  982. ExecuteOnce( DevMsg( "NULL instance passed to vscript!\n" ) );
  983. return;
  984. }
  985. HSQOBJECT *pInstance = (HSQOBJECT *)hInstance;
  986. Assert( pInstance->_type == OT_INSTANCE );
  987. if ( pInstance->_type == OT_INSTANCE )
  988. ((InstanceContext_t *)(pInstance->_unVal.pInstance->_userpointer))->pInstance = NULL;
  989. ReleaseScriptObject( hInstance );
  990. }
  991. //-------------------------------------------------------------
  992. //
  993. //-------------------------------------------------------------
  994. void *GetInstanceValue( HSCRIPT hInstance, ScriptClassDesc_t *pExpectedType )
  995. {
  996. if ( !hInstance )
  997. {
  998. ExecuteOnce( DevMsg( "NULL instance passed to vscript!\n" ) );
  999. return NULL;
  1000. }
  1001. HSQOBJECT *pInstance = (HSQOBJECT *)hInstance;
  1002. if ( pInstance->_type == OT_INSTANCE && pInstance->_unVal.pInstance->_userpointer )
  1003. {
  1004. InstanceContext_t *pContext = ((InstanceContext_t *)(pInstance->_unVal.pInstance->_userpointer));
  1005. if ( !pExpectedType || pContext->pClassDesc == pExpectedType || IsClassDerivedFrom( pContext->pClassDesc, pExpectedType ) )
  1006. return pContext->pInstance;
  1007. }
  1008. return NULL;
  1009. }
  1010. //-------------------------------------------------------------
  1011. //
  1012. //-------------------------------------------------------------
  1013. bool IsClassDerivedFrom( const ScriptClassDesc_t *pDerivedClass, const ScriptClassDesc_t *pBaseClass )
  1014. {
  1015. const ScriptClassDesc_t* pType = pDerivedClass->m_pBaseDesc;
  1016. while ( pType )
  1017. {
  1018. if ( pType == pBaseClass )
  1019. return true;
  1020. pType = pType->m_pBaseDesc;
  1021. }
  1022. return false;
  1023. }
  1024. //-------------------------------------------------------------
  1025. //
  1026. //-------------------------------------------------------------
  1027. bool GenerateUniqueKey( const char *pszRoot, char *pBuf, int nBufSize )
  1028. {
  1029. Assert( V_strlen(pszRoot) + 40 + 1 <= nBufSize );
  1030. if ( V_strlen(pszRoot) + 40 + 1 <= nBufSize )
  1031. {
  1032. Q_snprintf( pBuf, nBufSize, "%x%x%llx_%s", RandomInt(0, 0xfff), Plat_MSTime(), m_iUniqueIdSerialNumber++, pszRoot ); // random to limit key compare when serial number gets large
  1033. return true;
  1034. }
  1035. Error( "GenerateUniqueKey: buffer too small" );
  1036. if ( nBufSize )
  1037. {
  1038. *pBuf = 0;
  1039. }
  1040. return false;
  1041. }
  1042. //-------------------------------------------------------------
  1043. //
  1044. //-------------------------------------------------------------
  1045. virtual bool ValueExists( HSCRIPT hScope, const char *pszKey )
  1046. {
  1047. return !sq_isnull( LookupObject( pszKey, hScope, false ) );
  1048. }
  1049. bool SetValue( HSCRIPT hScope, const char *pszKey, const char *pszValue )
  1050. {
  1051. if ( !hScope )
  1052. {
  1053. sq_pushroottable( m_hVM );
  1054. }
  1055. else
  1056. {
  1057. if ( hScope == INVALID_HSCRIPT || *((HSQOBJECT *)hScope) == INVALID_HSQOBJECT || !sq_istable( *((HSQOBJECT *)hScope) ) )
  1058. {
  1059. return false;
  1060. }
  1061. sq_pushobject( m_hVM, *((HSQOBJECT *)hScope) );
  1062. }
  1063. sq_pushstring( m_hVM, pszKey, -1 );
  1064. sq_pushstring( m_hVM, pszValue, -1 );
  1065. sq_createslot( m_hVM, -3 );
  1066. sq_pop( m_hVM, 1 );
  1067. return true;
  1068. }
  1069. //-------------------------------------------------------------
  1070. //
  1071. //-------------------------------------------------------------
  1072. bool SetValue( HSCRIPT hScope, const char *pszKey, const ScriptVariant_t &value )
  1073. {
  1074. if ( !hScope )
  1075. {
  1076. sq_pushroottable( m_hVM );
  1077. }
  1078. else
  1079. {
  1080. if ( hScope == INVALID_HSCRIPT || *((HSQOBJECT *)hScope) == INVALID_HSQOBJECT || !sq_istable( *((HSQOBJECT *)hScope) ) )
  1081. {
  1082. return false;
  1083. }
  1084. sq_pushobject( m_hVM, *((HSQOBJECT *)hScope) );
  1085. }
  1086. sq_pushstring( m_hVM, pszKey, -1 );
  1087. if ( value.m_type == FIELD_HSCRIPT && value.m_hScript )
  1088. {
  1089. HSQOBJECT hObject = *((HSQOBJECT *)value.m_hScript);
  1090. if ( sq_isinstance( hObject ) )
  1091. {
  1092. SQInstance *pInstance = hObject._unVal.pInstance;
  1093. if ( pInstance->_class->_typetag && pInstance->_class->_typetag != TYPETAG_VECTOR )
  1094. {
  1095. InstanceContext_t *pContext = (InstanceContext_t *)pInstance->_userpointer;
  1096. if ( sq_isnull( pContext->name ) )
  1097. {
  1098. pContext->name = m_hVM->_stack[m_hVM->_top - 1];
  1099. }
  1100. }
  1101. }
  1102. }
  1103. PushVariant( value, true );
  1104. sq_createslot( m_hVM, -3 );
  1105. sq_pop(m_hVM,1);
  1106. return true;
  1107. }
  1108. void CreateTable( ScriptVariant_t &Table )
  1109. {
  1110. HSQOBJECT hObject;
  1111. sq_newtable( m_hVM );
  1112. sq_getstackobj(m_hVM, -1, &hObject );
  1113. sq_addref( m_hVM, &hObject );
  1114. ConvertToVariant( hObject, &Table );
  1115. sq_pop( m_hVM, 1 );
  1116. }
  1117. //------------------------------------------------------------------------------
  1118. // Purpose: returns the number of elements in the table
  1119. // Input : hScope - the table
  1120. // Output : returns the number of elements in the table
  1121. //------------------------------------------------------------------------------
  1122. int GetNumTableEntries( HSCRIPT hScope )
  1123. {
  1124. if ( !hScope )
  1125. {
  1126. sq_pushroottable( m_hVM );
  1127. }
  1128. else
  1129. {
  1130. if ( hScope == INVALID_HSCRIPT || *((HSQOBJECT *)hScope) == INVALID_HSQOBJECT || !sq_istable( *((HSQOBJECT *)hScope) ) )
  1131. {
  1132. return 0;
  1133. }
  1134. sq_pushobject( m_hVM, *((HSQOBJECT *)hScope) );
  1135. }
  1136. int nCount = sq_getsize( m_hVM, -1 );
  1137. sq_pop( m_hVM , 1 );
  1138. return nCount;
  1139. }
  1140. //------------------------------------------------------------------------------
  1141. // Purpose: Gets a key / value pair from the table
  1142. // Input : hScope - the table
  1143. // nInterator - the current location inside of the table. NOTE this is nota linear representation
  1144. // Output : returns the next iterator spot, otherwise -1 if error or end of table
  1145. // pKey - the key entry
  1146. // pValue - the value entry
  1147. //------------------------------------------------------------------------------
  1148. virtual int GetKeyValue( HSCRIPT hScope, int nIterator, ScriptVariant_t *pKey, ScriptVariant_t *pValue )
  1149. {
  1150. HSQOBJECT KeyResult = { OT_NULL, NULL };
  1151. HSQOBJECT ValueResult = { OT_NULL, NULL };
  1152. if ( !hScope )
  1153. {
  1154. sq_pushroottable( m_hVM );
  1155. }
  1156. else
  1157. {
  1158. if ( hScope == INVALID_HSCRIPT || *((HSQOBJECT *)hScope) == INVALID_HSQOBJECT || !sq_istable( *((HSQOBJECT *)hScope) ) )
  1159. {
  1160. return -1;
  1161. }
  1162. sq_pushobject( m_hVM, *((HSQOBJECT *)hScope) );
  1163. }
  1164. intp nReturnValue;
  1165. sq_pushinteger(m_hVM, nIterator);
  1166. if ( SQ_SUCCEEDED(sq_next(m_hVM,-2) ) )
  1167. {
  1168. sq_getstackobj(m_hVM,-2, &KeyResult );
  1169. sq_getstackobj(m_hVM,-1, &ValueResult );
  1170. sq_addref( m_hVM,&KeyResult );
  1171. sq_addref( m_hVM,&ValueResult );
  1172. ConvertToVariant( KeyResult, pKey );
  1173. ConvertToVariant( ValueResult, pValue );
  1174. sq_pop(m_hVM,2); //pops key and val before the nex iteration
  1175. sq_getinteger(m_hVM, -1, &nReturnValue);
  1176. }
  1177. else
  1178. {
  1179. nReturnValue = -1;
  1180. }
  1181. sq_pop( m_hVM, 1 ); //pops the null iterator
  1182. sq_pop( m_hVM, 1 );
  1183. return nReturnValue;
  1184. }
  1185. //-------------------------------------------------------------
  1186. //
  1187. //-------------------------------------------------------------
  1188. bool GetValue( HSCRIPT hScope, const char *pszKey, ScriptVariant_t *pValue )
  1189. {
  1190. HSQOBJECT result = LookupObject( pszKey, hScope );
  1191. if ( ConvertToVariant( result, pValue ) && !sq_isnull( result ) )
  1192. {
  1193. return true;
  1194. }
  1195. __Release( result._type, result._unVal );
  1196. return false;
  1197. }
  1198. //-------------------------------------------------------------
  1199. //
  1200. //-------------------------------------------------------------
  1201. bool ClearValue( HSCRIPT hScope, const char *pszKey )
  1202. {
  1203. if ( !hScope )
  1204. {
  1205. sq_pushroottable( m_hVM );
  1206. }
  1207. else
  1208. {
  1209. if ( hScope == INVALID_HSCRIPT || *((HSQOBJECT *)hScope) == INVALID_HSQOBJECT || !sq_istable( *((HSQOBJECT *)hScope) ) )
  1210. {
  1211. return false;
  1212. }
  1213. sq_pushobject( m_hVM, *((HSQOBJECT *)hScope) );
  1214. }
  1215. sq_pushstring( m_hVM, pszKey, -1 );
  1216. sq_deleteslot( m_hVM, -2, false );
  1217. sq_pop(m_hVM,1);
  1218. return false;
  1219. }
  1220. //-------------------------------------------------------------
  1221. //
  1222. //-------------------------------------------------------------
  1223. virtual void ReleaseValue( ScriptVariant_t &value )
  1224. {
  1225. if ( value.m_type == FIELD_HSCRIPT )
  1226. {
  1227. sq_release( m_hVM, (HSQOBJECT *)value.m_hScript );
  1228. delete ((HSQOBJECT *)value.m_hScript);
  1229. }
  1230. else
  1231. {
  1232. value.Free();
  1233. }
  1234. value.m_type = FIELD_VOID;
  1235. }
  1236. //-------------------------------------------------------------
  1237. //
  1238. //-------------------------------------------------------------
  1239. virtual bool RaiseException( const char *pszExceptionText )
  1240. {
  1241. m_ErrorString = SQString::Create( m_hVM->_sharedstate, pszExceptionText );
  1242. return true;
  1243. }
  1244. //-------------------------------------------------------------
  1245. //
  1246. //-------------------------------------------------------------
  1247. virtual void DumpState()
  1248. {
  1249. struct CIterator : public CSQStateIterator
  1250. {
  1251. CIterator( HSQUIRRELVM hVM )
  1252. {
  1253. indent = 0;
  1254. m_hVM = hVM;
  1255. m_bKey = false;
  1256. }
  1257. void Indent()
  1258. {
  1259. for ( int i = 0; i < indent; i++)
  1260. {
  1261. Msg( " " );
  1262. }
  1263. }
  1264. virtual void PsuedoKey( const char *pszPsuedoKey )
  1265. {
  1266. Indent();
  1267. Msg( "%s: ", pszPsuedoKey );
  1268. m_bKey = true;
  1269. }
  1270. virtual void Key( SQObjectPtr &key )
  1271. {
  1272. Indent();
  1273. SQObjectPtr res;
  1274. m_hVM->ToString( key, res );
  1275. Msg( "%s: ", res._unVal.pString->_val );
  1276. m_bKey = true;
  1277. }
  1278. virtual void Value( SQObjectPtr &value )
  1279. {
  1280. if ( !m_bKey )
  1281. {
  1282. Indent();
  1283. }
  1284. m_bKey = false;
  1285. SQObjectPtr res;
  1286. m_hVM->ToString( value, res );
  1287. if ( ISREFCOUNTED(value._type) )
  1288. Msg( "%s [%d]\n", res._unVal.pString->_val, value._unVal.pRefCounted->_uiRef );
  1289. else
  1290. Msg( "%s\n", res._unVal.pString->_val );
  1291. }
  1292. virtual bool BeginContained()
  1293. {
  1294. if ( m_bKey )
  1295. {
  1296. Msg( "\n" );
  1297. }
  1298. m_bKey = false;
  1299. Indent();
  1300. Msg( "{\n" );
  1301. indent++;
  1302. return true;
  1303. }
  1304. virtual void EndContained()
  1305. {
  1306. indent--;
  1307. Indent();
  1308. Msg( "}\n" );
  1309. }
  1310. int indent;
  1311. HSQUIRRELVM m_hVM;
  1312. bool m_bKey;
  1313. };
  1314. CIterator iter( m_hVM );
  1315. m_hVM->_sharedstate->Iterate( m_hVM, &iter );
  1316. }
  1317. //-------------------------------------------------------------
  1318. //
  1319. //-------------------------------------------------------------
  1320. virtual void WriteState( CUtlBuffer *pBuffer)
  1321. {
  1322. #ifdef VSQUIRREL_DEBUG_SERIALIZATION
  1323. Msg( "BEGIN WRITE\n" );
  1324. #endif
  1325. m_pBuffer = pBuffer;
  1326. sq_collectgarbage( m_hVM );
  1327. m_pBuffer->PutInt( SAVEVERSION );
  1328. m_pBuffer->PutInt64( (int64)m_iUniqueIdSerialNumber );
  1329. WriteVM( m_hVM );
  1330. m_pBuffer = NULL;
  1331. SQCollectable *t = m_hVM->_sharedstate->_gc_chain;
  1332. while(t)
  1333. {
  1334. t->UnMark();
  1335. t = t->_next;
  1336. }
  1337. m_PtrMap.Purge();
  1338. }
  1339. //-------------------------------------------------------------
  1340. //
  1341. //-------------------------------------------------------------
  1342. virtual void ReadState( CUtlBuffer *pBuffer )
  1343. {
  1344. #ifdef VSQUIRREL_DEBUG_SERIALIZATION
  1345. #ifdef VSQUIRREL_DEBUG_SERIALIZATION_HEAPCHK
  1346. g_pMemAlloc->CrtCheckMemory();
  1347. int flags = g_pMemAlloc->CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
  1348. g_pMemAlloc->CrtSetDbgFlag( flags | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_CHECK_CRT_DF );
  1349. #endif
  1350. Msg( "BEGIN READ\n" );
  1351. #endif
  1352. if ( pBuffer->GetInt() != SAVEVERSION )
  1353. {
  1354. DevMsg( "Incompatible script version\n" );
  1355. return;
  1356. }
  1357. sq_collectgarbage( m_hVM );
  1358. m_hVM->_sharedstate->_gc_disableDepth++;
  1359. m_pBuffer = pBuffer;
  1360. uint64 uniqueIdSerialNumber = (uint64)m_pBuffer->GetInt64();
  1361. m_iUniqueIdSerialNumber = max( m_iUniqueIdSerialNumber, uniqueIdSerialNumber );
  1362. Verify( pBuffer->GetInt() == OT_THREAD );
  1363. m_PtrMap.Insert( pBuffer->GetPtr(), m_hVM );
  1364. ReadVM( m_hVM );
  1365. m_pBuffer = NULL;
  1366. m_PtrMap.Purge();
  1367. m_hVM->_sharedstate->_gc_disableDepth--;
  1368. sq_collectgarbage( m_hVM );
  1369. #ifdef VSQUIRREL_DEBUG_SERIALIZATION_HEAPCHK
  1370. g_pMemAlloc->CrtSetDbgFlag( flags );
  1371. #endif
  1372. }
  1373. //-------------------------------------------------------------
  1374. //
  1375. //-------------------------------------------------------------
  1376. virtual void RemoveOrphanInstances()
  1377. {
  1378. }
  1379. //-------------------------------------------------------------
  1380. //
  1381. //-------------------------------------------------------------
  1382. virtual void SetOutputCallback( ScriptOutputFunc_t pFunc )
  1383. {
  1384. }
  1385. //-------------------------------------------------------------
  1386. //
  1387. //-------------------------------------------------------------
  1388. virtual void SetErrorCallback( ScriptErrorFunc_t pFunc )
  1389. {
  1390. }
  1391. private:
  1392. struct InstanceContext_t
  1393. {
  1394. void *pInstance;
  1395. ScriptClassDesc_t *pClassDesc;
  1396. SQObjectPtr name;
  1397. };
  1398. //---------------------------------------------------------
  1399. // Callbacks
  1400. //---------------------------------------------------------
  1401. static void PrintFunc(HSQUIRRELVM m_hVM,const SQChar* s,...)
  1402. {
  1403. char string[2048];
  1404. va_list argptr;
  1405. va_start (argptr,s);
  1406. Q_vsnprintf (string,sizeof(string),s,argptr);
  1407. va_end (argptr);
  1408. Msg( "%s", string );
  1409. }
  1410. //-------------------------------------------------------------
  1411. //
  1412. //-------------------------------------------------------------
  1413. static SQInteger ReleaseHook( SQUserPointer p, SQInteger size )
  1414. {
  1415. InstanceContext_t *pInstanceContext = (InstanceContext_t *)p;
  1416. pInstanceContext->pClassDesc->m_pfnDestruct( pInstanceContext->pInstance );
  1417. delete pInstanceContext;
  1418. return 0;
  1419. }
  1420. //-------------------------------------------------------------
  1421. //
  1422. //-------------------------------------------------------------
  1423. static SQInteger ExternalInstanceReleaseHook( SQUserPointer p, SQInteger size )
  1424. {
  1425. InstanceContext_t *pInstanceContext = (InstanceContext_t *)p;
  1426. delete pInstanceContext;
  1427. return 0;
  1428. }
  1429. //-------------------------------------------------------------
  1430. //
  1431. //-------------------------------------------------------------
  1432. static SQInteger GetFunctionSignature( HSQUIRRELVM hVM )
  1433. {
  1434. StackHandler sa(hVM);
  1435. if ( sa.GetParamCount() != 3 )
  1436. {
  1437. return 0;
  1438. }
  1439. HSQOBJECT hFunction = sa.GetObjectHandle( 2 );
  1440. if ( !sq_isclosure( hFunction ) )
  1441. {
  1442. return 0;
  1443. }
  1444. char result[ 512 ] = {0};
  1445. const char *pszName = sa.GetString( 3 );
  1446. SQClosure *pClosure = hFunction._unVal.pClosure;
  1447. SQFunctionProto *pProto = pClosure->_function._unVal.pFunctionProto;
  1448. V_strcat_safe( result,
  1449. "function " );
  1450. if ( pszName && *pszName )
  1451. {
  1452. V_strcat_safe( result,
  1453. pszName );
  1454. }
  1455. else if ( sq_isstring( pProto->_name ) )
  1456. {
  1457. V_strcat_safe( result,
  1458. pProto->_name._unVal.pString->_val );
  1459. }
  1460. else
  1461. {
  1462. V_strcat_safe( result,
  1463. "<unnamed>" );
  1464. }
  1465. V_strcat_safe( result,
  1466. "(" );
  1467. for ( int i = 1; i < pProto->_nparameters; i++ )
  1468. {
  1469. if ( i != 1 )
  1470. {
  1471. V_strcat_safe( result,
  1472. ", " );
  1473. }
  1474. if ( sq_isstring( pProto->_parameters[i] ) )
  1475. {
  1476. V_strcat_safe( result,
  1477. pProto->_parameters[i]._unVal.pString->_val );
  1478. }
  1479. else
  1480. {
  1481. V_strcat_safe( result,
  1482. "arg" );
  1483. }
  1484. }
  1485. V_strcat_safe( result,
  1486. ")" );
  1487. result[ sizeof( result ) - 1 ] = 0;
  1488. sa.Return( result );
  1489. return 1;
  1490. }
  1491. //-------------------------------------------------------------
  1492. //
  1493. //-------------------------------------------------------------
  1494. static SQInteger GetDeveloper( HSQUIRRELVM hVM )
  1495. {
  1496. StackHandler sa(hVM);
  1497. sa.Return( ((CSquirrelVM *)hVM->_sharedstate->m_pOwnerData)->developer.GetInt() );
  1498. return 1;
  1499. }
  1500. //-------------------------------------------------------------
  1501. //
  1502. //-------------------------------------------------------------
  1503. static SQInteger CallConstructor( HSQUIRRELVM hVM )
  1504. {
  1505. StackHandler sa(hVM);
  1506. int nActualParams = sa.GetParamCount();
  1507. ScriptClassDesc_t *pClassDesc = *((ScriptClassDesc_t **)sa.GetUserData( nActualParams ));
  1508. InstanceContext_t *pInstanceContext = new InstanceContext_t;
  1509. pInstanceContext->pInstance = pClassDesc->m_pfnConstruct();
  1510. pInstanceContext->pClassDesc = pClassDesc;
  1511. sq_setinstanceup(hVM, 1, pInstanceContext);
  1512. sq_setreleasehook( hVM, 1, &ReleaseHook );
  1513. return 0;
  1514. }
  1515. //-------------------------------------------------------------
  1516. //
  1517. //-------------------------------------------------------------
  1518. static SQInteger TranslateCall( HSQUIRRELVM hVM )
  1519. {
  1520. StackHandler sa(hVM);
  1521. int nActualParams = sa.GetParamCount();
  1522. ScriptFunctionBinding_t *pVMScriptFunction = *((ScriptFunctionBinding_t **)sa.GetUserData( nActualParams ));
  1523. int nFormalParams = pVMScriptFunction->m_desc.m_Parameters.Count();
  1524. CUtlVectorFixed<ScriptVariant_t, 14> params;
  1525. ScriptVariant_t returnValue;
  1526. bool bCallFree = false;
  1527. params.SetSize( nFormalParams );
  1528. int i = 0;
  1529. if ( nActualParams )
  1530. {
  1531. int iLimit = MIN( nActualParams, nFormalParams );
  1532. ScriptDataType_t *pCurParamType = pVMScriptFunction->m_desc.m_Parameters.Base();
  1533. for ( i = 0; i < iLimit; i++, pCurParamType++ )
  1534. {
  1535. switch ( *pCurParamType )
  1536. {
  1537. case FIELD_FLOAT: params[i] = sa.GetFloat( i + 2 ); break;
  1538. case FIELD_CSTRING: params[i] = sa.GetString( i + 2 ); break;
  1539. case FIELD_VECTOR:
  1540. {
  1541. Vector *pVector = (Vector *)sa.GetInstanceUp( i + 2, TYPETAG_VECTOR );
  1542. if ( pVector )
  1543. {
  1544. params[i] = pVector;
  1545. break;
  1546. }
  1547. else
  1548. {
  1549. sq_throwerror( hVM, "Vector argument expected" );
  1550. return SQ_ERROR;
  1551. }
  1552. }
  1553. case FIELD_INTEGER: params[i] = sa.GetInt( i + 2 ); break;
  1554. case FIELD_BOOLEAN: params[i] = sa.GetBool( i + 2 ); break;
  1555. case FIELD_CHARACTER: params[i] = sa.GetString( i + 2 )[0]; break;
  1556. case FIELD_HSCRIPT:
  1557. {
  1558. HSQOBJECT object = sa.GetObjectHandle( i+2 );
  1559. if ( object._type == OT_NULL)
  1560. {
  1561. params[i] = (HSCRIPT)NULL;
  1562. }
  1563. else
  1564. {
  1565. HSQOBJECT *pObject = new HSQOBJECT;
  1566. *pObject = object;
  1567. params[i] = (HSCRIPT)pObject;
  1568. params[i].m_flags |= SV_FREE;
  1569. bCallFree = true;
  1570. }
  1571. break;
  1572. }
  1573. default: break;
  1574. }
  1575. }
  1576. }
  1577. #ifdef _DEBUG
  1578. for ( ; i < nFormalParams; i++ )
  1579. {
  1580. Assert( params[i].IsNull() );
  1581. }
  1582. #endif
  1583. InstanceContext_t *pContext;
  1584. void *pObject;
  1585. if ( pVMScriptFunction->m_flags & SF_MEMBER_FUNC )
  1586. {
  1587. pContext = (InstanceContext_t *)sa.GetInstanceUp(1,0);
  1588. if ( !pContext )
  1589. {
  1590. sq_throwerror( hVM, "Accessed null instance" );
  1591. return SQ_ERROR;
  1592. }
  1593. pObject = pContext->pInstance;
  1594. if ( !pObject )
  1595. {
  1596. sq_throwerror( hVM, "Accessed null instance" );
  1597. return SQ_ERROR;
  1598. }
  1599. if ( pContext->pClassDesc->pHelper )
  1600. {
  1601. pObject = pContext->pClassDesc->pHelper->GetProxied( pObject );
  1602. }
  1603. if ( !pObject )
  1604. {
  1605. sq_throwerror( hVM, "Accessed null instance" );
  1606. return SQ_ERROR;
  1607. }
  1608. }
  1609. else
  1610. {
  1611. pObject = NULL;
  1612. }
  1613. (*pVMScriptFunction->m_pfnBinding)( pVMScriptFunction->m_pFunction, pObject, params.Base(), params.Count(), ( pVMScriptFunction->m_desc.m_ReturnType != FIELD_VOID ) ? &returnValue : NULL );
  1614. if ( pVMScriptFunction->m_desc.m_ReturnType != FIELD_VOID )
  1615. {
  1616. switch ( returnValue.m_type )
  1617. {
  1618. case FIELD_FLOAT: sa.Return( (float)returnValue ); break;
  1619. case FIELD_CSTRING: sa.Return( (const char *)returnValue ); break;
  1620. case FIELD_VECTOR:
  1621. {
  1622. sq_pushobject( hVM, ((CSquirrelVM *)hVM->_sharedstate->m_pOwnerData)->m_hClassVector );
  1623. sq_createinstance( hVM, -1 );
  1624. sq_setinstanceup( hVM, -1, (SQUserPointer)returnValue.m_pVector );
  1625. sq_setreleasehook( hVM, -1, &VectorRelease );
  1626. sq_remove( hVM, -2 );
  1627. break;
  1628. }
  1629. case FIELD_INTEGER: sa.Return( (int)returnValue ); break;
  1630. case FIELD_BOOLEAN: sa.Return( (bool)returnValue ); break;
  1631. case FIELD_CHARACTER: Assert( 0 ); sq_pushnull( hVM ); break;
  1632. case FIELD_HSCRIPT:
  1633. {
  1634. if ( returnValue.m_hScript )
  1635. {
  1636. sq_pushobject( hVM, *((HSQOBJECT *)returnValue.m_hScript) );
  1637. }
  1638. else
  1639. {
  1640. sq_pushnull( hVM );
  1641. }
  1642. break;
  1643. }
  1644. default: sq_pushnull( hVM ); break;
  1645. }
  1646. }
  1647. if ( bCallFree )
  1648. {
  1649. for ( i = 0; i < params.Count(); i++ )
  1650. {
  1651. params[i].Free();
  1652. }
  1653. }
  1654. if ( !sq_isnull( ((CSquirrelVM *)hVM->_sharedstate->m_pOwnerData)->m_ErrorString ) )
  1655. {
  1656. if ( sq_isstring( ((CSquirrelVM *)hVM->_sharedstate->m_pOwnerData)->m_ErrorString ) )
  1657. {
  1658. sq_throwerror( hVM, ((CSquirrelVM *)hVM->_sharedstate->m_pOwnerData)->m_ErrorString._unVal.pString->_val );
  1659. }
  1660. else
  1661. {
  1662. sq_throwerror( hVM, "Internal error" );
  1663. }
  1664. ((CSquirrelVM *)hVM->_sharedstate->m_pOwnerData)->m_ErrorString = _null_;
  1665. return SQ_ERROR;
  1666. }
  1667. return ( pVMScriptFunction->m_desc.m_ReturnType != FIELD_VOID );
  1668. }
  1669. //-------------------------------------------------------------
  1670. static int QueryContinue( HSQUIRRELVM hVM )
  1671. {
  1672. CSquirrelVM *pVM = ((CSquirrelVM *)hVM->_sharedstate->m_pOwnerData);
  1673. if ( !pVM->m_hDbg )
  1674. {
  1675. if ( pVM->m_TimeStartExecute != 0.0f && Plat_FloatTime() - pVM->m_TimeStartExecute > 0.03f )
  1676. {
  1677. DevMsg( "Script running too long, terminating\n" );
  1678. // @TODO: Mark the offending closure so that it won't be executed again [5/13/2008 tom]
  1679. return SQ_QUERY_BREAK;
  1680. }
  1681. }
  1682. return SQ_QUERY_CONTINUE;
  1683. }
  1684. //-------------------------------------------------------------
  1685. //
  1686. //-------------------------------------------------------------
  1687. static SQInteger InstanceToString( HSQUIRRELVM hVM )
  1688. {
  1689. StackHandler sa(hVM);
  1690. InstanceContext_t *pContext = (InstanceContext_t *)sa.GetInstanceUp(1,0);
  1691. char szBuf[64];
  1692. if ( pContext && pContext->pInstance && pContext->pClassDesc->pHelper && pContext->pClassDesc->pHelper->ToString( pContext->pInstance, szBuf, ARRAYSIZE(szBuf) ) )
  1693. {
  1694. sa.Return( szBuf );
  1695. }
  1696. else
  1697. {
  1698. HSQOBJECT hInstance = sa.GetObjectHandle( 1 );
  1699. sq_pushstring( hVM, CFmtStr( "(instance : 0x%p)", (void*)_rawval(hInstance) ), -1 );
  1700. }
  1701. return 1;
  1702. }
  1703. //-------------------------------------------------------------
  1704. //
  1705. //-------------------------------------------------------------
  1706. static SQInteger InstanceIsValid( HSQUIRRELVM hVM )
  1707. {
  1708. StackHandler sa(hVM);
  1709. InstanceContext_t *pContext = (InstanceContext_t *)sa.GetInstanceUp(1,0);
  1710. sq_pushbool( hVM, ( pContext && pContext->pInstance ) );
  1711. return 1;
  1712. }
  1713. //-------------------------------------------------------------
  1714. //
  1715. //-------------------------------------------------------------
  1716. HSQOBJECT CreateClass( ScriptClassDesc_t *pDesc )
  1717. {
  1718. int oldtop = sq_gettop(m_hVM);
  1719. sq_pushroottable(m_hVM);
  1720. sq_pushstring(m_hVM,pDesc->m_pszScriptName,-1);
  1721. if (pDesc->m_pBaseDesc)
  1722. {
  1723. sq_pushstring(m_hVM,pDesc->m_pBaseDesc->m_pszScriptName,-1);
  1724. if (SQ_FAILED(sq_get(m_hVM,-3)))
  1725. { // Make sure the base exists if specified by baseName.
  1726. sq_settop(m_hVM,oldtop);
  1727. return INVALID_HSQOBJECT;
  1728. }
  1729. }
  1730. if (SQ_FAILED(sq_newclass(m_hVM,pDesc->m_pBaseDesc ? 1 : 0)))
  1731. { // Will inherit from base class on stack from sq_get() above.
  1732. sq_settop(m_hVM,oldtop);
  1733. return INVALID_HSQOBJECT;
  1734. }
  1735. HSQOBJECT hObject;
  1736. sq_getstackobj(m_hVM,-1, &hObject);
  1737. sq_addref(m_hVM, &hObject);
  1738. sq_settypetag(m_hVM,-1,pDesc);
  1739. sq_createslot(m_hVM,-3);
  1740. sq_pop(m_hVM,1);
  1741. return hObject;
  1742. }
  1743. //-------------------------------------------------------------
  1744. //
  1745. //-------------------------------------------------------------
  1746. void RegisterFunctionGuts( ScriptFunctionBinding_t *pScriptFunction, ScriptClassDesc_t *pClassDesc = NULL )
  1747. {
  1748. char szTypeMask[64];
  1749. if ( pScriptFunction->m_desc.m_Parameters.Count() > ARRAYSIZE(szTypeMask) - 1 )
  1750. {
  1751. AssertMsg1( 0, "Too many agruments for script function %s\n", pScriptFunction->m_desc.m_pszFunction );
  1752. return;
  1753. }
  1754. szTypeMask[0] = '.';
  1755. char *pCurrent = &szTypeMask[1];
  1756. for ( int i = 0; i < pScriptFunction->m_desc.m_Parameters.Count(); i++, pCurrent++ )
  1757. {
  1758. switch ( pScriptFunction->m_desc.m_Parameters[i] )
  1759. {
  1760. case FIELD_CSTRING:
  1761. *pCurrent = 's';
  1762. break;
  1763. case FIELD_FLOAT:
  1764. case FIELD_INTEGER:
  1765. *pCurrent = 'n';
  1766. break;
  1767. case FIELD_BOOLEAN:
  1768. *pCurrent = 'b';
  1769. break;
  1770. case FIELD_VECTOR:
  1771. *pCurrent = 'x';
  1772. break;
  1773. case FIELD_HSCRIPT:
  1774. *pCurrent = '.';
  1775. break;
  1776. case FIELD_CHARACTER:
  1777. default:
  1778. *pCurrent = FIELD_VOID;
  1779. AssertMsg( 0 , "Not supported" );
  1780. break;
  1781. }
  1782. }
  1783. Assert( pCurrent - szTypeMask < ARRAYSIZE(szTypeMask) - 1 );
  1784. *pCurrent = 0;
  1785. sq_pushstring( m_hVM, pScriptFunction->m_desc.m_pszScriptName, -1 );
  1786. ScriptFunctionBinding_t **pVMScriptFunction = (ScriptFunctionBinding_t **)sq_newuserdata(m_hVM, sizeof(ScriptFunctionBinding_t *));
  1787. *pVMScriptFunction = pScriptFunction;
  1788. sq_newclosure( m_hVM, &TranslateCall, 1 );
  1789. HSQOBJECT hFunction;
  1790. sq_getstackobj( m_hVM, -1, &hFunction );
  1791. sq_setnativeclosurename(m_hVM, -1, pScriptFunction->m_desc.m_pszScriptName );
  1792. sq_setparamscheck( m_hVM, pScriptFunction->m_desc.m_Parameters.Count() + 1, szTypeMask );
  1793. sq_createslot( m_hVM, -3 );
  1794. if ( developer.GetInt() )
  1795. {
  1796. const char *pszHide = SCRIPT_HIDE;
  1797. if ( !pScriptFunction->m_desc.m_pszDescription || *pScriptFunction->m_desc.m_pszDescription != *pszHide )
  1798. {
  1799. char name[512] = {0};
  1800. char signature[512] = {0};
  1801. if ( pClassDesc )
  1802. {
  1803. V_strcat_safe( name,
  1804. pClassDesc->m_pszScriptName );
  1805. V_strcat_safe( name,
  1806. "::" );
  1807. }
  1808. V_strcat_safe( name,
  1809. pScriptFunction->m_desc.m_pszScriptName );
  1810. V_strcat_safe( signature,
  1811. FieldTypeToString( pScriptFunction->m_desc.m_ReturnType ) );
  1812. V_strcat_safe( signature,
  1813. " " );
  1814. V_strcat_safe( signature,
  1815. name );
  1816. V_strcat_safe( signature,
  1817. "(" );
  1818. for ( int i = 0; i < pScriptFunction->m_desc.m_Parameters.Count(); i++ )
  1819. {
  1820. if ( i != 0 )
  1821. {
  1822. V_strcat_safe( signature,
  1823. ", " );
  1824. }
  1825. V_strcat_safe( signature,
  1826. FieldTypeToString( pScriptFunction->m_desc.m_Parameters[i] ) );
  1827. }
  1828. V_strcat_safe( signature,
  1829. ")" );
  1830. sq_pushobject( m_hVM, LookupObject( "RegisterFunctionDocumentation", NULL, false ) );
  1831. sq_pushroottable( m_hVM );
  1832. sq_pushobject( m_hVM, hFunction );
  1833. sq_pushstring( m_hVM, name, -1 );
  1834. sq_pushstring( m_hVM, signature, -1 );
  1835. sq_pushstring( m_hVM, pScriptFunction->m_desc.m_pszDescription, -1 );
  1836. sq_call( m_hVM, 5, false, /*false*/ true );
  1837. sq_pop( m_hVM, 1 );
  1838. }
  1839. }
  1840. }
  1841. //-------------------------------------------------------------
  1842. //
  1843. //-------------------------------------------------------------
  1844. void ReleaseScriptObject( HSCRIPT hScript )
  1845. {
  1846. if ( hScript )
  1847. {
  1848. HSQOBJECT *pScript = (HSQOBJECT *)hScript;
  1849. sq_release( m_hVM, pScript );
  1850. delete pScript;
  1851. }
  1852. }
  1853. //-------------------------------------------------------------
  1854. //
  1855. //-------------------------------------------------------------
  1856. void PushVariant( const ScriptVariant_t &value, bool bCopy = false )
  1857. {
  1858. switch ( value.m_type )
  1859. {
  1860. case FIELD_VOID: sq_pushnull( m_hVM ); break;
  1861. case FIELD_FLOAT: sq_pushfloat( m_hVM, value ); break;
  1862. case FIELD_CSTRING: sq_pushstring( m_hVM, value, strlen( value.m_pszString ) ); break;
  1863. case FIELD_VECTOR:
  1864. {
  1865. // @TODO: should make a pool of these and reuse [4/22/2008 tom]
  1866. sq_pushobject( m_hVM, m_hClassVector );
  1867. sq_createinstance( m_hVM, -1 );
  1868. if ( !bCopy )
  1869. {
  1870. sq_setinstanceup( m_hVM, -1, (SQUserPointer)value.m_pVector );
  1871. }
  1872. else
  1873. {
  1874. sq_setinstanceup( m_hVM, -1, (SQUserPointer)new Vector( *value.m_pVector ) );
  1875. sq_setreleasehook( m_hVM, -1, &VectorRelease );
  1876. }
  1877. sq_remove( m_hVM, -2 );
  1878. break;
  1879. }
  1880. case FIELD_INTEGER: sq_pushinteger( m_hVM, value ); break;
  1881. case FIELD_BOOLEAN: sq_pushbool( m_hVM, value.m_bool ); break;
  1882. case FIELD_CHARACTER: { char sz[2]; sz[0] = value.m_char; sz[1] = 0; sq_pushstring( m_hVM, sz, 1 ); break; }
  1883. case FIELD_HSCRIPT: if ( value.m_hScript ) sq_pushobject( m_hVM, *((HSQOBJECT *)value.m_hScript) ); else sq_pushnull( m_hVM ); break;
  1884. }
  1885. }
  1886. //-------------------------------------------------------------
  1887. //
  1888. //-------------------------------------------------------------
  1889. bool ConvertToVariant( HSQOBJECT object, ScriptVariant_t *pReturn )
  1890. {
  1891. switch ( object._type )
  1892. {
  1893. case OT_NULL: pReturn->m_type = FIELD_VOID; break;
  1894. case OT_INTEGER: *pReturn = object._unVal.nInteger; break;
  1895. case OT_FLOAT: *pReturn = object._unVal.fFloat; break;
  1896. case OT_BOOL: *pReturn = (object._unVal.nInteger != 0); break;
  1897. case OT_STRING:
  1898. {
  1899. int size = object._unVal.pString->_len + 1;
  1900. pReturn->m_type = FIELD_CSTRING;
  1901. pReturn->m_pszString = new char[size];
  1902. memcpy( (void *)pReturn->m_pszString, object._unVal.pString->_val, size );
  1903. pReturn->m_flags |= SV_FREE;
  1904. }
  1905. break;
  1906. case OT_INSTANCE:
  1907. {
  1908. SQUserPointer pVector;
  1909. sq_pushobject( m_hVM, object );
  1910. SQRESULT getResult = sq_getinstanceup( m_hVM, -1, &pVector, TYPETAG_VECTOR );
  1911. sq_poptop( m_hVM );
  1912. if ( getResult == SQ_OK )
  1913. {
  1914. pReturn->m_type = FIELD_VECTOR;
  1915. pReturn->m_pVector = new Vector( *((Vector *)pVector) );
  1916. pReturn->m_flags |= SV_FREE;
  1917. break;
  1918. }
  1919. }
  1920. // fall through
  1921. default:
  1922. {
  1923. pReturn->m_type = FIELD_HSCRIPT;
  1924. HSQOBJECT *pObject = new HSQOBJECT;
  1925. *pObject = object;
  1926. pReturn->m_hScript = (HSCRIPT)pObject;
  1927. }
  1928. }
  1929. return true;
  1930. }
  1931. //-------------------------------------------------------------------------
  1932. // Serialization
  1933. //-------------------------------------------------------------------------
  1934. enum
  1935. {
  1936. SAVEVERSION = 2
  1937. };
  1938. void WriteObject( const SQObjectPtr &object )
  1939. {
  1940. switch ( object._type )
  1941. {
  1942. case OT_NULL:
  1943. m_pBuffer->PutInt( OT_NULL );
  1944. break;
  1945. case OT_INTEGER:
  1946. m_pBuffer->PutInt( OT_INTEGER );
  1947. m_pBuffer->PutInt( object._unVal.nInteger );
  1948. break;
  1949. case OT_FLOAT:
  1950. m_pBuffer->PutInt( OT_FLOAT );
  1951. m_pBuffer->PutFloat( object._unVal.fFloat);
  1952. break;
  1953. case OT_BOOL:
  1954. m_pBuffer->PutInt( OT_BOOL );
  1955. m_pBuffer->PutInt( object._unVal.nInteger );
  1956. break;
  1957. case OT_STRING:
  1958. m_pBuffer->PutInt( OT_STRING );
  1959. m_pBuffer->PutInt( object._unVal.pString->_len );
  1960. m_pBuffer->PutString( object._unVal.pString->_val );
  1961. break;
  1962. case OT_TABLE: WriteTable( object._unVal.pTable ); break;
  1963. case OT_ARRAY: WriteArray( object._unVal.pArray ); break;
  1964. case OT_USERDATA: WriteUserData( object._unVal.pUserData ); break;
  1965. case OT_CLOSURE: WriteClosure( object._unVal.pClosure ); break;
  1966. case OT_NATIVECLOSURE: WriteNativeClosure( object._unVal.pNativeClosure ); break;
  1967. case OT_GENERATOR: WriteGenerator( object._unVal.pGenerator ); break;
  1968. case OT_USERPOINTER: WriteUserPointer( object._unVal.pUserPointer ); break;
  1969. case OT_THREAD: WriteVM( object._unVal.pThread ); break;
  1970. case OT_FUNCPROTO: WriteFuncProto( object._unVal.pFunctionProto ); break;
  1971. case OT_CLASS: WriteClass( object._unVal.pClass ); break;
  1972. case OT_INSTANCE: WriteInstance( object._unVal.pInstance ); break;
  1973. case OT_WEAKREF: WriteWeakRef( object._unVal.pWeakRef ); break;
  1974. default: Assert( 0 ); break;
  1975. }
  1976. #ifdef VSQUIRREL_DEBUG_SERIALIZATION
  1977. SQObjectPtr res;
  1978. m_hVM->ToString( object, res );
  1979. Msg( "%d: %s\n", m_pBuffer->TellPut(), res._unVal.pString->_val );
  1980. #endif
  1981. }
  1982. //-------------------------------------------------------------
  1983. //
  1984. //-------------------------------------------------------------
  1985. void WriteVM( SQVM *pVM )
  1986. {
  1987. unsigned i;
  1988. m_pBuffer->PutInt( OT_THREAD );
  1989. m_pBuffer->PutPtr( pVM );
  1990. if ( pVM->_uiRef & MARK_FLAG )
  1991. return;
  1992. pVM->_uiRef |= MARK_FLAG;
  1993. WriteObject( pVM->_roottable );
  1994. m_pBuffer->PutInt( pVM->_top );
  1995. m_pBuffer->PutInt( pVM->_stackbase );
  1996. m_pBuffer->PutUnsignedInt( pVM->_stack.size() );
  1997. for( i = 0; i < pVM->_stack.size(); i++ )
  1998. {
  1999. WriteObject( pVM->_stack[i] );
  2000. }
  2001. m_pBuffer->PutUnsignedInt( pVM->_vargsstack.size() );
  2002. for( i = 0; i < pVM->_vargsstack.size(); i++ )
  2003. {
  2004. WriteObject( pVM->_vargsstack[i] );
  2005. }
  2006. }
  2007. //-------------------------------------------------------------
  2008. //
  2009. //-------------------------------------------------------------
  2010. void WriteArray( SQArray *pArray )
  2011. {
  2012. m_pBuffer->PutInt( OT_ARRAY );
  2013. m_pBuffer->PutPtr( pArray );
  2014. if ( pArray->_uiRef & MARK_FLAG )
  2015. return;
  2016. pArray->_uiRef |= MARK_FLAG;
  2017. int len = pArray->_values.size();
  2018. m_pBuffer->PutInt( len );
  2019. for ( int i = 0; i < len; i++ )
  2020. WriteObject( pArray->_values[i] );
  2021. }
  2022. //-------------------------------------------------------------
  2023. //
  2024. //-------------------------------------------------------------
  2025. void WriteTable( SQTable *pTable )
  2026. {
  2027. m_pBuffer->PutInt( OT_TABLE );
  2028. m_pBuffer->PutPtr( pTable );
  2029. if ( pTable->_uiRef & MARK_FLAG )
  2030. return;
  2031. pTable->_uiRef |= MARK_FLAG;
  2032. m_pBuffer->PutInt( pTable->_delegate != NULL );
  2033. if ( pTable->_delegate )
  2034. {
  2035. WriteObject( pTable->_delegate );
  2036. }
  2037. int len = pTable->_numofnodes;
  2038. m_pBuffer->PutInt( len );
  2039. for(int i = 0; i < len; i++)
  2040. {
  2041. WriteObject( pTable->_nodes[i].key );
  2042. WriteObject( pTable->_nodes[i].val );
  2043. }
  2044. }
  2045. //-------------------------------------------------------------
  2046. //
  2047. //-------------------------------------------------------------
  2048. void WriteClass( SQClass *pClass )
  2049. {
  2050. m_pBuffer->PutInt( OT_CLASS );
  2051. m_pBuffer->PutPtr( pClass );
  2052. if ( !pClass || ( pClass->_uiRef & MARK_FLAG ) )
  2053. return;
  2054. pClass->_uiRef |= MARK_FLAG;
  2055. bool bIsNative = ( pClass->_typetag != NULL );
  2056. unsigned i;
  2057. if ( !bIsNative )
  2058. {
  2059. for( i = 0; i < pClass->_methods.size(); i++)
  2060. {
  2061. if ( sq_isnativeclosure( pClass->_methods[i].val ) )
  2062. {
  2063. bIsNative = true;
  2064. break;
  2065. }
  2066. }
  2067. }
  2068. m_pBuffer->PutInt( bIsNative );
  2069. if ( !bIsNative )
  2070. {
  2071. m_pBuffer->PutInt( pClass->_base != NULL );
  2072. if ( pClass->_base )
  2073. {
  2074. WriteObject( pClass->_base );
  2075. }
  2076. WriteObject( pClass->_members );
  2077. WriteObject( pClass->_attributes );
  2078. m_pBuffer->PutInt( pClass->_defaultvalues.size() );
  2079. for( i = 0; i< pClass->_defaultvalues.size(); i++)
  2080. {
  2081. WriteObject(pClass->_defaultvalues[i].val);
  2082. WriteObject(pClass->_defaultvalues[i].attrs);
  2083. }
  2084. m_pBuffer->PutInt( pClass->_methods.size() );
  2085. for( i = 0; i < pClass->_methods.size(); i++)
  2086. {
  2087. WriteObject(pClass->_methods[i].val);
  2088. WriteObject(pClass->_methods[i].attrs);
  2089. }
  2090. m_pBuffer->PutInt( pClass->_metamethods.size() );
  2091. for( i = 0; i < pClass->_metamethods.size(); i++)
  2092. {
  2093. WriteObject(pClass->_metamethods[i]);
  2094. }
  2095. }
  2096. else
  2097. {
  2098. if ( pClass->_typetag )
  2099. {
  2100. if ( pClass->_typetag == TYPETAG_VECTOR )
  2101. {
  2102. m_pBuffer->PutString( "Vector" );
  2103. }
  2104. else
  2105. {
  2106. ScriptClassDesc_t *pDesc = (ScriptClassDesc_t *)pClass->_typetag;
  2107. m_pBuffer->PutString( pDesc->m_pszScriptName );
  2108. }
  2109. }
  2110. else
  2111. {
  2112. // Have to grovel for the name
  2113. SQObjectPtr key;
  2114. if ( FindKeyForObject( m_hVM->_roottable, pClass, key ) )
  2115. {
  2116. m_pBuffer->PutString( key._unVal.pString->_val );
  2117. }
  2118. else
  2119. {
  2120. Assert( 0 );
  2121. m_pBuffer->PutString( "" );
  2122. }
  2123. }
  2124. }
  2125. }
  2126. //-------------------------------------------------------------
  2127. //
  2128. //-------------------------------------------------------------
  2129. void WriteInstance( SQInstance *pInstance )
  2130. {
  2131. m_pBuffer->PutInt( OT_INSTANCE );
  2132. m_pBuffer->PutPtr( pInstance );
  2133. if ( pInstance->_uiRef & MARK_FLAG )
  2134. return;
  2135. pInstance->_uiRef |= MARK_FLAG;
  2136. WriteObject( pInstance->_class );
  2137. unsigned nvalues = pInstance->_class->_defaultvalues.size();
  2138. m_pBuffer->PutInt( nvalues );
  2139. for ( unsigned i =0; i< nvalues; i++ )
  2140. {
  2141. WriteObject( pInstance->_values[i] );
  2142. }
  2143. m_pBuffer->PutPtr( pInstance->_class->_typetag );
  2144. if ( pInstance->_class->_typetag )
  2145. {
  2146. if ( pInstance->_class->_typetag == TYPETAG_VECTOR )
  2147. {
  2148. Vector *pVector = (Vector *)pInstance->_userpointer;
  2149. m_pBuffer->PutFloat( pVector->x );
  2150. m_pBuffer->PutFloat( pVector->y );
  2151. m_pBuffer->PutFloat( pVector->z );
  2152. }
  2153. else
  2154. {
  2155. InstanceContext_t *pContext = ((InstanceContext_t *)pInstance->_userpointer);
  2156. WriteObject( pContext->name );
  2157. m_pBuffer->PutPtr( pContext->pInstance );
  2158. }
  2159. }
  2160. else
  2161. {
  2162. WriteUserPointer( NULL );
  2163. }
  2164. }
  2165. //-------------------------------------------------------------
  2166. //
  2167. //-------------------------------------------------------------
  2168. void WriteGenerator( SQGenerator *pGenerator )
  2169. {
  2170. ExecuteOnce( Msg( "Save load of generators not well tested. caveat emptor\n" ) );
  2171. WriteObject(pGenerator->_closure);
  2172. m_pBuffer->PutInt( OT_GENERATOR );
  2173. m_pBuffer->PutPtr( pGenerator );
  2174. if ( pGenerator->_uiRef & MARK_FLAG )
  2175. return;
  2176. pGenerator->_uiRef |= MARK_FLAG;
  2177. WriteObject( pGenerator->_closure );
  2178. m_pBuffer->PutInt( pGenerator->_stack.size() );
  2179. for(SQUnsignedInteger i = 0; i < pGenerator->_stack.size(); i++) WriteObject(pGenerator->_stack[i]);
  2180. m_pBuffer->PutInt( pGenerator->_vargsstack.size() );
  2181. for(SQUnsignedInteger j = 0; j < pGenerator->_vargsstack.size(); j++) WriteObject(pGenerator->_vargsstack[j]);
  2182. }
  2183. //-------------------------------------------------------------
  2184. //
  2185. //-------------------------------------------------------------
  2186. void WriteClosure( SQClosure *pClosure )
  2187. {
  2188. m_pBuffer->PutInt( OT_CLOSURE );
  2189. m_pBuffer->PutPtr( pClosure );
  2190. if ( pClosure->_uiRef & MARK_FLAG )
  2191. return;
  2192. pClosure->_uiRef |= MARK_FLAG;
  2193. WriteObject( pClosure->_function );
  2194. WriteObject( pClosure->_env );
  2195. m_pBuffer->PutInt( pClosure->_outervalues.size() );
  2196. for(SQUnsignedInteger i = 0; i < pClosure->_outervalues.size(); i++) WriteObject(pClosure->_outervalues[i]);
  2197. m_pBuffer->PutInt( pClosure->_defaultparams.size() );
  2198. for(SQUnsignedInteger i = 0; i < pClosure->_defaultparams.size(); i++) WriteObject(pClosure->_defaultparams[i]);
  2199. }
  2200. //-------------------------------------------------------------
  2201. //
  2202. //-------------------------------------------------------------
  2203. void WriteNativeClosure( SQNativeClosure *pNativeClosure )
  2204. {
  2205. m_pBuffer->PutInt( OT_NATIVECLOSURE );
  2206. m_pBuffer->PutPtr( pNativeClosure );
  2207. if ( pNativeClosure->_uiRef & MARK_FLAG )
  2208. return;
  2209. pNativeClosure->_uiRef |= MARK_FLAG;
  2210. WriteObject( pNativeClosure->_name );
  2211. return;
  2212. }
  2213. //-------------------------------------------------------------
  2214. //
  2215. //-------------------------------------------------------------
  2216. void WriteUserData( SQUserData *pUserData )
  2217. {
  2218. m_pBuffer->PutInt( OT_USERDATA );
  2219. m_pBuffer->PutPtr( pUserData );
  2220. if ( pUserData->_uiRef & MARK_FLAG )
  2221. return;
  2222. pUserData->_uiRef |= MARK_FLAG;
  2223. // Need to call back or something. Unsure, TBD. [4/3/2008 tom]
  2224. }
  2225. //-------------------------------------------------------------
  2226. //
  2227. //-------------------------------------------------------------
  2228. void WriteUserPointer( SQUserPointer pUserPointer )
  2229. {
  2230. m_pBuffer->PutInt( OT_USERPOINTER );
  2231. // Need to call back or something. Unsure, TBD. [4/3/2008 tom]
  2232. m_pBuffer->PutPtr( pUserPointer );
  2233. }
  2234. //-------------------------------------------------------------
  2235. //
  2236. //-------------------------------------------------------------
  2237. static SQInteger SqWriteFunc(SQUserPointer up,SQUserPointer data, SQInteger size)
  2238. {
  2239. CSquirrelVM *pThis = (CSquirrelVM *)up;
  2240. pThis->m_pBuffer->Put( data, size );
  2241. return size;
  2242. }
  2243. void WriteFuncProto( SQFunctionProto *pFuncProto )
  2244. {
  2245. m_pBuffer->PutInt( OT_FUNCPROTO );
  2246. m_pBuffer->PutPtr( pFuncProto );
  2247. // Using the map to track these as they're not collectables
  2248. if ( m_PtrMap.Find( pFuncProto ) != m_PtrMap.InvalidIndex() )
  2249. {
  2250. return;
  2251. }
  2252. m_PtrMap.Insert( pFuncProto, pFuncProto );
  2253. pFuncProto->Save( m_hVM, this, &SqWriteFunc );
  2254. }
  2255. //-------------------------------------------------------------
  2256. //
  2257. //-------------------------------------------------------------
  2258. void WriteWeakRef( SQWeakRef *pWeakRef )
  2259. {
  2260. m_pBuffer->PutInt( OT_WEAKREF );
  2261. WriteObject( pWeakRef->_obj );
  2262. }
  2263. //--------------------------------------------------------
  2264. template <typename T>
  2265. bool BeginRead( T **ppOld, T **ppNew )
  2266. {
  2267. *ppOld = (T *)m_pBuffer->GetPtr();
  2268. if ( *ppOld )
  2269. {
  2270. int iNew = m_PtrMap.Find( *ppOld );
  2271. if ( iNew != m_PtrMap.InvalidIndex() )
  2272. {
  2273. *ppNew = (T*)m_PtrMap[iNew];
  2274. return false;
  2275. }
  2276. }
  2277. *ppNew = NULL;
  2278. return true;
  2279. }
  2280. //-------------------------------------------------------------
  2281. //
  2282. //-------------------------------------------------------------
  2283. void MapPtr( void *pOld, void *pNew )
  2284. {
  2285. Assert( m_PtrMap.Find( pOld ) == m_PtrMap.InvalidIndex() );
  2286. m_PtrMap.Insert( pOld, pNew );
  2287. }
  2288. //-------------------------------------------------------------
  2289. //
  2290. //-------------------------------------------------------------
  2291. bool ReadObject( SQObjectPtr &objectOut, const char *pszName = NULL )
  2292. {
  2293. SQObject object;
  2294. bool bResult = true;
  2295. object._type = (SQObjectType)m_pBuffer->GetInt();
  2296. if ( _RAW_TYPE(object._type) < _RT_TABLE )
  2297. {
  2298. switch ( object._type )
  2299. {
  2300. case OT_NULL:
  2301. object._unVal.pUserPointer = 0;
  2302. break;
  2303. case OT_INTEGER:
  2304. object._unVal.nInteger = m_pBuffer->GetInt();
  2305. break;
  2306. case OT_FLOAT:
  2307. object._unVal.fFloat = m_pBuffer->GetFloat();
  2308. break;
  2309. case OT_BOOL:
  2310. object._unVal.nInteger = m_pBuffer->GetInt();
  2311. break;
  2312. case OT_STRING:
  2313. {
  2314. int len = m_pBuffer->GetInt();
  2315. char *pString = (char *)stackalloc( len + 1 );
  2316. m_pBuffer->GetString( pString, len + 1 );
  2317. pString[len] = 0;
  2318. object._unVal.pString = SQString::Create( m_hVM->_sharedstate, pString, len );
  2319. break;
  2320. }
  2321. default:
  2322. Assert( 0 );
  2323. break;
  2324. }
  2325. }
  2326. else
  2327. {
  2328. switch ( object._type )
  2329. {
  2330. case OT_TABLE:
  2331. {
  2332. object._unVal.pTable = ReadTable();
  2333. break;
  2334. }
  2335. case OT_ARRAY:
  2336. {
  2337. object._unVal.pArray = ReadArray();
  2338. break;
  2339. }
  2340. case OT_USERDATA:
  2341. {
  2342. object._unVal.pUserData = ReadUserData();
  2343. break;
  2344. }
  2345. case OT_CLOSURE:
  2346. {
  2347. object._unVal.pClosure = ReadClosure();
  2348. break;
  2349. }
  2350. case OT_NATIVECLOSURE:
  2351. {
  2352. object._unVal.pNativeClosure = ReadNativeClosure();
  2353. break;
  2354. }
  2355. case OT_GENERATOR:
  2356. {
  2357. object._unVal.pGenerator = ReadGenerator();
  2358. break;
  2359. }
  2360. case OT_USERPOINTER:
  2361. {
  2362. object._unVal.pUserPointer = ReadUserPointer();
  2363. break;
  2364. }
  2365. case OT_THREAD:
  2366. {
  2367. object._unVal.pThread = ReadVM();
  2368. break;
  2369. }
  2370. case OT_FUNCPROTO:
  2371. {
  2372. object._unVal.pFunctionProto = ReadFuncProto();
  2373. break;
  2374. }
  2375. case OT_CLASS:
  2376. {
  2377. object._unVal.pClass = ReadClass();
  2378. break;
  2379. }
  2380. case OT_INSTANCE:
  2381. {
  2382. object._unVal.pInstance = ReadInstance();
  2383. if ( !object._unVal.pInstance )
  2384. {
  2385. // Look for a match in the current root table
  2386. HSQOBJECT hExistingObject = LookupObject( pszName, NULL, false );
  2387. if ( sq_isinstance( hExistingObject ) )
  2388. {
  2389. object._unVal.pInstance = hExistingObject._unVal.pInstance;
  2390. }
  2391. }
  2392. break;
  2393. }
  2394. case OT_WEAKREF:
  2395. {
  2396. object._unVal.pWeakRef = ReadWeakRef();
  2397. break;
  2398. }
  2399. default:
  2400. {
  2401. object._unVal.pUserPointer = NULL;
  2402. Assert( 0 );
  2403. }
  2404. }
  2405. if ( !object._unVal.pUserPointer )
  2406. {
  2407. DevMsg( "Failed to restore a Squirrel object of type %s\n", SQTypeToString( object._type ) );
  2408. object._type = OT_NULL;
  2409. bResult = false;
  2410. }
  2411. }
  2412. #ifdef VSQUIRREL_DEBUG_SERIALIZATION
  2413. lastType = object._type;
  2414. SQObjectPtr res;
  2415. if ( ISREFCOUNTED(object._type) )
  2416. {
  2417. SQ_VALIDATE_REF_COUNT( object._unVal.pRefCounted );
  2418. object._unVal.pRefCounted->_uiRef++;
  2419. }
  2420. m_hVM->ToString( object, res );
  2421. if ( ISREFCOUNTED(object._type) )
  2422. {
  2423. object._unVal.pRefCounted->_uiRef--;
  2424. SQ_VALIDATE_REF_COUNT( object._unVal.pRefCounted );
  2425. }
  2426. Msg( "%d: %s [%d]\n", m_pBuffer->TellGet(), res._unVal.pString->_val, ( ISREFCOUNTED(object._type) ) ? object._unVal.pRefCounted->_uiRef : -1 );
  2427. #ifdef VSQUIRREL_DEBUG_SERIALIZATION_HEAPCHK
  2428. _heapchk();
  2429. #endif
  2430. #endif
  2431. objectOut = object;
  2432. return bResult;
  2433. }
  2434. //-------------------------------------------------------------
  2435. //
  2436. //-------------------------------------------------------------
  2437. SQVM *ReadVM()
  2438. {
  2439. SQVM *pVM = sq_newthread( m_hVM, MIN_STACK_OVERHEAD + 2 );
  2440. m_hVM->Pop();
  2441. return pVM;
  2442. }
  2443. //-------------------------------------------------------------
  2444. //
  2445. //-------------------------------------------------------------
  2446. void ReadVM( SQVM *pVM )
  2447. {
  2448. unsigned i;
  2449. ReadObject( pVM->_roottable );
  2450. pVM->_top = m_pBuffer->GetInt();
  2451. pVM->_stackbase = m_pBuffer->GetInt();
  2452. unsigned stackSize = m_pBuffer->GetUnsignedInt();
  2453. pVM->_stack.resize( stackSize );
  2454. for( i = 0; i < pVM->_stack.size(); i++ )
  2455. {
  2456. ReadObject( pVM->_stack[i] );
  2457. }
  2458. stackSize = m_pBuffer->GetUnsignedInt();
  2459. for( i = 0; i < pVM->_vargsstack.size(); i++ )
  2460. {
  2461. ReadObject( pVM->_vargsstack[i] );
  2462. }
  2463. }
  2464. //-------------------------------------------------------------
  2465. //
  2466. //-------------------------------------------------------------
  2467. SQTable *ReadTable()
  2468. {
  2469. SQTable *pOld;
  2470. SQTable *pTable;
  2471. if ( !BeginRead( &pOld, &pTable ) )
  2472. {
  2473. return pTable;
  2474. }
  2475. pTable = SQTable::Create(_ss(m_hVM), 0);
  2476. MapPtr( pOld, pTable );
  2477. if ( m_pBuffer->GetInt() )
  2478. {
  2479. SQObjectPtr delegate;
  2480. ReadObject( delegate );
  2481. pTable->SetDelegate( delegate._unVal.pTable );
  2482. }
  2483. else
  2484. {
  2485. pTable->_delegate = NULL;
  2486. }
  2487. int n = m_pBuffer->GetInt();
  2488. while ( n-- )
  2489. {
  2490. SQObjectPtr key, value;
  2491. ReadObject( key );
  2492. if ( !ReadObject( value, ( key._type == OT_STRING ) ? key._unVal.pString->_val : NULL ) )
  2493. {
  2494. DevMsg( "Failed to read Squirrel table entry %s\n", ( key._type == OT_STRING ) ? key._unVal.pString->_val : SQTypeToString( key._type ) );
  2495. }
  2496. if ( key._type != OT_NULL )
  2497. {
  2498. pTable->NewSlot( key, value );
  2499. }
  2500. }
  2501. return pTable;
  2502. }
  2503. //-------------------------------------------------------------
  2504. //
  2505. //-------------------------------------------------------------
  2506. SQArray *ReadArray()
  2507. {
  2508. SQArray *pOld;
  2509. SQArray *pArray;
  2510. if ( !BeginRead( &pOld, &pArray ) )
  2511. {
  2512. return pArray;
  2513. }
  2514. pArray = SQArray::Create(_ss(m_hVM), 0);
  2515. MapPtr( pOld, pArray );
  2516. int n = m_pBuffer->GetInt();
  2517. pArray->Reserve( n );
  2518. while ( n-- )
  2519. {
  2520. SQObjectPtr value;
  2521. ReadObject( value );
  2522. pArray->Append( value );
  2523. }
  2524. return pArray;
  2525. }
  2526. //-------------------------------------------------------------
  2527. //
  2528. //-------------------------------------------------------------
  2529. SQClass *ReadClass()
  2530. {
  2531. SQClass *pOld;
  2532. SQClass *pClass;
  2533. if ( !BeginRead( &pOld, &pClass ) )
  2534. {
  2535. return pClass;
  2536. }
  2537. SQClass *pBase = NULL;
  2538. bool bIsNative = !!m_pBuffer->GetInt();
  2539. // If it's not a C++ defined type...
  2540. if ( !bIsNative )
  2541. {
  2542. if ( m_pBuffer->GetInt() )
  2543. {
  2544. SQObjectPtr base;
  2545. ReadObject( base );
  2546. pBase = base._unVal.pClass;
  2547. }
  2548. SQClass *pClass = SQClass::Create( _ss(m_hVM), pBase );
  2549. MapPtr( pOld, pClass );
  2550. SQObjectPtr members;
  2551. ReadObject( members );
  2552. pClass->_members->Release();
  2553. pClass->_members = members._unVal.pTable;
  2554. __ObjAddRef( members._unVal.pTable );
  2555. ReadObject( pClass->_attributes );
  2556. unsigned i, n;
  2557. n = m_pBuffer->GetUnsignedInt();
  2558. pClass->_defaultvalues.resize( n );
  2559. for ( i = 0; i < n; i++ )
  2560. {
  2561. ReadObject(pClass->_defaultvalues[i].val);
  2562. ReadObject(pClass->_defaultvalues[i].attrs);
  2563. }
  2564. n = m_pBuffer->GetUnsignedInt();
  2565. pClass->_methods.resize( n );
  2566. for ( i = 0; i < n; i++ )
  2567. {
  2568. ReadObject(pClass->_methods[i].val);
  2569. ReadObject(pClass->_methods[i].attrs);
  2570. }
  2571. n = m_pBuffer->GetUnsignedInt();
  2572. pClass->_metamethods.resize( n );
  2573. for ( i = 0; i < n; i++ )
  2574. {
  2575. ReadObject(pClass->_metamethods[i]);
  2576. }
  2577. return pClass;
  2578. }
  2579. else
  2580. {
  2581. char *pszName = (char *)stackalloc( 1024 );
  2582. m_pBuffer->GetString( pszName, 1024 );
  2583. pszName[1023] = 0;
  2584. SQObjectPtr value;
  2585. if ( m_hVM->_roottable._unVal.pTable->Get( SQString::Create( _ss(m_hVM ), pszName ), value ) && sq_isclass( value ) )
  2586. {
  2587. MapPtr( pOld, value._unVal.pClass );
  2588. return value._unVal.pClass;
  2589. }
  2590. MapPtr( pOld, NULL );
  2591. }
  2592. return NULL;
  2593. }
  2594. //-------------------------------------------------------------
  2595. //
  2596. //-------------------------------------------------------------
  2597. SQInstance *ReadInstance()
  2598. {
  2599. SQInstance *pOld;
  2600. SQInstance *pInstance;
  2601. if ( !BeginRead( &pOld, &pInstance ) )
  2602. {
  2603. return pInstance;
  2604. }
  2605. SQObjectPtr pClass;
  2606. ReadObject( pClass );
  2607. unsigned i, n;
  2608. if ( pClass._unVal.pClass )
  2609. {
  2610. pInstance = SQInstance::Create( _ss(m_hVM), pClass._unVal.pClass );
  2611. n = m_pBuffer->GetUnsignedInt();
  2612. for ( i = 0; i < n; i++ )
  2613. {
  2614. ReadObject(pInstance->_values[i]);
  2615. }
  2616. m_pBuffer->GetPtr(); // ignored in this path
  2617. if ( pInstance->_class->_typetag )
  2618. {
  2619. if ( pInstance->_class->_typetag == TYPETAG_VECTOR )
  2620. {
  2621. Vector *pValue = new Vector;
  2622. pValue->x = m_pBuffer->GetFloat();
  2623. pValue->y = m_pBuffer->GetFloat();
  2624. pValue->z = m_pBuffer->GetFloat();
  2625. pInstance->_userpointer = pValue;
  2626. }
  2627. else
  2628. {
  2629. InstanceContext_t *pContext = new InstanceContext_t;
  2630. pContext->pInstance = NULL;
  2631. ReadObject( pContext->name );
  2632. pContext->pClassDesc = (ScriptClassDesc_t *)( pInstance->_class->_typetag );
  2633. void *pOldInstance = m_pBuffer->GetPtr();
  2634. if ( sq_isstring(pContext->name) )
  2635. {
  2636. char *pszName = pContext->name._unVal.pString->_val;
  2637. if ( pContext->pClassDesc->pHelper )
  2638. {
  2639. HSQOBJECT *pInstanceHandle = new HSQOBJECT;
  2640. pInstanceHandle->_type = OT_INSTANCE;
  2641. pInstanceHandle->_unVal.pInstance = pInstance;
  2642. pContext->pInstance = pContext->pClassDesc->pHelper->BindOnRead( (HSCRIPT)pInstanceHandle, pOldInstance, pszName );
  2643. if ( pContext->pInstance )
  2644. {
  2645. SQ_VALIDATE_REF_COUNT( pInstance );
  2646. pInstance->_uiRef++;
  2647. sq_addref( m_hVM, pInstanceHandle );
  2648. pInstance->_uiRef--;
  2649. SQ_VALIDATE_REF_COUNT( pInstance );
  2650. }
  2651. else
  2652. {
  2653. delete pInstanceHandle;
  2654. }
  2655. }
  2656. if ( !pContext->pInstance )
  2657. {
  2658. // Look for a match in the current root table
  2659. HSQOBJECT hExistingObject = LookupObject( pszName, NULL, false );
  2660. if ( sq_isinstance(hExistingObject) && hExistingObject._unVal.pInstance->_class == pInstance->_class )
  2661. {
  2662. delete pInstance;
  2663. return hExistingObject._unVal.pInstance;
  2664. }
  2665. pContext->pInstance = NULL;
  2666. }
  2667. }
  2668. pInstance->_userpointer = pContext;
  2669. }
  2670. }
  2671. else
  2672. {
  2673. Verify( m_pBuffer->GetInt() == OT_USERPOINTER );
  2674. pInstance->_userpointer = ReadUserPointer();
  2675. Assert( pInstance->_userpointer == NULL );
  2676. }
  2677. MapPtr( pOld, pInstance );
  2678. }
  2679. else
  2680. {
  2681. MapPtr( pOld, NULL );
  2682. n = m_pBuffer->GetUnsignedInt();
  2683. for ( i = 0; i < n; i++ )
  2684. {
  2685. SQObjectPtr ignored;
  2686. ReadObject(ignored);
  2687. }
  2688. void *pOldTypeTag = m_pBuffer->GetPtr(); // ignored in this path
  2689. if ( pOldTypeTag )
  2690. {
  2691. if ( pOldTypeTag == TYPETAG_VECTOR )
  2692. {
  2693. m_pBuffer->GetFloat();
  2694. m_pBuffer->GetFloat();
  2695. m_pBuffer->GetFloat();
  2696. }
  2697. else
  2698. {
  2699. SQObjectPtr ignored;
  2700. ReadObject( ignored );
  2701. m_pBuffer->GetPtr();
  2702. }
  2703. }
  2704. else
  2705. {
  2706. Verify( m_pBuffer->GetInt() == OT_USERPOINTER );
  2707. ReadUserPointer();
  2708. }
  2709. pInstance = NULL;
  2710. }
  2711. return pInstance;
  2712. }
  2713. //-------------------------------------------------------------
  2714. //
  2715. //-------------------------------------------------------------
  2716. SQGenerator *ReadGenerator()
  2717. {
  2718. SQGenerator *pOld;
  2719. SQGenerator *pGenerator;
  2720. if ( !BeginRead( &pOld, &pGenerator ) )
  2721. {
  2722. return pGenerator;
  2723. }
  2724. SQObjectPtr closure;
  2725. ReadObject( closure );
  2726. pGenerator = SQGenerator::Create( _ss(m_hVM), closure._unVal.pClosure );
  2727. MapPtr( pOld, pGenerator );
  2728. unsigned i, n;
  2729. n = m_pBuffer->GetUnsignedInt();
  2730. pGenerator->_stack.resize( n );
  2731. for ( i = 0; i < n; i++ )
  2732. {
  2733. ReadObject(pGenerator->_stack[i]);
  2734. }
  2735. n = m_pBuffer->GetUnsignedInt();
  2736. pGenerator->_vargsstack.resize( n );
  2737. for ( i = 0; i < n; i++ )
  2738. {
  2739. ReadObject(pGenerator->_vargsstack[i]);
  2740. }
  2741. return pGenerator;
  2742. }
  2743. //-------------------------------------------------------------
  2744. //
  2745. //-------------------------------------------------------------
  2746. SQClosure *ReadClosure()
  2747. {
  2748. SQClosure *pOld;
  2749. SQClosure *pClosure;
  2750. if ( !BeginRead( &pOld, &pClosure ) )
  2751. {
  2752. return pClosure;
  2753. }
  2754. SQObjectPtr proto;
  2755. ReadObject( proto );
  2756. pClosure = SQClosure::Create( _ss(m_hVM), proto._unVal.pFunctionProto );
  2757. MapPtr( pOld, pClosure );
  2758. ReadObject( pClosure->_env );
  2759. unsigned i, n;
  2760. n = m_pBuffer->GetUnsignedInt();
  2761. pClosure->_outervalues.resize( n );
  2762. for ( i = 0; i < n; i++ )
  2763. {
  2764. ReadObject(pClosure->_outervalues[i]);
  2765. }
  2766. n = m_pBuffer->GetUnsignedInt();
  2767. pClosure->_defaultparams.resize( n );
  2768. for ( i = 0; i < n; i++ )
  2769. {
  2770. ReadObject(pClosure->_defaultparams[i]);
  2771. }
  2772. return pClosure;
  2773. }
  2774. //-------------------------------------------------------------
  2775. //
  2776. //-------------------------------------------------------------
  2777. SQNativeClosure *ReadNativeClosure()
  2778. {
  2779. SQNativeClosure *pOld;
  2780. SQNativeClosure *pClosure;
  2781. if ( !BeginRead( &pOld, &pClosure ) )
  2782. {
  2783. return pClosure;
  2784. }
  2785. SQObjectPtr name;
  2786. ReadObject( name );
  2787. SQObjectPtr value;
  2788. if ( m_hVM->_roottable._unVal.pTable->Get( name, value ) && sq_isnativeclosure(value) )
  2789. {
  2790. MapPtr( pOld, value._unVal.pNativeClosure );
  2791. return value._unVal.pNativeClosure;
  2792. }
  2793. MapPtr( pOld, NULL );
  2794. return NULL; // @TBD [4/15/2008 tom]
  2795. }
  2796. //-------------------------------------------------------------
  2797. //
  2798. //-------------------------------------------------------------
  2799. SQUserData *ReadUserData()
  2800. {
  2801. m_pBuffer->GetPtr();
  2802. return NULL; // @TBD [4/15/2008 tom]
  2803. }
  2804. //-------------------------------------------------------------
  2805. //
  2806. //-------------------------------------------------------------
  2807. SQUserPointer *ReadUserPointer()
  2808. {
  2809. m_pBuffer->GetPtr();
  2810. return NULL; // @TBD [4/15/2008 tom]
  2811. }
  2812. //-------------------------------------------------------------
  2813. //
  2814. //-------------------------------------------------------------
  2815. static SQInteger SqReadFunc(SQUserPointer up,SQUserPointer data, SQInteger size)
  2816. {
  2817. CSquirrelVM *pThis = (CSquirrelVM *)up;
  2818. pThis->m_pBuffer->Get( data, size );
  2819. return size;
  2820. }
  2821. //-------------------------------------------------------------
  2822. //
  2823. //-------------------------------------------------------------
  2824. SQFunctionProto *ReadFuncProto()
  2825. {
  2826. SQFunctionProto *pOld;
  2827. SQFunctionProto *pResult;
  2828. if ( !BeginRead( &pOld, &pResult ) )
  2829. {
  2830. return pResult;
  2831. }
  2832. SQObjectPtr result;
  2833. SQFunctionProto::Load( m_hVM, this, &SqReadFunc, result );
  2834. pResult = result._unVal.pFunctionProto;
  2835. SQ_VALIDATE_REF_COUNT( pResult );
  2836. pResult->_uiRef++;
  2837. result.Null();
  2838. pResult->_uiRef--;
  2839. SQ_VALIDATE_REF_COUNT( pResult );
  2840. MapPtr( pOld, pResult );
  2841. return pResult;
  2842. }
  2843. //-------------------------------------------------------------
  2844. //
  2845. //-------------------------------------------------------------
  2846. SQWeakRef *ReadWeakRef( )
  2847. {
  2848. SQObjectPtr obj;
  2849. ReadObject( obj );
  2850. if ( !obj._unVal.pRefCounted )
  2851. {
  2852. return NULL;
  2853. }
  2854. // Need to up ref count if read order has weak ref loading first
  2855. Assert( ISREFCOUNTED(obj._type) );
  2856. SQRefCounted *pRefCounted = obj._unVal.pRefCounted;
  2857. SQ_VALIDATE_REF_COUNT( pRefCounted );
  2858. pRefCounted->_uiRef++;
  2859. SQWeakRef *pResult = obj._unVal.pRefCounted->GetWeakRef( obj._type );
  2860. obj.Null();
  2861. pRefCounted->_uiRef--;
  2862. SQ_VALIDATE_REF_COUNT( pRefCounted );
  2863. return pResult;
  2864. }
  2865. //-------------------------------------------------------------
  2866. //
  2867. //-------------------------------------------------------------
  2868. bool FindKeyForObject( const SQObjectPtr &table, void *p, SQObjectPtr &key )
  2869. {
  2870. SQTable *pTable = table._unVal.pTable;
  2871. int len = pTable->_numofnodes;
  2872. for(int i = 0; i < len; i++)
  2873. {
  2874. if ( pTable->_nodes[i].val._unVal.pUserPointer == p )
  2875. {
  2876. key = pTable->_nodes[i].key;
  2877. return true;
  2878. }
  2879. if ( sq_istable( pTable->_nodes[i].val ) )
  2880. {
  2881. if ( FindKeyForObject( pTable->_nodes[i].val, p, key ) )
  2882. {
  2883. return true;
  2884. }
  2885. }
  2886. }
  2887. return false;
  2888. }
  2889. //-------------------------------------------------------------------------
  2890. //
  2891. //-------------------------------------------------------------------------
  2892. HSQUIRRELVM m_hVM;
  2893. HSQREMOTEDBG m_hDbg;
  2894. HSQOBJECT m_hOnCreateScopeFunc;
  2895. HSQOBJECT m_hOnReleaseScopeFunc;
  2896. HSQOBJECT m_hClassVector;
  2897. SQObjectPtr m_ErrorString;
  2898. uint64 m_iUniqueIdSerialNumber;
  2899. float m_TimeStartExecute;
  2900. #ifdef VSQUIRREL_TEST
  2901. ConVar developer;
  2902. #else
  2903. ConVarRef developer;
  2904. #endif
  2905. CUtlHashFast<SQClass *, CUtlHashFastGenericHash> m_TypeMap;
  2906. friend class CVSquirrelSerializer;
  2907. // Serialization support
  2908. CUtlBuffer *m_pBuffer;
  2909. CUtlMap<void *, void *> m_PtrMap;
  2910. };
  2911. //-----------------------------------------------------------------------------
  2912. //
  2913. //-----------------------------------------------------------------------------
  2914. IScriptVM *ScriptCreateSquirrelVM()
  2915. {
  2916. return new CSquirrelVM;
  2917. }
  2918. void ScriptDestroySquirrelVM( IScriptVM *pVM )
  2919. {
  2920. CSquirrelVM *pSquirrelVM = assert_cast<CSquirrelVM *>( pVM );
  2921. delete pSquirrelVM;
  2922. }
  2923. //-----------------------------------------------------------------------------
  2924. //-----------------------------------------------------------------------------
  2925. //
  2926. //-----------------------------------------------------------------------------
  2927. //-----------------------------------------------------------------------------
  2928. #ifdef VSQUIRREL_TEST
  2929. #include "fasttimer.h"
  2930. CSquirrelVM g_SquirrelVM;
  2931. IScriptVM *g_pScriptVM = &g_SquirrelVM;
  2932. //-----------------------------------------------------------------------------
  2933. //
  2934. //-----------------------------------------------------------------------------
  2935. //-----------------------------------------------------------------------------
  2936. //
  2937. //-----------------------------------------------------------------------------
  2938. #include <time.h>
  2939. #include "fasttimer.h"
  2940. static void FromScript_AddBehavior( const char *pBehaviorName, HSCRIPT hTable )
  2941. {
  2942. ScriptVariant_t KeyVariant, ValueVariant;
  2943. Msg( "Behavior: %s\n", pBehaviorName );
  2944. int nInterator = 0;
  2945. int index = g_pScriptVM->GetNumTableEntries( hTable );
  2946. for( int i = 0; i < index; i++ )
  2947. {
  2948. nInterator = g_pScriptVM->GetKeyValue( hTable, nInterator, &KeyVariant, &ValueVariant );
  2949. Msg( " %d: %s / %s\n", i, KeyVariant.m_pszString, ValueVariant.m_pszString );
  2950. g_pScriptVM->ReleaseValue( KeyVariant );
  2951. g_pScriptVM->ReleaseValue( ValueVariant );
  2952. }
  2953. }
  2954. static ScriptVariant_t TestReturn( )
  2955. {
  2956. return ScriptVariant_t("test");
  2957. }
  2958. static Vector MyVectorAdd( Vector A, Vector B )
  2959. {
  2960. return A + B;
  2961. }
  2962. void TestOutput( const char *pszText )
  2963. {
  2964. Msg( "%s\n", pszText );
  2965. }
  2966. bool TestError( const char *pszText )
  2967. {
  2968. Msg( "%s\n", pszText );
  2969. return true;
  2970. }
  2971. class CMyClass
  2972. {
  2973. public:
  2974. bool Foo( int );
  2975. void Bar( HSCRIPT TableA, HSCRIPT TableB );
  2976. float FooBar( int, const char * );
  2977. float OverlyTechnicalName( bool );
  2978. };
  2979. bool CMyClass::Foo( int test )
  2980. {
  2981. return true;
  2982. }
  2983. void CMyClass::Bar( HSCRIPT TableA, HSCRIPT TableB )
  2984. {
  2985. ScriptVariant_t MyValue;
  2986. // g_pScriptVM->CreateTable( MyTable );
  2987. MyValue = 10;
  2988. g_pScriptVM->SetValue( TableA, "1", MyValue );
  2989. MyValue = 20;
  2990. g_pScriptVM->SetValue( TableA, "2", MyValue );
  2991. MyValue = 30;
  2992. g_pScriptVM->SetValue( TableA, "3", MyValue );
  2993. MyValue = 100;
  2994. g_pScriptVM->SetValue( TableB, "1", MyValue );
  2995. MyValue = 200;
  2996. g_pScriptVM->SetValue( TableB, "2", MyValue );
  2997. MyValue = 300;
  2998. g_pScriptVM->SetValue( TableB, "3", MyValue );
  2999. // return MyTable;
  3000. }
  3001. float CMyClass::FooBar( int test1, const char *test2 )
  3002. {
  3003. return 2.34f;
  3004. }
  3005. float CMyClass::OverlyTechnicalName( bool test )
  3006. {
  3007. return 4.56f;
  3008. }
  3009. BEGIN_SCRIPTDESC_ROOT_NAMED( CMyClass , "CMyClass", SCRIPT_SINGLETON "" )
  3010. DEFINE_SCRIPTFUNC( Foo, "" )
  3011. DEFINE_SCRIPTFUNC( Bar, "" )
  3012. DEFINE_SCRIPTFUNC( FooBar, "" )
  3013. DEFINE_SCRIPTFUNC_NAMED( OverlyTechnicalName, "SimpleMemberName", "" )
  3014. END_SCRIPTDESC();
  3015. class CMyDerivedClass : public CMyClass
  3016. {
  3017. public:
  3018. float DerivedFunc() const;
  3019. };
  3020. BEGIN_SCRIPTDESC( CMyDerivedClass, CMyClass, SCRIPT_SINGLETON "" )
  3021. DEFINE_SCRIPTFUNC( DerivedFunc, "" )
  3022. END_SCRIPTDESC();
  3023. float CMyDerivedClass::DerivedFunc() const
  3024. {
  3025. return 8.91f;
  3026. }
  3027. CMyDerivedClass derivedInstance;
  3028. void AnotherFunction()
  3029. {
  3030. // Manual class exposure
  3031. g_pScriptVM->RegisterClass( GetScriptDescForClass( CMyClass ) );
  3032. // Auto registration by instance
  3033. g_pScriptVM->RegisterInstance( &derivedInstance, "theInstance" );
  3034. }
  3035. int main( int argc, const char **argv)
  3036. {
  3037. if ( argc < 2 )
  3038. {
  3039. printf( "No script specified" );
  3040. return 1;
  3041. }
  3042. g_pScriptVM->Init();
  3043. g_pScriptVM->SetOutputCallback( TestOutput );
  3044. AnotherFunction();
  3045. CCycleCount count;
  3046. count.Sample();
  3047. RandomSeed( time( NULL ) ^ count.GetMicroseconds() );
  3048. ScriptRegisterFunction( g_pScriptVM, RandomFloat, "" );
  3049. ScriptRegisterFunction( g_pScriptVM, RandomInt, "" );
  3050. ScriptRegisterFunction( g_pScriptVM, FromScript_AddBehavior, "" );
  3051. ScriptRegisterFunction( g_pScriptVM, MyVectorAdd, "" );
  3052. ScriptRegisterFunction( g_pScriptVM, TestReturn, "" );
  3053. if ( argc == 3 && *argv[2] == 'd' )
  3054. {
  3055. g_pScriptVM->ConnectDebugger();
  3056. }
  3057. int key;
  3058. CScriptScope scope;
  3059. scope.Init( "TestScope" );
  3060. do
  3061. {
  3062. const char *pszScript = argv[1];
  3063. FILE *hFile = fopen( pszScript, "rb" );
  3064. if ( !hFile )
  3065. {
  3066. printf( "\"%s\" not found.\n", pszScript );
  3067. return 1;
  3068. }
  3069. int nFileLen = _filelength( _fileno( hFile ) );
  3070. char *pBuf = new char[nFileLen + 1];
  3071. fread( pBuf, 1, nFileLen, hFile );
  3072. pBuf[nFileLen] = 0;
  3073. fclose( hFile );
  3074. if (1)
  3075. {
  3076. printf( "Executing script \"%s\"\n----------------------------------------\n", pszScript );
  3077. HSCRIPT hScript = g_pScriptVM->CompileScript( pBuf, ( strrchr( pszScript, '\\' ) ? strrchr( pszScript, '\\' ) + 1 : pszScript ) );
  3078. if ( hScript )
  3079. {
  3080. ScriptVariant_t Table;
  3081. if ( scope.Run( hScript ) != SCRIPT_ERROR )
  3082. {
  3083. printf( "----------------------------------------\n" );
  3084. printf("Script complete. Press q to exit, r to reset the scope, m to dump memory usage, enter to run again.\n");
  3085. }
  3086. else
  3087. {
  3088. printf( "----------------------------------------\n" );
  3089. printf("Script execution error. Press q to exit, r to reset the scope, m to dump memory usage, enter to run again.\n");
  3090. }
  3091. g_pScriptVM->ReleaseScript( hScript );
  3092. }
  3093. else
  3094. {
  3095. printf( "----------------------------------------\n" );
  3096. printf("Script failed to compile. Press q to exit, r to reset the scope, m to dump memory usage, enter to run again.\n");
  3097. }
  3098. }
  3099. key = _getch(); // Keypress before exit
  3100. if ( key == 'm' )
  3101. {
  3102. Msg( "%d\n", g_pMemAlloc->GetSize( NULL ) );
  3103. }
  3104. if ( key == 'r' )
  3105. {
  3106. scope.Term();
  3107. scope.Init( "TestScope" );
  3108. }
  3109. delete pBuf;
  3110. } while ( key != 'q' );
  3111. scope.Term();
  3112. g_pScriptVM->DisconnectDebugger();
  3113. g_pScriptVM->Shutdown();
  3114. return 0;
  3115. }
  3116. #endif