1
0
Fork 0
mirror of https://codeberg.org/demostf/api.git synced 2026-06-03 18:04:08 +02:00

upload wip

This commit is contained in:
Robin Appelman 2017-01-31 13:34:54 +01:00
commit fca5d7b0a6
15 changed files with 2146 additions and 164 deletions

42
Demo/AzureStore.php Normal file
View file

@ -0,0 +1,42 @@
<?php namespace Demo;
use MicrosoftAzure\Storage\Blob\Internal\IBlob;
class AzureStore implements IDemoStore {
/**
* @var IBlob
*/
private $blobStorage;
/**
* @param IBlob $blobStorage
*/
public function __construct(IBlob $blobStorage) {
$this->blobStorage = $blobStorage;
}
/**
* @param resource $stream
* @param string $name
* @return StoredDemo
*/
public function store($stream, $name) {
$name = preg_replace("/[^A-Za-z0-9\\.\\-]/", '', $name);
if (substr($name, -4) !== '.dem') {
$name .= '.dem';
}
$id = uniqid() . $name;
$this->upload($stream, $id);
$url = 'https://demostf.blob.core.windows.net/demos/' . $id;
return new StoredDemo('azure', $id, $url);
}
/**
* @param resource $stream
* @param string $id
* @return string mixed
*/
private function upload($stream, $id) {
$this->blobStorage->createBlockBlob('demos', $id, $stream);
}
}

156
Demo/Header.php Normal file
View file

@ -0,0 +1,156 @@
<?php namespace Demo;
/**
* HL2 demo metadata
*/
class Header {
/**
* @var string
*/
protected $type;
/**
* @var int
*/
protected $version;
/**
* @var int
*/
protected $protocol;
/**
* @var string
*/
protected $server;
/**
* @var string
*/
protected $nick;
/**
* @var string
*/
protected $map;
/**
* @var string
*/
protected $game;
/**
* @var float
*/
protected $duration;
/**
* @var int
*/
protected $ticks;
/**
* @var int
*/
protected $frames;
/**
* @var int
*/
protected $sigon;
/**
* @param array $info
*/
public function __construct($info) {
$this->type = $info['type'];
$this->version = $info['version'];
$this->protocol = $info['protocol'];
$this->server = $info['server'];
$this->nick = $info['nick'];
$this->map = $info['map'];
$this->game = $info['game'];
$this->duration = $info['duration'];
$this->ticks = $info['ticks'];
$this->frames = $info['frames'];
$this->sigon = $info['sigon'];
}
/**
* @return float
*/
public function getDuration() {
return $this->duration;
}
/**
* @return int
*/
public function getFrames() {
return $this->frames;
}
/**
* @return string
*/
public function getGame() {
return $this->game;
}
/**
* @return string
*/
public function getMap() {
return $this->map;
}
/**
* @return string
*/
public function getNick() {
return $this->nick;
}
/**
* @return int
*/
public function getProtocol() {
return $this->protocol;
}
/**
* @return string
*/
public function getServer() {
return $this->server;
}
/**
* @return int
*/
public function getSigon() {
return $this->sigon;
}
/**
* @return int
*/
public function getTicks() {
return $this->ticks;
}
/**
* @return string
*/
public function getType() {
return $this->type;
}
/**
* @return int
*/
public function getVersion() {
return $this->version;
}
}

10
Demo/IDemoStore.php Normal file
View file

@ -0,0 +1,10 @@
<?php namespace Demo;
interface IDemoStore {
/**
* @param resource $stream
* @param string $name
* @return StoredDemo
*/
public function store($stream, $name);
}

133
Demo/Parser.php Normal file
View file

@ -0,0 +1,133 @@
<?php namespace Demo;
use GuzzleHttp\Client;
class Parser {
const ANALYSER_BASEURL = 'http://demoserver.azurewebsites.net';
/**
* @param string $head string containing the demo header binary data
* @return Header
* @throws \Exception
*/
public function parseString($head) {
set_error_handler(array($this, 'errorHandler'));
$info = unpack("A8type/Iversion/Iprotocol/A260server/A260nick/A260map/A260game/fduration/Iticks/Iframes/Isigon",
$head);
restore_error_handler();
if ($info['type'] !== 'HL2DEMO') {
throw new \Exception('Not an HL2 demo');
}
return new Header($info);
}
/**
* Parse demo info from a stream
*
* @param resource $stream
* @return Header
* @throws \Exception
*/
public function parseStream($stream) {
$head = fread($stream, 2048);
return $this->parseString($head);
}
/**
* Parse demo info from a local file
*
* @param string $path
* @return Header
* @throws \Exception
*/
public function parseFile($path) {
if (!is_readable($path)) {
throw new \Exception('Unable to open demo: ' . $path);
}
$fh = fopen($path, 'rb');
return $this->parseStream($fh);
}
public function analyse(StoredDemo $storedDemo) {
$endPoint = self::ANALYSER_BASEURL . '/url';
$client = new Client();
$response = $client->post($endPoint, [
'body' => $storedDemo->getUrl()
]);
$data = $response->getBody();
return $this->handleData($data);
}
private function handleData($data) {
if (!is_array($data)) {
throw new \Exception('Error parsing demo');
}
$intervalPerTick = $data['intervalPerTick'];
$red = 0;
$blue = 0;
$chat = [];
$players = [];
foreach ($data['rounds'] as $round) {
if ($round['winner'] === 'red') {
$red++;
} else {
$blue++;
}
}
foreach ($data['chat'] as $message) {
if (isset($message['from'])) {
$chat[] = [
'time' => floor(($message['tick'] - $data['startTick']) * $intervalPerTick),
'from' => $message['from'],
'text' => $message['text']
];
}
}
foreach ($data['users'] as $player) {
$class = 0;
$classSpawns = 0;
foreach ($player['classes'] as $classId => $spawns) {
if ($spawns > $classSpawns) {
$classSpawns = $spawns;
$class = $classId;
}
}
if ($class and $player['steamId']) {//skip spectators
$players[] = [
'name' => $player['name'],
'demo_user_id' => $player['userId'],
'steam_id' => $player['steamId'],
'team' => $player['team'],
'class' => $this->getClassName($class)
];
}
}
return [
'score' => [
'red' => $red,
'blue' => $blue
],
'chat' => $chat,
'players' => $players,
'kills' => $data['deaths']
];
}
private function getClassName($classId) {
$classes = [
1 => 'scout',
2 => 'sniper',
3 => 'soldier',
4 => 'demoman',
5 => 'medic',
6 => 'heavyweapons',
7 => 'pyro',
8 => 'spy',
9 => 'engineer'
];
return isset($classes[$classId]) ? $classes[$classId] : 'Unknown';
}
}

50
Demo/StoredDemo.php Normal file
View file

@ -0,0 +1,50 @@
<?php namespace Demo;
class StoredDemo {
/**
* @var string
*/
private $backend;
/**
* @var string
*/
private $path;
/**
* @var string
*/
private $url;
/**
* @param string $backend
* @param string $path
* @param string $url
*/
public function __construct($backend, $path, $url) {
$this->backend = $backend;
$this->path = $path;
$this->url = $url;
}
/**
* @return string
*/
public function getBackend() {
return $this->backend;
}
/**
* @return string
*/
public function getPath() {
return $this->path;
}
/**
* @return string
*/
public function getUrl() {
return $this->url;
}
}