分享

【函数库】PHP RXData(RPGXP数据文件) 解析库 V1.0

 勤奋不止 2024-01-11 发布于北京
                     文件名:rxdata_library.php
  1. </pre><pre name="code" class="php"><?php
  2. /**
  3. ** PHP RXData 解析库 V1.0
  4. **
  5. ** 本函数库是巨大八爪鱼编写的
  6. ** 使用和转载时请保留此信息
  7. **/
  8. define('MARSHAL_MAJOR', 4);
  9. define('MARSHAL_MINOR', 8);
  10. define('RBT_NIL', '0');
  11. define('RBT_TRUE', 'T');
  12. define('RBT_FALSE', 'F');
  13. define('RBT_FIXNUM', 'i');
  14. define('RBT_EXTENDED', 'e');
  15. define('RBT_UCLASS', 'C');
  16. define('RBT_OBJECT', 'o');
  17. define('RBT_DATA', 'd');
  18. define('RBT_USERDEF', 'u');
  19. define('RBT_USRMARSHAL', 'U');
  20. define('RBT_FLOAT', 'f');
  21. define('RBT_BIGNUM', 'l');
  22. define('RBT_STRING', '"');
  23. define('RBT_REGEXP', '/');
  24. define('RBT_ARRAY', '[');
  25. define('RBT_HASH', '{');
  26. define('RBT_HASH_DEF', '}');
  27. define('RBT_STRUCT', 'S');
  28. define('RBT_MODULE_OLD', 'M'); // 该类型为老版格式,已弃用
  29. define('RBT_CLASS', 'c');
  30. define('RBT_MODULE', 'm');
  31. define('RBT_SYMBOL', ':'); // 符号对象
  32. define('RBT_SYMLINK', ';'); // 链接到符号对象
  33. define('RBT_IVAR', 'I');
  34. define('RBT_LINK', '@'); // 链接到非符号对象
  35. define('ONIG_OPTION_IGNORECASE', 0x01);
  36. define('ONIG_OPTION_EXTEND', 0x02);
  37. define('ONIG_OPTION_MULTILINE', 0x04);
  38. define('SIZEOF_CHAR', 1);
  39. define('SIZEOF_DOUBLE', 8);
  40. define('SIZEOF_INT', 2);
  41. define('SIZEOF_LONG', 4); // 在C语言中,int和long都是4个字节...
  42. define('SIZEOF_LONGLONG', 8);
  43. class RubyClass {
  44. public $name;
  45. }
  46. class RubyModule extends RubyClass {}
  47. class RubyNil {}
  48. class RubyObject {
  49. public $_name = '';
  50. public $_length = 0;
  51. public $_extension = '';
  52. public $_data = array();
  53. public function __get($property) {
  54. if (is_numeric($this->_length)) {
  55. return $this->_data[$property];
  56. } else {
  57. if (isset($this->_data['extension'][$property])) {
  58. return $this->_data['extension'][$property];
  59. } else if (isset($this->data['base'][$property])) {
  60. return $this->_data['base'][$property];
  61. } else {
  62. return NULL;
  63. }
  64. }
  65. }
  66. }
  67. class RubySymbol {
  68. public $name;
  69. public function getMember(RubyObject $obj) {
  70. $member = $this->getMemberName();
  71. return $obj->_data[$member];
  72. }
  73. public function getMemberName() {
  74. if ($this->isMember()) {
  75. return substr($this->name, 1);
  76. } else {
  77. return $this->name;
  78. }
  79. }
  80. // 判断该符号对象是不是一个类的属性名称
  81. public function isMember() {
  82. return ($this->name{0} == '@');
  83. }
  84. public function setMember(RubyObject $obj, $value) {
  85. $member = $this->getMemberName();
  86. $obj->_data[$member] = $value;
  87. }
  88. }
  89. /* 根据文件名打开文件并读取一个项目,返回读取的对象并关闭文件 */
  90. function rxdata_load($filename) {
  91. $file = fopen($filename, 'rb');
  92. if ($file === false) {
  93. return NULL;
  94. }
  95. $data = rxdata_load_one($file);
  96. fclose($file);
  97. return $data;
  98. }
  99. /* 根据文件名打开文件并读取全部项目,通过数组返回后关闭文件 */
  100. function rxdata_load_all($filename) {
  101. $file = fopen($filename, 'rb');
  102. if ($file === false) {
  103. return NULL;
  104. }
  105. $data = array();
  106. while ($obj = rxdata_load_one($file)) {
  107. array_push($data, $obj);
  108. }
  109. return $data;
  110. }
  111. /* 从打开的文件中读取一个项目 */
  112. function rxdata_load_one($file) {
  113. $data = NULL;
  114. if (rxdata_read_header($file)) {
  115. rxdata_reset(); // 移除之前的符号表
  116. $data = rxdata_read($file);
  117. }
  118. return $data;
  119. }
  120. /* 读取文件中接下来的符号对象或符号链接所指向的符号对象,以该符号的名称作为对象名,创建并注册对象,返回所创建的对象 */
  121. function rxdata_prepare_object($file, $has_length = true) {
  122. // 在Ruby中,类名和变量名都是符号,且同名符号只能在内存中存在一次
  123. $sym = rxdata_read_symbol_block($file);
  124. $obj = new RubyObject();
  125. $obj->_name = $sym->name;
  126. if ($has_length) {
  127. $obj->_length = rxdata_read_long($file);
  128. }
  129. rxdata_register_object($obj); // 创建对象后立即注册对象(的引用),以便于之后能够链接到该对象
  130. return $obj;
  131. }
  132. function rxdata_read($file) {
  133. $type = fgetc($file);
  134. switch ($type) {
  135. case RBT_ARRAY:
  136. return rxdata_read_array($file);
  137. case RBT_BIGNUM:
  138. return rxdata_read_bignum($file);
  139. case RBT_CLASS:
  140. return rxdata_read_class($file);
  141. case RBT_EXTENDED:
  142. return rxdata_read_extended($file);
  143. case RBT_FALSE:
  144. return false;
  145. case RBT_FIXNUM:
  146. return rxdata_read_fixnum($file);
  147. case RBT_FLOAT:
  148. return rxdata_read_float($file);
  149. case RBT_HASH:
  150. return rxdata_read_hash($file);
  151. case RBT_HASH_DEF:
  152. return rxdata_read_hash($file, true);
  153. case RBT_IVAR:
  154. return rxdata_read_ivar($file);
  155. case RBT_LINK:
  156. return rxdata_read_link($file);
  157. case RBT_MODULE:
  158. return rxdata_read_module($file);
  159. case RBT_NIL:
  160. return new RubyNil();
  161. case RBT_OBJECT:
  162. case RBT_STRUCT:
  163. return rxdata_read_object($file);
  164. case RBT_REGEXP:
  165. return rxdata_read_regexp($file);
  166. case RBT_TRUE:
  167. return true;
  168. case RBT_STRING:
  169. return rxdata_read_string($file, true);
  170. case RBT_SYMBOL:
  171. return rxdata_read_symbol($file);
  172. case RBT_SYMLINK:
  173. return rxdata_read_symlink($file);
  174. case RBT_UCLASS:
  175. return rxdata_read_uclass($file);
  176. case RBT_USERDEF:
  177. return rxdata_read_userdef($file);
  178. case RBT_USRMARSHAL:
  179. return rxdata_read_usrmarshal($file);
  180. default:
  181. trigger_error(sprintf('文件中0x%x处含有无法识别的Ruby数据类型: \'%s\' (0x%02X)', ftell($file), $type, ord($type)), E_USER_WARNING);
  182. return NULL;
  183. }
  184. }
  185. function rxdata_read_array($file) {
  186. $arr = array();
  187. rxdata_register_object($arr);
  188. $len = rxdata_read_long($file);
  189. for ($i = 0; $i < $len; $i++) {
  190. $arr[$i] = rxdata_read($file);
  191. }
  192. return $arr;
  193. }
  194. /* 从文件中读取一个字节 */
  195. /* 此函数读出来的字节一定是无符号十六进制整数 */
  196. function rxdata_read_byte($file) {
  197. $ch = ord(fgetc($file));
  198. return $ch;
  199. }
  200. function rxdata_read_bignum($file) {
  201. $sign = fgetc($file);
  202. $n = rxdata_read_long($file);
  203. $num = rxdata_read_ulong($file, 2 * $n);
  204. if ($sign == '-') {
  205. $num = -$num;
  206. }
  207. rxdata_register_object($num);
  208. return $num;
  209. }
  210. function rxdata_read_class($file) {
  211. $class = new RubyClass();
  212. rxdata_register_object($class);
  213. $class->name = rxdata_read_string($file);
  214. return $class;
  215. }
  216. function rxdata_read_extended($file) {
  217. $ex = rxdata_read_symbol_block($file);
  218. $obj = rxdata_read($file);
  219. if (is_object($obj)) {
  220. $obj->_extension = $ex->name;
  221. return $obj;
  222. } else {
  223. $package = new RubyObject();
  224. $package->_length = count($obj);
  225. $package->_extension = $ex->name;
  226. $package->_data = $obj;
  227. rxdata_registry_replace($obj, $package); // 重定向连接表中的注册信息
  228. return $package;
  229. }
  230. }
  231. /*
  232. 注意:
  233. 使用rxdata_read_fixnum读取一个Fixnum对象
  234. 使用rxdata_read_long读取任意对象原始二进制数据中的长整数值(例如String对象中表示字符串长度的长整数)
  235. */
  236. function rxdata_read_fixnum($file) {
  237. // 在Ruby Marshal中,Fixnum类型的数据无需注册
  238. return rxdata_read_long($file);
  239. }
  240. function rxdata_read_float($file) {
  241. $str = rxdata_read_string($file);
  242. if (in_array($str, array('nan', 'inf', '-inf'))) {
  243. $data = $str;
  244. } else {
  245. $data = (float)$str;
  246. }
  247. rxdata_register_object($data);
  248. return $data;
  249. }
  250. function rxdata_read_hash($file, $hasDefaultValue = false) {
  251. $len = rxdata_read_long($file);
  252. $hash = array();
  253. if ($hasDefaultValue) {
  254. $obj = array(&$hash);
  255. } else {
  256. $obj = &$hash;
  257. }
  258. rxdata_register_object($obj);
  259. for ($i = 0; $i < $len; $i++) {
  260. $key = rxdata_read($file);
  261. $hash[$key] = rxdata_read($file);
  262. }
  263. if ($hasDefaultValue) {
  264. $obj[1] = rxdata_read($file);
  265. }
  266. return $obj;
  267. }
  268. /* 读取Marshal数据头 */
  269. function rxdata_read_header($file) {
  270. $oldpos = ftell($file);
  271. $a = rxdata_read_byte($file);
  272. $b = rxdata_read_byte($file);
  273. if ($a == MARSHAL_MAJOR && $b == MARSHAL_MINOR) {
  274. return true; // 如果读取成功则返回true,且指针移动到数据头的后面
  275. } else {
  276. fseek($file, $oldpos); // 如果读取失败,则退回到读取前的位置,并返回false
  277. return false;
  278. }
  279. }
  280. function rxdata_read_ivar($file) {
  281. $obj = rxdata_read($file);
  282. $base_len = $obj->_length;
  283. $base_data = $obj->_data;
  284. $obj->_length = rxdata_read_long($file);
  285. $obj->_data = array();
  286. rxdata_read_object($file, $obj);
  287. $obj->_length = array('base' => $base_len, 'extension' => $obj->_length);
  288. $obj->_data = array('base' => $base_data, 'extension' => $obj->_data);
  289. return $obj;
  290. }
  291. /* 链接到字节流中的非符号对象 */
  292. function rxdata_read_link($file) {
  293. $id = rxdata_read_long($file);
  294. return rxdata_fetch_object($id);
  295. }
  296. /* 读取一个经过Ruby Marshal特殊处理的有符号长整数(不含类型标记) */
  297. function rxdata_read_long($file) {
  298. $ch = to_signed(rxdata_read_byte($file));
  299. if ($ch == 0) {
  300. return 0;
  301. }
  302. if ($ch > 0) {
  303. if ($ch > 4 && $ch < 128) {
  304. return $ch - 5;
  305. }
  306. $x = 0;
  307. for ($i = 0; $i < $ch; $i++) {
  308. $x |= to_signed(rxdata_read_byte($file), SIZEOF_LONG) << (8 * $i);
  309. }
  310. } else {
  311. if ($ch > -129 && $ch < -4) {
  312. return $ch + 5;
  313. }
  314. $ch = -$ch;
  315. $x = -1;
  316. for ($i = 0; $i < $ch; $i++) {
  317. $x &= ~(0xff << (8 * $i));
  318. $x |= to_signed(rxdata_read_byte($file), SIZEOF_LONG) << (8 * $i);
  319. }
  320. }
  321. return $x;
  322. }
  323. function rxdata_read_module($file) {
  324. $module = new RubyModule();
  325. rxdata_register_object($module);
  326. $module->name = rxdata_read_string($file);
  327. return $module;
  328. }
  329. // 如果指定了参数$obj,则此函数只读取成员变量
  330. function rxdata_read_object($file, $obj = NULL) {
  331. if (is_null($obj)) {
  332. $obj = rxdata_prepare_object($file);
  333. }
  334. for ($i = 0; $i < $obj->_length; $i++) {
  335. $memsym = rxdata_read_symbol_block($file);
  336. $memsym->setMember($obj, rxdata_read($file, $obj));
  337. }
  338. return $obj;
  339. }
  340. function rxdata_read_regexp($file) {
  341. $reg = '/' . rxdata_read_string($file) . '/';
  342. $options = rxdata_read_byte($file);
  343. if ($options & ONIG_OPTION_IGNORECASE) {
  344. $reg .= 'i';
  345. }
  346. if ($options & ONIG_OPTION_MULTILINE) {
  347. $reg .= 'm';
  348. }
  349. if ($options & ONIG_OPTION_EXTEND) {
  350. $reg .= 'x';
  351. }
  352. rxdata_register_object($reg);
  353. return $reg;
  354. }
  355. function rxdata_read_string($file, $register = false) {
  356. $len = rxdata_read_long($file);
  357. if ($len > 0) {
  358. $str = fread($file, $len);
  359. } else {
  360. $str = '';
  361. }
  362. if ($register) {
  363. rxdata_register_object($str);
  364. }
  365. return $str;
  366. }
  367. function rxdata_read_symbol($file) {
  368. $symbol = new RubySymbol();
  369. $symbol->name = rxdata_read_string($file);
  370. rxdata_register_symbol($symbol); // 注册该符号,以便于之后链接回来。因为在内存中,同名符号对象只允许存在一次
  371. return $symbol;
  372. }
  373. function rxdata_read_symbol_block($file) {
  374. $type = fgetc($file);
  375. if ($type == RBT_SYMBOL) {
  376. return rxdata_read_symbol($file);
  377. } else if ($type == RBT_SYMLINK) {
  378. return rxdata_read_symlink($file);
  379. } else {
  380. return NULL;
  381. }
  382. }
  383. function rxdata_read_symlink($file) {
  384. $id = rxdata_read_long($file);
  385. return rxdata_fetch_symbol($id);
  386. }
  387. function rxdata_read_uclass($file) {
  388. $obj = rxdata_prepare_object($file, false);
  389. $next_registry = count($GLOBALS['_RBOBJLIST']);
  390. $obj->_data = rxdata_read($file);
  391. rxdata_unregister_object($next_registry); // 由于$obj已经注册,所以需要删除重复注册的$obj->_data
  392. $obj->_length = count($obj->_data);
  393. return $obj;
  394. }
  395. /* 获取一个由固定n个字节(小端序)表示的无符号整数 */
  396. function rxdata_read_ulong($file, $n = SIZEOF_LONG) {
  397. $num = 0;
  398. for ($i = 0; $i < $n; $i++) {
  399. $v = rxdata_read_byte($file);
  400. $num += ($v << ($i * 8));
  401. }
  402. return $num;
  403. }
  404. // 注意:由于$obj已经注册,所以返回时必须返回$obj,不能返回其他变量
  405. function rxdata_read_userdef($file) {
  406. $obj = rxdata_prepare_object($file);
  407. switch ($obj->_name) {
  408. case 'Table':
  409. // Table是RGSS自带的内部类,不是Ruby自带的类
  410. // 地图图层的三维数组的结构是: data[x坐标, y坐标, 地图id]
  411. $dim = rxdata_read_ulong($file); // 数组的维数
  412. $xsize = rxdata_read_ulong($file);
  413. $ysize = rxdata_read_ulong($file);
  414. $zsize = rxdata_read_ulong($file);
  415. $total = rxdata_read_ulong($file);
  416. $arr = array();
  417. for ($i = 0; $i < $total; $i++) {
  418. $value = to_signed(rxdata_read_ulong($file, SIZEOF_INT), SIZEOF_INT);
  419. if ($dim == 1) {
  420. $arr[$i] = $value;
  421. } else if ($dim == 2) {
  422. $x = $i % $xsize;
  423. $y = (int)($i / $xsize);
  424. if (!isset($arr[$x])) {
  425. $arr[$x] = array();
  426. }
  427. $arr[$x][$y] = $value;
  428. } else if ($dim == 3) {
  429. $x = $i % $xsize;
  430. $y = (int)($i % ($xsize * $ysize) / $xsize);
  431. $z = (int)($i / ($xsize * $ysize));
  432. if (!isset($arr[$x])) {
  433. $arr[$x] = array();
  434. }
  435. if (!isset($arr[$x][$y])) {
  436. $arr[$x][$y] = array();
  437. }
  438. $arr[$x][$y][$z] = $value;
  439. }
  440. }
  441. $obj->_data = $arr;
  442. break;
  443. case 'Color':
  444. case 'Tone':
  445. $format = 'dred/dgreen/dblue/d';
  446. if ($obj->_name == 'Color') {
  447. $format .= 'alpha';
  448. } else {
  449. $format .= 'gray';
  450. }
  451. $data = fread($file, 4 * SIZEOF_DOUBLE);
  452. $obj->_data = unpack($format, $data);
  453. break;
  454. default:
  455. /* 输出范例:
  456. ** Array ( [0] => RubyObject Object ( [_name] => Color [_length] => 32 [_data] => Array ( ) [data] => 00 00 00 00 00 C0 58 40 00 00 00 00 00 00 59 40 00 00 00 00 00 C0 62 40 00 00 00 00 00 E0 6F 40 ) )
  457. **/
  458. $data = fread($file, $obj->_length);
  459. trigger_error("无法解析的自定义对象类型\"{$obj->_name}\"", E_USER_NOTICE);
  460. $obj->_data = '';
  461. for ($i = 0; $i < $obj->_length; $i++) {
  462. $obj->_data .= sprintf("%02X ", ord($data{$i}));
  463. }
  464. $obj->_data = rtrim($obj->_data);
  465. }
  466. return $obj;
  467. }
  468. function rxdata_read_usrmarshal($file) {
  469. $obj = rxdata_prepare_object($file, false);
  470. $obj->_length = 1;
  471. $obj->_data = rxdata_read($file);
  472. return $obj;
  473. }
  474. /* Ruby链接列表相关函数 */
  475. $_RBOBJLIST = array(); // 当前字节流中出现的所有非符号对象
  476. $_RBSYMLIST = array(); // 当前字节流中出现的所有符号对象
  477. // 获取已注册的非符号对象
  478. function rxdata_fetch_object($id) {
  479. global $_RBOBJLIST;
  480. if (isset($_RBOBJLIST[$id])) {
  481. return $_RBOBJLIST[$id];
  482. } else {
  483. trigger_error(sprintf('引用未注册的非符号对象ID: %d,已注册的最大ID为: %d', $id, count($_RBOBJLIST) - 1), E_USER_WARNING);
  484. return NULL;
  485. }
  486. }
  487. // 获取已注册的符号对象
  488. function rxdata_fetch_symbol($id) {
  489. global $_RBSYMLIST;
  490. if (isset($_RBSYMLIST[$id])) {
  491. return $_RBSYMLIST[$id];
  492. } else {
  493. trigger_error(sprintf('引用未注册的符号对象ID: %d,已注册的最大ID为: %d', $id, count($_RBSYMLIST) - 1), E_USER_WARNING);
  494. return NULL;
  495. }
  496. }
  497. // 注册非符号对象
  498. function rxdata_register_object(&$obj) {
  499. global $_RBOBJLIST;
  500. $id = count($_RBOBJLIST);
  501. $_RBOBJLIST[$id] = &$obj;
  502. return $id;
  503. }
  504. // 注册符号对象
  505. function rxdata_register_symbol(RubySymbol $sym) {
  506. global $_RBSYMLIST;
  507. $id = count($_RBSYMLIST);
  508. $_RBSYMLIST[$id] = $sym; // $sym本身就是一个php对象,所以这里无需加上引用符号
  509. return $id;
  510. }
  511. // 替换非符号对象注册信息
  512. function rxdata_registry_replace(&$old, &$new) {
  513. global $_RBOBJLIST;
  514. foreach ($_RBOBJLIST as $i => $v) {
  515. if ($v === $old) {
  516. $_RBOBJLIST[$i] = &$new;
  517. }
  518. }
  519. }
  520. // 清空上一个字节流的所有链接列表
  521. function rxdata_reset() {
  522. $GLOBALS['_RBOBJLIST'] = array();
  523. $GLOBALS['_RBSYMLIST'] = array();
  524. }
  525. function rxdata_unregister_object($id = NULL) {
  526. global $_RBOBJLIST;
  527. if (is_null($id)) {
  528. // 取消注册最近注册的对象
  529. array_pop($_RBOBJLIST);
  530. } else {
  531. // 取消注册指定序号的对象
  532. unset($_RBOBJLIST[$id]);
  533. $_RBOBJLIST = array_values($_RBOBJLIST);
  534. }
  535. }
  536. /* 将无符号十六进制数转换为有符号十进制整数, 参数$bytes规定了有符号整数类型的字节数 */
  537. /* 在marshal.c中,宏SIGN_EXTEND_CHAR(n)就相当于这里的to_signed(n) */
  538. function to_signed($hex, $bytes = SIZEOF_CHAR) {
  539. $mask = 1 << ($bytes * 8 - 1);
  540. return ($hex ^ $mask) - $mask;
  541. }
  542. /* 将有符号十进制整数转换为无符号十六进制整数 */
  543. function to_unsigned($dex, $bytes = SIZEOF_CHAR) {
  544. $mask = 1 << ($bytes * 8 - 1);
  545. return ($dex + $mask) ^ $mask;
  546. }
  547. // 在64位php中,整数1的十六进制是0x01,而整数-1的十六进制数是0xffffffffffffffff
  548. // 因此,如果想要char a = -1的十六进制值,只需在php中写上-1 & 0xff即可
  549. // echo '0x', dechex(-1 & 0xff); // 输出0xff
  550. // 使用to_unsigned函数也能达到同样的目的: echo to_unsigned(-1, SIZEOF_CHAR);
  551. // 此外,php还提供了unpack函数读取二进制字符串表示的无符号整数
  552. ?>

