PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/cod_daemon/lib/classes/PlayerManager.php

https://code.google.com/p/php-blackops-rcon/
PHP | 790 lines | 451 code | 110 blank | 229 comment | 73 complexity | 20cf96c4d0f5168aeb198a2596dfb255 MD5 | raw file
  1. <?php defined('ROOT_PATH') or die('No direct script access.');
  2. __autoload('Player');
  3. /**
  4. * Player manager
  5. *
  6. * Copyright (c) 2011, EpicLegion
  7. * All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  10. *
  11. * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  16. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  18. * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  19. * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  20. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  21. * POSSIBILITY OF SUCH DAMAGE.
  22. *
  23. * @author EpicLegion
  24. * @package cod_daemon
  25. * @subpackage game
  26. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  27. */
  28. final class PlayerManager
  29. {
  30. // Deny / allow
  31. const DENY = 1;
  32. const ALLOW = 2;
  33. /**
  34. * @var array
  35. */
  36. static protected $acl = array();
  37. /**
  38. * @var array
  39. */
  40. static protected $aclDefault = array();
  41. /**
  42. * @var array
  43. */
  44. static protected $groups = array();
  45. /**
  46. * @var array
  47. */
  48. static protected $players = array();
  49. /**
  50. * @var array
  51. */
  52. static protected $users = array();
  53. /**
  54. * Do ACL check
  55. *
  56. * @return bool
  57. */
  58. public static function aclCheck($guid, $id)
  59. {
  60. // Server ID
  61. $server = Server::get('id');
  62. // Check expiration
  63. if (isset(self::$acl[$server][$guid]) AND self::$acl[$server][$guid]['expires'] > 0 AND self::$acl[$server][$guid]['expires'] <= time())
  64. {
  65. unset(self::$acl[$server][$guid]);
  66. }
  67. // ACL
  68. if ((self::$aclDefault[$server] == self::DENY AND !isset(self::$acl[$server][$guid]))
  69. OR (isset(self::$acl[$server][$guid]) AND self::$acl[$server][$guid]['action'] == self::DENY))
  70. {
  71. // Fake player object
  72. $player = new Player($guid, $id, 'none', 'none');
  73. // Reason
  74. if (isset(self::$acl[$server][$guid]))
  75. {
  76. $reason = self::$acl[$server][$guid]['reason'];
  77. }
  78. else
  79. {
  80. $reason = __('Private server');
  81. }
  82. // Kick
  83. Server::get()->kick($player, $reason);
  84. // Done
  85. return FALSE;
  86. }
  87. // Valid player
  88. return TRUE;
  89. }
  90. /**
  91. * Cleanup player list
  92. */
  93. public static function clear()
  94. {
  95. if (isset(self::$players[Server::get('id')]))
  96. {
  97. self::$players[Server::get('id')] = array();
  98. }
  99. }
  100. /**
  101. * Find matching user(s) by name
  102. *
  103. * @param string $rule
  104. * @param bool $multiple
  105. * @return Player
  106. */
  107. public static function find($rule, $multiple = FALSE)
  108. {
  109. // No server?
  110. if (!isset(self::$players[Server::get('id')]))
  111. {
  112. return $multiple ? array() : NULL;
  113. }
  114. // Result
  115. $result = array();
  116. // Iterate
  117. foreach (self::$players[Server::get('id')] as $p)
  118. {
  119. // Exact match
  120. if ($p->name == $rule)
  121. {
  122. $result[] = $p;
  123. }
  124. elseif (stripos($p->name, $rule) !== FALSE)
  125. {
  126. $result[] = $p;
  127. }
  128. // Break
  129. if (!$multiple AND !empty($result)) break;
  130. }
  131. // Single player
  132. if (!$multiple)
  133. {
  134. // Found?
  135. if (!isset($result[0]))
  136. {
  137. // Get status
  138. $status = Server::get()->teamStatus();
  139. // Iterate
  140. foreach ($status['players'] as $p)
  141. {
  142. // Match
  143. if ($p['name'] == $rule OR stripos($p['name'], $rule) !== FALSE)
  144. {
  145. // Exists?
  146. if (!isset(self::$players[Server::get('id')][$p['guid']]))
  147. {
  148. self::readPlayer($p['guid'], $p['id'], $p['name']);
  149. }
  150. return self::$players[Server::get('id')][$p['guid']];
  151. }
  152. }
  153. return NULL;
  154. }
  155. return $result[0];
  156. }
  157. // Multiple players
  158. return $result;
  159. }
  160. /**
  161. * Find player by GUID
  162. *
  163. * @param int $guid
  164. * @return Player
  165. */
  166. public static function findGUID($guid)
  167. {
  168. // No server?
  169. if (!isset(self::$players[Server::get('id')]))
  170. {
  171. return NULL;
  172. }
  173. // Iterate
  174. foreach (self::$players[Server::get('id')] as $p)
  175. {
  176. // Exact match
  177. if ($p->guid == $guid)
  178. {
  179. return $p;
  180. }
  181. }
  182. // Not found
  183. return NULL;
  184. }
  185. /**
  186. * Get flags for player
  187. *
  188. * @param int $guid
  189. * @return array
  190. */
  191. public static function getFlags($guid)
  192. {
  193. // Nope?
  194. if (!isset(self::$users[Server::get('id')][$guid]))
  195. {
  196. return isset(self::$users[Server::get('id')]['none']) ? self::$users[Server::get('id')]['none']['flags'] : array();
  197. }
  198. // Yeah they do exist
  199. return self::$users[Server::get('id')][$guid]['flags'];
  200. }
  201. /**
  202. * Get group name
  203. *
  204. * @param int $guid
  205. * @return string
  206. */
  207. public static function getGroup($guid)
  208. {
  209. // None?
  210. if (!isset(self::$users[Server::get('id')][$guid]))
  211. {
  212. return NULL;
  213. }
  214. // Return
  215. return self::$users[Server::get('id')][$guid]['group'];
  216. }
  217. /**
  218. * Get players list
  219. *
  220. * @param bool $all
  221. * @return array
  222. */
  223. public static function getPlayers($all = FALSE)
  224. {
  225. // All servers
  226. if ($all) return self::$players;
  227. // Single server
  228. if (isset(self::$players[Server::get('id')]))
  229. {
  230. return self::$players[Server::get('id')];
  231. }
  232. // None
  233. return array();
  234. }
  235. /**
  236. * Initialize player manager
  237. */
  238. public static function init()
  239. {
  240. // Clear
  241. self::$groups = array();
  242. self::$users = array();
  243. self::$acl = array();
  244. self::$aclDefault = array();
  245. // Events
  246. Event::add('onExitLevel' , array('PlayerManager', 'clear'));
  247. Event::add('onQuit' , array('PlayerManager', 'removePlayer'));
  248. Event::add('onConfigReload', array('PlayerManager', 'reloadConfig'));
  249. // Set group command
  250. Commands::add('setgroup', array('PlayerManager', 'setGroup'), 'setgroup');
  251. // Config for every server
  252. foreach (ServerManager::get() as $server)
  253. {
  254. // Server ID
  255. $id = $server->id;
  256. // Arrays
  257. self::$groups[$id] = array();
  258. self::$users[$id] = array();
  259. self::$acl[$id] = array();
  260. // Default ACL action
  261. self::$aclDefault[$id] = Config::get('users.private_server', FALSE, 'server-'.$id) ? self::DENY : self::ALLOW;
  262. // Load config
  263. $config = Config::get('users', array(), 'server-'.$id);
  264. // ACL
  265. if (isset($config['acl']) AND is_array($config['acl']))
  266. {
  267. // Iterate
  268. foreach ($config['acl'] as $guid => $info)
  269. {
  270. // Invalid
  271. if (!ctype_digit($guid) OR !is_array($info) OR !isset($info['deny']) OR !isset($info['expires']))
  272. {
  273. continue;
  274. }
  275. // Reason?
  276. if (!isset($info['reason']))
  277. {
  278. $info['reason'] = __('Access denied');
  279. }
  280. // Set
  281. self::$acl[$id][(int) $guid] = array('action' => $info['deny'] ? self::DENY : self::ALLOW, 'expires' => (int) $info['expires'], 'reason' => $info['reason']);
  282. }
  283. }
  284. // Groups
  285. if (isset($config['groups']) AND is_array($config['groups']))
  286. {
  287. // Iterate
  288. foreach ($config['groups'] as $g)
  289. {
  290. // Validate
  291. if (!is_array($g) OR count($g) != 2 OR !isset($g[0]) OR !isset($g[1]))
  292. {
  293. continue;
  294. }
  295. // Flags
  296. $flags = array();
  297. if ($g[1] AND is_string($g[1]))
  298. {
  299. // Single flag
  300. if (!strstr($g[1], ';'))
  301. {
  302. $flags[$g[1]] = $g[1];
  303. }
  304. else
  305. {
  306. $g[1] = explode(';', $g[1]);
  307. foreach ($g[1] as $v)
  308. {
  309. if (empty($v))
  310. {
  311. continue;
  312. }
  313. $flags[$v] = $v;
  314. }
  315. }
  316. }
  317. // Add
  318. self::$groups[$id][(string) $g[0]] = $flags;
  319. }
  320. }
  321. // Users
  322. if (isset($config['users']) AND is_array($config['users']))
  323. {
  324. // Iterate
  325. foreach ($config['users'] as $u)
  326. {
  327. // Validate
  328. if (!is_array($u) OR count($u) != 2 OR !isset($u[0]) OR !isset($u[1]))
  329. {
  330. continue;
  331. }
  332. // Type
  333. if ($u[0] == 'none')
  334. {
  335. $type = 'guest';
  336. }
  337. elseif (is_int($u[0]))
  338. {
  339. $type = 'guid';
  340. }
  341. else
  342. {
  343. continue;
  344. }
  345. // Group?
  346. if (isset(self::$groups[$id][$u[1]]))
  347. {
  348. $group = (string) $u[1];
  349. $flags = self::$groups[$id][$u[1]];
  350. }
  351. else
  352. {
  353. $group = NULL;
  354. $flags = array();
  355. if ($u[1] AND is_string($u[1]))
  356. {
  357. // Single flag
  358. if (!strstr($u[1], ';'))
  359. {
  360. $flags[$u[1]] = $u[1];
  361. }
  362. else
  363. {
  364. $u[1] = explode(';', $u[1]);
  365. foreach ($u[1] as $v)
  366. {
  367. if (empty($v))
  368. {
  369. continue;
  370. }
  371. $flags[$v] = $v;
  372. }
  373. }
  374. }
  375. }
  376. // Add user
  377. self::$users[$id][$u[0]] = array('group' => $group, 'flags' => $flags, 'type' => $type, 'rule' => $u[0]);
  378. }
  379. }
  380. }
  381. }
  382. /**
  383. * Read player
  384. *
  385. * @param int $guid
  386. * @param int $id
  387. * @param string $name
  388. * @param string $team
  389. * @return Player
  390. */
  391. public static function readPlayer($guid, $id, $name, $team = NULL)
  392. {
  393. // Bad clients
  394. if (empty($guid) OR empty($id) OR $id <= 0 OR $guid <= 0)
  395. {
  396. // World
  397. if ($name == '[3arc]democlient')
  398. {
  399. return new DemoclientPlayer;
  400. }
  401. else
  402. {
  403. return new WorldPlayer;
  404. }
  405. }
  406. // Clean name
  407. $name = utf8_clean($name);
  408. // Server ID
  409. $serverId = Server::get('id');
  410. // Server exists?
  411. if (!isset(self::$players[$serverId]))
  412. {
  413. self::$players[$serverId] = array();
  414. }
  415. // Player exists?
  416. if (!isset(self::$players[$serverId][$guid]))
  417. {
  418. self::$players[$serverId][$guid] = new Player($guid, $id, $name, $team);
  419. }
  420. else
  421. {
  422. // Update
  423. self::$players[$serverId][$guid]->update($id, $name, $team);
  424. }
  425. // Return
  426. return self::$players[$serverId][$guid];
  427. }
  428. /**
  429. * Reload configuration
  430. */
  431. public static function reloadConfig()
  432. {
  433. // Server ID
  434. $id = Server::get('id');
  435. // Arrays
  436. self::$groups[$id] = array();
  437. self::$users[$id] = array();
  438. self::$acl[$id] = array();
  439. // Default ACL action
  440. self::$aclDefault[$id] = Config::get('users.private_server', FALSE, 'server-'.$id) ? self::DENY : self::ALLOW;
  441. // Load config
  442. $config = Config::get('users', array());
  443. // ACL
  444. if (isset($config['acl']) AND is_array($config['acl']))
  445. {
  446. // Iterate
  447. foreach ($config['acl'] as $guid => $info)
  448. {
  449. // Invalid
  450. if (!ctype_digit($guid) OR !is_array($info) OR !isset($info['deny']) OR !isset($info['expires']))
  451. {
  452. continue;
  453. }
  454. // Reason?
  455. if (!isset($info['reason']))
  456. {
  457. $info['reason'] = 'Access denied';
  458. }
  459. // Set
  460. self::$acl[$id][(int) $guid] = array('action' => $info['deny'] ? self::DENY : self::ALLOW, 'expires' => (int) $info['expires'], 'reason' => $info['reason']);
  461. }
  462. }
  463. // Groups
  464. if (isset($config['groups']) AND is_array($config['groups']))
  465. {
  466. // Iterate
  467. foreach ($config['groups'] as $g)
  468. {
  469. // Validate
  470. if (!is_array($g) OR count($g) != 2 OR !isset($g[0]) OR !isset($g[1]))
  471. {
  472. continue;
  473. }
  474. // Flags
  475. $flags = array();
  476. if ($g[1] AND is_string($g[1]))
  477. {
  478. // Single flag
  479. if (!strstr($g[1], ';'))
  480. {
  481. $flags[$g[1]] = $g[1];
  482. }
  483. else
  484. {
  485. $g[1] = explode(';', $g[1]);
  486. foreach ($g[1] as $v)
  487. {
  488. if (empty($v))
  489. {
  490. continue;
  491. }
  492. $flags[$v] = $v;
  493. }
  494. }
  495. }
  496. // Add
  497. self::$groups[$id][(string) $g[0]] = $flags;
  498. }
  499. }
  500. // Users
  501. if (isset($config['users']) AND is_array($config['users']))
  502. {
  503. // Iterate
  504. foreach ($config['users'] as $u)
  505. {
  506. // Validate
  507. if (!is_array($u) OR count($u) != 2 OR !isset($u[0]) OR !isset($u[1]))
  508. {
  509. continue;
  510. }
  511. // Type
  512. if ($u[0] == 'none')
  513. {
  514. $type = 'guest';
  515. }
  516. elseif (is_int($u[0]))
  517. {
  518. $type = 'guid';
  519. }
  520. else
  521. {
  522. continue;
  523. }
  524. // Group?
  525. if (isset(self::$groups[$id][$u[1]]))
  526. {
  527. $group = (string) $u[1];
  528. $flags = self::$groups[$id][$u[1]];
  529. }
  530. else
  531. {
  532. $group = NULL;
  533. $flags = array();
  534. if ($u[1] AND is_string($u[1]))
  535. {
  536. // Single flag
  537. if (!strstr($u[1], ';'))
  538. {
  539. $flags[$u[1]] = $u[1];
  540. }
  541. else
  542. {
  543. $u[1] = explode(';', $u[1]);
  544. foreach ($u[1] as $v)
  545. {
  546. if (empty($v))
  547. {
  548. continue;
  549. }
  550. $flags[$v] = $v;
  551. }
  552. }
  553. }
  554. }
  555. // Add user
  556. self::$users[$id][$u[0]] = array('group' => $group, 'flags' => $flags, 'type' => $type, 'rule' => $u[0]);
  557. }
  558. }
  559. }
  560. /**
  561. * Remove player (when he has left)
  562. *
  563. * @param Player $guid
  564. */
  565. public static function removePlayer(Player $player)
  566. {
  567. // Server ID
  568. $id = Server::get('id');
  569. // Remove
  570. if (isset(self::$players[$id]))
  571. {
  572. if (isset(self::$players[$id][$player->guid])) unset(self::$players[$id][$player->guid]);
  573. }
  574. }
  575. /**
  576. * Restore session
  577. *
  578. * @param array $players
  579. */
  580. public static function resume(array $players = array())
  581. {
  582. // Init
  583. self::init();
  584. // Restore players
  585. self::$players = $players;
  586. }
  587. /**
  588. * Write new config
  589. */
  590. private static function saveConfig()
  591. {
  592. // Server ID
  593. $id = Server::get('id');
  594. // Generate new config
  595. $config = array('groups' => array(), 'users' => array(), 'acl' => array(), 'private_server' => (self::$aclDefault[$id] == self::DENY));
  596. foreach (self::$acl[$id] as $guid => $info)
  597. {
  598. // Invalid
  599. if ($info['expires'] AND $info['expires'] <= time())
  600. {
  601. continue;
  602. }
  603. // Add
  604. $config['acl'][$guid] = array('deny' => ($info['action'] == self::DENY), 'expires' => $info['expires'], 'reason' => $info['reason']);
  605. }
  606. foreach (self::$groups[$id] as $k => $v)
  607. {
  608. $config['groups'][] = array($k, implode(';', $v));
  609. }
  610. foreach (self::$users[$id] as $u)
  611. {
  612. $config['users'][] = array($u['rule'], ($u['group'] ? $u['group'] : implode(';', $u['flags'])));
  613. }
  614. // Set and save
  615. Config::set('users', $config);
  616. Config::save();
  617. }
  618. /**
  619. * Set player access
  620. *
  621. * @param Player $player
  622. * @param int $action
  623. * @param string $reason
  624. * @param int $expires
  625. */
  626. public static function setACL(Player $player, $action, $reason = NULL, $expires = 0)
  627. {
  628. // Set
  629. self::$acl[Server::get('id')][$player->guid] = array(
  630. 'action' => ($action == self::DENY ? self::DENY : self::ALLOW),
  631. 'expires' => $expires,
  632. 'reason' => ($reason ? $reason : __('Access denied'))
  633. );
  634. // Save config
  635. self::saveConfig();
  636. }
  637. /**
  638. * Set player group
  639. *
  640. * @param Player $player
  641. * @param string $text
  642. */
  643. public static function setGroup(Player $player, $text)
  644. {
  645. // Valid syntax
  646. if (!isset($text[1]) OR !isset($text[2]))
  647. {
  648. return;
  649. }
  650. // Permissions
  651. if (!$player->hasFlag('setgroup'))
  652. {
  653. Server::get()->message(__('Insufficient permissions'), $player);
  654. return;
  655. }
  656. // Find player
  657. $target = self::find($text[1]);
  658. if ($target === NULL OR (!$player->hasFlag('immunity') AND $target->hasFlag('immunity')))
  659. {
  660. Server::get()->message(__('Invalid target (player not found or has immunity)'), $player);
  661. return;
  662. }
  663. // Server ID
  664. $id = Server::get('id');
  665. // Find group
  666. if (!isset(self::$groups[$id][$text[2]]))
  667. {
  668. Server::get()->message(__('Invalid group'), $player);
  669. return;
  670. }
  671. // Set permissions
  672. self::$users[$id][$target->guid] = array('group' => $text[2], 'flags' => self::$groups[$id][$text[2]], 'type' => 'guid', 'rule' => $target->guid);
  673. // Set player
  674. self::$players[$id][$target->guid]->flags = self::$groups[$id][$text[2]];
  675. // Save config
  676. self::saveConfig();
  677. // Message
  678. Server::get()->message(__('Group successfully set'), $player);
  679. }
  680. }