From 723b223fd5624da852e48d653071f2609f19fb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kooi?= Date: Sat, 10 Dec 2016 17:06:20 +0100 Subject: [PATCH] Implement reading Stop, Work, Buy/Sell, Garrison, Gather Point, Repair, Unload, Wall actions --- src/Analyzers/BodyAnalyzer.php | 201 ++++++++++++++++++++- src/Model/Actions/BuildWallAction.php | 40 +++- src/Model/Actions/BuyCommodityAction.php | 55 +++++- src/Model/Actions/CancelBuildAction.php | 35 +++- src/Model/Actions/CreateAction.php | 27 ++- src/Model/Actions/FormFormationAction.php | 74 +++++++- src/Model/Actions/MakeAction.php | 39 +++- src/Model/Actions/SellCommodityAction.php | 55 +++++- src/Model/Actions/SetGatherPointAction.php | 28 ++- src/Model/Actions/UnitOrderAction.php | 28 ++- src/Model/Actions/UnloadAction.php | 37 +++- src/Model/Actions/WorkAction.php | 33 +++- 12 files changed, 591 insertions(+), 61 deletions(-) diff --git a/src/Analyzers/BodyAnalyzer.php b/src/Analyzers/BodyAnalyzer.php index 391b009..df4677a 100644 --- a/src/Analyzers/BodyAnalyzer.php +++ b/src/Analyzers/BodyAnalyzer.php @@ -258,6 +258,30 @@ protected function run() $this->readUnits($unitCount) )); break; + case self::COMMAND_STOP: + $count = ord($this->body[$this->position++]); + $this->push(new Actions\StopAction( + $this->rec, + $this->currentTime, + $this->readUnits($count) + )); + break; + case self::COMMAND_WORK: + $this->position += 3; + $targetId = $this->readBody('l', 4); + $count = ord($this->body[$this->position++]); + $this->position += 3; + $x = $this->readBody('f', 4); + $y = $this->readBody('f', 4); + $this->push(new Actions\WorkAction( + $this->rec, + $this->currentTime, + $targetId, + $x, + $y, + $this->readUnits($count) + )); + break; case self::COMMAND_MOVE: $playerId = ord($this->body[$this->position++]); $this->position += 2; @@ -272,6 +296,24 @@ protected function run() $this->readUnits($count) )); break; + case self::COMMAND_CREATE: + $this->position++; + $objectCategory = $this->readBody('v', 2); + $playerId = ord($this->body[$this->position++]); + $this->position += 3; + $x = $this->readBody('f', 4); + $y = $this->readBody('f', 4); + $z = $this->readBody('f', 4); + $this->push(new Actions\CreateAction( + $this->rec, + $this->currentTime, + $playerId, + $objectCategory, + $x, + $y, + $z + )); + break; case self::COMMAND_UNIT_AI_STATE: $numUnits = ord($this->body[$this->position++]); $stance = ord($this->body[$this->position++]); @@ -284,9 +326,9 @@ protected function run() break; // player resign case self::COMMAND_RESIGN: - $playerIndex = ord($this->body[$this->position]); - $playerNumber = ord($this->body[$this->position + 1]); - $dropped = ord($this->body[$this->position + 2]); + $playerIndex = ord($this->body[$this->position++]); + $playerNumber = ord($this->body[$this->position++]); + $dropped = ord($this->body[$this->position++]); $this->push(new Actions\ResignAction( $this->rec, @@ -296,7 +338,6 @@ protected function run() $dropped )); - $this->position += 3; $player = $playersByIndex[$playerIndex]; if ($player && $player->resignTime === 0) { $player->resignTime = $this->currentTime; @@ -304,6 +345,20 @@ protected function run() $this->chatMessages[] = new ChatMessage($this->currentTime, null, $message); } break; + case self::COMMAND_FORM_FORMATION: + $count = ord($this->body[$this->position++]); + $playerId = ord($this->body[$this->position++]); + $this->position += 1; + $formation = $this->readBody('l', 4); + + $this->push(new Actions\FormFormationAction( + $this->rec, + $this->currentTime, + $playerId, + $formation, + $this->readUnits($count) + )); + break; // researches case self::COMMAND_RESEARCH: $this->position += 3; @@ -371,11 +426,44 @@ protected function run() case self::COMMAND_GAME: $this->processGameAction(); break; + case self::COMMAND_BUILD_WALL: + $count = ord($this->body[$this->position++]); + $playerId = ord($this->body[$this->position++]); + $x1 = ord($this->body[$this->position++]); + $y1 = ord($this->body[$this->position++]); + $x2 = ord($this->body[$this->position++]); + $y2 = ord($this->body[$this->position++]); + $this->position += 1; // Padding + $objectType = $this->readBody('v', 2); + $this->position += 2; // Padding + $this->position += 4; // Always -1 + + $this->push(new Actions\BuildWallAction( + $this->rec, + $this->currentTime, + $playerId, + $objectType, + [$x1, $y1], + [$x2, $y2], + $this->readUnits($count) + )); + break; + case self::COMMAND_CANCEL_BUILD: + $this->position += 3; + $objectId = $this->readBody('l', 4); + $playerId = $this->readBody('l', 4); + $this->push(new Actions\CancelBuildAction( + $this->rec, + $this->currentTime, + $playerId, + $objectId + )); + break; // AI trains unit case self::COMMAND_MAKE: - $this->position += 9; - $playerId = -1; - $objectId = -1; + $this->position += 3; + $objectId = $this->readBody('l', 4); + $playerId = $this->readBody('v', 2); $unitType = $this->readBody('v', 2); $this->push(new Actions\MakeAction( @@ -454,6 +542,105 @@ protected function run() $this->position += 8; } break; + case self::COMMAND_REPAIR: + $count = ord($this->body[$this->position++]); + $this->position += 2; + $targetId = $this->readBody('l', 4); + $this->push(new Actions\RepairAction( + $this->rec, + $this->currentTime, + $targetId, + $this->readUnits($count) + )); + break; + case self::COMMAND_UNLOAD: + $count = ord($this->body[$this->position++]); + $this->position += 2; + $x = $this->readBody('f', 4); + $y = $this->readBody('f', 4); + $flag = ord($this->body[$this->position++]); + $this->position += 3; + $unitType = $this->readBody('l', 4); + + $this->push(new Actions\UnloadAction( + $this->rec, + $this->currentTime, + $x, + $y, + $flag, + $unitType, + $this->readUnits($count) + )); + break; + case self::COMMAND_UNIT_ORDER: + $count = ord($this->body[$this->position++]); + $this->position += 2; + $targetId = $this->readBody('l', 4); + $action = ord($this->body[$this->position++]); + $this->position += 3; + $x = $this->readBody('f', 4); + $y = $this->readBody('f', 4); + $parameter = $this->readBody('l', 4); + + $this->push(new Actions\UnitOrderAction( + $this->rec, + $this->currentTime, + $x, + $y, + $targetId, + $action, + $parameter, + $this->readUnits($count) + )); + break; + case self::COMMAND_SET_GATHER_POINT: + $count = ord($this->body[$this->position++]); + $this->position += 2; + $targetId = $this->readBody('l', 4); + $targetType = $this->readBody('l', 4); + $x = $this->readBody('f', 4); + $y = $this->readBody('f', 4); + + $this->push(new Actions\SetGatherPointAction( + $this->rec, + $this->currentTime, + $targetId, + $targetType, + $x, + $y, + $this->readUnits($count) + )); + break; + case self::COMMAND_SELL_COMMODITY: + $playerId = ord($this->body[$this->position++]); + $resourceType = ord($this->body[$this->position++]); + $amount = ord($this->body[$this->position++]); + $marketId = $this->readBody('l', 4); + + $this->push(new Actions\SellCommodityAction( + $this->rec, + $this->currentTime, + $playerId, + $resourceType, + $amount, + $marketId + )); + break; + case self::COMMAND_BUY_COMMODITY: + $playerId = ord($this->body[$this->position++]); + $resourceType = ord($this->body[$this->position++]); + $amount = ord($this->body[$this->position++]); + $marketId = $this->readBody('l', 4); + + $this->push(new Actions\BuyCommodityAction( + $this->rec, + $this->currentTime, + $playerId, + $resourceType, + $amount, + $marketId + )); + break; // multiplayer postgame data in UP1.4 RC2+ case self::COMMAND_POSTGAME: $this->postGameData = $this->read(PostgameDataAnalyzer::class); diff --git a/src/Model/Actions/BuildWallAction.php b/src/Model/Actions/BuildWallAction.php index bf25aeb..a951290 100644 --- a/src/Model/Actions/BuildWallAction.php +++ b/src/Model/Actions/BuildWallAction.php @@ -17,13 +17,11 @@ class BuildWallAction extends Action const ID = 0x69; // BuildWall(num=%d, x1=%d, y1=%d, x2=%d, y2=%d, pId=%d, oId=%d, qId=%d) - private $num; - private $x1; - private $y1; - private $x2; - private $y2; - private $playerId; - private $objectId; + public $playerId; + public $objectId; + public $from; + public $to; + public $units; /** * Create a ... @@ -31,8 +29,34 @@ class BuildWallAction extends Action * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time) + public function __construct(RecordedGame $rec, $time, $playerId, $objectType, $from, $to, $builders) { parent::__construct($rec, $time); + + $this->playerId = $playerId; + $this->objectType = $objectType; + $this->from = $from; + $this->to = $to; + $this->builders = $builders; + } + + /** + * Get a string representation of the action. + * + * @return string + */ + public function __toString() + { + return sprintf( + 'BuildWall(playerId=%d, objectType=%d, from={%d,%d}, to={%d,%d}, builders[%d]={%s})', + $this->playerId, + $this->objectType, + $this->from[0], + $this->from[1], + $this->to[0], + $this->to[1], + count($this->builders), + implode(', ', $this->builders) + ); } } diff --git a/src/Model/Actions/BuyCommodityAction.php b/src/Model/Actions/BuyCommodityAction.php index ab0b776..d9c9963 100644 --- a/src/Model/Actions/BuyCommodityAction.php +++ b/src/Model/Actions/BuyCommodityAction.php @@ -16,11 +16,33 @@ class BuyCommodityAction extends Action */ const ID = 0x7b; - // BuySellAttr(uId=%d, pId=%d, attr=%d, amt=%d) - private $unitId; - private $playerId; - private $attribute; - private $amount; + /** + * Player who is buying resources. + * + * @var int + */ + public $playerId; + + /** + * Resource type to buy. + * + * @var int + */ + public $resourceType; + + /** + * Amount of the resource to buy, in hundreds. + * + * @var int + */ + public $amount; + + /** + * Market to buy the resources at. + * + * @var int + */ + public $objectId; /** * Create a ... @@ -28,8 +50,29 @@ class BuyCommodityAction extends Action * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time) + public function __construct(RecordedGame $rec, $time, $playerId, $resourceType, $amount, $objectId) { parent::__construct($rec, $time); + + $this->playerId = $playerId; + $this->resourceType = $resourceType; + $this->amount = $amount; + $this->objectId = $objectId; + } + + /** + * Get a string representation of the action. + * + * @return string + */ + public function __toString() + { + return sprintf( + 'BuyCommodity(playerId=%d, resourceType=%d, amount=%d, objectId=%d)', + $this->playerId, + $this->resourceType, + $this->amount, + $this->objectId + ); } } diff --git a/src/Model/Actions/CancelBuildAction.php b/src/Model/Actions/CancelBuildAction.php index e24f17a..e359470 100644 --- a/src/Model/Actions/CancelBuildAction.php +++ b/src/Model/Actions/CancelBuildAction.php @@ -16,9 +16,19 @@ class CancelBuildAction extends Action */ const ID = 0x6a; - // CancelBuild( uId=%d, pId=%d) - private $playerId; - private $unitId; + /** + * Player who is canceling this object. + * + * @var int + */ + public $playerId; + + /** + * Object to cancel or delete. + * + * @var int + */ + public $objectId; /** * Create a ... @@ -26,8 +36,25 @@ class CancelBuildAction extends Action * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time) + public function __construct(RecordedGame $rec, $time, $playerId, $objectId) { parent::__construct($rec, $time); + + $this->playerId = $playerId; + $this->objectId = $objectId; + } + + /** + * Get a string representation of the action. + * + * @return string + */ + public function __toString() + { + return sprintf( + 'CancelBuild(playerId=%d, objectId=%d)', + $this->playerId, + $this->objectId + ); } } diff --git a/src/Model/Actions/CreateAction.php b/src/Model/Actions/CreateAction.php index e94737e..8ca4abd 100644 --- a/src/Model/Actions/CreateAction.php +++ b/src/Model/Actions/CreateAction.php @@ -17,8 +17,8 @@ class CreateAction extends Action const ID = 0x4; // Create( obj_cat=%d, pId=%d, loc=%.10f,%.10f,%.10f ) - private $objectCategory; private $playerId; + private $objectCategory; private $x; private $y; private $z; @@ -29,8 +29,31 @@ class CreateAction extends Action * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time) + public function __construct(RecordedGame $rec, $time, $playerId, $objectCategory, $x, $y, $z) { parent::__construct($rec, $time); + + $this->playerId = $playerId; + $this->objectCategory = $objectCategory; + $this->x = $x; + $this->y = $y; + $this->z = $z; + } + + /** + * Get a string representation of the action. + * + * @return string + */ + public function __toString() + { + return sprintf( + 'Create(playerId=%d, objectCategory=%d, loc=%.10f,%.10f,%.10f)', + $this->playerId, + $this->objectCategory, + $this->x, + $this->y, + $this->z + ); } } diff --git a/src/Model/Actions/FormFormationAction.php b/src/Model/Actions/FormFormationAction.php index 8f28972..814fb85 100644 --- a/src/Model/Actions/FormFormationAction.php +++ b/src/Model/Actions/FormFormationAction.php @@ -16,10 +16,54 @@ class FormFormationAction extends Action */ const ID = 0x17; - // FormFormation(num=%d, pId=%d, formation=%d) - private $num; - private $playerId; - private $formation; + /** + * ID of the Line formation. + * + * @var int + */ + const LINE_FORMATION = 0x02; + + /** + * ID of the Box formation. + * + * @var int + */ + const BOX_FORMATION = 0x04; + + /** + * ID of the Staggered formation. + * + * @var int + */ + const STAGGERED_FORMATION = 0x07; + + /** + * ID of the Flank (split) formation. + * + * @var int + */ + const FLANK_FORMATION = 0x08; + + /** + * ID of the player who is changing the formation. + * + * @var int + */ + public $playerId; + + /** + * Formation type to form. + * + * @var int + */ + public $formation; + + /** + * Units that should form a formation. + * + * @var int[] + */ + public $units; /** * Create a ... @@ -27,8 +71,28 @@ class FormFormationAction extends Action * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time) + public function __construct(RecordedGame $rec, $time, $playerId, $formation, $units) { parent::__construct($rec, $time); + + $this->playerId = $playerId; + $this->formation = $formation; + $this->units = $units; + } + + /** + * Get a string representation of the action. + * + * @return string + */ + public function __toString() + { + return sprintf( + 'FormFormation(playerId=%d, formation=%d, units[%d]={%s})', + $this->playerId, + $this->formation, + count($this->units), + implode(', ', $this->units) + ); } } diff --git a/src/Model/Actions/MakeAction.php b/src/Model/Actions/MakeAction.php index edf5cf4..b64fa7d 100644 --- a/src/Model/Actions/MakeAction.php +++ b/src/Model/Actions/MakeAction.php @@ -16,9 +16,25 @@ class MakeAction extends Action */ const ID = 0x64; - // Make(pId=%d, uId=%d, oId=%d, qId=%d) + /** + * Player who is "making" a unit. + * + * @var int + */ private $playerId; - private $unitId; + + /** + * Unit type ID to create. + * + * @var int + */ + private $typeId; + + /** + * Object ID where the unit will be created. Usually a building. + * + * @var int + */ private $objectId; /** @@ -27,12 +43,27 @@ class MakeAction extends Action * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time, $playerId, $unitId, $objectId) + public function __construct(RecordedGame $rec, $time, $playerId, $typeId, $objectId) { parent::__construct($rec, $time); $this->playerId = $playerId; - $this->unitId = $unitId; + $this->typeId = $typeId; $this->objectId = $objectId; } + + /** + * Get a string representation of the action. + * + * @return string + */ + public function __toString() + { + return sprintf( + 'Make(playerId=%d, typeId=%d, objectId=%d)', + $this->playerId, + $this->typeId, + $this->objectId + ); + } } diff --git a/src/Model/Actions/SellCommodityAction.php b/src/Model/Actions/SellCommodityAction.php index 1ba969f..1406225 100644 --- a/src/Model/Actions/SellCommodityAction.php +++ b/src/Model/Actions/SellCommodityAction.php @@ -16,11 +16,33 @@ class SellCommodityAction extends Action */ const ID = 0x7a; - // BuySellAttr(uId=%d, pId=%d, attr=%d, amt=%d) - private $unitId; - private $playerId; - private $attribute; - private $amount; + /** + * Player who is selling resources. + * + * @var int + */ + public $playerId; + + /** + * Resource type to sell. + * + * @var int + */ + public $resourceType; + + /** + * Amount of the resource to sell, in hundreds. + * + * @var int + */ + public $amount; + + /** + * Market to sell the resources at. + * + * @var int + */ + public $objectId; /** * Create a ... @@ -28,8 +50,29 @@ class SellCommodityAction extends Action * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time) + public function __construct(RecordedGame $rec, $time, $playerId, $resourceType, $amount, $objectId) { parent::__construct($rec, $time); + + $this->playerId = $playerId; + $this->resourceType = $resourceType; + $this->amount = $amount; + $this->objectId = $objectId; + } + + /** + * Get a string representation of the action. + * + * @return string + */ + public function __toString() + { + return sprintf( + 'SellCommodity(playerId=%d, resourceType=%d, amount=%d, objectId=%d)', + $this->playerId, + $this->resourceType, + $this->amount, + $this->objectId + ); } } diff --git a/src/Model/Actions/SetGatherPointAction.php b/src/Model/Actions/SetGatherPointAction.php index e2692f1..8ddfd71 100644 --- a/src/Model/Actions/SetGatherPointAction.php +++ b/src/Model/Actions/SetGatherPointAction.php @@ -49,7 +49,7 @@ class SetGatherPointAction extends Action * * @var int */ - public $tmid; + public $targetType; /** * Create a ... @@ -57,8 +57,32 @@ class SetGatherPointAction extends Action * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time) + public function __construct(RecordedGame $rec, $time, $targetId, $targetType, $x, $y, $units) { parent::__construct($rec, $time); + + $this->targetId = $targetId; + $this->targetType = $targetType; + $this->x = $x; + $this->y = $y; + $this->units = $units; + } + + /** + * Get a string representation of the action. + * + * @return string + */ + public function __toString() + { + return sprintf( + 'SetGatherPoint(targetId=%d, typeId=%d, x=%.2f, y=%.2f, units[%d]={%s})', + $this->targetId, + $this->targetType, + $this->x, + $this->y, + count($this->units), + implode(', ', $this->units) + ); } } diff --git a/src/Model/Actions/UnitOrderAction.php b/src/Model/Actions/UnitOrderAction.php index 7fba74b..460da4a 100644 --- a/src/Model/Actions/UnitOrderAction.php +++ b/src/Model/Actions/UnitOrderAction.php @@ -16,6 +16,13 @@ class UnitOrderAction extends Action */ const ID = 0x75; + /** + * ID of the Garrison action. + * + * @var int + */ + const GARRISON = 0x05; + /** * @var int[] */ @@ -36,11 +43,6 @@ class UnitOrderAction extends Action */ public $targetId; - /** - * @var int - */ - public $qId; - /** * @var int */ @@ -57,19 +59,28 @@ class UnitOrderAction extends Action * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time, $x, $y, $targetId, $qId, $action, $parameter, $units) + public function __construct(RecordedGame $rec, $time, $x, $y, $targetId, $action, $parameter, $units) { parent::__construct($rec, $time); $this->x = $x; $this->y = $y; $this->targetId = $targetId; - $this->qId = $qId; $this->action = $action; $this->parameter = $parameter; $this->units = $units; } + /** + * Determine whether the order is targeted at an object. + * + * @return bool True if the order has an object target, false if it does not. + */ + public function hasTarget() + { + return $this->targetId !== -1; + } + /** * Get a string representation of the action. * @@ -78,11 +89,10 @@ public function __construct(RecordedGame $rec, $time, $x, $y, $targetId, $qId, $ public function __toString() { return sprintf( - 'UnitOrder(x=%.2f, y=%.2f, targetId=%d, qId=%d, action=%d, parameter=%d, units[%d]={%s})', + 'UnitOrder(x=%.2f, y=%.2f, targetId=%d, action=%d, parameter=%d, units[%d]={%s})', $this->x, $this->y, $this->targetId, - $this->qId, $this->action, $this->parameter, count($this->units), diff --git a/src/Model/Actions/UnloadAction.php b/src/Model/Actions/UnloadAction.php index 24d3efc..3aa3308 100644 --- a/src/Model/Actions/UnloadAction.php +++ b/src/Model/Actions/UnloadAction.php @@ -16,12 +16,11 @@ class UnloadAction extends Action */ const ID = 0x6f; - // Unload(num=%d, x=%.2f, y=%.2f, flag=%d, unitType=%d) - private $num; - private $x; - private $y; - private $flag; - private $unitType; + public $x; + public $y; + public $flag; + public $unitType; + public $units; /** * Create a ... @@ -29,8 +28,32 @@ class UnloadAction extends Action * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time) + public function __construct(RecordedGame $rec, $time, $x, $y, $flag, $unitType, $units) { parent::__construct($rec, $time); + + $this->x = $x; + $this->y = $y; + $this->flag = $flag; + $this->unitType = $unitType; + $this->units = $units; + } + + /** + * Get a string representation of the action. + * + * @return string + */ + public function __toString() + { + return sprintf( + 'Unload(x=%.2f, y=%.2f, flag=%d, unitType=%d, units[%d]={%s})', + $this->x, + $this->y, + $this->flag, + $this->unitType, + count($this->units), + implode(', ', $this->units) + ); } } diff --git a/src/Model/Actions/WorkAction.php b/src/Model/Actions/WorkAction.php index a158347..f01a15b 100644 --- a/src/Model/Actions/WorkAction.php +++ b/src/Model/Actions/WorkAction.php @@ -16,14 +16,45 @@ class WorkAction extends Action */ const ID = 0x02; + private $targetId; + private $x; + private $y; + + /** + * @var int[] + */ + public $units; + /** * Create a ... * * @param \RecAnalyst\RecordedGame $rec Recorded game instance. * @param int $time Recorded game instance. */ - public function __construct(RecordedGame $rec, $time) + public function __construct(RecordedGame $rec, $time, $targetId, $x, $y, $units) { parent::__construct($rec, $time); + + $this->targetId = $targetId; + $this->x = $x; + $this->y = $y; + $this->units = $units; + } + + /** + * Get a string representation of the action. + * + * @return string + */ + public function __toString() + { + return sprintf( + 'Work(targetId=%d, x=%.2f, y=%.2f, units[%d]={%s})', + $this->targetId, + $this->x, + $this->y, + count($this->units), + implode(', ', $this->units) + ); } }