Skip to content

Commit

Permalink
Merge pull request #36 from goto-bus-stop/feature/objectives-map-name
Browse files Browse the repository at this point in the history
Add map name reader for custom random maps
  • Loading branch information
goto-bus-stop authored Dec 8, 2016
2 parents 06a8de8 + ec8f5d3 commit 5035738
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 1 deletion.
15 changes: 14 additions & 1 deletion src/Model/GameSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace RecAnalyst\Model;

use RecAnalyst\RecordedGame;
use RecAnalyst\Processors\MapName as MapNameExtractor;

class GameSettings
{
Expand Down Expand Up @@ -216,10 +217,22 @@ public function isScenario()
/**
* Get the map name.
*
* @param array $options Options.
* - `$options['extractRMSName']` - Whether to attempt to find the RMS
* file names of custom random maps. Defaults to `true`.
*
* @return string Map name.
*/
public function mapName()
public function mapName($options = [])
{
$extractRmsName = isset($options['extractRMSName']) ? $options['extractRMSName'] : true;
if ($extractRmsName && $this->isCustomMap()) {
$nameExtractor = new MapNameExtractor($this->rec);
$likelyName = $nameExtractor->run();
if ($likelyName) {
return $likelyName;
}
}
return $this->rec->trans('map_names', $this->mapId);
}

Expand Down
85 changes: 85 additions & 0 deletions src/Processors/MapName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace RecAnalyst\Processors;

use RecAnalyst\RecordedGame;

/**
* Extracts the map name from the Objectives tab of a recorded game. That's the
* only place where the name of a custom random map is stored.
*/
class MapName
{
/**
* Recorded game file to use.
*
* @var \RecAnalyst\RecordedGame
*/
private $rec;

/**
* Possible formats for map type lines in the Objectives tab.
*
* @var string[]
*/
private $mapTypeRegexes;

/**
* Create a map name extractor.
*
* @param \RecAnalyst\RecordedGame $rec Recorded game instance.
*/
public function __construct(RecordedGame $rec)
{
$this->rec = $rec;

// The Map Type strings used in the Objectives message tab are stored in
// string id 9654. This array was generated using:
// grep "9654" "SteamApps/common/Age2HD/resources/*/strings/key-value/key-value-strings-utf8.txt"
//
// HD Edition uses UTF-8, but older versions used localization-specific code pages.
// Code page information for zh, jp and ko was taken from:
// https://msdn.microsoft.com/en-us/library/cc194886.aspx
$this->mapTypeRegexes = [
'br' => '/Tipo de Mapa: (.*)/',
'de' => '/Kartentyp: (.*)/',
'en' => '/Map Type: (.*)/',
'es' => '/Tipo de mapa: (.*)/',
'fr' => '/Type de carte : (.*)/',
'it' => '/Tipo di mappa: (.*)/',
'jp' => '/' . mb_convert_encoding('マップの種類', 'cp932', 'utf-8') . ': (.*)/',
'jp_utf8' => '/マップの種類: (.*)/',
'ko' => '/' . mb_convert_encoding('지도 종류', 'cp949', 'utf-8') . ': (.*)/',
'ko_utf8' => '/지도 종류: (.*)/',
'nl' => '/Kaarttype: (.*)/',
'ru' => '/' . mb_convert_encoding('Тип карты', 'windows-1251', 'utf-8') . ': (.*)/',
'ru_utf8' => '/Тип карты: (.*)/',
'zh' => '/' . mb_convert_encoding('地图类别', 'cp936', 'utf-8') . ': (.*)/',
'zh_utf8' => '/地图类型: (.*)/',
'zh_wide' => '/' . mb_convert_encoding('地图类别:', 'cp936', 'utf-8') . '(.*)/',
];
}

/**
* Run the processor.
*
* @return string|null The map name, if found.
*/
public function run()
{
$header = $this->rec->header();
$messages = $header->messages;
$instructions = $messages->instructions;
$lines = explode("\n", $instructions);
foreach ($lines as $line) {
// We don't know what language the game was played in, so we try
// every language we know.
foreach ($this->mapTypeRegexes as $rx) {
$matches = [];
if (preg_match($rx, $line, $matches)) {
return $matches[1];
}
}
}
}
}
32 changes: 32 additions & 0 deletions test/MapNameTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Webmozart\PathUtil\Path;
use PHPUnit\Framework\TestCase;

use RecAnalyst\RecordedGame;

class MapNameTest extends TestCase
{
private function load($path)
{
return new RecordedGame(Path::join(__DIR__, $path));
}

public function testCustomMapNameExtract()
{
$rec = $this->load('recs/game-settings/[AoFE-FF DE R1] RoOk_FaLCoN - [Pervert]Moneimon (pov) G1.mgz');
$this->assertEquals($rec->gameSettings()->mapName(), 'Acropolis');
$this->assertEquals($rec->gameSettings()->mapName([
'extractRMSName' => false
]), 'Custom');
}

public function testNonEnglishMapNameExtract()
{
$rec = $this->load('recs/game-settings/rec.20140311-034826.mgz');
$this->assertEquals($rec->gameSettings()->mapName(), 'Golden Pit');
$this->assertEquals($rec->gameSettings()->mapName([
'extractRMSName' => false
]), 'Custom');
}
}
Binary file not shown.
Binary file added test/recs/game-settings/rec.20140311-034826.mgz
Binary file not shown.

0 comments on commit 5035738

Please sign in to comment.