mirror of
https://codeberg.org/demostf/api.git
synced 2026-06-04 02:14:06 +02:00
upload framework
This commit is contained in:
parent
754b1ce108
commit
a1a9504f11
30 changed files with 1578 additions and 155 deletions
26
src/Demo/DemoStore.php
Normal file
26
src/Demo/DemoStore.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php namespace Demostf\API\Demo;
|
||||
|
||||
class DemoStore {
|
||||
/** @var string */
|
||||
private $root;
|
||||
/** @var string */
|
||||
private $webroot;
|
||||
|
||||
public function __construct(string $root, string $webroot) {
|
||||
$this->root = $root;
|
||||
$this->webroot = $webroot;
|
||||
}
|
||||
|
||||
public function store(string $sourcePath, string $name): string {
|
||||
rename($sourcePath, $this->generatePath($name));
|
||||
return $this->getUrl($name);
|
||||
}
|
||||
|
||||
private function generatePath(string $name): string {
|
||||
return $this->root . '/' . substr($name, 0, 2) . '/' . substr($name, 2, 4) . '/' . $name;
|
||||
}
|
||||
|
||||
private function getUrl(string $name): string {
|
||||
return 'https://' . $this->webroot . '/' . substr($name, 0, 2) . '/' . substr($name, 2, 4) . '/' . $name;
|
||||
}
|
||||
}
|
||||
156
src/Demo/Header.php
Normal file
156
src/Demo/Header.php
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
<?php namespace Demostf\API\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;
|
||||
}
|
||||
|
||||
}
|
||||
133
src/Demo/Parser.php
Normal file
133
src/Demo/Parser.php
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
<?php namespace Demostf\API\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 parseHeader($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';
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue