Adds character stats and tests.

This commit is contained in:
Basilius Sauter
2019-04-03 16:17:36 +02:00
parent 4d1ab9e763
commit 248258a8fe
11 changed files with 719 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Exceptions;
/**
* Class CharacterStatException
* @package LotGD\Core\Exceptions
*/
class CharacterStatException extends CoreException
{
}
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Exceptions;
/**
* Class CharacterStatExistsException
* @package LotGD\Core\Exceptions
*/
class CharacterStatExistsException extends CharacterStatException
{
}
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Exceptions;
/**
* Class CharacterStatGroupExistsException
* @package LotGD\Core\Exceptions
*/
class CharacterStatGroupExistsException extends CharacterStatException
{
}
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Exceptions;
/**
* Class CharacterStatGroupNotFoundException
* @package LotGD\Core\Exceptions
*/
class CharacterStatGroupNotFoundException extends CharacterStatException
{
}
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Exceptions;
/**
* Class CharacterStatNotFoundException
* @package LotGD\Core\Exceptions
*/
class CharacterStatNotFoundException extends CharacterStatException
{
}
+119
View File
@@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Models;
use LotGD\Core\Exceptions\CharacterStatExistsException;
use LotGD\Core\Exceptions\CharacterStatNotFoundException;
use LotGD\Core\Models\CharacterStats\CharacterStatInterface;
/**
* Class CharacterStatGroup
* @package LotGD\Core\Models
*/
class CharacterStatGroup
{
private $id;
private $name;
private $stats = [];
private $weight;
private $sorted = true;
/**
* CharacterStatGroup constructor.
* @param string $id
* @param string $name
*/
public function __construct(string $id, string $name, int $weight = 0)
{
$this->id = $id;
$this->name = $name;
$this->weight = $weight;
}
/**
* @return string
*/
public function getId(): string
{
return $this->id;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @return int
*/
public function getWeight(): int
{
return $this->weight;
}
/**
* @param CharacterStatInterface $characterStat
* @throws CharacterStatExistsException
*/
public function addCharacterStat(CharacterStatInterface $characterStat)
{
if (isset($this->stats[$characterStat->getId()])) {
throw new CharacterStatExistsException("There is already a character stat registered to this group with the id {$characterStat->getId()}");
}
$this->stats[$characterStat->getId()] = $characterStat;
$this->sorted = false;
}
/**
* @param string $id
* @return CharacterStatInterface
* @throws CharacterStatNotFoundException
*/
public function getCharacterStat(string $id): CharacterStatInterface
{
if (empty($this->stats[$id])) {
throw new CharacterStatNotFoundException("Character stat with id {$id} not found.");
}
return $this->stats[$id];
}
/**
* @param string $id
* @return bool
*/
public function hasCharacterStat(string $id): bool
{
if (isset($this->stats[$id])) {
return true;
}
return false;
}
/**
* @return \Generator|CharacterStatInterface[]
*/
public function iterate(): \Generator
{
// First, sort stat set by weight if not sorted
if (!$this->sorted) {
uasort($this->stats, function (CharacterStatInterface $a, CharacterStatInterface $b) {
return $a->getWeight() <=> $b->getWeight();
});
$this->sorted = true;
}
// Now, iterate.
foreach ($this->stats as $stat) {
yield $stat;
}
}
}
+100
View File
@@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Models;
use LotGD\Core\Events\EventContextData;
use LotGD\Core\Exceptions\CharacterStatGroupExistsException;
use LotGD\Core\Exceptions\CharacterStatGroupNotFoundException;
use LotGD\Core\Game;
/**
* Class CharacterStats
* @package LotGD\Core\Models
*/
class CharacterStats
{
private $game;
private $character;
private $stat_groups;
private $sorted = true;
/**
* CharacterStats constructor.
* @param Game $game
* @param Character $character
*/
public function __construct(Game $game, Character $character)
{
$this->game = $game;
$this->character = $character;
// Hook
$eventData = $this->game->getEventManager()->publish(
"h/lotgd/core/characterStats/populate",
EventContextData::create(["character" => $character, "stats" => $this])
);
}
/**
* @return \Generator|CharacterStatGroup[]
*/
public function iterate(): \Generator
{
// First, sort stat set by weight if not sorted yet
if (!$this->sorted) {
uasort($this->stat_groups, function (CharacterStatGroup $a, CharacterStatGroup $b) {
return $a->getWeight() <=> $b->getWeight();
});
$this->sorted = true;
}
// Now, iterate.
foreach ($this->stat_groups as $id => $stat_group) {
yield $stat_group;
}
}
/**
* @param CharacterStatGroup $group
* @throws CharacterStatGroupExistsException
*/
public function addCharacterStatGroup(CharacterStatGroup $group)
{
if (isset($this->stat_groups[$group->getId()])) {
throw new CharacterStatGroupExistsException("Character stat {$group->getId()} already exists.");
}
$this->stat_groups[$group->getId()] = $group;
$this->sorted = false;
}
/**
* @param string $id
* @return CharacterStatGroup
* @throws CharacterStatGroupNotFoundException
*/
public function getCharacterStatGroup(string $id): CharacterStatGroup
{
if (empty($this->stat_groups[$id])) {
throw new CharacterStatGroupNotFoundException("Character stat {$id} does not exists.");
}
return $this->stat_groups[$id];
}
/**
* @param string $id
* @return bool
*/
public function hasCharacterStatGroup(string $id): bool
{
if (isset($this->stat_groups[$id])) {
return true;
}
return false;
}
}
@@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Models\CharacterStats;
/**
* Class BaseCharacterStat
* @package LotGD\Core\Models\CharacterStats
*/
class BaseCharacterStat implements CharacterStatInterface
{
private $id;
private $name;
private $value;
private $weight;
/**
* BaseCharacterStat constructor.
* @param string $id
* @param string $name
* @param $value
*/
public function __construct(string $id, string $name, $value, int $weight = 0)
{
$this->id = $id;
$this->name = $name;
$this->value = $value;
$this->weight = $weight;
}
/** @inheritdoc */
public function getId(): string
{
return $this->id;
}
/** @inheritdoc */
public function getName(): string
{
return $this->name;
}
/** @inheritdoc */
public function setName(string $name)
{
$this->name = $name;
}
/** @inheritdoc */
public function getValue()
{
return $this->value;
}
/** @inheritdoc */
public function setValue($value)
{
$this->value = $value;
}
/** @inheritdoc */
public function getValueAsString(): string
{
return sprintf("%s", $this->getValue());
}
/** @inheritdoc */
public function setWeight(int $weight)
{
$this->weight = $weight;
}
/** @inheritdoc */
public function getWeight(): int
{
return $this->weight;
}
}
@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Models\CharacterStats;
interface CharacterStatInterface
{
/**
* CharacterStatInterface constructor.
* @param string $id
* @param string $name
* @param $value
*/
public function __construct(string $id, string $name, $value, int $weight = 0);
/**
* @return string
*/
public function getId(): string;
/**
* @return string
*/
public function getName(): string;
/**
* @param string $name
* @return mixed
*/
public function setName(string $name);
/**
* @return mixed
*/
public function getValue();
/**
* @param $value
* @return mixed
*/
public function setValue($value);
/**
* @return string
*/
public function getValueAsString(): string;
/**
* @param $weight
* @return int
*/
public function getWeight(): int;
/**
* @param int $weight
* @return mixed
*/
public function setWeight(int $weight);
}
+269
View File
@@ -0,0 +1,269 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Tests\Models;
use LotGD\Core\EventHandler;
use LotGD\Core\Events\EventContext;
use LotGD\Core\Exceptions\CharacterStatExistsException;
use LotGD\Core\Exceptions\CharacterStatGroupExistsException;
use LotGD\Core\Exceptions\CharacterStatGroupNotFoundException;
use LotGD\Core\Exceptions\CharacterStatNotFoundException;
use LotGD\Core\Game;
use LotGD\Core\Models\Character;
use LotGD\Core\Models\CharacterStatGroup;
use LotGD\Core\Models\CharacterStats;
use LotGD\Core\Tests\CoreModelTestCase;
class TestEventProvider implements EventHandler
{
static $called = 0;
static $last_context;
public static function handleEvent(Game $g, EventContext $context): EventContext
{
$stats = $context->getDataField("stats");
$character = $context->getDataField("character");
self::$called++;
self::$last_context = $context;
return $context;
}
}
class CharaterStatsTest extends CoreModelTestCase
{
/** @var string default data set */
protected $dataset = "character_stats";
public function setUp()
{
parent::setUp();
$game = $this->g;
$game->getEventManager()->subscribe("#h/lotgd/core/characterStats/populate#", TestEventProvider::class, "lotgd/test");
$this->getEntityManager()->flush();
}
public function tearDown()
{
$game = $this->g;
$game->getEventManager()->unsubscribe("#h/lotgd/core/characterStats/populate#", TestEventProvider::class, "lotgd/test");
$this->getEntityManager()->flush();
parent::tearDown();
}
public function testICharacterStatPopulationEventGetsCalled()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$this->assertSame(1, TestEventProvider::$called);
}
public function testIfCharacterStatPopulationEventUsesCorrectTypes()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$this->assertInstanceOf(CharacterStats::class, TestEventProvider::$last_context->getDataField("stats"));
$this->assertInstanceOf(Character::class, TestEventProvider::$last_context->getDataField("character"));
}
public function testIfCharacterStatGroupCanGetAddedToCharacterStats()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$group = new CharacterStatGroup("vendor/test", "Test");
$stats->addCharacterStatGroup($group);
$this->assertSame($group, $stats->getCharacterStatGroup("vendor/test"));
}
public function testIfAddingCharacterStatGroupWithSameIdResultsInException()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$group = new CharacterStatGroup("vendor/test", "Test");
$stats->addCharacterStatGroup($group);
$this->assertTrue($stats->hasCharacterStatGroup($group->getId()));
$this->expectException(CharacterStatGroupExistsException::class);
$group2 = new CharacterStatGroup("vendor/test", "Test");
$stats->addCharacterStatGroup($group2);
}
public function testIfGettingUnknownCharacterStatGroupResultsInException()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$group = new CharacterStatGroup("vendor/test", "Test");
$this->assertFalse($stats->hasCharacterStatGroup($group->getId()));
$this->expectException(CharacterStatGroupNotFoundException::class);
$stats->getCharacterStatGroup($group->getId());
}
public function testIfIteratingCharacterStatsYieldsAllStatGroups()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$groups = [
new CharacterStatGroup("vendor/test-0", "Test 1"),
new CharacterStatGroup("vendor/test-1", "Test 2"),
new CharacterStatGroup("vendor/test-2", "Test 3")
];
foreach ($groups as $group) {
$stats->addCharacterStatGroup($group);
}
$i = 0;
foreach($stats->iterate() as $statGroup)
{
$this->assertInstanceOf(CharacterStatGroup::class, $statGroup);
$this->assertTrue($stats->hasCharacterStatGroup($statGroup->getId()));
$this->assertSame($groups[$i], $statGroup);
$i++;
}
}
public function testIfIteratingCharacterStatsYieldsAllStatGroupsSortedAccordingToTheirWeight()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$groups = [
new CharacterStatGroup("vendor/test-0", "Test 1", 100),
new CharacterStatGroup("vendor/test-1", "Test 2", 0),
new CharacterStatGroup("vendor/test-2", "Test 3", -100)
];
foreach ($groups as $group) {
$stats->addCharacterStatGroup($group);
}
$i = 0;
foreach($stats->iterate() as $statGroup)
{
$this->assertInstanceOf(CharacterStatGroup::class, $statGroup);
$this->assertTrue($stats->hasCharacterStatGroup($statGroup->getId()));
$this->assertSame($groups[2-$i], $statGroup);
$i++;
}
}
public function testIfCharacterStatCanGetAddedToCharacterStatGroup()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$group = new CharacterStatGroup("vendor/test", "Test");
$stats->addCharacterStatGroup($group);
$stat = new CharacterStats\BaseCharacterStat("vendor/test/item", "Item", 17);
$group->addCharacterStat($stat);
$this->assertSame($stat, $group->getCharacterStat("vendor/test/item"));
}
public function testIfAddingCharacterStatWithSameIdResultsInException()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$group = new CharacterStatGroup("vendor/test", "Test");
$stats->addCharacterStatGroup($group);
$stat = new CharacterStats\BaseCharacterStat("vendor/test/item", "Item", 17);
$group->addCharacterStat($stat);
$this->assertTrue($group->hasCharacterStat($stat->getId()));
$this->expectException(CharacterStatExistsException::class);
$stat2 = new CharacterStats\BaseCharacterStat("vendor/test/item", "Item", 17);
$group->addCharacterStat($stat2);
}
public function testIfGettingUnknownCharacterStatResultsInException()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$group = new CharacterStatGroup("vendor/test", "Test");
$stats->addCharacterStatGroup($group);
$stat = new CharacterStats\BaseCharacterStat("vendor/test/item", "Item", 17);
$this->assertFalse($group->hasCharacterStat($stat->getId()));
$this->expectException(CharacterStatNotFoundException::class);
$group->getCharacterStat($group->getId());
}
public function testIfIteratingCharacterGroupYieldsAllStatGroups()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$stats = [
new CharacterStats\BaseCharacterStat("vendor/test/item-0", "Item 1", 17),
new CharacterStats\BaseCharacterStat("vendor/test/item-1", "Item 2", 18),
new CharacterStats\BaseCharacterStat("vendor/test/item-2", "Item 3", 19),
];
$group = new CharacterStatGroup("vendor/test", "Test-Group");
foreach ($stats as $stat) {
$group->addCharacterStat($stat);
}
$i = 0;
foreach($group->iterate() as $stat) {
$this->assertInstanceOf(CharacterStats\BaseCharacterStat::class, $stat);
$this->assertTrue($group->hasCharacterStat($stat->getId()));
$this->assertSame($stats[$i], $stat);
$i++;
}
}
public function testIfIteratingCharacterGroupYieldsAllStatGroupsIfWeightsAreGiven()
{
$character = $this->getEntityManager()->getRepository(Character::class)->find("10000000-0000-0000-0000-000000000001");
$stats = new CharacterStats($this->g, $character);
$stats = [
new CharacterStats\BaseCharacterStat("vendor/test/item-0", "Item 1", 17, 100),
new CharacterStats\BaseCharacterStat("vendor/test/item-1", "Item 2", 18, 0),
new CharacterStats\BaseCharacterStat("vendor/test/item-2", "Item 3", 19, -1),
];
$group = new CharacterStatGroup("vendor/test", "Test-Group");
foreach ($stats as $stat) {
$group->addCharacterStat($stat);
}
$i = 0;
foreach($group->iterate() as $stat) {
$this->assertInstanceOf(CharacterStats\BaseCharacterStat::class, $stat);
$this->assertTrue($group->hasCharacterStat($stat->getId()));
$this->assertSame($stats[2-$i], $stat);
$i++;
}
}
}
+15
View File
@@ -0,0 +1,15 @@
characters:
-
id: "10000000-0000-0000-0000-000000000001"
name: "Testcharacter 1"
displayName: "Testcharacter 1"
level: 1
health: 13
maxhealth: 100
-
id: "10000000-0000-0000-0000-000000000002"
name: "Testcharacter 2"
displayName: "Testcharacter 2"
level: 2
health: 90
maxhealth: 90