ini.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /**--------------------------------------------------------------------------**\
  2. =================================
  3. y_svar - Automatic data saving.
  4. =================================
  5. Description:
  6. Declares data to be automatically saved and loaded for the whole server.
  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
  43. Changelog:
  44. 25/02/12:
  45. First version.
  46. Functions:
  47. Stock:
  48. -
  49. Inline:
  50. -
  51. Variables:
  52. Global:
  53. -
  54. </remarks>
  55. \**--------------------------------------------------------------------------**/
  56. #include "internal\y_version"
  57. #include "y_amx"
  58. #include "y_debug"
  59. #include "y_utils"
  60. #include "y_ini"
  61. #include "y_hooks"
  62. #include "internal\y_stripnumbers"
  63. // Third "uvar" version.
  64. #define _YS@LE@E%0>
  65. #define _YS@LT@E%0> ;
  66. #define _YS@LM:%0[%1][%2] STRIP_NUMBERS:%0[%1]|||%2:0|||,sizeof(%0[])
  67. // Needs two levels of indirection to strip the excess commas (,%0,%1).
  68. #define _YS@LO(,%0,[%2]%4) %0@yS_();public %0@yS_(){M@(#...#%0,_:%2,STRIP_NUMBERS:_YS@LM:%0|||%2:0|||%4);}
  69. #define _YS@LE%0[%3]%4,%2> _YS@LO(%0,[%3]%4) _YS@LE%2>
  70. // Recursive local default string definition.
  71. #define _YS@LJ(,%0,%2) %0%2
  72. #define _YS@LT%0[%3]%4,%2> ,_YS@LJ(%0,[%3]%4)_YS@LT%2>
  73. #define _YS@LA%0[%3]%4,%2> _YS@LJ(%0,[%3]%4)_YS@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] - Size of enum.
  79. // [3] - Start of name.
  80. //
  81. //#define svar%0[%1]%2; stock _YS@LA,%0[%1]%2@E>_YS@LE,%0[%1]%2@E>
  82. #define svar%0; stock _YS@LA,%0,@E>_YS@LE,%0,@E>
  83. //%0@yS_();public%0@yS_()M@(_:%0,#....#%0 _YA@LT %1,@E|||);
  84. // This is a structure defining the data stored on the enum structure.
  85. /*enum E_USERS_FAKE_DATA
  86. {
  87. E_USERS_FAKE_DATA_NEXT,
  88. E_USERS_FAKE_DATA_DATA,
  89. E_USERS_FAKE_DATA_LEN,
  90. E_USERS_FAKE_DATA_STR[2]
  91. }*/
  92. static stock
  93. YSI_g_sFirstUVarData = -1,
  94. // These three variables are used to speed up data loading through caching.
  95. YSI_g_sLastName[32] = "\1\0",
  96. YSI_g_sLastAddr,
  97. YSI_g_sLastSize;
  98. forward _y_svar_include_@();
  99. public _y_svar_include_@()
  100. {
  101. //memset("", 0, 0, 0);
  102. INI_WriteArray(INI_NO_FILE, "", "", 0);
  103. }
  104. static stock Svar_FindData(const name[], data[])
  105. {
  106. // This function gets passed an empty string so that we can use "data" as a
  107. // string, while secretly changing the pointer in AMX code.
  108. new
  109. p = YSI_g_sFirstUVarData;
  110. while (p != -1)
  111. {
  112. // Modify our data pointer.
  113. #emit LOAD.S.pri p
  114. #emit STOR.S.pri data
  115. if (!strcmp(data[3], name))
  116. {
  117. strcpy(YSI_g_sLastName, name);
  118. YSI_g_sLastSize = data[2];
  119. YSI_g_sLastAddr = data[1];
  120. //printf("found %s, %d, %d, %d", YSI_g_sLastName, YSI_g_sLastSize, YSI_g_sLastPlayers, YSI_g_sLastAddr);
  121. return;
  122. }
  123. p = data[0];
  124. }
  125. YSI_g_sLastAddr = -1;
  126. }
  127. forward _Config_Load_y_svar(name[], value[]);
  128. public _Config_Load_y_svar(name[], value[])
  129. {
  130. P:1("_Config_Load_y_svar called: %s %s", name, value);
  131. // See what the name of the loaded data was.
  132. new
  133. pos = strfind(name, "-");
  134. if (pos == -1)
  135. {
  136. if (strcmp(name, YSI_g_sLastName))
  137. {
  138. // Find the data.
  139. Svar_FindData(name, "");
  140. }
  141. if (YSI_g_sLastAddr == -1)
  142. {
  143. return;
  144. }
  145. // Check that the data is the right size.
  146. P:C(if (strval(value) != YSI_g_sLastSize) P:E("uvar data changed in %s", YSI_g_sLastName););
  147. }
  148. else
  149. {
  150. // Get the position in the array of this data.
  151. name[pos] = '\0';
  152. pos = strval(name[pos + 1]) * ((MAX_INI_ENTRY_TEXT - 1) / 16 * 3);
  153. if (strcmp(name[2], YSI_g_sLastName, false))
  154. {
  155. // Find the data.
  156. Svar_FindData(name[2], "");
  157. }
  158. if (YSI_g_sLastAddr == -1)
  159. {
  160. return;
  161. }
  162. // This must come BEFORE the "#emit" due to bugs with braces.
  163. new
  164. len = strlen(value),
  165. idx;
  166. // Save this pointer to an array variable for simplicity.
  167. #emit LOAD.pri YSI_g_sLastAddr
  168. #emit STOR.S.pri name
  169. // "pos" holds the offset of this data. "value" always holds a
  170. // whole number of cells worth of data.
  171. while (idx + 16 <= len)
  172. {
  173. // Do the large chunks.
  174. name[pos++] = ((value[idx + 0] - '>') << 26)
  175. | ((value[idx + 1] - '>') << 20)
  176. | ((value[idx + 2] - '>') << 14)
  177. | ((value[idx + 3] - '>') << 8)
  178. | ((value[idx + 4] - '>') << 2)
  179. | ((value[idx + 5] - '>') >> 4);
  180. // Second cell.
  181. name[pos++] = ((value[idx + 5] - '>') << 28)
  182. | ((value[idx + 6] - '>') << 22)
  183. | ((value[idx + 7] - '>') << 16)
  184. | ((value[idx + 8] - '>') << 10)
  185. | ((value[idx + 9] - '>') << 4)
  186. | ((value[idx + 10] - '>') >> 2);
  187. // Third cell.
  188. name[pos++] = ((value[idx + 10] - '>') << 30)
  189. | ((value[idx + 11] - '>') << 24)
  190. | ((value[idx + 12] - '>') << 18)
  191. | ((value[idx + 13] - '>') << 12)
  192. | ((value[idx + 14] - '>') << 6)
  193. | ((value[idx + 15] - '>') >> 0);
  194. // 16 characters are used to encode 3 cells (12 bytes) by only
  195. // saving 6 bits per character to ensure that they are always
  196. // valid characters. 7 bits may be easier, but would mean the
  197. // encoding fit less well to small numbers of cells.
  198. idx += 16;
  199. }
  200. if (idx + 6 <= len)
  201. {
  202. // Save any few extra bytes.
  203. name[pos++] = ((value[idx + 0] - '>') << 26)
  204. | ((value[idx + 1] - '>') << 20)
  205. | ((value[idx + 2] - '>') << 14)
  206. | ((value[idx + 3] - '>') << 8)
  207. | ((value[idx + 4] - '>') << 2)
  208. | ((value[idx + 5] - '>') >> 4);
  209. if (idx + 11 <= len)
  210. {
  211. name[pos++] = ((value[idx + 5] - '>') << 28)
  212. | ((value[idx + 6] - '>') << 22)
  213. | ((value[idx + 7] - '>') << 16)
  214. | ((value[idx + 8] - '>') << 10)
  215. | ((value[idx + 9] - '>') << 4)
  216. | ((value[idx + 10] - '>') >> 2);
  217. }
  218. }
  219. }
  220. }
  221. /**--------------------------------------------------------------------------**\
  222. <summary>M@</summary>
  223. <param name="volatile vardata[]">Handle to the memory location in which to store info.</param>
  224. <param name="dataSize">The size of the array (first dimension).</param>
  225. <param name="&pointer">The start of the data.</param>
  226. <param name="ds2 = 1">The second dimension of the data.</param>
  227. <returns>
  228. -
  229. </returns>
  230. <remarks>
  231. This function modifies "vardata" well beyond its original limits to contain
  232. information on the structure of the enum used to define "val". This code
  233. uses the name and size information passed in the additional parameters as
  234. strings, and makes assumptions about how the compiler lays out memory to
  235. combine all the passed strings in to one big string in what could be ROM,
  236. but in SA:MP isn't. This takes a human readable(ish) description of the
  237. array elements and converts it in to a much simpler to read format for the
  238. computer to use later when loading and storing data.
  239. </remarks>
  240. \**--------------------------------------------------------------------------**/
  241. stock M@(volatile const vardata[], dataSize, &pointer, ds2 = 1)
  242. {
  243. dataSize *= ds2;
  244. P:2("M@ called");
  245. new
  246. sAddr;
  247. // Store the basic data, including linked-list pointers and a pointer to the
  248. // location at which the data is stored.
  249. #emit LOAD.S.pri vardata
  250. #emit STOR.S.pri sAddr
  251. printf("", YSI_g_sFirstUVarData);
  252. #emit LOAD.pri YSI_g_sFirstUVarData
  253. #emit SREF.S.pri sAddr
  254. YSI_g_sFirstUVarData = sAddr;
  255. sAddr += 4;
  256. #emit LOAD.S.pri pointer
  257. #emit SREF.S.pri sAddr
  258. sAddr += 4;
  259. #emit LOAD.S.pri dataSize
  260. #emit SREF.S.pri sAddr
  261. P:5("M@: %d %d %d %d %s", vardata[0], vardata[1], vardata[2], vardata[3], vardata[4]);
  262. P:5("M@: %d", YSI_g_sFirstUVarData);
  263. }
  264. hook OnScriptExit()
  265. {
  266. P:1("Svar_OnScriptExit called");
  267. // Loop through all the player data items and write them to a file.
  268. new
  269. INI:__fwrite = INI_Open("YSI/" #MODE_NAME "_config.ini");
  270. if (__fwrite == INI_NO_FILE)
  271. {
  272. P:E("y_svar could not open data file for " #MODE_NAME);
  273. return;
  274. }
  275. INI_SetTag(__fwrite, "y_svar");
  276. new
  277. p = YSI_g_sFirstUVarData,
  278. temp;
  279. while (p != -1)
  280. {
  281. // DO NOT CHANGE THE CODE BELOW HERE!!!
  282. // Get the data size.
  283. #emit LOAD.S.pri p
  284. #emit ADD.C 8
  285. #emit STOR.S.pri temp
  286. #emit LREF.S.pri temp
  287. #emit PUSH.pri
  288. // Get the data pointer.
  289. #emit LOAD.S.pri p
  290. #emit ADD.C 4
  291. #emit STOR.S.pri temp
  292. #emit LREF.S.pri temp
  293. #emit PUSH.pri
  294. // Get the function name.
  295. #emit LOAD.S.pri p
  296. #emit ADD.C 12
  297. #emit PUSH.pri
  298. // Save the next pointer.
  299. #emit LREF.S.pri p
  300. #emit STOR.S.pri p
  301. // Now push the size of data put on the stack.
  302. #emit PUSH.S __fwrite
  303. #emit PUSH.C 16
  304. // Now get the return address and push it.
  305. #emit LCTRL 6
  306. #emit ADD.C 28
  307. #emit PUSH.pri
  308. // Call "Player_WriteArray" directly.
  309. #emit CONST.pri INI_WriteArray
  310. #emit SCTRL 6
  311. // DO NOT CHANGE THE CODE ABOVE HERE!!!
  312. }
  313. INI_Close(__fwrite);
  314. }
  315. hook OnScriptInit()
  316. {
  317. P:1("hook Svar_OnScriptInit called");
  318. // List them all.
  319. YSI_g_sFirstUVarData = -1;
  320. // Call all @yS_ functions to get all required data.
  321. new
  322. idx,
  323. buffer;
  324. while ((idx = AMX_GetPublicPointerSuffix(idx, buffer, _A<@yS_>)))
  325. {
  326. #emit PUSH.C 0
  327. #emit LCTRL 6
  328. #emit ADD.C 28
  329. #emit PUSH.pri
  330. #emit LOAD.S.pri buffer
  331. #emit SCTRL 6
  332. }
  333. // We don't need any of the reset code, but we do need the loading code.
  334. #if !defined _YSI_ONLY_ONE_CONFIG_LOAD
  335. #define _YSI_ONLY_ONE_CONFIG_LOAD
  336. INI_ParseFile("YSI/" #MODE_NAME "_config.ini", "_Config_Load_%s");
  337. #endif
  338. }