Counter-Strike/test/og/BaseTestCase.php

193 lines
5.8 KiB
PHP
Raw Normal View History

2022-08-13 12:40:42 +02:00
<?php
declare(strict_types=1);
namespace Test;
use Closure;
use cs\Core\Action;
2022-08-13 12:40:42 +02:00
use cs\Core\GameProperty;
use cs\Core\GameState;
use cs\Core\Player;
use cs\Core\Util;
use cs\Enum\Color;
use cs\Map\TestMap;
use InvalidArgumentException;
2022-10-02 20:03:15 +02:00
use ReflectionProperty;
2022-08-13 12:40:42 +02:00
2022-09-21 19:13:50 +02:00
abstract class BaseTestCase extends BaseTest
2022-08-13 12:40:42 +02:00
{
2022-09-23 15:41:27 +02:00
private int $testTickRateMs = 10;
2022-10-02 20:03:15 +02:00
/** @var int[] */
private array $defaultTestAction = [
'moveOneMs' => 5,
'moveWalkOneMs' => 4,
'moveCrouchOneMs' => 3,
'fallAmountOneMs' => 6,
'crouchDurationMs' => 100,
'jumpDurationMs' => 50,
'jumpMovementSpeedMultiplier' => 100,
'flyingMovementSpeedMultiplier' => 80,
// NOTE: Better to use even numbers for player const
'playerHeadRadius' => 30,
'playerBoundingRadius' => 44,
'playerJumpHeight' => 150,
'playerHeadHeightStand' => 190,
'playerHeadHeightCrouch' => 140,
'playerObstacleOvercomeHeight' => 20,
'playerFallDamageThreshold' => 570,
'playerBoxHeightCrouchCover' => 142,
'playerGunHeightStand' => 160,
];
2022-08-13 12:40:42 +02:00
public function __construct()
{
parent::__construct(...func_get_args());
2022-09-23 15:41:27 +02:00
Util::$TICK_RATE = $this->testTickRateMs;
2022-10-02 20:03:15 +02:00
Action::loadConstants($this->defaultTestAction);
2022-08-13 12:40:42 +02:00
}
/**
* @param array<Closure|int|false> $commands
* @param array<string,int|string> $gameProperties
*/
protected function simulateGame(array $commands, array $gameProperties = []): TestGame
{
$tickMax = count($commands);
foreach ($commands as $command) {
if (!is_int($command)) {
continue;
}
$tickMax += $command;
}
$game = $this->createOneRoundGame($tickMax, $gameProperties);
$this->playPlayer($game, $commands);
return $game;
}
/**
* @param array<string,int|string> $gameProperties
*/
protected function createOneRoundGame(int $tickMax = 1, array $gameProperties = []): TestGame
{
$properties = GameProperty::fromArray([
...[
GameProperty::MAX_ROUNDS => 1,
GameProperty::START_MONEY => 0,
GameProperty::FREEZE_TIME_SEC => 0,
GameProperty::ROUND_END_COOL_DOWN_SEC => 0,
GameProperty::RANDOMIZE_SPAWN_POSITION => false,
],
...$gameProperties,
]
);
$game = new TestGame($properties);
$game->loadMap(new TestMap());
$game->setTickMax($tickMax);
$testPlayer = new Player(1, Color::BLUE, true);
2022-10-02 20:03:15 +02:00
$boundingRadius = new ReflectionProperty($testPlayer, 'playerBoundingRadius');
$boundingRadius->setAccessible(true);
$boundingRadius->setValue($testPlayer, 0);
2022-09-20 13:19:28 +02:00
$testPlayer->equipKnife();
$game->addPlayer($testPlayer);
return $game;
}
protected function createTestGame(?int $tickMax = null, GameProperty $gameProperty = new GameProperty()): TestGame
{
$game = new TestGame($gameProperty);
$game->setTickMax($tickMax ?? PHP_INT_MAX);
$game->loadMap(new TestMap());
$testPlayer = new Player(1, Color::GREEN, true);
$testPlayer->equipKnife();
2022-08-13 12:40:42 +02:00
$game->addPlayer($testPlayer);
return $game;
}
/**
* @param array<string,int|string> $gameProperties
*/
protected function createGame(array $gameProperties = []): TestGame
{
return $this->createOneRoundGame(PHP_INT_MAX, $gameProperties);
}
/**
* @param array<Closure|int|false> $commands
*/
2022-09-20 13:19:28 +02:00
protected function playPlayerDebug(TestGame $game, array $commands, int $playerId = 1): void
{
$this->playPlayer($game, $commands, $playerId, true);
}
/**
* @param array<Closure|int|false> $commands
*/
protected function playPlayer(TestGame $game, array $commands, int $playerId = 1, bool $debug = false): void
2022-08-13 12:40:42 +02:00
{
$i = 0;
$skipNTicks = 0;
$game->onTick(function (GameState $state) use (&$i, &$skipNTicks, $game, $playerId, $commands): void {
if ($skipNTicks-- > 0) {
return;
}
if (!isset($commands[$i])) {
throw new InvalidArgumentException("No command defined for tick '{$i}' or too many tickMax in Game");
}
if (false === $commands[$i]) {
$game->setTickMax(0);
$i++;
return;
}
if (is_int($commands[$i])) {
if ($commands[$i] <= 0) {
$this->fail("Skip ticks cannot be zero or negative");
}
$skipNTicks = $commands[$i];
$i++;
return;
}
$commands[$i]($state->getPlayer($playerId));
$i++;
});
2022-09-20 13:19:28 +02:00
if ($debug) {
$game->startDebug();
} else {
$game->start();
}
2022-08-13 12:40:42 +02:00
if (isset($commands[$i])) {
throw new InvalidArgumentException("Some command(s) were not processed, starting from tick '{$i}'");
}
}
/**
* @return false
*/
protected function endGame(): bool
{
return false;
}
protected function waitXTicks(int $numberOfTicks): int
{
return $numberOfTicks;
}
protected function waitNTicks(int $waitTimeMs): int
{
$waitTick = Util::millisecondsToFrames($waitTimeMs) - 1;
if ($waitTick < 1) {
throw new InvalidArgumentException("Value too low");
}
return $waitTick;
}
}