函数库中的三个重要函数:
rxdata_load($filename)
根据文件名打开文件并读取一个项目,返回读取的对象并关闭文件。

rxdata_load_all($filename)
根据文件名打开文件并读取全部项目,通过数组返回后关闭文件。
如果文件打开失败,返回NULL。如果文件打开成功但读取失败,则返回空数组。

rxdata_load_one($file)
从打开的文件中读取一个项目,$file为fopen打开的文件。

注意:
如果读到的是Ruby的nil对象,函数返回PHP的RubyNil对象。

如果读取失败或遇到文件结束,则返回NULL。

一般情况下,RMXP工程中的Data文件夹中的每个rxdata文件都只含有一个项目,而Save存档的rxdata文件中则含有多个项目。
读取Scripts.rxdata时,如果需要获取其中的Ruby脚本内容,只需执行php的gzuncompress函数即可完成解码。

【示例代码1:读取一个存档文件的内容】
<?php
include_once('rxdata_library.php');
$maps = rxdata_load_all('project/Save1.rxdata');
print_r($maps);
?>
【运行结果】

【示例代码2:读取Data文件夹下一个普通的rxdata文件】
<?php
include_once('rxdata_library.php');
$maps = rxdata_load('project/Data/MapInfos.rxdata');
print_r($maps);
?>
【运行结果】

