<?php
class OutfitCodeReader
{
/** @var resource */
private $data;
/** @var array */
private $outfitData = [];
/** @var array */
private $mountData = [];
/**
* @param string $code
*/
public function parseOutfitData($code)
{
$this->mountData = [];
$this->outfitData = [];
try {
$base64Code = base64_decode($code);
$this->data = fopen('php://memory', 'wb+');
fwrite($this->data, $base64Code);
$this->length = ftell($this->data);
rewind($this->data);
$ignoredByte1 = $this->getByte();
$stringMount = $this->getString();
$ignoredByte2 = $this->getByte();
$stringMountColor = $this->getString();
$ignoredByte3 = $this->getByte();
// detail
$this->mountData[$this->getString()] = $this->getNumber();
// head
$this->mountData[$this->getString()] = $this->getNumber();
// legs
$this->mountData[$this->getString()] = $this->getNumber();
// torso
$this->mountData[$this->getString()] = $this->getNumber();
// id
$this->mountData[$this->getString()] = $this->getNumber();
// name
$this->mountData[$this->getString()] = $this->getString();
$stringOutfit = $this->getString();
$ignoredByte4 = $this->getByte();
$stringOutfitColor = $this->getString();
$ignoredByte5 = $this->getByte();
// detail
$this->outfitData[$this->getString()] = $this->getNumber();
// head
$this->outfitData[$this->getString()] = $this->getNumber();
// legs
$this->outfitData[$this->getString()] = $this->getNumber();
// torso
$this->outfitData[$this->getString()] = $this->getNumber();
// firstAddOn
$this->outfitData[$this->getString()] = $this->getBool();
// id
$this->outfitData[$this->getString()] = $this->getNumber();
// secondAddOn
$this->outfitData[$this->getString()] = $this->getBool();
return true;
} catch (RuntimeException $exception) {
return false;
}
}
public function getMountData()
{
return $this->mountData;
}
public function getOutfitData()
{
return $this->outfitData;
}
/**
* @return int
*/
private function getByte()
{
return unpack('C', fread($this->data, 1))[1];
}
/**
* @return bool
*/
private function getBool()
{
$byte = $this->getByte();
if ($byte === 244) {
return false;
} elseif ($byte === 245) {
return true;
} else {
throw new RuntimeException('Parser error.');
}
}
/**
* @return int
*/
private function getNumber()
{
$byte = $this->getByte();
if ($byte < 24) {
return $byte;
} elseif ($byte === 24) {
return $this->getByte();
} elseif ($byte === 25) {
return $this->getByte() * 256 + $this->getByte();
} else {
throw new RuntimeException('Parser error.');
}
}
/**
* @return string
*/
private function getString()
{
$stringLength = $this->getByte() - 96;
if ($stringLength === 0) {
return '';
} elseif ($stringLength < 0) {
throw new RuntimeException('Parser error.');
}
return fread($this->data, $stringLength);
}
}
$codes = [
'Mage outfit, no mount' => 'pGVtb3VudKJlY29sb3KkZmRldGFpbABkaGVhZABkbGVncwBldG9yc28AYmlkAGRuYW1lYGZvdXRmaXSkZWNvbG9ypGZkZXRhaWwAZGhlYWQAZGxlZ3MYhGV0b3JzbxiEamZpcnN0QWRkT270YmlkGIJrc2Vjb25kQWRkT270ZnN1bW1vbqFiaWQA',
'Paladin outfit, with store moun' => 'pGVtb3VudKJlY29sb3KkZmRldGFpbABkaGVhZABkbGVncwBldG9yc28AYmlkGQJzZG5hbWVgZm91dGZpdKRlY29sb3KkZmRldGFpbABkaGVhZABkbGVncxiEZXRvcnNvGIRqZmlyc3RBZGRPbvRiaWQYgWtzZWNvbmRBZGRPbvRmc3VtbW9uoWJpZAA',
'Retro knight (store outfit), no mount' => 'pGVtb3VudKJlY29sb3KkZmRldGFpbABkaGVhZABkbGVncwBldG9yc28AYmlkAGRuYW1lYGZvdXRmaXSkZWNvbG9ypGZkZXRhaWwAZGhlYWQAZGxlZ3MYhGV0b3JzbxiEamZpcnN0QWRkT270YmlkGQPKa3NlY29uZEFkZE9u9GZzdW1tb26hYmlkAA',
'Retro knight (store outfit), with mount' => 'pGVtb3VudKJlY29sb3KkZmRldGFpbABkaGVhZABkbGVncwBldG9yc28AYmlkGQJzZG5hbWVgZm91dGZpdKRlY29sb3KkZmRldGFpbABkaGVhZABkbGVncxiEZXRvcnNvGIRqZmlyc3RBZGRPbvRiaWQZA8prc2Vjb25kQWRkT270ZnN1bW1vbqFiaWQA',
'citizen female no addon' => 'pGVtb3VudKJlY29sb3KkZmRldGFpbABkaGVhZABkbGVncwBldG9yc28AYmlkAGRuYW1lYGZvdXRmaXSkZWNvbG9ypGZkZXRhaWwAZGhlYWQAZGxlZ3MYJmV0b3JzbwxqZmlyc3RBZGRPbvViaWQYiGtzZWNvbmRBZGRPbvVmc3VtbW9uoWJpZBkFVg',
'citizen female 1 addon' => 'pGVtb3VudKJlY29sb3KkZmRldGFpbABkaGVhZABkbGVncwBldG9yc28AYmlkAGRuYW1lYGZvdXRmaXSkZWNvbG9ypGZkZXRhaWwAZGhlYWQAZGxlZ3MYJmV0b3JzbwxqZmlyc3RBZGRPbvViaWQYiGtzZWNvbmRBZGRPbvRmc3VtbW9uoWJpZBkFVg',
'citizen female 2 addon' => 'pGVtb3VudKJlY29sb3KkZmRldGFpbABkaGVhZABkbGVncwBldG9yc28AYmlkAGRuYW1lYGZvdXRmaXSkZWNvbG9ypGZkZXRhaWwAZGhlYWQAZGxlZ3MYJmV0b3JzbwxqZmlyc3RBZGRPbvRiaWQYiGtzZWNvbmRBZGRPbvVmc3VtbW9uoWJpZBkFVg',
];
$outfitCodeReader = new OutfitCodeReader();
foreach ($codes as $name => $code) {
if ($outfitCodeReader->parseOutfitData($code)) {
var_dump($outfitCodeReader->getMountData());
/*
array (size=6)
'detail' => int 0
'head' => int 0
'legs' => int 0
'torso' => int 0
'id' => int 0
'name' => string '' (length=0)
*/
var_dump($outfitCodeReader->getOutfitData());
/*
array (size=7)
'detail' => int 0
'head' => int 0
'legs' => int 132
'torso' => int 132
'firstAddOn' => boolean false
'id' => int 130
'secondAddOn' => boolean false
*/
} else {
echo 'failed to load code, probably modified by player';
}
}