#!/usr/bin/php InitWithIp($Ip, $Port)) { trigger_error("[".$client->getErrorCode()."] ".$client->getErrorMessage()); } DoQuerry("Authenticate", $AuthLogin, $AuthPassword); DoQuerry("EnableCallbacks", True); } function DoQuerry($querry /*...*/) { global $client; $args = func_get_args(); if (!call_user_func_array(array($client, 'query'), $args)) { trigger_error("[".$client->getErrorCode()."] ".$client->getErrorMessage()); exit(1); } return $client->getResponse(); } function TryQuerry($querry /*...*/) { global $client; $args = func_get_args(); if (!call_user_func_array(array($client, 'query'), $args)) { print ("Warning: '$querry' -> " . "[".$client->getErrorCode()."] ".$client->getErrorMessage()); return False; } return $client->getResponse(); } function XMLEscapeString( $String ) { return htmlspecialchars( $String, ENT_NOQUOTES ) ; } function MwTimeToString($MwTime) { if ($MwTime == -1) { return "???"; } else { $minutes = floor($MwTime/(1000*60)); $seconds = floor(($MwTime-$minutes*60*1000)/1000); $millisec = floor(($MwTime - $minutes*60*1000 - $seconds*1000)/10); return $minutes.":".$seconds.".".$millisec; } } // UI construction: $ActionChangeSpec = 1*1000; function MakePlayerFrame($PlayerRanking, $CurTarget, $GameInfos, &$posx, &$posy) { global $ActionChangeSpec; $NickName = XMLEscapeString($PlayerRanking['NickName']); $Rank = $PlayerRanking['Rank']; $Score = $PlayerRanking['Score']; $Time = MwTimeToString($PlayerRanking["BestTime"]); $PlayerUId = $PlayerRanking['PlayerId']; $Action = $ActionChangeSpec + $PlayerUId; $Frame = ""; $Frame .= ""; $Frame .= ""; $Frame .= ""; if ($GameInfos["GameMode"] == 5) { // Cup Mode $Limit = $GameInfos["CupPointsLimit"]; if ($Score == $Limit) { $Frame .= ""; } else if ($Score > $Limit) { $Frame .= ""; } else { $Frame .= ""; } } else if ($GameInfos["GameMode"] == 0) { // Rounds $Frame .= ""; } else if ($GameInfos["GameMode"] == 1) { // TimeAttack $Frame .= ""; } else { // mode not supported. } if ($PlayerUId == $CurTarget) { $Frame .= ""; } $Frame .= ""; $posy -= 10; return $Frame; } function BuildUiForSpectator($Login, $Target, $Rankings, $GameInfos) { $Page = ''; // rankings and scores. $Page .= ''; $posx=-63; $posy=37; foreach ($Rankings as $Ranking) { if ($Ranking['Rank'] == 0) break; // there aren't 5 players in the top 5, so cut up earlier. $Page .= MakePlayerFrame($Ranking, $Target, $GameInfos, $posx, $posy); } $Page .= ''; // customui $Page .= 'i'; $Page .= ''; return $Page; } // SpectatorManager $SpectatorManager_Status = array(); $SpectatorManager_GlobalDirty = False; function SpectatorManager_Add($Login) { global $SpectatorManager_Status, $SpectatorManager_GlobalDirty; $SpectatorManager_GlobalDirty = True; $SpectatorManager_Status[$Login]= array( "uptodate" => False, "page" => "", "target" => "" ); } function SpectatorManager_Remove($Login) { global $SpectatorManager_Status, $SpectatorManager_GlobalDirty; unset($SpectatorManager_Status[$Login]); } function SpectatorManager_SetDirtyAll() { global $SpectatorManager_Status, $SpectatorManager_GlobalDirty; $SpectatorManager_GlobalDirty = True; foreach($SpectatorManager_Status as $s) { $s["uptodate"] = False; } } function SpectatorManager_Update() { global $SpectatorManager_Status, $SpectatorManager_GlobalDirty; if (!$SpectatorManager_GlobalDirty) return; $SpectatorManager_GlobalDirty = False; $GameInfos = DoQuerry('GetCurrentGameInfo', 1); $Rankings = DoQuerry('GetCurrentRanking', 5, 0); foreach($SpectatorManager_Status as $Login => $s) { if ($s["uptodate"]) continue; $NewPage = BuildUiForSpectator($Login, $s["target"], $Rankings, $GameInfos); if ($s["page"] != $NewPage) { $s["page"] = $NewPage; DoQuerry('SendDisplayManialinkPageToLogin', $Login, $NewPage, 0, False); } $s["uptodate"] = True; } } // Callbacks function OnManialinkPageAnswer($PlayerUId, $Login, $Answer) { global $SpectatorManager_Status, $SpectatorManager_GlobalDirty; global $ActionChangeSpec; $Argument = $Answer%1000; $Action = $Answer - $Argument ; if ($Action == $ActionChangeSpec) { $SpectatorManager_Status[$Login]["target"] = $Argument; $SpectatorManager_Status[$Login]["uptodate"] = False; $SpectatorManager_GlobalDirty = True; TryQuerry('ForceSpectatorTargetId', $PlayerUId, $Argument, 0); } } function OnPlayerInfoChanged($PlayerInfo) { return; } // ------------------------------------------------------ // -- (1) Server Adress here!--------------------------------- // ------------------------------------------------------ ConnectToServer("localhost", 5000, "Admin", "Admin"); // register already connected specs. $PlayerList = DoQuerry("GetPlayerList", 250, 0, 1); foreach ($PlayerList as $Player) { $Login = $Player["Login"]; $IsPureSpec = ($Player["SpectatorStatus"]/100)%10 != 0; if ($IsPureSpec) SpectatorManager_Add($Login); } while (true) { // FIXME Sleep(1); $client->readCB(5*1000*1000); $calls = $client->getCBResponses(); if (!empty($calls)) { foreach ($calls as $call) { switch($call[0]){ case 'TrackMania.BeginRace': case 'TrackMania.EndRace': case 'TrackMania.EndRound': SpectatorManager_SetDirtyAll(); break; case 'TrackMania.PlayerManialinkPageAnswer': OnManialinkPageAnswer($call[1][0], $call[1][1], $call[1][2]); break; case 'TrackMania.PlayerConnect': if ($call[1][1]) // is spectator SpectatorManager_Add($call[1][0]); break; case 'TrackMania.PlayerDisconnect': SpectatorManager_Remove($call[1][0]); break; case 'TrackMania.PlayerInfoChanged': OnPlayerInfoChanged($call[1][0]); break; } } } SpectatorManager_Update(); flush(); } $client->Terminate(); ?>