【示例代码3:打开MapInfos.rxdata文件并输出其中存储的RPGXP工程中所有地图的名称】
<?php
include_once('rxdata_library.php');
$maps = rxdata_load('project/Data/MapInfos.rxdata');
foreach ($maps as $map) {
 echo $map->name, '<br>';
}
?>
【运行结果】

【示例代码4:输出所有地图的名称和大小等信息】
<?php
include_once('rxdata_library.php');
$maps = rxdata_load('project/Data/MapInfos.rxdata');
foreach ($maps as $map_id => $map) {
 $map_info = rxdata_load(sprintf('project/Data/Map%03d.rxdata', $map_id));
 $events_num = count($map_info->events);
 if (isset($map_info->events[1])) {
  $first_event_name = $map_info->events[1]->name;
 } else {
  $first_event_name = '无';
 }
 printf('地图: %s, 尺寸: %dx%d, 事件数: %d, 第一个事件的名称: %s<br>', $map->name, $map_info->width, $map_info->height, $events_num, $first_event_name);
}
?>

【运行结果】

【示例代码5:以表格的形式输出工程中的所有地图】
<?php
include_once('rxdata_library.php');
$maps = rxdata_load('Data/MapInfos.rxdata');
?>
<!doctype html>
<html>
<head>
<title>地图列表</title>
<style>
body {
 font-family: Arial, Helvetica;
 font-size: 14px;
}
</style>
</head>
<body>
<table border="1">
  <tr>
    <td>地图ID</td>
    <td>地图名称</td>
    <td>地图尺寸</td>
    <td>事件数量</td>
  </tr>
