306 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			306 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| namespace iControl;
 | |
| 
 | |
| /**
 | |
|  * iControl Karma Plugin
 | |
|  *
 | |
|  * @author : steeffeen
 | |
|  */
 | |
| class Plugin_Karma {
 | |
| 	/**
 | |
| 	 * Constants
 | |
| 	 */
 | |
| 	const VERSION = '1.0';
 | |
| 	const MLID_KARMA = 'KarmaPlugin.MLID';
 | |
| 	const TABLE_KARMA = 'ic_karma';
 | |
| 
 | |
| 	/**
 | |
| 	 * Private properties
 | |
| 	 */
 | |
| 	private $iControl = null;
 | |
| 
 | |
| 	private $config = null;
 | |
| 
 | |
| 	private $sendManialinkRequested = -1;
 | |
| 
 | |
| 	/**
 | |
| 	 * Construct plugin
 | |
| 	 *
 | |
| 	 * @param object $iControl        	
 | |
| 	 */
 | |
| 	public function __construct($iControl) {
 | |
| 		$this->iControl = $iControl;
 | |
| 		
 | |
| 		// Load config
 | |
| 		$this->config = Tools::loadConfig('karma.plugin.xml');
 | |
| 		if (!Tools::toBool($this->config->enabled)) return;
 | |
| 		
 | |
| 		// Init database
 | |
| 		$this->initDatabase();
 | |
| 		
 | |
| 		// Register for callbacks
 | |
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_ONINIT, $this, 'handleOnInitCallback');
 | |
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_IC_BEGINMAP, $this, 'handleBeginMapCallback');
 | |
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERCONNECT, $this, 'handlePlayerConnectCallback');
 | |
| 		$this->iControl->callbacks->registerCallbackHandler(Callbacks::CB_MP_PLAYERMANIALINKPAGEANSWER, $this, 
 | |
| 				'handleManialinkPageAnswerCallback');
 | |
| 		
 | |
| 		error_log('Karma Pugin v' . self::VERSION . ' ready!');
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Repetitive actions
 | |
| 	 */
 | |
