1
0

y_uvar.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. /*----------------------------------------------------------------------------*\
  2. =================================
  3. y_uvar - Automatic data saving.
  4. =================================
  5. Description:
  6. Declares data to be automatically saved and loaded on a per-player basis.
  7. Legal:
  8. Version: MPL 1.1
  9. The contents of this file are subject to the Mozilla Public License Version
  10. 1.1 (the "License"); you may not use this file except in compliance with
  11. the License. You may obtain a copy of the License at
  12. http://www.mozilla.org/MPL/
  13. Software distributed under the License is distributed on an "AS IS" basis,
  14. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  15. for the specific language governing rights and limitations under the
  16. License.
  17. The Original Code is the YSI utils include.
  18. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  19. Portions created by the Initial Developer are Copyright (C) 2011
  20. the Initial Developer. All Rights Reserved.
  21. Contributors:
  22. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  23. Thanks:
  24. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  25. ZeeX - Very productive conversations.
  26. koolk - IsPlayerinAreaEx code.
  27. TheAlpha - Danish translation.
  28. breadfish - German translation.
  29. Fireburn - Dutch translation.
  30. yom - French translation.
  31. 50p - Polish translation.
  32. Zamaroht - Spanish translation.
  33. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  34. for me to strive to better.
  35. Pixels^ - Running XScripters where the idea was born.
  36. Matite - Pestering me to release it and using it.
  37. Very special thanks to:
  38. Thiadmer - PAWN, whose limits continue to amaze me!
  39. Kye/Kalcor - SA:MP.
  40. SA:MP Team past, present and future - SA:MP.
  41. Version:
  42. 0.1.3
  43. Changelog:
  44. 25/02/12:
  45. First version.
  46. Functions:
  47. Stock:
  48. -
  49. Inline:
  50. -
  51. Variables:
  52. Global:
  53. -
  54. \*----------------------------------------------------------------------------*/
  55. // y_uvars
  56. #include "internal\y_version"
  57. #include "y_amx"
  58. #include "y_debug"
  59. #include "y_utils"
  60. #include "y_users"
  61. #include "y_ini"
  62. #include "y_hooks"
  63. #include "internal\y_stripnumbers"
  64. // Third "uvar" version.
  65. #define _YU@LE@E%0>
  66. #define _YU@LT@E%0> ;
  67. // Needs two levels of indirection to strip the excess commas (,%0,%1).
  68. #define _YU@LO(,%0,%1,%2) %0@yA_();public %0@yA_(){N@(#....#%0,_:%1,_:%2,STRIP_NUMBERS:%0[0]|||%2:0|||);}
  69. #define _YU@LE%0[%1][%3]%2> _YU@LO(%0,%1,%3) _YU@LE%2>
  70. // Recursive local default string definition.
  71. #define _YU@LJ(,%0,%1,%2) %0[%1][%2]
  72. #define _YU@LT%0[%1][%3]%2> ,_YU@LJ(%0,%1,%3)_YU@LT%2>
  73. #define _YU@LA%0[%1][%3]%2> _YU@LJ(%0,%1,%3)_YU@LT%2>
  74. // Entry point for the loaders. The structure of stored pvar data is:
  75. //
  76. // [0] - Pointer to next pvar in list (-1 for end).
  77. // [1] - Pointer to data.
  78. // [2] - Number of players.
  79. // [3] - Size of enum.
  80. // [4] - Start of name.
  81. //
  82. // It is VERY important to note that using "%0[0][0]" when calling "N@" instead
  83. // of "%0" gives a DIFFERENT address - we get the address of the first data
  84. // element in the array, not the address of the start of the array pointer table
  85. // which is used to index multi-dimensional arrays when the size is not known
  86. // (which in this case it is). This makes calculating offsets later possible.
  87. #define uvar%0[%8][%1]%2; stock _YU@LA,%0[%8][%1]%2@E>_YU@LE,%0[%8][%1]%2@E>
  88. //%0@yA_();public%0@yA_()N@(_:%0,#....#%0 _YA@LT %1,@E|||);
  89. // This is a structure defining the data stored on the enum structure.
  90. /*enum E_USERS_FAKE_DATA
  91. {
  92. E_USERS_FAKE_DATA_NEXT,
  93. E_USERS_FAKE_DATA_DATA,
  94. E_USERS_FAKE_DATA_LEN,
  95. E_USERS_FAKE_DATA_STR[2]
  96. }*/
  97. static stock
  98. YSI_g_sFirstUVarData = -1,
  99. // These three variables are used to speed up data loading through caching.
  100. YSI_g_sLastName[32] = "\1\0",
  101. YSI_g_sLastAddr,
  102. YSI_g_sLastPlayers,
  103. YSI_g_sLastSize;
  104. forward _y_uvar_include_@();
  105. public _y_uvar_include_@()
  106. {
  107. memset("", 0, 0);
  108. Player_WriteArray("", "", 0);
  109. }
  110. static stock Uvar_FindData(const name[], data[])
  111. {
  112. // This function gets passed an empty string so that we can use "data" as a
  113. // string, while secretly changing the pointer in AMX code.
  114. new
  115. p = YSI_g_sFirstUVarData;
  116. while (p != -1)
  117. {
  118. // Modify our data pointer.
  119. #emit LOAD.S.pri p
  120. #emit STOR.S.pri data
  121. if (!strcmp(data[4], name))
  122. {
  123. strcpy(YSI_g_sLastName, name);
  124. YSI_g_sLastSize = data[3];
  125. YSI_g_sLastPlayers = data[2];
  126. YSI_g_sLastAddr = data[1];
  127. //printf("found %s, %d, %d, %d", YSI_g_sLastName, YSI_g_sLastSize, YSI_g_sLastPlayers, YSI_g_sLastAddr);
  128. return;
  129. }
  130. p = data[0];
  131. }
  132. YSI_g_sLastAddr = -1;
  133. }
  134. forward OnUserData[y_uvar](playerid, name[], value[]);
  135. public OnUserData[y_uvar](playerid, name[], value[])
  136. {
  137. // See what the name of the loaded data was.
  138. new
  139. pos = strfind(name, "-");
  140. if (pos == -1)
  141. {
  142. if (strcmp(name, YSI_g_sLastName))
  143. {
  144. // Find the data.
  145. Uvar_FindData(name, "");
  146. }
  147. if (YSI_g_sLastAddr == -1)
  148. {
  149. return;
  150. }
  151. // Check that the data is the right size.
  152. P:C(if (strval(value) != YSI_g_sLastSize) P:E("uvar data changed in %s", YSI_g_sLastName););
  153. }
  154. else
  155. {
  156. // Get the position in the array of this data.
  157. //printf("call pos 0");
  158. name[pos] = '\0';
  159. pos = strval(name[pos + 1]) * ((MAX_INI_ENTRY_TEXT - 1) / 16 * 3);
  160. if (strcmp(name[2], YSI_g_sLastName, false))
  161. {
  162. // Find the data.
  163. Uvar_FindData(name[2], "");
  164. }
  165. if (YSI_g_sLastAddr == -1)
  166. {
  167. return;
  168. }
  169. // Get the offset in the array for this player.
  170. if (playerid < YSI_g_sLastPlayers)
  171. {
  172. new
  173. len = strlen(value),
  174. idx;
  175. pos += YSI_g_sLastSize * playerid;
  176. // Save this pointer to an array variable for simplicity.
  177. #emit LOAD.pri YSI_g_sLastAddr
  178. #emit STOR.S.pri name
  179. // "pos" holds the offset of this data. "value" always holds a
  180. // whole number of cells worth of data.
  181. while (idx + 16 <= len)
  182. {
  183. // Do the large chunks.
  184. name[pos++] = ((value[idx + 0] - '>') << 26)
  185. | ((value[idx + 1] - '>') << 20)
  186. | ((value[idx + 2] - '>') << 14)
  187. | ((value[idx + 3] - '>') << 8)
  188. | ((value[idx + 4] - '>') << 2)
  189. | ((value[idx + 5] - '>') >> 4);
  190. // Second cell.
  191. name[pos++] = ((value[idx + 5] - '>') << 28)
  192. | ((value[idx + 6] - '>') << 22)
  193. | ((value[idx + 7] - '>') << 16)
  194. | ((value[idx + 8] - '>') << 10)
  195. | ((value[idx + 9] - '>') << 4)
  196. | ((value[idx + 10] - '>') >> 2);
  197. // Third cell.
  198. name[pos++] = ((value[idx + 10] - '>') << 30)
  199. | ((value[idx + 11] - '>') << 24)
  200. | ((value[idx + 12] - '>') << 18)
  201. | ((value[idx + 13] - '>') << 12)
  202. | ((value[idx + 14] - '>') << 6)
  203. | ((value[idx + 15] - '>') >> 0);
  204. // 16 characters are used to encode 3 cells (12 bytes) by only
  205. // saving 6 bits per character to ensure that they are always
  206. // valid characters. 7 bits may be easier, but would mean the
  207. // encoding fit less well to small numbers of cells.
  208. idx += 16;
  209. }
  210. if (idx + 6 <= len)
  211. {
  212. // Save any few extra bytes.
  213. name[pos++] = ((value[idx + 0] - '>') << 26)
  214. | ((value[idx + 1] - '>') << 20)
  215. | ((value[idx + 2] - '>') << 14)
  216. | ((value[idx + 3] - '>') << 8)
  217. | ((value[idx + 4] - '>') << 2)
  218. | ((value[idx + 5] - '>') >> 4);
  219. if (idx + 11 <= len)
  220. {
  221. name[pos++] = ((value[idx + 5] - '>') << 28)
  222. | ((value[idx + 6] - '>') << 22)
  223. | ((value[idx + 7] - '>') << 16)
  224. | ((value[idx + 8] - '>') << 10)
  225. | ((value[idx + 9] - '>') << 4)
  226. | ((value[idx + 10] - '>') >> 2);
  227. }
  228. }
  229. }
  230. }
  231. }
  232. /*----------------------------------------------------------------------------*\
  233. Function:
  234. N@
  235. Params:
  236. val[][] - Handle to the PAWN data array.
  237. volatile vardata[] - Handle to the memory location in which to store info.
  238. {K@, L@, M@, N@, _}:... - Array slot size information.
  239. Return:
  240. -
  241. Notes:
  242. This function modifies "vardata" well beyond its original limits to contain
  243. information on the structure of the enum used to define "val". This code
  244. uses the name and size information passed in the additional parameters as
  245. strings, and makes assumptions about how the compiler lays out memory to
  246. combine all the passed strings in to one big string in what could be ROM,
  247. but in SA:MP isn't. This takes a human readable(ish) description of the
  248. array elements and converts it in to a much simpler to read format for the
  249. computer to use later when loading and storing data.
  250. The description above is no longer the case. This code now just saves the
  251. size of the data, the number of players in the array, the address of the
  252. data, a pointer to another data set and the name of this data. This is by
  253. far much simpler than the old version.
  254. \*----------------------------------------------------------------------------*/
  255. stock N@(volatile const vardata[], playerCount, dataSize, &pointer)
  256. {
  257. new
  258. sAddr;
  259. // Store the basic data, including linked-list pointers and a pointer to the
  260. // location at which the data is stored.
  261. #emit LOAD.S.pri vardata
  262. #emit STOR.S.pri sAddr
  263. printf("", YSI_g_sFirstUVarData);
  264. #emit LOAD.pri YSI_g_sFirstUVarData
  265. #emit SREF.S.pri sAddr
  266. YSI_g_sFirstUVarData = sAddr;
  267. sAddr += 4;
  268. #emit LOAD.S.pri pointer
  269. #emit SREF.S.pri sAddr
  270. sAddr += 4;
  271. #emit LOAD.S.pri playerCount
  272. #emit SREF.S.pri sAddr
  273. sAddr += 4;
  274. #emit LOAD.S.pri dataSize
  275. #emit SREF.S.pri sAddr
  276. P:5("N@: %d %d %d %d %s", vardata[0], vardata[1], vardata[2], vardata[3], vardata[4]);
  277. P:5("N@: %d", YSI_g_sFirstUVarData);
  278. }
  279. hook OnScriptInit()
  280. {
  281. // List them all.
  282. YSI_g_sFirstUVarData = -1;
  283. // Call all @yA_ functions to get all required data.
  284. new
  285. idx,
  286. buffer;
  287. while ((idx = AMX_GetPublicPointerSuffix(idx, buffer, _A<@yA_>)))
  288. {
  289. #emit PUSH.C 0
  290. #emit LCTRL 6
  291. #emit ADD.C 28
  292. #emit PUSH.pri
  293. #emit LOAD.S.pri buffer
  294. #emit SCTRL 6
  295. }
  296. }
  297. hook OnPlayerLogout(playerid, yid)
  298. {
  299. // Loop through all the player data items and write them to a file.
  300. //static const
  301. // sc_cellsPerWrite =
  302. Player_SetTag("y_uvar");
  303. new
  304. p = YSI_g_sFirstUVarData,
  305. temp;
  306. while (p != -1)
  307. {
  308. // DO NOT CHANGE THE CODE BELOW HERE!!!
  309. // Call a function sort of. This allows us to push an arbitrary address
  310. // as an array to a function.
  311. #emit LOAD.S.pri p
  312. // Get the max players.
  313. #emit ADD.C 8
  314. #emit STOR.S.pri temp
  315. #emit LREF.S.pri temp
  316. #emit STOR.S.pri temp
  317. if (playerid < temp)
  318. {
  319. // Get the data size.
  320. #emit LOAD.S.pri p
  321. #emit ADD.C 12
  322. #emit STOR.S.pri temp
  323. #emit LREF.S.pri temp
  324. #emit PUSH.pri
  325. // Get the data offset.
  326. #emit LOAD.S.alt playerid
  327. #emit SMUL
  328. #emit SMUL.C 4
  329. #emit MOVE.alt
  330. // Get the data pointer.
  331. #emit LOAD.S.pri p
  332. #emit ADD.C 4
  333. #emit STOR.S.pri temp
  334. #emit LREF.S.pri temp
  335. #emit ADD
  336. #emit PUSH.pri
  337. // Get the function name.
  338. #emit LOAD.S.pri p
  339. #emit ADD.C 16
  340. #emit PUSH.pri
  341. // Save the next pointer.
  342. #emit LREF.S.pri p
  343. #emit STOR.S.pri p
  344. // Now push the size of data put on the stack.
  345. #emit PUSH.C 12
  346. // Now get the return address and push it.
  347. #emit LCTRL 6
  348. #emit ADD.C 28
  349. #emit PUSH.pri
  350. // Call "Player_WriteArray" directly.
  351. #emit CONST.pri Player_WriteArray
  352. #emit SCTRL 6
  353. // DO NOT CHANGE THE CODE ABOVE HERE!!!
  354. }
  355. }
  356. }
  357. hook OnPlayerConnect(playerid)
  358. {
  359. P:1("hook Users_OnPlayerConnect called: %i", playerid);
  360. new
  361. p = YSI_g_sFirstUVarData,
  362. temp;
  363. while (p != -1)
  364. {
  365. // DO NOT CHANGE THE CODE BELOW HERE!!!
  366. // Call a function sort of. This allows us to push an arbitrary address
  367. // as an array to a function.
  368. #emit LOAD.S.pri p
  369. // Get the max players.
  370. #emit ADD.C 8
  371. #emit STOR.S.pri temp
  372. #emit LREF.S.pri temp
  373. #emit STOR.S.pri temp
  374. if (playerid < temp)
  375. {
  376. // Get the data enum size.
  377. //#emit PUSH.C 8
  378. #emit PUSH.C 0
  379. #emit LOAD.S.pri p
  380. #emit ADD.C 12
  381. #emit STOR.S.pri temp
  382. #emit LREF.S.pri temp
  383. #emit PUSH.pri
  384. // Get the data offset.
  385. #emit LOAD.S.alt playerid
  386. #emit SMUL
  387. #emit SMUL.C 4
  388. #emit MOVE.alt
  389. // Get the data pointer.
  390. #emit LOAD.S.pri p
  391. #emit ADD.C 4
  392. #emit STOR.S.pri temp
  393. #emit LREF.S.pri temp
  394. #emit ADD
  395. #emit PUSH.pri
  396. // Save the next pointer.
  397. #emit LREF.S.pri p
  398. #emit STOR.S.pri p
  399. // Now push the size of data put on the stack.
  400. #emit PUSH.C 12
  401. // Now get the return address and push it.
  402. #emit LCTRL 6
  403. #emit ADD.C 28
  404. #emit PUSH.pri
  405. // Call "memset" directly.
  406. #emit CONST.pri memset
  407. #emit SCTRL 6
  408. // DO NOT CHANGE THE CODE ABOVE HERE!!!
  409. }
  410. }
  411. }
  412. #endinput
  413. /*stock Users_Debug()
  414. {
  415. // Print the first value from every array.
  416. }*/
  417. //#endinput
  418. Users_DoDataPrint(const playerid, const uid, data[], len, const structure[])
  419. {
  420. #pragma unused len
  421. // DO NOT CHANGE THE CODE BELOW HERE!!!
  422. // Find and save the information on this function for later. We don't even
  423. // need any checks here because we are saving the address of the instruction
  424. // after this code then returning in an invisible way.
  425. #emit LCTRL 6
  426. #emit ADD.C 20
  427. #emit STOR.pri YSI_g_sDoDataPrintAddr
  428. #emit RETN
  429. // DO NOT CHANGE THE CODE ABOVE HERE!!!
  430. //new
  431. // str[64];
  432. //strunpack(str, structure);
  433. //printf("%d, %d", playerid, uid);
  434. //printf("structure: %s, len: %d, data: %d %d", str, len, data[0], data[1]);
  435. P:5("Users_DoDataPrint: len: %d, data: %d %d", len, data[0], data[1]);
  436. P:C(for(new _i = 0, _j = strlen(structure); _i != _j; ++_i) {P:5("%d: %08x (%c", _i, structure[_i], structure[_i]);});
  437. //printf("%d, %d, %d, %s", data[E_USERS_FAKE_DATA_NEXT], data[E_USERS_FAKE_DATA_DATA], data[E_USERS_FAKE_DATA_LEN], str);
  438. //printf("hi");
  439. //return data[E_USERS_FAKE_DATA_NEXT];
  440. //return -1;
  441. // OK, let's get started on trying to write code to output these various
  442. // arrays, even if at this point they are only printed to the console, it is
  443. // still a step in the right direction (and with the speed I'm currently
  444. // going ANY step is a good step)!
  445. // Print the user data.
  446. if (IsPlayerConnected(playerid))
  447. {
  448. printf("Users_DoDataPrint: %d (%d) = %s", playerid, uid, ReturnPlayerName(playerid));
  449. }
  450. // Print the variable name.
  451. new
  452. namelen = structure[0],
  453. datalen,
  454. datatype,
  455. dataOffset = 0,
  456. indexOffset = 1;
  457. printf("Users_DoDataPrint: %d: %.*s", namelen, namelen, structure[indexOffset]);
  458. for ( ; ; )
  459. {
  460. indexOffset = indexOffset + namelen + 1;
  461. namelen = structure[indexOffset - 1];
  462. if (!namelen)
  463. {
  464. // If the returned length is 0, that means we have reached a null
  465. // character, and thus the end of the string.
  466. break;
  467. }
  468. else switch (namelen & 0xFF000000)
  469. {
  470. case 0x00000000:
  471. {
  472. printf("Variable: %d: %.*s", namelen, namelen, structure[indexOffset]);
  473. ++dataOffset;
  474. }
  475. case 0x10000000:
  476. {
  477. datalen = structure[indexOffset++] + dataOffset;
  478. //datalen = structure[indexOffset++];
  479. datatype = structure[indexOffset++] - '0';
  480. // Remove the flag and excess length at the same time.
  481. namelen -= 0x10000002;
  482. printf("Special array %d: %d: %.*s (%d)", datatype, namelen, namelen, structure[indexOffset], datalen - dataOffset);
  483. switch (datatype)
  484. {
  485. case BitArray@:
  486. {
  487. printf("data = %s", Bit_Display(BitArray:data[dataOffset], bits<datalen>));
  488. }
  489. }
  490. dataOffset = datalen;
  491. }
  492. case 0x20000000:
  493. {
  494. datalen = structure[indexOffset++] + dataOffset;
  495. // Remove the flag and excess length at the same time.
  496. namelen -= 0x20000001;
  497. printf("Array: %d: %.*s (%d)", namelen, namelen, structure[indexOffset], datalen - dataOffset);
  498. for (new i = dataOffset; i != datalen; ++i)
  499. {
  500. printf("data[%d] = %d", i, data[i]);
  501. }
  502. dataOffset = datalen;
  503. }
  504. default:
  505. {
  506. // Error!
  507. P:E("Attempted to save unknown data type, failing!");
  508. return;
  509. }
  510. }
  511. }
  512. //printf("
  513. }
  514. hook OnPlayerLogout(playerid, uid)
  515. {
  516. // Users_DoLogout(playerid, uid);
  517. //}
  518. //
  519. //stock Users_DoLogout(playerid, uid)
  520. //{
  521. P:1("hook Users_OnPlayerLogout called: %i, %i", playerid, uid);
  522. new
  523. p = YSI_g_sFirstUVarData,
  524. temp;
  525. while (p != -1)
  526. {
  527. // DO NOT CHANGE THE CODE BELOW HERE!!!
  528. // Call a function sort of. This allows us to push an arbitrary address
  529. // as an array to a function.
  530. #emit LOAD.S.pri p
  531. // Get the structure.
  532. #emit ADD.C 12
  533. #emit PUSH.pri
  534. // Get the length.
  535. #emit ADD.C 0xFFFFFFFC // -4
  536. #emit STOR.S.pri temp
  537. #emit LREF.S.pri temp
  538. #emit PUSH.pri
  539. // Get the data offset.
  540. #emit LOAD.S.alt playerid
  541. #emit SMUL
  542. #emit SMUL.C 4
  543. #emit MOVE.alt
  544. // Get the data pointer.
  545. #emit LOAD.S.pri p
  546. #emit ADD.C 4
  547. #emit STOR.S.pri temp
  548. #emit LREF.S.alt temp
  549. #emit LOAD.S.pri playerid
  550. #emit IDXADDR
  551. #emit MOVE.alt
  552. #emit LOAD.i
  553. #emit ADD
  554. #emit PUSH.pri
  555. // Save the next pointer.
  556. #emit LREF.S.pri p
  557. #emit STOR.S.pri p
  558. // Push the other parameters.
  559. #emit PUSH.S uid
  560. #emit PUSH.S playerid
  561. // Now push the size of data put on the stack.
  562. #emit PUSH.C 20
  563. // Now get the return address and push it.
  564. #emit LCTRL 6
  565. #emit ADD.C 32
  566. #emit PUSH.pri
  567. // Now start the function to store certain data.
  568. #emit PROC
  569. // Now jump in to the middle of the function.
  570. #emit LOAD.pri YSI_g_sDoDataPrintAddr
  571. #emit SCTRL 6
  572. // Now store the return value.
  573. /*#emit STOR.S.pri p*/
  574. // DO NOT CHANGE THE CODE ABOVE HERE!!!
  575. }
  576. }
  577. Users_DoDataReset(data[], len)
  578. {
  579. // OK, since it says not to change anything here, I should briefly explain
  580. // what it does so that people know why not to change it. This basically
  581. // gets the address of the code after the "#emit" blocks and stores that
  582. // address in a variable, then ends the function in a compiler-invisible
  583. // way. This variable is used to call this function directly later on in
  584. // the code from more "#emit" blocks so that pure addresses can be passed
  585. // instead of having the compiler complain that a variable is not an array
  586. // (it isn't, but it holds a reference to an array, and the method used to
  587. // pass the variable means the run-time thinks this is correct).
  588. // DO NOT CHANGE THE CODE BELOW HERE!!!
  589. #emit LCTRL 6
  590. #emit ADD.C 20
  591. #emit STOR.pri YSI_g_sDoDataResetAddr
  592. #emit RETN
  593. // DO NOT CHANGE THE CODE ABOVE HERE!!!
  594. // Need "memset" really! I have written a memset function based on looping
  595. // through a sub-set of an array, then using memcpy to copy that subset over
  596. // the rest of the array (which has shown nice speed-ups), but it needs more
  597. // testing to confirm that it does what I think it does. I also need to
  598. // determine the optimal block size (for which I have a script written, I
  599. // just need to run it).
  600. /*while (len--)
  601. {
  602. data[len] = 0;
  603. }*/
  604. // The "0" is the default parameter, but I've specified it anyway.
  605. memset(data, len, 0);
  606. }