<?php
$i = 0;
foreach ($maps as $id => $map) {
 $mapfile = rxdata_load(sprintf("Data/Map%03d.rxdata", $id));
?>
  <tr>
    <td><?=$id?></td>
    <td><?=$map->name?></td>
    <td><?=$mapfile->width?>x<?=$mapfile->height?></td>
    <td><?=count($mapfile->events)?></td>
  </tr>
<?php } ?>
  <tr>
    <td colspan="4">共有<span style="color:red"><?=count($maps)?></span>张地图。</td>
  </tr>
</table>
</body>
</html>
【运行结果】

【示例代码6:读取脚本内容】
<?php
include_once('rxdata_library.php');
$scripts = rxdata_load('project/Data/Scripts.rxdata');
$txt = gzuncompress($scripts[1][2]);
echo nl2br($txt); // 把\n转换为<br>
?>
【运行结果】

【示例7:把工程中的所有脚本全部保存为txt文件】
<?php
include_once('rxdata_library.php');
if (!is_writable(getcwd())) {
 die('当前文件夹下无写入权限!');
}
$folder_name = 'scripts';
if (is_dir($folder_name)) {
 // 如果目录存在,则删除目录下所有文件
 $dir = opendir($folder_name);
 while ($file = readdir($dir)) {
  $file = $folder_name . '/' . $file;
  if (!is_dir($file)) {
   unlink($file);
  }
 }
 closedir($dir);
} else {
 mkdir($folder_name);
}
$scripts = rxdata_load('project/Data/Scripts.rxdata');
foreach ($scripts as $script) {
 if ($script[1] == '')
  $script[1] = 'empty';
 $filename = $folder_name . '/' . $script[1] . '.txt';
 $fp = fopen($filename, 'w');
 fwrite($fp, gzuncompress($script[2]));
 fclose($fp);
}
printf("共保存了%d个文件", count($scripts));
?>

【运行结果】

保存的txt文件:

打开其中一个txt文件查看:


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多