| 	public function loop() {
 | |
| 		if ($this->sendManialinkRequested > 0 && $this->sendManialinkRequested <= time()) {
 | |
| 			$this->sendManialinkRequested = -1;
 | |
| 			
 | |
| 			// Send manialink to all players
 | |
| 			$players = $this->iControl->server->getPlayers();
 | |
| 			foreach ($players as $player) {
 | |
| 				$login = $player['Login'];
 | |
| 				$manialink = $this->buildManialink($login);
 | |
| 				if (!$manialink) {
 | |
| 					// Skip and retry
 | |
| 					$this->sendManialinkRequested = time() + 5;
 | |
| 					continue;
 | |
| 				}
 | |
| 				Tools::sendManialinkPage($this->iControl->client, $manialink->asXml(), $login);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Handle OnInit iControl callback
 | |
| 	 *
 | |
| 	 * @param array $callback        	
 | |
| 	 */
 | |
| 	public function handleOnInitCallback($callback) {
 | |
| 		// Send manialink to all players once
 | |
| 		$this->sendManialinkRequested = time() + 3;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Handle iControl BeginMap callback
 | |
| 	 *
 | |
| 	 * @param array $callback        	
 | |
| 	 */
 | |
| 	public function handleBeginMapCallback($callback) {
 | |
| 		// Send manialink to all players once
 | |
| 		$this->sendManialinkRequested = time() + 2;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Handle PlayerConnect callback
 | |
| 	 *
 | |
| 	 * @param array $callback        	
 | |
| 	 */
 | |
| 	public function handlePlayerConnectCallback($callback) {
 | |
| 		$login = $callback[1][0];
 | |
| 		$manialink = $this->buildManialink($login);
 | |
| 		if (!$manialink) return;
 | |
| 		Tools::sendManialinkPage($this->iControl->client, $manialink->asXml(), $login);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Create necessary tables
 | |
| 	 */
 | |
| 	private function initDatabase() {
 | |
| 		$query = "CREATE TABLE IF NOT EXISTS `" . self::TABLE_KARMA . "` (
 | |
| 			`index` int(11) NOT NULL AUTO_INCREMENT,
 | |
| 			`mapIndex` int(11) NOT NULL,
 | |
| 			`playerIndex` int(11) NOT NULL,
 | |
| 			`vote` tinyint(1) NOT NULL,
 | |
| 			`changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 | |
| 			PRIMARY KEY (`index`),
 | |
| 			UNIQUE KEY `player_map_vote` (`mapIndex`, `playerIndex`)
 | |
| 			) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Save players map votes' AUTO_INCREMENT=1;";
 | |
| 		$result = $this->iControl->database->query($query);
 | |
| 		if ($this->iControl->database->mysqli->error) {
 | |
| 			trigger_error('MySQL Error on creating karma table. ' . $this->iControl->database->mysqli->error, E_USER_ERROR);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Handle ManialinkPageAnswer callback
 | |
| 	 *
 | |
| 	 * @param array $callback        	
 | |
| 	 */
 | |
| 	public function handleManialinkPageAnswerCallback($callback) {
 | |
| 		$action = $callback[1][2];
 | |
| 		if (substr($action, 0, strlen(self::MLID_KARMA)) !== self::MLID_KARMA) return;
 | |
| 		
 | |
| 		// Get vote
 | |
| 		$action = substr($action, -4);
 | |
| 		$vote = null;
 | |
| 		switch ($action) {
 | |
| 			case '.pos':
 | |
| 				{
 | |
| 					$vote = 1;
 | |
| 					break;
 | |
| 				}
 | |
| 			case '.neu':
 | |
| 				{
 | |
| 					$vote = 0;
 | |
| 					break;
 | |
| 				}
 | |
| 			case '.neg':
 | |
| 				{
 | |
| 					$vote = -1;
 | |
| 					break;
 | |
| 				}
 | |
| 			default:
 | |
| 				{
 | |
| 					return;
 | |
| 				}
 | |
| 		}
 | |
| 		
 | |
| 		// Save vote
 | |
| 		$login = $callback[1][1];
 | |
| 		$playerIndex = $this->iControl->database->getPlayerIndex($login);
 | |
| 		$map = $this->iControl->server->getMap();
 | |
| 		$mapIndex = $this->iControl->database->getMapIndex($map['UId']);
 | |
| 		$query = "INSERT INTO `" . self::TABLE_KARMA . "` (
 | |
| 			`mapIndex`,
 | |
| 			`playerIndex`,
 | |
| 			`vote`
 | |
| 			) VALUES (
 | |
| 			" . $mapIndex . ",
 | |
| 			" . $playerIndex . ",
 | |
| 			" . $vote . "
 | |
| 			) ON DUPLICATE KEY UPDATE
 | |
| 			`vote` = VALUES(`vote`);";
 | |
| 		$result = $this->iControl->database->query($query);
 | |
| 		if (!$result) return;
 | |
| 		
 | |
| 		// Send success message
 | |
| 		$this->iControl->chat->sendSuccess('Vote successfully updated!', $login);
 | |
| 		
 | |
| 		// Send updated manialink
 | |
| 		$this->sendManialinkRequested = time() + 1;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Build karma voting manialink xml for the given login
 | |
| 	 */
 | |
| 	private function buildManialink($login) {
 | |
| 		// Get config
 | |
| 		$title = (string) $this->config->title;
 | |
| 		$pos_x = (float) $this->config->pos_x;
 | |
| 		$pos_y = (float) $this->config->pos_y;
 | |
| 		
 | |
| 		$mysqli = $this->iControl->database->mysqli;
 | |
| 		
 | |
| 		// Get indezes
 | |
| 		$playerIndex = $this->iControl->database->getPlayerIndex($login);
 | |
| 		if ($playerIndex === null) return null;
 | |
| 		$map = $this->iControl->server->getMap();
 | |
| 		if (!$map) return null;
 | |
| 		$mapIndex = $this->iControl->database->getMapIndex($map['UId']);
 | |
| 		if ($mapIndex === null) return null;
 | |
| 		
 | |
| 		// Get votings
 | |
| 		$query = "SELECT
 | |
| 			(SELECT `vote` FROM `" .
 | |
| 				 self::TABLE_KARMA . "` WHERE `mapIndex` = " . $mapIndex . " AND `playerIndex` = " . $playerIndex . ") as `playerVote`,
 | |
| 			(SELECT COUNT(`vote`) FROM `" .
 | |
| 				 self::TABLE_KARMA . "` WHERE `mapIndex` = " . $mapIndex . " AND `vote` = 1) AS `positiveVotes`,
 | |
| 			(SELECT COUNT(`vote`) FROM `" .
 | |
| 				 self::TABLE_KARMA . "` WHERE `mapIndex` = " . $mapIndex . " AND `vote` = 0) AS `neutralVotes`,
 | |
| 			(SELECT COUNT(`vote`) FROM `" .
 | |
| 				 self::TABLE_KARMA . "` WHERE `mapIndex` = " . $mapIndex . " AND `vote` = -1) AS `negativeVotes`
 | |
| 			FROM `" . self::TABLE_KARMA . "`;";
 | |
| 		$result = $mysqli->query($query);
 | |
| 		if ($mysqli->error) {
 | |
| 			trigger_error('MySQL ERROR: ' . $mysqli->error);
 | |
| 		}
 | |
| 		$votes = $result->fetch_assoc();
 | |
| 		if (!$votes) {
 | |
| 			$votes = array('playerVote' => null, 'positiveVotes' => 0, 'neutralVotes' => 0, 'negativeVotes' => 0);
 | |
| 		}
 | |
| 		
 | |
| 		// Build manialink
 | |
| 		$xml = Tools::newManialinkXml(self::MLID_KARMA);
 | |
| 		
 | |
| 		$frameXml = $xml->addChild('frame');
 | |
| 		$frameXml->addAttribute('posn', $pos_x . ' ' . $pos_y);
 | |
| 		
 | |
| 		// Title
 | |
| 		$labelXml = $frameXml->addChild('label');
 | |
| 		Tools::addAlignment($labelXml);
 | |
| 		$labelXml->addAttribute('posn', '0 4.5 -1');
 | |
| 		$labelXml->addAttribute('sizen', '22 0');
 | |
| 		$labelXml->addAttribute('style', 'TextTitle1');
 | |
| 		$labelXml->addAttribute('textsize', '1');
 | |
| 		$labelXml->addAttribute('text', $title);
 | |
| 		
 | |
| 		// Background
 | |
| 		$quadXml = $frameXml->addChild('quad');
 | |
| 		Tools::addAlignment($quadXml);
 | |
| 		$quadXml->addAttribute('sizen', '23 15 -2');
 | |
| 		$quadXml->addAttribute('style', 'Bgs1InRace');
 | |
| 		$quadXml->addAttribute('substyle', 'BgTitleShadow');
 | |
| 		
 | |
| 		// Votes
 | |
| 		for ($i = 1; $i >= -1; $i--) {
 | |
| 			$x = $i * 7.;
 | |
| 			
 | |
| 			// Vote button
 | |
| 			$quadXml = $frameXml->addChild('quad');
 | |
| 			Tools::addAlignment($quadXml);
 | |
| 			$quadXml->addAttribute('posn', $x . ' 0 0');
 | |
| 			$quadXml->addAttribute('sizen', '6 6');
 | |
| 			$quadXml->addAttribute('style', 'Icons64x64_1');
 | |
| 			
 | |
| 			// Vote count
 | |
| 			$labelXml = $frameXml->addChild('label');
 | |
| 			Tools::addAlignment($labelXml);
 | |
| 			$labelXml->addAttribute('posn', $x . ' -4.5 0');
 | |
| 			$labelXml->addAttribute('style', 'TextTitle1');
 | |
| 			$labelXml->addAttribute('textsize', '2');
 | |
| 			
 | |
| 			if ((string) $i === $votes['playerVote']) {
 | |
| 				// Player vote X
 | |
| 				$voteQuadXml = $frameXml->addChild('quad');
 | |
| 				Tools::addAlignment($voteQuadXml);
 | |
| 				$voteQuadXml->addAttribute('posn', $x . ' 0 1');
 | |
| 				$voteQuadXml->addAttribute('sizen', '6 6');
 | |
| 				$voteQuadXml->addAttribute('style', 'Icons64x64_1');
 | |
| 				$voteQuadXml->addAttribute('substyle', 'Close');
 | |
| 			}
 | |
| 			
 | |
| 			switch ($i) {
 | |
| 				case 1:
 | |
| 					{
 | |
| 						// Positive
 | |
| 						$quadXml->addAttribute('substyle', 'LvlGreen');
 | |
| 						$quadXml->addAttribute('action', self::MLID_KARMA . '.pos');
 | |
| 						$labelXml->addAttribute('text', $votes['positiveVotes']);
 | |
| 						break;
 | |
| 					}
 | |
| 				case 0:
 | |
| 					{
 | |
| 						// Neutral
 | |
| 						$quadXml->addAttribute('substyle', 'LvlYellow');
 | |
| 						$quadXml->addAttribute('action', self::MLID_KARMA . '.neu');
 | |
| 						$labelXml->addAttribute('text', $votes['neutralVotes']);
 | |
| 						break;
 | |
| 					}
 | |
| 				case -1:
 | |
| 					{
 | |
| 						// Negative
 | |
| 						$quadXml->addAttribute('substyle', 'LvlRed');
 | |
| 						$quadXml->addAttribute('action', self::MLID_KARMA . '.neg');
 | |
| 						$labelXml->addAttribute('text', $votes['negativeVotes']);
 | |
| 						break;
 | |
| 					}
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		return $xml;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| ?>
 |