Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ca81a3789 | |||
| 353c4251c4 | |||
| 248258a8fe | |||
| 4d1ab9e763 | |||
| d7229858cc | |||
| 14b1db8b82 | |||
| d7100deb0f | |||
| e260a1d661 | |||
| 2ff8d647e8 | |||
| 8d9a186b46 | |||
| 8f69527764 | |||
| 684f86aed6 | |||
| 55481c30b1 | |||
| 6b383be1cd | |||
| d609f981aa | |||
| 4ec84dfec3 | |||
| 049d116028 | |||
| aa63259992 | |||
| a097c29d67 | |||
| bab3e0f236 | |||
| 2f89bbc7e3 | |||
| 6e2ba248c4 | |||
| b398ffae14 | |||
| 90971d152a | |||
| 04b3b6aaf9 | |||
| 0aaba1b94b | |||
| 2affd4803f | |||
| c07f7b3342 | |||
| 8a75e81431 | |||
| ccfb432e4d | |||
| 2a0bf5f038 | |||
| 4248dad033 | |||
| b89f6d7b0c | |||
| 6c4b1e15f4 | |||
| ddb7ae08a6 | |||
| 8ba04dade4 | |||
| 70243f4662 | |||
| 77b33d7385 | |||
| db49e63c99 | |||
| d90e4d0ba9 | |||
| ccbfa0553c | |||
| 04a5b59ea2 | |||
| 846ab6018e | |||
| efb333d08a | |||
| 92c0f71ed6 | |||
| c9e6f679c4 | |||
| 17ebdbdbe5 | |||
| 55b821c8e8 | |||
| 45a785a8f5 | |||
| ff713ac333 | |||
| aba0d53a68 | |||
| 9ddd16b4e8 | |||
| c0edd3ac67 | |||
| 81d773720a | |||
| 5ac7098f35 | |||
| 41db0ddfda | |||
| 003a6517ba | |||
| af6a6cbff0 | |||
| 56c80e3f8d | |||
| 4b82ee4b89 | |||
| 829d63d7f6 | |||
| 94763f8d6e | |||
| a287313f6f | |||
| 51a102f981 | |||
| 9842fa9ace | |||
| adf4eeac5e | |||
| 533378d006 | |||
| 867843dddd | |||
| 329430c547 | |||
| d20a59e68a | |||
| 29e474b9c1 | |||
| bbc960fd3d | |||
| 7e58c72526 | |||
| 1eeca4ef9e | |||
| 201a3a032f | |||
| a790eab5ee | |||
| e6e9e6e102 | |||
| 214b1de95f | |||
| f5380de501 | |||
| 70d29f67b8 | |||
| a33473d435 | |||
| d126b0207f | |||
| f201784291 | |||
| 39b9ec318a | |||
| 5668c08f45 | |||
| a739aed94a | |||
| d408aa0755 | |||
| af98ab0f36 | |||
| 03fc114775 | |||
| 848e6b022c | |||
| 5c3fd4714d | |||
| 498f4965e6 | |||
| 2970bd09d7 | |||
| e82e72a183 | |||
| 9ecd0ddc58 | |||
| 64cb22d3c0 | |||
| f8057077bc | |||
| 1c89d8f204 | |||
| 3b8537fab6 | |||
| 3bf23f3ac7 | |||
| 94e18b8d11 | |||
| b8f47c6d53 |
@@ -1,5 +1,6 @@
|
|||||||
### Project related
|
### Project related
|
||||||
vendor/
|
vendor/
|
||||||
|
.idea/
|
||||||
|
|
||||||
logs/*
|
logs/*
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -1,7 +1,8 @@
|
|||||||
sudo: false
|
sudo: false
|
||||||
language: php
|
language: php
|
||||||
php:
|
php:
|
||||||
- '7.0'
|
- '7.1'
|
||||||
|
- '7.2'
|
||||||
install:
|
install:
|
||||||
- composer install
|
- composer install
|
||||||
script:
|
script:
|
||||||
|
|||||||
+8
-6
@@ -2,6 +2,7 @@
|
|||||||
"name": "lotgd/core",
|
"name": "lotgd/core",
|
||||||
"description": "Core functionality for Legend of the Green Dragon, a text-based RPG game.",
|
"description": "Core functionality for Legend of the Green Dragon, a text-based RPG game.",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
|
"version": "0.5.0",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"LotGD\\Core\\": "src/",
|
"LotGD\\Core\\": "src/",
|
||||||
@@ -12,14 +13,15 @@
|
|||||||
"bin/daenerys"
|
"bin/daenerys"
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.0.0",
|
"php": "^7.1.0",
|
||||||
"composer/composer": "*",
|
"composer/composer": "*",
|
||||||
"gedmo/doctrine-extensions": "*",
|
"gedmo/doctrine-extensions": "*",
|
||||||
"doctrine/orm": "^2.5",
|
"doctrine/orm": "^2.5",
|
||||||
"monolog/monolog": "^1.12",
|
"monolog/monolog": "^1.12",
|
||||||
"symfony/console": "^3.0",
|
"symfony/console": "^3.0|^4.0",
|
||||||
"symfony/yaml": "^3.0",
|
"symfony/yaml": "^3.0|^4.0",
|
||||||
"d11wtq/boris": "^1.0"
|
"d11wtq/boris": "^1.0",
|
||||||
|
"ramsey/uuid-doctrine": "^1.5"
|
||||||
},
|
},
|
||||||
"repositories": [
|
"repositories": [
|
||||||
{
|
{
|
||||||
@@ -29,8 +31,8 @@
|
|||||||
|
|
||||||
],
|
],
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "*",
|
"phpunit/phpunit": "^5.0",
|
||||||
"phpunit/dbunit": "*",
|
"phpunit/dbunit": "^2.0",
|
||||||
"block8/php-docblock-checker": "2.0.0"
|
"block8/php-docblock-checker": "2.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+1109
-481
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@ database:
|
|||||||
name: daenerys
|
name: daenerys
|
||||||
user: root
|
user: root
|
||||||
password:
|
password:
|
||||||
|
disableAutoSchemaUpdate: false
|
||||||
game:
|
game:
|
||||||
epoch: 2016-07-01 00:00:00.0 -8
|
epoch: 2016-07-01 00:00:00.0 -8
|
||||||
offsetSeconds: 0
|
offsetSeconds: 0
|
||||||
|
|||||||
+43
-3
@@ -11,15 +11,21 @@ class Action
|
|||||||
{
|
{
|
||||||
protected $id;
|
protected $id;
|
||||||
protected $destinationSceneId;
|
protected $destinationSceneId;
|
||||||
|
protected $title = null;
|
||||||
|
protected $parameters = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new action with the specified Scene as its destination.
|
* Construct a new action with the specified Scene as its destination.
|
||||||
* @param int $destinationSceneId
|
* @param int $destinationSceneId
|
||||||
|
* @param string|null $title
|
||||||
|
* @param array $parameters
|
||||||
*/
|
*/
|
||||||
public function __construct(int $destinationSceneId)
|
public function __construct(string $destinationSceneId, ?string $title = null, array $parameters = [])
|
||||||
{
|
{
|
||||||
$this->id = bin2hex(random_bytes(8));
|
$this->id = bin2hex(random_bytes(8));
|
||||||
$this->destinationSceneId = $destinationSceneId;
|
$this->destinationSceneId = $destinationSceneId;
|
||||||
|
$this->title = $title;
|
||||||
|
$this->parameters = $parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,10 +41,44 @@ class Action
|
|||||||
/**
|
/**
|
||||||
* Return the database ID of the destination scene, where the user will
|
* Return the database ID of the destination scene, where the user will
|
||||||
* go if they take this action.
|
* go if they take this action.
|
||||||
* @return string
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getDestinationSceneId(): int
|
public function getDestinationSceneId(): string
|
||||||
{
|
{
|
||||||
return $this->destinationSceneId;
|
return $this->destinationSceneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public function getTitle(): ?string
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public function setTitle(?string $title)
|
||||||
|
{
|
||||||
|
$this->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all parameters for this action
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getParameters(): array
|
||||||
|
{
|
||||||
|
return $this->parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets all parameters for this action
|
||||||
|
* @param array $parameters
|
||||||
|
*/
|
||||||
|
public function setParameters(array $parameters): void
|
||||||
|
{
|
||||||
|
$this->parameters = $parameters;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-3
@@ -6,7 +6,7 @@ namespace LotGD\Core;
|
|||||||
/**
|
/**
|
||||||
* A grouping of navigation actions, like a submenu.
|
* A grouping of navigation actions, like a submenu.
|
||||||
*/
|
*/
|
||||||
class ActionGroup
|
class ActionGroup implements \Countable
|
||||||
{
|
{
|
||||||
const DefaultGroup = 'lotgd/core/default';
|
const DefaultGroup = 'lotgd/core/default';
|
||||||
const HiddenGroup = 'lotgd/core/hidden';
|
const HiddenGroup = 'lotgd/core/hidden';
|
||||||
@@ -30,6 +30,15 @@ class ActionGroup
|
|||||||
$this->actions = [];
|
$this->actions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of registered Actions for this group.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return count($this->actions);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the unique identifier for this group, in the vendor/module/group format.
|
* Returns the unique identifier for this group, in the vendor/module/group format.
|
||||||
* @return string
|
* @return string
|
||||||
@@ -61,7 +70,7 @@ class ActionGroup
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ordered array of actions.
|
* Returns the ordered array of actions.
|
||||||
* @return array<Action>
|
* @return Action[]
|
||||||
*/
|
*/
|
||||||
public function getActions(): array
|
public function getActions(): array
|
||||||
{
|
{
|
||||||
@@ -70,10 +79,19 @@ class ActionGroup
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the ordered array of actions.
|
* Sets the ordered array of actions.
|
||||||
* @param array<Action> $actions
|
* @param Action[] $actions
|
||||||
*/
|
*/
|
||||||
public function setActions(array $actions)
|
public function setActions(array $actions)
|
||||||
{
|
{
|
||||||
$this->actions = $actions;
|
$this->actions = $actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a single action to the list of actions.
|
||||||
|
* @param Action $action
|
||||||
|
*/
|
||||||
|
public function addAction(Action $action)
|
||||||
|
{
|
||||||
|
$this->actions[] = $action;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+38
-19
@@ -16,11 +16,7 @@ use LotGD\Core\{
|
|||||||
Models\FighterInterface
|
Models\FighterInterface
|
||||||
};
|
};
|
||||||
use LotGD\Core\Models\{
|
use LotGD\Core\Models\{
|
||||||
Buff,
|
Buff, BattleEvents\BuffMessageEvent, BattleEvents\CriticalHitEvent, BattleEvents\DamageEvent, BattleEvents\DeathEvent, Scene
|
||||||
BattleEvents\BuffMessageEvent,
|
|
||||||
BattleEvents\CriticalHitEvent,
|
|
||||||
BattleEvents\DamageEvent,
|
|
||||||
BattleEvents\DeathEvent
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,7 +43,7 @@ class Battle
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Battle Configuration
|
* Battle Configuration
|
||||||
* @var type
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $configuration = [
|
protected $configuration = [
|
||||||
"riposteEnabled" => true,
|
"riposteEnabled" => true,
|
||||||
@@ -61,31 +57,50 @@ class Battle
|
|||||||
* @param FighterInterface $player
|
* @param FighterInterface $player
|
||||||
* @param FighterInterface $monster
|
* @param FighterInterface $monster
|
||||||
*/
|
*/
|
||||||
public function __construct(Game $game, FighterInterface $player, FighterInterface $monster)
|
public function __construct(Game $game, FighterInterface $player, ?FighterInterface $monster)
|
||||||
{
|
{
|
||||||
$this->game = $game;
|
$this->game = $game;
|
||||||
$this->player = $player;
|
$this->player = $player;
|
||||||
$this->monster = $monster;
|
$this->monster = $monster;
|
||||||
$this->events = new ArrayCollection();
|
$this->events = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ToDo Returns at some point battle actions
|
* Returns a string which contains the important fields that must be serialized.
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getActions()
|
public function serialize(): string
|
||||||
{
|
{
|
||||||
|
return serialize([
|
||||||
|
"monster" => $this->monster,
|
||||||
|
"result" => $this->result,
|
||||||
|
"round" => $this->round,
|
||||||
|
"configuration" => $this->configuration,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ToDo Do some action
|
* @param Game $game
|
||||||
|
* @param FighterInterface $player
|
||||||
|
* @param string $serialized
|
||||||
|
* @return Battle
|
||||||
*/
|
*/
|
||||||
public function selectAction()
|
public static function unserialize(Game $game, FighterInterface $player, string $serialized): self
|
||||||
{
|
{
|
||||||
|
$battle = new self($game, $player, null);
|
||||||
|
$unserialized = unserialize($serialized);
|
||||||
|
|
||||||
|
$battle->monster = $unserialized["monster"];
|
||||||
|
$battle->result = $unserialized["result"];
|
||||||
|
$battle->round = $unserialized["round"];
|
||||||
|
$battle->configuration = $unserialized["configuration"];
|
||||||
|
|
||||||
|
return $battle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of all battle events
|
* Returns a list of all battle events
|
||||||
* @return \LotGD\Core\Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function getEvents(): Collection
|
public function getEvents(): Collection
|
||||||
{
|
{
|
||||||
@@ -197,6 +212,7 @@ class Battle
|
|||||||
/**
|
/**
|
||||||
* Returns the winner of this fight
|
* Returns the winner of this fight
|
||||||
* @return FighterInterface
|
* @return FighterInterface
|
||||||
|
* @throws BattleNotOverException if battle is not over.
|
||||||
*/
|
*/
|
||||||
public function getWinner(): FighterInterface
|
public function getWinner(): FighterInterface
|
||||||
{
|
{
|
||||||
@@ -210,6 +226,7 @@ class Battle
|
|||||||
/**
|
/**
|
||||||
* Returns the loser of this fight
|
* Returns the loser of this fight
|
||||||
* @return FighterInterface
|
* @return FighterInterface
|
||||||
|
* @throws BattleNotOverException if battle is not over.
|
||||||
*/
|
*/
|
||||||
public function getLoser(): FighterInterface
|
public function getLoser(): FighterInterface
|
||||||
{
|
{
|
||||||
@@ -226,6 +243,8 @@ class Battle
|
|||||||
* @param int $n
|
* @param int $n
|
||||||
* @param bool $firstDamageRound Which damage rounds are calculated. Cannot be 0.
|
* @param bool $firstDamageRound Which damage rounds are calculated. Cannot be 0.
|
||||||
* @return int Number of fights fought.
|
* @return int Number of fights fought.
|
||||||
|
* @throws ArgumentException if firstDamageRound is 0.
|
||||||
|
* @throws BattleIsOverException
|
||||||
*/
|
*/
|
||||||
public function fightNRounds(int $n = 1, int $firstDamageRound = self::DAMAGEROUND_BOTH): int
|
public function fightNRounds(int $n = 1, int $firstDamageRound = self::DAMAGEROUND_BOTH): int
|
||||||
{
|
{
|
||||||
@@ -346,12 +365,12 @@ class Battle
|
|||||||
|
|
||||||
// Apply buff scaling for the attacker's attack - this needs to take into
|
// Apply buff scaling for the attacker's attack - this needs to take into
|
||||||
// account the attacker's goodguyAttackModifier and the defenders badguyAttackModifier
|
// account the attacker's goodguyAttackModifier and the defenders badguyAttackModifier
|
||||||
$attackersAttack = $attacker->getAttack($this->game)
|
$attackersAttack = $attacker->getAttack()
|
||||||
* $attackersBuffs->getGoodguyAttackModifier()
|
* $attackersBuffs->getGoodguyAttackModifier()
|
||||||
* $defendersBuffs->getBadguyAttackModifier();
|
* $defendersBuffs->getBadguyAttackModifier();
|
||||||
// It's the opposite for the defender's defense - it needs to take into account the
|
// It's the opposite for the defender's defense - it needs to take into account the
|
||||||
// defender's goodguyDefenseModifier as well as the attacker's badguyDefenseModifier.
|
// defender's goodguyDefenseModifier as well as the attacker's badguyDefenseModifier.
|
||||||
$defendersDefense = $defender->getDefense($this->game)
|
$defendersDefense = $defender->getDefense()
|
||||||
* $defendersBuffs->getGoodguyDefenseModifier()
|
* $defendersBuffs->getGoodguyDefenseModifier()
|
||||||
* $attackersBuffs->getBadguyDefenseModifier()
|
* $attackersBuffs->getBadguyDefenseModifier()
|
||||||
* $defenseAdjustement;
|
* $defenseAdjustement;
|
||||||
@@ -369,13 +388,13 @@ class Battle
|
|||||||
$defendersDefense = (int) round($defendersDefense, 0);
|
$defendersDefense = (int) round($defendersDefense, 0);
|
||||||
|
|
||||||
// Lets roll the
|
// Lets roll the
|
||||||
$attackersAtkRoll = $this->game->getDiceBag()->normal(0, $attackersAttack);
|
$attackersAtkRoll = $this->game->getDiceBag()->pseudoBell(0, $attackersAttack);
|
||||||
$defendersDefRoll = $this->game->getDiceBag()->normal(0, $defendersDefense);
|
$defendersDefRoll = $this->game->getDiceBag()->pseudoBell(0, $defendersDefense);
|
||||||
$damage = $attackersAtkRoll - $defendersDefRoll;
|
$damage = $attackersAtkRoll - $defendersDefRoll;
|
||||||
|
|
||||||
// If the attacker's attack after modification is bigger than before,
|
// If the attacker's attack after modification is bigger than before,
|
||||||
// we call it a critical hit and apply the CriticalHitEvent.
|
// we call it a critical hit and apply the CriticalHitEvent.
|
||||||
if ($attackersAttack > $attacker->getAttack($this->game) && $this->isCriticalHitEnabled()) {
|
if ($attackersAttack > $attacker->getAttack() && $this->isCriticalHitEnabled()) {
|
||||||
$events->add(new CriticalHitEvent($attacker, $attackersAttack));
|
$events->add(new CriticalHitEvent($attacker, $attackersAttack));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+52
-14
@@ -3,6 +3,11 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core;
|
namespace LotGD\Core;
|
||||||
|
|
||||||
|
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||||
|
use Doctrine\Common\EventManager as DoctrineEventManager;
|
||||||
|
use Doctrine\Common\Util\Debug;
|
||||||
|
use Doctrine\DBAL\DBALException;
|
||||||
|
use Doctrine\ORM\Events as DoctrineEvents;
|
||||||
use Doctrine\ORM\ {
|
use Doctrine\ORM\ {
|
||||||
EntityManager,
|
EntityManager,
|
||||||
EntityManagerInterface,
|
EntityManagerInterface,
|
||||||
@@ -17,10 +22,8 @@ use Monolog\ {
|
|||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\Console\Application;
|
use Symfony\Component\Console\Application;
|
||||||
|
|
||||||
use LotGD\Core\ {
|
use LotGD\Core\{
|
||||||
ComposerManager,
|
ComposerManager, BootstrapInterface, Doctrine\EntityPostLoadEventListener, Exceptions\InvalidConfigurationException
|
||||||
BootstrapInterface,
|
|
||||||
Exceptions\InvalidConfigurationException
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +33,8 @@ class Bootstrap
|
|||||||
{
|
{
|
||||||
private $logger;
|
private $logger;
|
||||||
private $game;
|
private $game;
|
||||||
private $libraryConfigurationManager = [];
|
/** @var LibraryConfigurationManager */
|
||||||
|
private $libraryConfigurationManager;
|
||||||
private $annotationDirectories = [];
|
private $annotationDirectories = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,9 +66,21 @@ class Bootstrap
|
|||||||
|
|
||||||
list($dsn, $user, $password) = $config->getDatabaseConnectionDetails($cwd);
|
list($dsn, $user, $password) = $config->getDatabaseConnectionDetails($cwd);
|
||||||
$pdo = $this->connectToDatabase($dsn, $user, $password);
|
$pdo = $this->connectToDatabase($dsn, $user, $password);
|
||||||
$entityManager = $this->createEntityManager($pdo);
|
$entityManager = $this->createEntityManager($pdo, $config);
|
||||||
|
|
||||||
$this->game = new Game($config, $this->logger, $entityManager, $cwd);
|
$this->game = (new GameBuilder())
|
||||||
|
->withConfiguration($config)
|
||||||
|
->withLogger($this->logger)
|
||||||
|
->withEntityManager($entityManager)
|
||||||
|
->withCwd($cwd)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
// Add Event listener to entity manager
|
||||||
|
$dem = $entityManager->getEventManager();
|
||||||
|
$dem->addEventListener([DoctrineEvents::postLoad], new EntityPostLoadEventListener($this->game));
|
||||||
|
|
||||||
|
// Run model extender
|
||||||
|
$this->extendModels();
|
||||||
|
|
||||||
return $this->game;
|
return $this->game;
|
||||||
}
|
}
|
||||||
@@ -143,7 +159,7 @@ class Bootstrap
|
|||||||
* @param \PDO $pdo
|
* @param \PDO $pdo
|
||||||
* @return EntityManagerInterface
|
* @return EntityManagerInterface
|
||||||
*/
|
*/
|
||||||
protected function createEntityManager(\PDO $pdo): EntityManagerInterface
|
protected function createEntityManager(\PDO $pdo, Configuration $config): EntityManagerInterface
|
||||||
{
|
{
|
||||||
$this->annotationDirectories = $this->generateAnnotationDirectories();
|
$this->annotationDirectories = $this->generateAnnotationDirectories();
|
||||||
$this->logger->addDebug("Adding annotation directories:");
|
$this->logger->addDebug("Adding annotation directories:");
|
||||||
@@ -152,16 +168,20 @@ class Bootstrap
|
|||||||
}
|
}
|
||||||
$configuration = Setup::createAnnotationMetadataConfiguration($this->annotationDirectories, true);
|
$configuration = Setup::createAnnotationMetadataConfiguration($this->annotationDirectories, true);
|
||||||
|
|
||||||
// Set a quote
|
|
||||||
$configuration->setQuoteStrategy(new AnsiQuoteStrategy());
|
|
||||||
|
|
||||||
// Create entity manager
|
// Create entity manager
|
||||||
$entityManager = EntityManager::create(["pdo" => $pdo], $configuration);
|
$entityManager = EntityManager::create(["pdo" => $pdo], $configuration);
|
||||||
|
|
||||||
|
// Register uuid type
|
||||||
|
try {
|
||||||
|
\Doctrine\DBAL\Types\Type::addType('uuid', 'Ramsey\Uuid\Doctrine\UuidType');
|
||||||
|
} catch (DBALException $e) {}
|
||||||
|
|
||||||
// Create Schema and update database if needed
|
// Create Schema and update database if needed
|
||||||
$metaData = $entityManager->getMetadataFactory()->getAllMetadata();
|
if ($config->getDatabaseAutoSchemaUpdate()) {
|
||||||
$schemaTool = new SchemaTool($entityManager);
|
$metaData = $entityManager->getMetadataFactory()->getAllMetadata();
|
||||||
$schemaTool->updateSchema($metaData);
|
$schemaTool = new SchemaTool($entityManager);
|
||||||
|
$schemaTool->updateSchema($metaData);
|
||||||
|
}
|
||||||
|
|
||||||
return $entityManager;
|
return $entityManager;
|
||||||
}
|
}
|
||||||
@@ -194,4 +214,22 @@ class Bootstrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the code to extend models.
|
||||||
|
*/
|
||||||
|
public function extendModels()
|
||||||
|
{
|
||||||
|
AnnotationRegistry::registerLoader("class_exists");
|
||||||
|
|
||||||
|
$modelExtender = new ModelExtender();
|
||||||
|
|
||||||
|
foreach ($this->libraryConfigurationManager->getConfigurations() as $config) {
|
||||||
|
$modelExtensions = $config->getSubKeyIfItExists(["modelExtensions"]);
|
||||||
|
|
||||||
|
if ($modelExtensions) {
|
||||||
|
$modelExtender->addMore($modelExtensions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -536,7 +536,7 @@ class BuffList
|
|||||||
if ($buff->getBadguyDamageReflection() !== 0.) {
|
if ($buff->getBadguyDamageReflection() !== 0.) {
|
||||||
if ($damage > 0) {
|
if ($damage > 0) {
|
||||||
// Damage is > 0, so badguy takes damage, we can normally reflect
|
// Damage is > 0, so badguy takes damage, we can normally reflect
|
||||||
$reflectedDamage = (int)round($buff->getGoodguyDamageReflection() * $damage, 0);
|
$reflectedDamage = (int)round($buff->getBadguyDamageReflection() * $damage, 0);
|
||||||
if ($reflectedDamage === 0) {
|
if ($reflectedDamage === 0) {
|
||||||
$message = $buff->getNoEffectMessage();
|
$message = $buff->getNoEffectMessage();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+9
-11
@@ -4,9 +4,7 @@ declare(strict_types=1);
|
|||||||
namespace LotGD\Core;
|
namespace LotGD\Core;
|
||||||
|
|
||||||
use Composer\{
|
use Composer\{
|
||||||
Composer,
|
Composer, Factory, IO\NullIO, Package\CompletePackageInterface, Package\PackageInterface
|
||||||
Factory,
|
|
||||||
IO\NullIO
|
|
||||||
};
|
};
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
|
|
||||||
@@ -41,13 +39,13 @@ class ComposerManager
|
|||||||
{
|
{
|
||||||
if ($this->composer === null) {
|
if ($this->composer === null) {
|
||||||
// Verify location of composer.json.
|
// Verify location of composer.json.
|
||||||
$path = $this->cwd . DIRECTORY_SEPARATOR . "composer.json";
|
$composerConfigPath = $this->cwd . DIRECTORY_SEPARATOR . "composer.json";
|
||||||
if (!file_exists($path)) {
|
if (!file_exists($composerConfigPath)) {
|
||||||
throw new InvalidConfigurationException("composer.json cannot be found at {$path}.");
|
throw new InvalidConfigurationException("composer.json cannot be found at {$composerConfigPath}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$io = new NullIO();
|
$factory = new Factory();
|
||||||
$this->composer = Factory::create($io, $path);
|
$this->composer = $factory->createComposer(new NullIO(), $composerConfigPath, false, $this->cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->composer;
|
return $this->composer;
|
||||||
@@ -58,7 +56,7 @@ class ComposerManager
|
|||||||
* @return PackageInterface Package corresponding to this library.
|
* @return PackageInterface Package corresponding to this library.
|
||||||
* @throws LibraryDoesNotExistException
|
* @throws LibraryDoesNotExistException
|
||||||
*/
|
*/
|
||||||
public function getPackageForLibrary(string $library): PackageInterface
|
public function getPackageForLibrary(string $library): CompletePackageInterface
|
||||||
{
|
{
|
||||||
// TODO: should probably do something better than O(n) here.
|
// TODO: should probably do something better than O(n) here.
|
||||||
$packages = $this->getComposer()->getRepositoryManager()->getLocalRepository()->getPackages();
|
$packages = $this->getComposer()->getRepositoryManager()->getLocalRepository()->getPackages();
|
||||||
@@ -72,7 +70,7 @@ class ComposerManager
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all the packages installed in the current setup.
|
* Return all the packages installed in the current setup.
|
||||||
* @return array<Composer\PackageInterface>
|
* @return PackageInterface[]
|
||||||
*/
|
*/
|
||||||
public function getPackages(): array
|
public function getPackages(): array
|
||||||
{
|
{
|
||||||
@@ -84,7 +82,7 @@ class ComposerManager
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of the configured packages which are LotGD modules (type = 'lotgd-module').
|
* Return a list of the configured packages which are LotGD modules (type = 'lotgd-module').
|
||||||
* @return array Array of \Composer\PackageInterface.
|
* @return PackageInterface[]
|
||||||
*/
|
*/
|
||||||
public function getModulePackages(): array
|
public function getModulePackages(): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class Configuration
|
|||||||
private $databaseName;
|
private $databaseName;
|
||||||
private $databaseUser;
|
private $databaseUser;
|
||||||
private $databasePassword;
|
private $databasePassword;
|
||||||
|
private $databaseAutoSchemaUpdate;
|
||||||
private $logPath;
|
private $logPath;
|
||||||
private $gameEpoch;
|
private $gameEpoch;
|
||||||
private $gameOffsetSeconds;
|
private $gameOffsetSeconds;
|
||||||
@@ -70,6 +71,12 @@ class Configuration
|
|||||||
$this->databasePassword = $passwd;
|
$this->databasePassword = $passwd;
|
||||||
$this->databaseName = $name;
|
$this->databaseName = $name;
|
||||||
|
|
||||||
|
if (empty($rawConfig['database']['disableAutoSchemaUpdate'])) {
|
||||||
|
$this->databaseAutoSchemaUpdate = true;
|
||||||
|
} else {
|
||||||
|
$this->databaseAutoSchemaUpdate = false;
|
||||||
|
}
|
||||||
|
|
||||||
$gameEpoch = $rawConfig['game']['epoch'];
|
$gameEpoch = $rawConfig['game']['epoch'];
|
||||||
$gameOffsetSeconds = $rawConfig['game']['offsetSeconds'];
|
$gameOffsetSeconds = $rawConfig['game']['offsetSeconds'];
|
||||||
$gameDaysPerDay = $rawConfig['game']['daysPerDay'];
|
$gameDaysPerDay = $rawConfig['game']['daysPerDay'];
|
||||||
@@ -157,6 +164,15 @@ class Configuration
|
|||||||
return $this->databasePassword;
|
return $this->databasePassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if doctrine should not auto update.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getDatabaseAutoSchemaUpdate(): bool
|
||||||
|
{
|
||||||
|
return $this->databaseAutoSchemaUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the path to the directory to store log files.
|
* Return the path to the directory to store log files.
|
||||||
* @return string The configured log directory path.
|
* @return string The configured log directory path.
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
|
||||||
|
namespace LotGD\Core\Console\Command;
|
||||||
|
|
||||||
|
|
||||||
|
use LotGD\Core\Models\Character;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to list all characters.
|
||||||
|
* @package LotGD\Core\Console\Command
|
||||||
|
*/
|
||||||
|
class CharacterListCommand extends BaseCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('character:list')
|
||||||
|
->setDescription('Lists all characters');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
$characters = $this->game->getEntityManager()->getRepository(Character::class)->findAll();
|
||||||
|
|
||||||
|
$table = [["id", "name", "level"], []];
|
||||||
|
foreach ($characters as $character) {
|
||||||
|
$table[1][] = [
|
||||||
|
$character->getId(),
|
||||||
|
$character->getDisplayName(),
|
||||||
|
$character->getLevel()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->table(...$table);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
|
||||||
|
namespace LotGD\Core\Console\Command;
|
||||||
|
|
||||||
|
|
||||||
|
use LotGD\Core\Models\Character;
|
||||||
|
use Symfony\Component\Console\Input\InputDefinition;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the viewpoint of a given character.
|
||||||
|
* @package LotGD\Core\Console\Command
|
||||||
|
*/
|
||||||
|
class CharacterResetViewpointCommand extends BaseCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('character:resetViewpoint')
|
||||||
|
->setDescription('Resets the viewpoint of a given character.')
|
||||||
|
->setDefinition(
|
||||||
|
new InputDefinition([
|
||||||
|
new InputOption('id', null, InputOption::VALUE_REQUIRED)
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
$id = $input->getOption("id");
|
||||||
|
|
||||||
|
/* @var $character \LotGD\Core\Models\Character */
|
||||||
|
$character = $this->game->getEntityManager()->getRepository(Character::class)->find($id);
|
||||||
|
|
||||||
|
if ($character === null) {
|
||||||
|
$io->error("Character not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->game->getEntityManager()->remove($character->getViewpoint());
|
||||||
|
$character->setViewpoint(null);
|
||||||
|
|
||||||
|
$this->game->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Console\Command;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Tools\SchemaTool;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use LotGD\Core\Console\Main;
|
||||||
|
use LotGD\Core\Game;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Danerys command to initiate the database with default values.
|
||||||
|
*/
|
||||||
|
class DatabaseSchemaUpdateCommand extends BaseCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('database:schemaUpdate')
|
||||||
|
->setDescription('Updates the database schema manually.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$entityManager = $this->game->getEntityManager();
|
||||||
|
$metaData = $entityManager->getMetadataFactory()->getAllMetadata();
|
||||||
|
$schemaTool = new SchemaTool($entityManager);
|
||||||
|
$schemaTool->updateSchema($metaData);
|
||||||
|
|
||||||
|
$entityManager->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,12 +3,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core\Console\Command;
|
namespace LotGD\Core\Console\Command;
|
||||||
|
|
||||||
|
use Composer\Repository\RepositoryInterface;
|
||||||
|
use LotGD\Core\ModuleManager;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
use LotGD\Core\Exceptions\ClassNotFoundException;
|
use LotGD\Core\Exceptions\ClassNotFoundException;
|
||||||
use LotGD\Core\Exceptions\ModuleAlreadyExistsException;
|
use LotGD\Core\Exceptions\ModuleAlreadyExistsException;
|
||||||
use LotGD\Core\LibraryConfiguration;
|
use LotGD\Core\LibraryConfiguration;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Danerys command to register and initiate any newly installed modules.
|
* Danerys command to register and initiate any newly installed modules.
|
||||||
@@ -29,21 +32,57 @@ class ModuleRegisterCommand extends BaseCommand
|
|||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
$modules = $this->game->getComposerManager()->getModulePackages();
|
$modules = $this->game->getComposerManager()->getModulePackages();
|
||||||
|
|
||||||
|
$registered = [];
|
||||||
foreach ($modules as $p) {
|
foreach ($modules as $p) {
|
||||||
$library = new LibraryConfiguration($this->game->getComposerManager(), $p, $this->game->getCWD());
|
$this->registerModule($p->getName(), $io, $registered);
|
||||||
$name = $library->getName();
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->game->getModuleManager()->register($library);
|
|
||||||
|
|
||||||
$output->writeln("<info>Registered new module {$name}</info>");
|
|
||||||
} catch (ModuleAlreadyExistsException $e) {
|
|
||||||
$output->writeln("Skipping already registered module {$name}");
|
|
||||||
} catch (ClassNotFoundException $e) {
|
|
||||||
$output->writeln("<error>Error installing module {$name}: " . $e->getMessage() . "</error>");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a given package as a module if it is of type lotdg-module. Resolves dependencies and skips already registered packages.
|
||||||
|
* @param string $packageName
|
||||||
|
* @param OutputInterface $output
|
||||||
|
* @param array $registered
|
||||||
|
* @throws \LotGD\Core\Exceptions\InvalidConfigurationException
|
||||||
|
* @throws \LotGD\Core\Exceptions\WrongTypeException
|
||||||
|
*/
|
||||||
|
protected function registerModule(
|
||||||
|
string $packageName,
|
||||||
|
SymfonyStyle $io,
|
||||||
|
array &$registered
|
||||||
|
) {
|
||||||
|
$composerRepository = $this->game->getComposerManager()->getComposer()
|
||||||
|
->getRepositoryManager()->getLocalRepository();
|
||||||
|
|
||||||
|
$package = $composerRepository->findPackage($packageName, "*");
|
||||||
|
if ($package->getType() !== "lotgd-module") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!empty($registered[$packageName])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->text("Reading module {$packageName} {$package->getPrettyVersion()}");
|
||||||
|
|
||||||
|
$library = new LibraryConfiguration($this->game->getComposerManager(), $package, $this->game->getCWD());
|
||||||
|
|
||||||
|
$dependencies = $package->getRequires();
|
||||||
|
foreach ($dependencies as $dependency) {
|
||||||
|
$this->registerModule($dependency->getTarget(), $io, $registered);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->game->getModuleManager()->register($library);
|
||||||
|
$io->success("\tRegistered new module {$packageName}");
|
||||||
|
} catch (ModuleAlreadyExistsException $e) {
|
||||||
|
$io->note("\tSkipping already registered module {$packageName}");
|
||||||
|
} catch (ClassNotFoundException $e) {
|
||||||
|
$io->error("\tError installing module {$packageName}: {$e->getMessage()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$registered[$packageName] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ use Symfony\Component\Console\Application;
|
|||||||
use LotGD\Core\Bootstrap;
|
use LotGD\Core\Bootstrap;
|
||||||
use LotGD\Core\Game;
|
use LotGD\Core\Game;
|
||||||
use LotGD\Core\Console\Command\{
|
use LotGD\Core\Console\Command\{
|
||||||
|
CharacterListCommand,
|
||||||
|
CharacterResetViewpointCommand,
|
||||||
DatabaseInitCommand,
|
DatabaseInitCommand,
|
||||||
|
DatabaseSchemaUpdateCommand,
|
||||||
ModuleValidateCommand,
|
ModuleValidateCommand,
|
||||||
ModuleRegisterCommand,
|
ModuleRegisterCommand,
|
||||||
ConsoleCommand
|
ConsoleCommand
|
||||||
@@ -42,7 +45,10 @@ class Main
|
|||||||
$this->application->add(new ModuleValidateCommand($this->game));
|
$this->application->add(new ModuleValidateCommand($this->game));
|
||||||
$this->application->add(new ModuleRegisterCommand($this->game));
|
$this->application->add(new ModuleRegisterCommand($this->game));
|
||||||
$this->application->add(new DatabaseInitCommand($this->game));
|
$this->application->add(new DatabaseInitCommand($this->game));
|
||||||
|
$this->application->add(new DatabaseSchemaUpdateCommand($this->game));
|
||||||
$this->application->add(new ConsoleCommand($this->game));
|
$this->application->add(new ConsoleCommand($this->game));
|
||||||
|
$this->application->add(new CharacterListCommand($this->game));
|
||||||
|
$this->application->add(new CharacterResetViewpointCommand($this->game));
|
||||||
|
|
||||||
// Add additional ones
|
// Add additional ones
|
||||||
$this->bootstrap->addDaenerysCommands($this->application);
|
$this->bootstrap->addDaenerysCommands($this->application);
|
||||||
|
|||||||
+25
-2
@@ -1,6 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
declare (strict_types = 1);
|
|
||||||
|
|
||||||
namespace LotGD\Core;
|
namespace LotGD\Core;
|
||||||
|
|
||||||
@@ -12,6 +11,7 @@ class DiceBag
|
|||||||
/**
|
/**
|
||||||
* Returns true $p percent of the time, where $p is between 0 and 1.
|
* Returns true $p percent of the time, where $p is between 0 and 1.
|
||||||
* @param float $p
|
* @param float $p
|
||||||
|
* @return bool True if you are lucky, False if not.
|
||||||
*/
|
*/
|
||||||
public function chance(float $p): bool
|
public function chance(float $p): bool
|
||||||
{
|
{
|
||||||
@@ -24,16 +24,39 @@ class DiceBag
|
|||||||
* Generates a uniformly randomly number between $min and $max.
|
* Generates a uniformly randomly number between $min and $max.
|
||||||
* @param float $min
|
* @param float $min
|
||||||
* @param float $max
|
* @param float $max
|
||||||
|
* @return float random number between $min and $max
|
||||||
*/
|
*/
|
||||||
public function uniform(float $min, float $max): float
|
public function uniform(float $min, float $max): float
|
||||||
{
|
{
|
||||||
return (mt_rand(0, 100) / 100.0) * ($max - $min) + $min;
|
return (mt_rand(0, 100) / 100.0) * ($max - $min) + $min;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a uniformly randomly integer between $min and $max.
|
||||||
|
* @param int $min
|
||||||
|
* @param int $max
|
||||||
|
* @return int random number between $min and $max
|
||||||
|
*/
|
||||||
|
public function dice(int $min, int $max): int
|
||||||
|
{
|
||||||
|
if ($min == $max) {
|
||||||
|
return $min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($min > $max) {
|
||||||
|
$a = $min;
|
||||||
|
$min = $max;
|
||||||
|
$max = $a;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mt_rand($min, $max);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a normally distributed random number between $min and $max.
|
* Generates a normally distributed random number between $min and $max.
|
||||||
* @param float $min
|
* @param float $min
|
||||||
* @param float $max
|
* @param float $max
|
||||||
|
* @return float normally distributed random number
|
||||||
*/
|
*/
|
||||||
public function normal(float $min, float $max): float
|
public function normal(float $min, float $max): float
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Doctrine\Annotations;
|
||||||
|
|
||||||
|
use Doctrine\Common\Annotations\Annotation;
|
||||||
|
use Doctrine\Common\Annotations\Annotation\Attributes;
|
||||||
|
use Doctrine\Common\Annotations\Annotation\Attribute;
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
use LotGD\Core\Models\ExtendableModelInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation that is used to flag which entity a class extends.
|
||||||
|
* @package LotGD\Core\Doctrine
|
||||||
|
* @Annotation
|
||||||
|
* @Target("CLASS")
|
||||||
|
* @Attributes({
|
||||||
|
* @Attribute("of", type = "string")
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
class Extension
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $modelClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension constructor.
|
||||||
|
* @param array $attributes
|
||||||
|
* @throws ArgumentException
|
||||||
|
*/
|
||||||
|
public function __construct(array $attributes) {
|
||||||
|
$this->modelClass = $attributes["of"];
|
||||||
|
|
||||||
|
if (!class_exists($this->modelClass)) {
|
||||||
|
throw new ArgumentException("The class given in of must be a valid class.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!in_array(ExtendableModelInterface::class, class_implements($this->modelClass))) {
|
||||||
|
throw new ArgumentException("The class given in of must implement the ExtendableModelInterface.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the model class name.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getModelClass(): string
|
||||||
|
{
|
||||||
|
return $this->modelClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Doctrine\Annotations;
|
||||||
|
|
||||||
|
use Doctrine\Common\Annotations\Annotation;
|
||||||
|
use Doctrine\Common\Annotations\Annotation\Attributes;
|
||||||
|
use Doctrine\Common\Annotations\Annotation\Attribute;
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation that is used to link a static method to a model entity.
|
||||||
|
* @package LotGD\Core\Doctrine\Annotations
|
||||||
|
* @Annotation
|
||||||
|
* @Target("METHOD")
|
||||||
|
* @Attributes({
|
||||||
|
* @Attribute("as", type = "string")
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
class ExtensionMethod
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
private $methodName = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ExtensionMethod constructor.
|
||||||
|
* @param array $attributes
|
||||||
|
* @throws ArgumentException
|
||||||
|
*/
|
||||||
|
public function __construct(array $attributes) {
|
||||||
|
$this->methodName = $attributes["as"];
|
||||||
|
|
||||||
|
if (!is_string($this->methodName)) {
|
||||||
|
throw new ArgumentException("Property 'as' must be a string.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($this->methodName) == 0) {
|
||||||
|
throw new ArgumentException("Property 'as' must not be an empty string.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the method name.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getMethodName(): string
|
||||||
|
{
|
||||||
|
return $this->methodName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Doctrine;
|
||||||
|
|
||||||
|
use Doctrine\Common\Util\Debug;
|
||||||
|
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||||
|
use LotGD\Core\Game;
|
||||||
|
use LotGD\Core\GameAwareInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EntityPostLoadEventListener
|
||||||
|
* @package LotGD\Core\Doctrine
|
||||||
|
*/
|
||||||
|
class EntityPostLoadEventListener
|
||||||
|
{
|
||||||
|
/** @var Game $game */
|
||||||
|
private $game;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EntityPostLoadEventListener constructor.
|
||||||
|
* @param Game $g
|
||||||
|
*/
|
||||||
|
public function __construct(Game $g)
|
||||||
|
{
|
||||||
|
$this->game = $g;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called upon event postLoad.
|
||||||
|
* @param LifecycleEventArgs $args
|
||||||
|
*/
|
||||||
|
public function postLoad(LifecycleEventArgs $args)
|
||||||
|
{
|
||||||
|
$entity = $args->getEntity();
|
||||||
|
if ($entity instanceof GameAwareInterface) {
|
||||||
|
$entity->setGame($this->game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace LotGD\Core;
|
namespace LotGD\Core;
|
||||||
|
use LotGD\Core\Events\EventContext;
|
||||||
|
|
||||||
interface EventHandler
|
interface EventHandler
|
||||||
{
|
{
|
||||||
@@ -8,11 +10,10 @@ interface EventHandler
|
|||||||
* Called when an event is published that is handled by this class.
|
* Called when an event is published that is handled by this class.
|
||||||
*
|
*
|
||||||
* @param Game $g The game.
|
* @param Game $g The game.
|
||||||
* @param string $event Name of this event.
|
* @param EventContext $context Arbitrary dictionary representing context around this event.
|
||||||
* @param array $context Arbitrary dictionary representing context around this event.
|
* @return EventContext Return an array if you want to make changes to the $context before
|
||||||
* @return array|null Return an array if you want to make changes to the $context before
|
|
||||||
* the next handler is called. Otherwise, return null. Any changes made will be propogated
|
* the next handler is called. Otherwise, return null. Any changes made will be propogated
|
||||||
* to the event publisher as well.
|
* to the event publisher as well.
|
||||||
*/
|
*/
|
||||||
public static function handleEvent(Game $g, string $event, array &$context);
|
public static function handleEvent(Game $g, EventContext $context): EventContext;
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-3
@@ -5,11 +5,13 @@ namespace LotGD\Core;
|
|||||||
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
use LotGD\Core\Events\EventContext;
|
||||||
use LotGD\Core\Models\EventSubscription;
|
use LotGD\Core\Models\EventSubscription;
|
||||||
use LotGD\Core\EventHandler;
|
use LotGD\Core\EventHandler;
|
||||||
use LotGD\Core\Exceptions\ClassNotFoundException;
|
use LotGD\Core\Exceptions\ClassNotFoundException;
|
||||||
use LotGD\Core\Exceptions\SubscriptionNotFoundException;
|
use LotGD\Core\Exceptions\SubscriptionNotFoundException;
|
||||||
use LotGD\Core\Exceptions\WrongTypeException;
|
use LotGD\Core\Exceptions\WrongTypeException;
|
||||||
|
use LotGD\Core\Events\EventContextData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages a simple publish/subscribe system based on regular expressions
|
* Manages a simple publish/subscribe system based on regular expressions
|
||||||
@@ -33,8 +35,10 @@ class EventManager
|
|||||||
* are run.
|
* are run.
|
||||||
*
|
*
|
||||||
* @param string $event The name of the event to publish.
|
* @param string $event The name of the event to publish.
|
||||||
|
* @param EventContextData $contextData The Data context
|
||||||
|
* @return EventContextData The changed data.
|
||||||
*/
|
*/
|
||||||
public function publish(string $event, array &$context)
|
public function publish(string $event, EventContextData $contextData): EventContextData
|
||||||
{
|
{
|
||||||
// For right now, implement the naive approach of iterating every entry
|
// For right now, implement the naive approach of iterating every entry
|
||||||
// in the subscription database, checking the regular expression. We
|
// in the subscription database, checking the regular expression. We
|
||||||
@@ -49,9 +53,17 @@ class EventManager
|
|||||||
if (preg_match($s->getPattern(), $event)) {
|
if (preg_match($s->getPattern(), $event)) {
|
||||||
$class = $s->getClass();
|
$class = $s->getClass();
|
||||||
$this->g->getLogger()->addDebug(" Handling with {$class}.");
|
$this->g->getLogger()->addDebug(" Handling with {$class}.");
|
||||||
$c = $class::handleEvent($this->g, $event, $context);
|
|
||||||
|
$eventContext = new EventContext($event, $s->getPattern(), $contextData);
|
||||||
|
|
||||||
|
$returnedEventContext = $class::handleEvent($this->g, $eventContext);
|
||||||
|
// Overwrite contextData - contextData might be the same if nothing has changed,
|
||||||
|
// or might reference a completely new object the event handler changed a value.
|
||||||
|
$contextData = $returnedEventContext->getData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $contextData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -99,7 +111,8 @@ class EventManager
|
|||||||
'class' => $class,
|
'class' => $class,
|
||||||
'library' => $library
|
'library' => $library
|
||||||
]);
|
]);
|
||||||
$e->save($this->g->getEntityManager());
|
|
||||||
|
$this->g->getEntityManager()->persist($e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace LotGD\Core\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
use LotGD\Core\Models\Character;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CharacterEventData
|
||||||
|
* @package LotGD\Core\Events
|
||||||
|
*/
|
||||||
|
class CharacterEventData extends EventContextData
|
||||||
|
{
|
||||||
|
protected static $argumentConfig = [
|
||||||
|
"character" => ["type" => Character::class, "required" => true],
|
||||||
|
"value" => ["type" => "mixed", "required" => false]
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Events;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class EventContext
|
||||||
|
* @package LotGD\Core
|
||||||
|
* @immutable
|
||||||
|
*/
|
||||||
|
class EventContext
|
||||||
|
{
|
||||||
|
private $matchingPattern;
|
||||||
|
private $event;
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventContext constructor.
|
||||||
|
* @param string $event The published event
|
||||||
|
* @param string $matchingPattern The matching pattern
|
||||||
|
* @param EventContextData $data
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
string $event,
|
||||||
|
string $matchingPattern,
|
||||||
|
EventContextData $data
|
||||||
|
) {
|
||||||
|
$this->event = $event;
|
||||||
|
$this->matchingPattern = $matchingPattern;
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the event of this context.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getEvent(): string
|
||||||
|
{
|
||||||
|
return $this->event;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the matching pattern of this context.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getMatchingPattern(): string
|
||||||
|
{
|
||||||
|
return $this->matchingPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the data in this event context has a certain subtype.
|
||||||
|
* @param string $type FQCN to be checked.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasDataType(string $type): bool
|
||||||
|
{
|
||||||
|
return $this->data instanceof $type ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the immutable data container.
|
||||||
|
* @return EventContextData
|
||||||
|
*/
|
||||||
|
public function getData(): EventContextData
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a data field
|
||||||
|
* @param $field
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getDataField($field)
|
||||||
|
{
|
||||||
|
return $this->data->get($field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a data field
|
||||||
|
* @param $field
|
||||||
|
* @param $value
|
||||||
|
*/
|
||||||
|
public function setDataField($field, $value)
|
||||||
|
{
|
||||||
|
$this->data = $this->data->set($field, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets multiple data fields at once.
|
||||||
|
* @param $data
|
||||||
|
*/
|
||||||
|
public function setDataFields($data)
|
||||||
|
{
|
||||||
|
$this->data = $this->data->setFields($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if given original data is the same as currently held within this context.
|
||||||
|
* @param EventContextData $originalData
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasDataChanged(EventContextData $originalData): bool
|
||||||
|
{
|
||||||
|
return $this->data === $originalData ? false : true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Events;
|
||||||
|
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EventContextData to provide a basic structure for managing contextual data of an event.
|
||||||
|
*
|
||||||
|
* This class must be immutable and returns always a new instance of itself for any change.
|
||||||
|
* @package LotGD\Core\Events
|
||||||
|
* @immutable
|
||||||
|
*/
|
||||||
|
class EventContextData
|
||||||
|
{
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of a data container.
|
||||||
|
*
|
||||||
|
* Sub types can change this method to force certain parameters.
|
||||||
|
* @param array $data
|
||||||
|
* @return EventContextData
|
||||||
|
*/
|
||||||
|
public static function create(array $data): self
|
||||||
|
{
|
||||||
|
if (isset(static::$argumentConfig)) {
|
||||||
|
static::checkConfiguration($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new static($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks a field configuration given in self::$argumentConfig.
|
||||||
|
* @param $data
|
||||||
|
* @throws ArgumentException
|
||||||
|
*/
|
||||||
|
public static function checkConfiguration($data)
|
||||||
|
{
|
||||||
|
$configuration = static::$argumentConfig;
|
||||||
|
$types = [
|
||||||
|
"mixed" => function ($x) {return true;},
|
||||||
|
"int" => function ($x) {return is_int($x);},
|
||||||
|
"float" => function ($x) {return is_float($x);},
|
||||||
|
"numeric" => function($x) {return is_numeric($x);},
|
||||||
|
"string" => function($x) {return is_string($x);},
|
||||||
|
];
|
||||||
|
|
||||||
|
$keys = array_keys($data);
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
if (!isset($configuration[$key])) {
|
||||||
|
throw new ArgumentException(sprintf("%s does not accept a field called %s", static::class, $key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($configuration as $key => $config) {
|
||||||
|
if ($config["required"] === true and !isset($data[$key])) {
|
||||||
|
throw new ArgumentException(sprintf("%s must have a field called %s.", static::class, $key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($types[$config["type"]])) {
|
||||||
|
if ($types[$config["type"]]($data[$key]) === false) {
|
||||||
|
throw new ArgumentException(sprintf("The field %s of %s must be of type %s.", $key, static::class, $config["type"]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!$data[$key] instanceof $config["type"]) {
|
||||||
|
throw new ArgumentException(sprintf("The field %s of %s must be of type %s", $key, static::class, $config["type"]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* protected constructor..
|
||||||
|
* @see self::create
|
||||||
|
* @param array $data
|
||||||
|
*/
|
||||||
|
protected function __construct(array $data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if container has a certain field.
|
||||||
|
* @param string $field
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function has(string $field): bool
|
||||||
|
{
|
||||||
|
return array_key_exists($field, $this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of a field.
|
||||||
|
* @param string $field
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function get(string $field)
|
||||||
|
{
|
||||||
|
if ($this->has($field)) {
|
||||||
|
return $this->data[$field];
|
||||||
|
} else {
|
||||||
|
$this->throwException($field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a field to a new value and returns a new data container
|
||||||
|
* @param string $field
|
||||||
|
* @param $value
|
||||||
|
* @return EventContextData
|
||||||
|
*/
|
||||||
|
public function set(string $field, $value): self
|
||||||
|
{
|
||||||
|
if ($this->has($field)) {
|
||||||
|
$data = $this->data;
|
||||||
|
$data[$field] = $value;
|
||||||
|
|
||||||
|
return new static($data);
|
||||||
|
} else {
|
||||||
|
$this->throwException($field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets multiple fields at once
|
||||||
|
* @param array $data array of $field=>$value pairs
|
||||||
|
* @return EventContextData
|
||||||
|
*/
|
||||||
|
public function setFields(array $data): self
|
||||||
|
{
|
||||||
|
$data = $this->data;
|
||||||
|
|
||||||
|
foreach ($data as $field => $value) {
|
||||||
|
if ($this->has($field)) {
|
||||||
|
$data[$field] = $value;
|
||||||
|
} else {
|
||||||
|
$this->throwException($field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new static($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of fields in this context
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function getListOfFields(): array
|
||||||
|
{
|
||||||
|
return array_keys($this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a comma separated string with all allowed fields, for debugging reasons.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getFormattedListOfFields(): string
|
||||||
|
{
|
||||||
|
return substr(
|
||||||
|
implode(", ", $this->getListOfFields()),
|
||||||
|
0,
|
||||||
|
-2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* internal use only - throws an ArgumentException a field is given that's not valid.
|
||||||
|
* @param $field
|
||||||
|
* @throws ArgumentException
|
||||||
|
*/
|
||||||
|
private function throwException($field)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
"{$field} is not valid in this context, only {$this->getFormattedListOfFields()} are allowed."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use Doctrine\Common\Util\Debug;
|
||||||
|
use Doctrine\DBAL\Schema\View;
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
use LotGD\Core\Models\Character;
|
||||||
|
use LotGD\Core\Models\Scene;
|
||||||
|
use LotGD\Core\Models\Viewpoint;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NavigateToScene data container which can be used for navigational events.
|
||||||
|
*
|
||||||
|
* Fields are:
|
||||||
|
* referrer Scene|null
|
||||||
|
* viewpoint Viewpoint
|
||||||
|
* scene Scene
|
||||||
|
* parameters array
|
||||||
|
* redirect Scene|null
|
||||||
|
* @package LotGD\Core\Events
|
||||||
|
*/
|
||||||
|
class NavigateToSceneData extends EventContextData
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* NavigateToScene constructor.
|
||||||
|
* @param array $data Must contain fields referrer, viewpoint, scene, parameters and redirect; none more.
|
||||||
|
* @throws ArgumentException
|
||||||
|
*/
|
||||||
|
protected function __construct(array $data)
|
||||||
|
{
|
||||||
|
$mustHaveForm = ["referrer", "viewpoint", "scene", "parameters", "redirect"];
|
||||||
|
$doesHaveForm = array_keys($data);
|
||||||
|
sort($mustHaveForm); sort($doesHaveForm);
|
||||||
|
|
||||||
|
if ($doesHaveForm !== $mustHaveForm) {
|
||||||
|
throw new ArgumentException("A new NavigateToScene event must have referrer, viewpoint, scene, parameters and redirect.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data["referrer"] instanceof Scene === false and $data["referrer"] !== null) {
|
||||||
|
throw new ArgumentException(sprintf(
|
||||||
|
"data[referrer] must be an instance of %s, %s given.",
|
||||||
|
Scene::class,
|
||||||
|
get_class($data["referrer"])
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data["scene"] instanceof Scene === false) {
|
||||||
|
throw new ArgumentException(sprintf(
|
||||||
|
"data[scene] must be an instance of %s, %s given.",
|
||||||
|
Scene::class,
|
||||||
|
get_class($data["scene"])
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data["viewpoint"] instanceof Viewpoint === false) {
|
||||||
|
throw new ArgumentException(sprintf(
|
||||||
|
"data[viewpoint] must be an instance of %s, %s given.",
|
||||||
|
Viewpoint::class,
|
||||||
|
get_class($data["viewpoint"])
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Events;
|
||||||
|
|
||||||
|
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
use LotGD\Core\Models\Character;
|
||||||
|
use LotGD\Core\Models\Scene;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NewViewpoint data container which is used if no scene has ever been visited.
|
||||||
|
*
|
||||||
|
* Fields are:
|
||||||
|
* character Character
|
||||||
|
* scene Scene|null
|
||||||
|
* @package LotGD\Core\Events
|
||||||
|
*/
|
||||||
|
class NewViewpointData extends EventContextData
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* NewViewpoint constructor.
|
||||||
|
* @param array $data
|
||||||
|
* @throws ArgumentException In case $data contains invalid data.
|
||||||
|
*/
|
||||||
|
protected function __construct(array $data)
|
||||||
|
{
|
||||||
|
if (array_keys($data) !== ["character", "scene"]) {
|
||||||
|
throw new ArgumentException("A NewViewpoint event must have only character and scene.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$data["character"] instanceof Character) {
|
||||||
|
throw new ArgumentException(sprintf(
|
||||||
|
"NewViewpoint data[character] must be an instance of %s, %s given.",
|
||||||
|
Character::class,
|
||||||
|
get_class($data)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data["scene"] !== null and !$data["scene"] instanceof Scene) {
|
||||||
|
throw new ArgumentException(sprintf(
|
||||||
|
"NewViewpoint data[scene] must be an instance of %s or null, %s given.",
|
||||||
|
Scene::class,
|
||||||
|
get_class($data)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Events;
|
||||||
|
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
use LotGD\Core\Models\Viewpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class ViewpointDecorationEventData
|
||||||
|
* @package LotGD\Core\Events
|
||||||
|
*/
|
||||||
|
class ViewpointDecorationEventData extends EventContextData
|
||||||
|
{
|
||||||
|
protected static $argumentConfig = [
|
||||||
|
"viewpoint" => ["type" => Viewpoint::class, "required" => true]
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception if a builder is missing an argument
|
||||||
|
*/
|
||||||
|
class BuilderException extends CoreException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception if an existing entity is tried to create again.
|
||||||
|
*/
|
||||||
|
class EntityAlreadyExistsException extends EntityException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception if a non-existing entity is requested.
|
||||||
|
*/
|
||||||
|
class EntityDoesNotExistException extends EntityException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A basic entity exception
|
||||||
|
*/
|
||||||
|
class EntityException extends CoreException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception if an existing entity is tried to create again.
|
||||||
|
*/
|
||||||
|
class PermissionAlreadyExistsException extends EntityAlreadyExistsException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception if an existing entity is tried to create again.
|
||||||
|
*/
|
||||||
|
class PermissionDoesNotExistException extends EntityDoesNotExistException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception if a requested permission id has not been found.
|
||||||
|
*/
|
||||||
|
class PermissionIdNotFoundException extends EntityDoesNotExistException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
+142
-46
@@ -3,19 +3,18 @@ declare (strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core;
|
namespace LotGD\Core;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use Doctrine\Common\Util\Debug;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use LotGD\Core\Events\NavigateToSceneData;
|
||||||
|
use LotGD\Core\Events\NewViewpointData;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
|
|
||||||
use LotGD\Core\Models\ {
|
use LotGD\Core\Models\{
|
||||||
Character,
|
Character, SceneConnectable, Viewpoint, Scene, SceneConnection
|
||||||
Viewpoint,
|
|
||||||
Scene
|
|
||||||
};
|
};
|
||||||
use LotGD\Core\Exceptions\ {
|
use LotGD\Core\Exceptions\ {
|
||||||
ActionNotFoundException,
|
ActionNotFoundException, CharacterNotFoundException, InvalidConfigurationException, SceneNotFoundException
|
||||||
CharacterNotFoundException,
|
|
||||||
InvalidConfigurationException,
|
|
||||||
SceneNotFoundException
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,6 +26,7 @@ class Game
|
|||||||
private $eventManager;
|
private $eventManager;
|
||||||
private $composerManager;
|
private $composerManager;
|
||||||
private $moduleManager;
|
private $moduleManager;
|
||||||
|
private $messageManager;
|
||||||
private $logger;
|
private $logger;
|
||||||
private $configuration;
|
private $configuration;
|
||||||
private $character;
|
private $character;
|
||||||
@@ -34,8 +34,13 @@ class Game
|
|||||||
private $cwd;
|
private $cwd;
|
||||||
private $timeKeeper;
|
private $timeKeeper;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a game. You probably want to use Bootstrap to do this.
|
* Construct a game. You probably want to use Bootstrap to do this.
|
||||||
|
* @param Configuration $configuration
|
||||||
|
* @param Logger $logger
|
||||||
|
* @param EntityManagerInterface $entityManager
|
||||||
|
* @param string $cwd
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Configuration $configuration,
|
Configuration $configuration,
|
||||||
@@ -55,7 +60,7 @@ class Game
|
|||||||
*/
|
*/
|
||||||
public static function getVersion(): string
|
public static function getVersion(): string
|
||||||
{
|
{
|
||||||
return '0.1.0';
|
return '0.5.0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,24 +88,36 @@ class Game
|
|||||||
*/
|
*/
|
||||||
public function getModuleManager(): ModuleManager
|
public function getModuleManager(): ModuleManager
|
||||||
{
|
{
|
||||||
if ($this->moduleManager === null) {
|
|
||||||
$this->moduleManager = new ModuleManager($this);
|
|
||||||
}
|
|
||||||
return $this->moduleManager;
|
return $this->moduleManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the game's module manager.
|
||||||
|
* @param ModuleManager $moduleManager
|
||||||
|
*/
|
||||||
|
public function setModuleManager(ModuleManager $moduleManager): void
|
||||||
|
{
|
||||||
|
$this->moduleManager = $moduleManager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the game's composer manager.
|
* Returns the game's composer manager.
|
||||||
* @return ComposerManager The game's composer manager.
|
* @return ComposerManager The game's composer manager.
|
||||||
*/
|
*/
|
||||||
public function getComposerManager(): ComposerManager
|
public function getComposerManager(): ComposerManager
|
||||||
{
|
{
|
||||||
if ($this->composerManager === null) {
|
|
||||||
$this->composerManager = new ComposerManager($this->cwd);
|
|
||||||
}
|
|
||||||
return $this->composerManager;
|
return $this->composerManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the game's composer manager.
|
||||||
|
* @param ComposerManager $composerManager
|
||||||
|
*/
|
||||||
|
public function setComposerManager(ComposerManager $composerManager): void
|
||||||
|
{
|
||||||
|
$this->composerManager = $composerManager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the game's entity manager.
|
* Returns the game's entity manager.
|
||||||
* @return EntityManagerInterface The game's database entity manager.
|
* @return EntityManagerInterface The game's database entity manager.
|
||||||
@@ -116,29 +133,41 @@ class Game
|
|||||||
*/
|
*/
|
||||||
public function getEventManager(): EventManager
|
public function getEventManager(): EventManager
|
||||||
{
|
{
|
||||||
if ($this->eventManager === null) {
|
|
||||||
$this->eventManager = new EventManager($this);
|
|
||||||
}
|
|
||||||
return $this->eventManager;
|
return $this->eventManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the game's event manager.
|
||||||
|
* @param EventManager $eventManager
|
||||||
|
*/
|
||||||
|
public function setEventManager(EventManager $eventManager): void
|
||||||
|
{
|
||||||
|
$this->eventManager = $eventManager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the game's dice bag.
|
* Returns the game's dice bag.
|
||||||
* @return DiceBag
|
* @return DiceBag
|
||||||
*/
|
*/
|
||||||
public function getDiceBag(): DiceBag
|
public function getDiceBag(): DiceBag
|
||||||
{
|
{
|
||||||
if ($this->diceBag === null) {
|
|
||||||
$this->diceBag = new DiceBag();
|
|
||||||
}
|
|
||||||
return $this->diceBag;
|
return $this->diceBag;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the logger instance to write logs.
|
* Sets the game's dice bag.
|
||||||
* @return \Monolog\Logger
|
* @param DiceBag $diceBag
|
||||||
*/
|
*/
|
||||||
public function getLogger(): \Monolog\Logger
|
public function setDiceBag(DiceBag $diceBag): void
|
||||||
|
{
|
||||||
|
$this->diceBag = $diceBag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the logger instance to write logs.
|
||||||
|
* @return Logger
|
||||||
|
*/
|
||||||
|
public function getLogger(): Logger
|
||||||
{
|
{
|
||||||
return $this->logger;
|
return $this->logger;
|
||||||
}
|
}
|
||||||
@@ -153,14 +182,33 @@ class Game
|
|||||||
$gameEpoch = $this->getConfiguration()->getGameEpoch();
|
$gameEpoch = $this->getConfiguration()->getGameEpoch();
|
||||||
$gameOffsetSeconds = $this->getConfiguration()->getGameOffsetSeconds();
|
$gameOffsetSeconds = $this->getConfiguration()->getGameOffsetSeconds();
|
||||||
$gameDaysPerDay = $this->getConfiguration()->getGameDaysPerDay();
|
$gameDaysPerDay = $this->getConfiguration()->getGameDaysPerDay();
|
||||||
$this->timeKeeper = new TimeKeeper($gameEpoch, $gameOffsetSeconds, $gameDaysPerDay);
|
$this->timeKeeper = new TimeKeeper($gameEpoch, new DateTime(), $gameOffsetSeconds, $gameDaysPerDay);
|
||||||
}
|
}
|
||||||
return $this->timeKeeper;
|
return $this->timeKeeper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Message manager
|
||||||
|
* @return MessageManager
|
||||||
|
*/
|
||||||
|
public function getMessageManager(): MessageManager
|
||||||
|
{
|
||||||
|
return $this->messageManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Message Manager
|
||||||
|
* @param MessageManager $messageManager
|
||||||
|
*/
|
||||||
|
public function setMessageManager(MessageManager $messageManager): void
|
||||||
|
{
|
||||||
|
$this->messageManager = $messageManager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the currently configured user character.
|
* Returns the currently configured user character.
|
||||||
* @return Character
|
* @return Character
|
||||||
|
* @throws CharacterNotFoundException
|
||||||
*/
|
*/
|
||||||
public function getCharacter(): Character
|
public function getCharacter(): Character
|
||||||
{
|
{
|
||||||
@@ -182,6 +230,7 @@ class Game
|
|||||||
/**
|
/**
|
||||||
* Return the viewpoint for the current user.
|
* Return the viewpoint for the current user.
|
||||||
* @return Viewpoint
|
* @return Viewpoint
|
||||||
|
* @throws InvalidConfigurationException
|
||||||
*/
|
*/
|
||||||
public function getViewpoint(): Viewpoint
|
public function getViewpoint(): Viewpoint
|
||||||
{
|
{
|
||||||
@@ -190,13 +239,14 @@ class Game
|
|||||||
if ($v === null) {
|
if ($v === null) {
|
||||||
// No viewpoint set up for this user. Run the hook to find the default
|
// No viewpoint set up for this user. Run the hook to find the default
|
||||||
// scene.
|
// scene.
|
||||||
$context = [
|
$contextData = NewViewpointData::create([
|
||||||
'character' => $this->getCharacter(),
|
'character' => $this->getCharacter(),
|
||||||
'scene' => null
|
'scene' => null
|
||||||
];
|
]);
|
||||||
$this->getEventManager()->publish('h/lotgd/core/default-scene', $context);
|
|
||||||
|
|
||||||
$s = $context['scene'];
|
$contextData = $this->getEventManager()->publish('h/lotgd/core/default-scene', $contextData);
|
||||||
|
|
||||||
|
$s = $contextData->get("scene");
|
||||||
if ($s === null) {
|
if ($s === null) {
|
||||||
throw new InvalidConfigurationException("No subscriber to h/lotgd/core/default-scene returned a scene.");
|
throw new InvalidConfigurationException("No subscriber to h/lotgd/core/default-scene returned a scene.");
|
||||||
}
|
}
|
||||||
@@ -236,34 +286,72 @@ class Game
|
|||||||
// Generate the default set of actions: the default group with
|
// Generate the default set of actions: the default group with
|
||||||
// all children.
|
// all children.
|
||||||
$this->getLogger()->addDebug("Building default action group...");
|
$this->getLogger()->addDebug("Building default action group...");
|
||||||
$defaultGroup = new ActionGroup(ActionGroup::DefaultGroup, '', 0);
|
$actionGroups = [
|
||||||
$as = array_map(function ($c) {
|
ActionGroup::DefaultGroup => new ActionGroup(ActionGroup::DefaultGroup, '', 0),
|
||||||
$id = $c->getId();
|
];
|
||||||
$this->getLogger()->addDebug(" Adding navigation action for child sceneId={$id}");
|
|
||||||
return new Action($c->getId());
|
|
||||||
}, $scene->getChildren()->toArray());
|
|
||||||
$defaultGroup->setActions($as);
|
|
||||||
$count = count($as);
|
|
||||||
$this->getLogger()->addDebug("Total actions: {$count}");
|
|
||||||
|
|
||||||
$hiddenGroup = new ActionGroup(ActionGroup::HiddenGroup, '', 100);
|
// Iterates through all connections and adds an action to the connected scene to the action group. If the connection
|
||||||
|
// belongs to a new connection Group, it creates a new ActionGroup.
|
||||||
|
$scene->getConnections()->map(function(SceneConnection $connection) use ($scene, &$actionGroups) {
|
||||||
|
if ($connection->getOutgoingScene() === $scene) {
|
||||||
|
// current scene is outgoing, use incoming.
|
||||||
|
$connectedScene = $connection->getIncomingScene();
|
||||||
|
$connectionGroupName = $connection->getOutgoingConnectionGroupName();
|
||||||
|
} else {
|
||||||
|
// current scene is not outgoing, thus incoming, use outgoing.
|
||||||
|
$connectedScene = $connection->getOutgoingScene();
|
||||||
|
$connectionGroupName = $connection->getIncomingConnectionGroupName();
|
||||||
|
|
||||||
$viewpoint->setActionGroups([$defaultGroup, $hiddenGroup]);
|
// Check if the connection is unidirectional - if yes, the current scene (incoming in this branch) cannot
|
||||||
|
// connect to the outgoing scene.
|
||||||
|
if ($connection->isDirectionality(SceneConnectable::Unidirectional)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getLogger()->addDebug(" Adding navigation action for child sceneId={$connectedScene->getId()}");
|
||||||
|
$action = new Action($connectedScene->getId(), $connectedScene->getTitle());
|
||||||
|
|
||||||
|
if ($connectionGroupName === null) {
|
||||||
|
$actionGroups[ActionGroup::DefaultGroup]->addAction($action);
|
||||||
|
} else {
|
||||||
|
if (isset($actionGroups[$connectionGroupName])) {
|
||||||
|
$actionGroups[$connectionGroupName]->addAction($action);
|
||||||
|
} else {
|
||||||
|
$connectionGroup = $scene->getConnectionGroup($connectionGroupName);
|
||||||
|
$actionGroup = new ActionGroup($connectionGroupName, $connectionGroup->getTitle(), 0);
|
||||||
|
$actionGroup->addAction($action);
|
||||||
|
|
||||||
|
$actionGroups[$connectionGroupName] = $actionGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
$counts = implode(", ", array_map(function($k, $v) {
|
||||||
|
return $k .count($v);
|
||||||
|
}, array_keys($actionGroups), array_values($actionGroups)));
|
||||||
|
$this->getLogger()->addDebug("Total actions: {$counts}");
|
||||||
|
|
||||||
|
$actionGroups[ActionGroup::HiddenGroup] = new ActionGroup(ActionGroup::HiddenGroup, '', 100);
|
||||||
|
|
||||||
|
$viewpoint->setActionGroups(array_values($actionGroups));
|
||||||
|
|
||||||
// Let and installed listeners (ie modules) make modifications to the
|
// Let and installed listeners (ie modules) make modifications to the
|
||||||
// new viewpoint, including the ability to redirect the user to
|
// new viewpoint, including the ability to redirect the user to
|
||||||
// a different scene, by setting $context['redirect'] to a new scene.
|
// a different scene, by setting $context['redirect'] to a new scene.
|
||||||
$context = [
|
$contextData = NavigateToSceneData::create([
|
||||||
'referrer' => $referrer,
|
'referrer' => $referrer,
|
||||||
'viewpoint' => $viewpoint,
|
'viewpoint' => $viewpoint,
|
||||||
'scene' => $scene,
|
'scene' => $scene,
|
||||||
'parameters' => $parameters,
|
'parameters' => $parameters,
|
||||||
'redirect' => null
|
'redirect' => null
|
||||||
];
|
]);
|
||||||
$hook = 'h/lotgd/core/navigate-to/' . $scene->getTemplate();
|
|
||||||
$this->getEventManager()->publish($hook, $context);
|
|
||||||
|
|
||||||
$scene = $context['redirect'];
|
$hook = 'h/lotgd/core/navigate-to/' . $scene->getTemplate();
|
||||||
|
$contextData = $this->getEventManager()->publish($hook, $contextData);
|
||||||
|
|
||||||
|
$scene = $contextData->get('redirect');
|
||||||
if ($scene !== null) {
|
if ($scene !== null) {
|
||||||
$id = $scene->getId();
|
$id = $scene->getId();
|
||||||
$this->getLogger()->debug("Redirecting to sceneId={$id}");
|
$this->getLogger()->debug("Redirecting to sceneId={$id}");
|
||||||
@@ -275,7 +363,9 @@ class Game
|
|||||||
* Take the specified navigation action for the currently configured
|
* Take the specified navigation action for the currently configured
|
||||||
* user. This action must be present in the current user's viewpoint.
|
* user. This action must be present in the current user's viewpoint.
|
||||||
* @param string $actionId The identifier of the action to take.
|
* @param string $actionId The identifier of the action to take.
|
||||||
* @param array $paramters
|
* @param array $parameters
|
||||||
|
* @throws ActionNotFoundException
|
||||||
|
* @throws SceneNotFoundException
|
||||||
*/
|
*/
|
||||||
public function takeAction(string $actionId, array $parameters = [])
|
public function takeAction(string $actionId, array $parameters = [])
|
||||||
{
|
{
|
||||||
@@ -288,6 +378,7 @@ class Game
|
|||||||
if ($action === null) {
|
if ($action === null) {
|
||||||
throw new ActionNotFoundException("Invalid actionId={$actionId} for current viewpoint.");
|
throw new ActionNotFoundException("Invalid actionId={$actionId} for current viewpoint.");
|
||||||
}
|
}
|
||||||
|
$actionParameters = $action->getParameters();
|
||||||
|
|
||||||
$sceneId = $action->getDestinationSceneId();
|
$sceneId = $action->getDestinationSceneId();
|
||||||
$scene = $this->getEntityManager()->getRepository(Scene::class)->find([
|
$scene = $this->getEntityManager()->getRepository(Scene::class)->find([
|
||||||
@@ -296,7 +387,12 @@ class Game
|
|||||||
if ($scene == null) {
|
if ($scene == null) {
|
||||||
throw new SceneNotFoundException("Cannot find sceneId={$sceneId} specified by actionId={$actionId}.");
|
throw new SceneNotFoundException("Cannot find sceneId={$sceneId} specified by actionId={$actionId}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// action parameters overwrite other parameters since the former cannot be changed by the user
|
||||||
|
$parameters = array_merge($parameters, $actionParameters);
|
||||||
|
|
||||||
$this->navigateToScene($scene, $parameters);
|
$this->navigateToScene($scene, $parameters);
|
||||||
|
|
||||||
$v->save($this->getEntityManager());
|
$v->save($this->getEntityManager());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for classes that are aware of the game
|
||||||
|
* @package LotGD\Core
|
||||||
|
*/
|
||||||
|
interface GameAwareInterface
|
||||||
|
{
|
||||||
|
public function setGame(Game $g);
|
||||||
|
public function getGame(): Game;
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core;
|
||||||
|
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Monolog\Logger;
|
||||||
|
|
||||||
|
use LotGD\Core\Exceptions\BuilderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GameBuilder class is used to build a Game object with all dependencies that are needed.
|
||||||
|
*
|
||||||
|
* You must provide $cwd, $configuration, $entityManager and a logger instance using the with* methods.
|
||||||
|
* You can provide additional class *names* for additional dependency injections using the use* methods.
|
||||||
|
* @package LotGD\Core
|
||||||
|
*/
|
||||||
|
class GameBuilder
|
||||||
|
{
|
||||||
|
private $cwd;
|
||||||
|
private $configuration;
|
||||||
|
private $entityManager;
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
private $moduleManagerClass;
|
||||||
|
private $composerManagerClass;
|
||||||
|
private $eventManagerClass;
|
||||||
|
private $diceBagClass;
|
||||||
|
private $messageManagerClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the game instance with the prepared parameters.
|
||||||
|
* @return Game
|
||||||
|
* @throws BuilderException if at least one of cwd, configuration, entityManager or logger as not been set.
|
||||||
|
*/
|
||||||
|
public function create(): Game
|
||||||
|
{
|
||||||
|
if (isset($this->cwd, $this->configuration, $this->entityManager, $this->logger) === false) {
|
||||||
|
throw new BuilderException(
|
||||||
|
"For creating a game, you must set at least: cwd, configuration, entityManager and logger."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct the game
|
||||||
|
$game = new Game(
|
||||||
|
$this->configuration,
|
||||||
|
$this->logger,
|
||||||
|
$this->entityManager,
|
||||||
|
$this->cwd
|
||||||
|
);
|
||||||
|
|
||||||
|
// add additional managers to it
|
||||||
|
$moduleManager = $this->moduleManagerClass ?? ModuleManager::class;
|
||||||
|
$game->setModuleManager(new $moduleManager($game));
|
||||||
|
|
||||||
|
$composerManager = $this->composerManagerClass ?? ComposerManager::class;
|
||||||
|
$game->setComposerManager(new $composerManager($this->cwd));
|
||||||
|
|
||||||
|
$eventManager = $this->eventManagerClass ?? EventManager::class;
|
||||||
|
$game->setEventManager(new $eventManager($game));
|
||||||
|
|
||||||
|
$diceBag = $this->diceBagClass ?? DiceBag::class;
|
||||||
|
$game->setDiceBag(new $diceBag());
|
||||||
|
|
||||||
|
$messageManager=$this->messageManagerClass ?? MessageManager::class;
|
||||||
|
$game->setMessageManager(new $messageManager());
|
||||||
|
return $game;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds current working directory argument
|
||||||
|
* @param string $cwd
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withCwd(string $cwd): self
|
||||||
|
{
|
||||||
|
$this->cwd = $cwd;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration
|
||||||
|
* @param Configuration $conf
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withConfiguration(Configuration $conf): self
|
||||||
|
{
|
||||||
|
$this->configuration = $conf;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the logger for the game instance.
|
||||||
|
* @param EntityManagerInterface $em
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withEntityManager(EntityManagerInterface $em): self
|
||||||
|
{
|
||||||
|
$this->entityManager = $em;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the logger for the game instance.
|
||||||
|
* @param Logger $logger
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withLogger(Logger $logger): self
|
||||||
|
{
|
||||||
|
$this->logger = $logger;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the fqcn for the message manager to be used
|
||||||
|
* @param string $messageManagerFqcn
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function withMessageManager(string $messageManagerFqcn): self
|
||||||
|
{
|
||||||
|
$this->messageManagerClass=$messageManagerFqcn;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the fqcn for the module manager to be used.
|
||||||
|
* @param string $moduleManagerFqcn
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function useModuleManager(string $moduleManagerFqcn): self
|
||||||
|
{
|
||||||
|
$this->moduleManagerClass = $moduleManagerFqcn;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the fqcn for the composer manager to be used.
|
||||||
|
* @param string $composerManagerFqcn
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function useComposerManager(string $composerManagerFqcn): self
|
||||||
|
{
|
||||||
|
$this->composerManagerClass = $composerManagerFqcn;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the fqcn for the event manager to be used.
|
||||||
|
* @param string $eventManagerFqcn
|
||||||
|
* @return GameBuilder
|
||||||
|
*/
|
||||||
|
public function useEventManager(string $eventManagerFqcn): self
|
||||||
|
{
|
||||||
|
$this->eventManagerClass = $eventManagerFqcn;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the fqcn for the dice bag to be used.
|
||||||
|
* @param string $diceBagFqcn
|
||||||
|
* @return GameBuilder
|
||||||
|
*/
|
||||||
|
public function useDiceBag(string $diceBagFqcn): self
|
||||||
|
{
|
||||||
|
$this->diceBagClass = $diceBagFqcn;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ class LibraryConfiguration
|
|||||||
if ($basePackage && $basePackage->getName() === $package->getName()) {
|
if ($basePackage && $basePackage->getName() === $package->getName()) {
|
||||||
// Whatever the base package is in this repo is at $cwd.
|
// Whatever the base package is in this repo is at $cwd.
|
||||||
$path = $cwd;
|
$path = $cwd;
|
||||||
} else if ($package->getType() === "lotgd-module") {
|
} elseif (in_array($package->getType(), ["lotgd-module", "lotgd-crate"])) {
|
||||||
// lotgd-modules are installed in the vendor directory.
|
// lotgd-modules are installed in the vendor directory.
|
||||||
$installationManager = $composerManager->getComposer()->getInstallationManager();
|
$installationManager = $composerManager->getComposer()->getInstallationManager();
|
||||||
$path = $installationManager->getInstallPath($package);
|
$path = $installationManager->getInstallPath($package);
|
||||||
@@ -124,9 +124,9 @@ class LibraryConfiguration
|
|||||||
/**
|
/**
|
||||||
* Returns a subkey if it exists or null.
|
* Returns a subkey if it exists or null.
|
||||||
* @param array $arguments
|
* @param array $arguments
|
||||||
* @return type
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
protected function getSubKeyIfItExists(array $arguments)
|
public function getSubKeyIfItExists(array $arguments)
|
||||||
{
|
{
|
||||||
$parent = $this->rawConfig;
|
$parent = $this->rawConfig;
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ class LibraryConfiguration
|
|||||||
* Tries to iterate an array element given by the arguments
|
* Tries to iterate an array element given by the arguments
|
||||||
* @param scalar $argument1,... array keys, by increasing depth
|
* @param scalar $argument1,... array keys, by increasing depth
|
||||||
*/
|
*/
|
||||||
protected function iterateKey(...$arguments)
|
public function iterateKey(...$arguments)
|
||||||
{
|
{
|
||||||
$result = $this->getSubKeyIfItExists($arguments);
|
$result = $this->getSubKeyIfItExists($arguments);
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class LibraryConfigurationManager
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an array of the library configurations.
|
* Return an array of the library configurations.
|
||||||
* @return array<LibraryConfiguration>
|
* @return LibraryConfiguration[]
|
||||||
*/
|
*/
|
||||||
public function getConfigurations(): array {
|
public function getConfigurations(): array {
|
||||||
return $this->configurations;
|
return $this->configurations;
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core;
|
||||||
|
|
||||||
|
use LotGD\Core\Models\Character;
|
||||||
|
use LotGD\Core\Models\Message;
|
||||||
|
use LotGD\Core\Models\MessageThread;
|
||||||
|
use LotGD\Core\Models\SystemCharacter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the message system overall
|
||||||
|
* Class MessageManager
|
||||||
|
* @package LotGD\Core
|
||||||
|
*/
|
||||||
|
class MessageManager
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sends a message to a MessageThread
|
||||||
|
* @param \LotGD\Core\Models\Character $from
|
||||||
|
* @param string $message
|
||||||
|
* @param \LotGD\Core\Models\MessageThread $thread
|
||||||
|
* @param bool $systemMessage
|
||||||
|
* @return \LotGD\Core\Models\Message
|
||||||
|
* @throws Exceptions\CoreException
|
||||||
|
*/
|
||||||
|
public function send(
|
||||||
|
Character $from,
|
||||||
|
string $message,
|
||||||
|
MessageThread $thread,
|
||||||
|
bool $systemMessage = false
|
||||||
|
) {
|
||||||
|
$message = new Message($from, $message, $thread, $systemMessage);
|
||||||
|
$thread->addMessage($message);
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a system message to a MessageThread
|
||||||
|
* @param string $message
|
||||||
|
* @param \LotGD\Core\Models\MessageThread $thread
|
||||||
|
* @return \LotGD\Core\Models\Message
|
||||||
|
* @throws Exceptions\ArgumentException
|
||||||
|
* @throws Exceptions\CoreException
|
||||||
|
*/
|
||||||
|
public function sendSystemMessage(
|
||||||
|
string $message,
|
||||||
|
MessageThread $thread
|
||||||
|
) {
|
||||||
|
$message = new Message(SystemCharacter::getInstance(), $message, $thread, true);
|
||||||
|
$thread->addMessage($message);
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core;
|
||||||
|
|
||||||
|
|
||||||
|
use LotGD\Core\Doctrine\Annotations\ExtensionMethod;
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
use ReflectionClass;
|
||||||
|
use Doctrine\Common\Annotations\AnnotationReader;
|
||||||
|
use LotGD\Core\Doctrine\Annotations\Extension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains method to help the extension of a model.
|
||||||
|
* @package LotGD\Core
|
||||||
|
*/
|
||||||
|
class ModelExtender
|
||||||
|
{
|
||||||
|
/** @var AnnotationReader */
|
||||||
|
private $reader;
|
||||||
|
/** @var array */
|
||||||
|
private static $classes = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModelExtender constructor.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->reader = new AnnotationReader();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[] $classes
|
||||||
|
*/
|
||||||
|
public function addMore(array $classes): void {
|
||||||
|
foreach($classes as $class) {
|
||||||
|
$this->add($class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
* @throws ArgumentException if the given class is not properly annotated.
|
||||||
|
*/
|
||||||
|
public function add(string $class): void
|
||||||
|
{
|
||||||
|
$reflectionClass = new ReflectionClass($class);
|
||||||
|
/** @var Extension $extensionAnnotation */
|
||||||
|
$extensionAnnotation = $this->reader->getClassAnnotation($reflectionClass, Extension::class);
|
||||||
|
|
||||||
|
if ($extensionAnnotation === null) {
|
||||||
|
throw new ArgumentException(sprintf("Class %s must have the class Annotation %s", $class, Extension::class));
|
||||||
|
}
|
||||||
|
|
||||||
|
$modelClass = $extensionAnnotation->getModelClass();
|
||||||
|
|
||||||
|
if (empty(self::$classes[$modelClass])) {
|
||||||
|
self::$classes[$modelClass] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run through static methods
|
||||||
|
$reflectionMethods = $reflectionClass->getMethods();
|
||||||
|
|
||||||
|
foreach ($reflectionMethods as $method) {
|
||||||
|
if ($method->isStatic() === false) {
|
||||||
|
throw new ArgumentException(sprintf("Method %s must be static.", $method->getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var ExtensionMethod $extensionMethodAnnotation */
|
||||||
|
$extensionMethodAnnotation = $this->reader->getMethodAnnotation($method, ExtensionMethod::class);
|
||||||
|
$methodName = $method->getName();
|
||||||
|
|
||||||
|
self::$classes[$modelClass][$extensionMethodAnnotation->getMethodName()] = [$class, $methodName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a callback registered in the model extender globally.
|
||||||
|
* @param string $modelClassName
|
||||||
|
* @param string $methodName
|
||||||
|
* @return callable|null
|
||||||
|
*/
|
||||||
|
public static function get(string $modelClassName, string $methodName): ?callable
|
||||||
|
{
|
||||||
|
if (empty(self::$classes[$modelClassName])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty(self::$classes[$modelClassName][$methodName])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$classes[$modelClassName][$methodName];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
use Generator;
|
||||||
|
|
||||||
|
use LotGD\Core\Exceptions\PermissionAlreadyExistsException;
|
||||||
|
use LotGD\Core\Exceptions\PermissionDoesNotExistException;
|
||||||
|
use LotGD\Core\Models\Permission;
|
||||||
|
use LotGD\Core\Models\PermissionAssociationInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This abtract class provides functionality for user entities that crates might
|
||||||
|
* want to implement, such as permissions.
|
||||||
|
*/
|
||||||
|
abstract class Actor
|
||||||
|
{
|
||||||
|
/** @var array Associations between permission-id and PermissionAssociation entity. */
|
||||||
|
private $permissionIdToAssociation = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Needs to return a generator which iterates through all permission associations.
|
||||||
|
* @return Generator List of PermissionAssociations.
|
||||||
|
*/
|
||||||
|
abstract protected function getPermissionAssociations(): Generator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the class of the permission associations used for the entity
|
||||||
|
* implementing this class.
|
||||||
|
* @return string fully qualified class name of the permission association entity.
|
||||||
|
*/
|
||||||
|
abstract protected function getPermissionAssociationClass(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all associated permissions for this actor.
|
||||||
|
* @throws PermissionAssociationEntityMissingException
|
||||||
|
*/
|
||||||
|
protected function loadPermissions()
|
||||||
|
{
|
||||||
|
if (class_exists($this->getPermissionAssociationClass()) === false) {
|
||||||
|
throw new PermissionAssociationEntityMissingException(
|
||||||
|
"The method getPermissionAssociationClass does not return a valid class name."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->permissionIdToAssociation)) {
|
||||||
|
foreach ($this->getPermissionAssociations() as $permission) {
|
||||||
|
$this->permissionIdToAssociation[$permission->getId()] = $permission;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the actor is associated with a given permission. For permission
|
||||||
|
* checking, use only the PermissionManager class.
|
||||||
|
* @param string $permissionId
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasPermissionSet(string $permissionId): bool
|
||||||
|
{
|
||||||
|
$this->loadPermissions();
|
||||||
|
|
||||||
|
return isset($this->permissionIdToAssociation[$permissionId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the associated permission given by an id. For permission
|
||||||
|
* checking, use only the PermissionManager class.
|
||||||
|
* @param string $permissionId
|
||||||
|
* @return PermissionAssociationInterface
|
||||||
|
*/
|
||||||
|
public function getPermission(string $permissionId): PermissionAssociationInterface
|
||||||
|
{
|
||||||
|
$this->loadPermissions();
|
||||||
|
|
||||||
|
return $this->permissionIdToAssociation[$permissionId];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw permission given by the id. For permission
|
||||||
|
* checking, use only the PermissionManager class.
|
||||||
|
* @param string $permissionId
|
||||||
|
* @return Permission
|
||||||
|
*/
|
||||||
|
public function getRawPermission(string $permissionId): Permission
|
||||||
|
{
|
||||||
|
$this->loadPermissions();
|
||||||
|
|
||||||
|
return $this->permissionIdToAssociation[$permissionId]->getPermission();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates a permission with this actor in a given state. For permission
|
||||||
|
* manipulation, use only the PermissionManager class.
|
||||||
|
* @param Permission $permission
|
||||||
|
* @param int $state
|
||||||
|
* @throws PermissionAlreadyExistsException
|
||||||
|
*/
|
||||||
|
public function addPermission(Permission $permission, int $state)
|
||||||
|
{
|
||||||
|
$this->loadPermissions();
|
||||||
|
|
||||||
|
if ($this->hasPermissionSet($permission->getId())) {
|
||||||
|
$permissionId = $permission->getId();
|
||||||
|
throw new PermissionAlreadyExistsException("The permission with the id {$permissionId} has already been set on this actor.");
|
||||||
|
} else {
|
||||||
|
$associationEntity = $this->getPermissionAssociationClass();
|
||||||
|
|
||||||
|
$permissionAssoc = new $associationEntity($this, $permission, $state);
|
||||||
|
$this->permissions->add($permissionAssoc);
|
||||||
|
$this->permissionIdToAssociation[$permissionAssoc->getId()] = $permissionAssoc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an associated permission from this actor by a given id. For permission
|
||||||
|
* manipulation, use only the PermissionManager class.
|
||||||
|
* @param string $permissionId
|
||||||
|
* @throws PermissionDoesNotExistException
|
||||||
|
*/
|
||||||
|
public function removePermission(string $permissionId)
|
||||||
|
{
|
||||||
|
$this->loadPermissions();
|
||||||
|
|
||||||
|
if ($this->hasPermissionSet($permissionId)) {
|
||||||
|
$permissionAssoc = $this->getPermission($permissionId);
|
||||||
|
$this->permissions->removeElement($permissionAssoc);
|
||||||
|
unset($this->permissionIdToAssociation[$permissionId]);
|
||||||
|
} else {
|
||||||
|
throw new PermissionDoesNotExistException("The permission with the id {$permissionId} has not been set on this actor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,26 +4,36 @@ declare(strict_types=1);
|
|||||||
namespace LotGD\Core\Models;
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping\MappedSuperclass;
|
use Doctrine\ORM\Mapping\MappedSuperclass;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
use Ramsey\Uuid\UuidInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @MappedSuperclass
|
* @MappedSuperclass
|
||||||
*/
|
*/
|
||||||
abstract class BasicEnemy implements FighterInterface
|
abstract class BasicEnemy implements FighterInterface
|
||||||
{
|
{
|
||||||
/** @Id @Column(type="integer") @GeneratedValue */
|
/** @Id @Column(type="uuid", unique=True) */
|
||||||
private $id;
|
protected $id;
|
||||||
/** @Column(type="string", length=50); */
|
/** @Column(type="string", length=50); */
|
||||||
private $name;
|
protected $name;
|
||||||
/** @Column(type="integer"); */
|
/** @Column(type="integer"); */
|
||||||
private $level;
|
protected $level;
|
||||||
/** @var int */
|
/** @var int */
|
||||||
private $health;
|
protected $health;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BasicEnemy constructor. Sets uuid upon creation.
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
$this->id = Uuid::uuid4();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the enemy's id
|
* Returns the enemy's id
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getId(): int
|
public function getId(): UuidInterface
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
namespace LotGD\Core\Models\BattleEvents;
|
namespace LotGD\Core\Models\BattleEvents;
|
||||||
|
|
||||||
use LotGD\Core\Exceptions\BattleEventException;
|
use LotGD\Core\Exceptions\BattleEventException;
|
||||||
|
use LotGD\Core\Game;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A representation of something that happened in battle.
|
* A representation of something that happened in battle.
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
namespace LotGD\Core\Models\BattleEvents;
|
namespace LotGD\Core\Models\BattleEvents;
|
||||||
|
|
||||||
use LotGD\Core\Exceptions\BattleEventException;
|
use LotGD\Core\Exceptions\BattleEventException;
|
||||||
|
use LotGD\Core\Game;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A battle event representing a message generated by a buff.
|
* A battle event representing a message generated by a buff.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core\Models\BattleEvents;
|
namespace LotGD\Core\Models\BattleEvents;
|
||||||
|
|
||||||
|
use LotGD\Core\Game;
|
||||||
use LotGD\Core\Models\FighterInterface;
|
use LotGD\Core\Models\FighterInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,7 +32,7 @@ class CriticalHitEvent extends BattleEvent
|
|||||||
*/
|
*/
|
||||||
public function decorate(Game $game): string
|
public function decorate(Game $game): string
|
||||||
{
|
{
|
||||||
$pureAttackersAttack = $this->attacker->getAttack($game, true);
|
$pureAttackersAttack = $this->attacker->getAttack(true);
|
||||||
|
|
||||||
if ($this->criticalAttackValue > $pureAttackersAttack * 4) {
|
if ($this->criticalAttackValue > $pureAttackersAttack * 4) {
|
||||||
return "You execute a MEGA power move!!!";
|
return "You execute a MEGA power move!!!";
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core\Models\BattleEvents;
|
namespace LotGD\Core\Models\BattleEvents;
|
||||||
|
|
||||||
|
use LotGD\Core\Game;
|
||||||
use LotGD\Core\Models\FighterInterface;
|
use LotGD\Core\Models\FighterInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core\Models\BattleEvents;
|
namespace LotGD\Core\Models\BattleEvents;
|
||||||
|
|
||||||
|
use LotGD\Core\Game;
|
||||||
use LotGD\Core\Models\FighterInterface;
|
use LotGD\Core\Models\FighterInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core\Models\BattleEvents;
|
namespace LotGD\Core\Models\BattleEvents;
|
||||||
|
|
||||||
|
use LotGD\Core\Game;
|
||||||
use LotGD\Core\Models\FighterInterface;
|
use LotGD\Core\Models\FighterInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core\Models\BattleEvents;
|
namespace LotGD\Core\Models\BattleEvents;
|
||||||
|
|
||||||
|
use LotGD\Core\Game;
|
||||||
use LotGD\Core\Models\FighterInterface;
|
use LotGD\Core\Models\FighterInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
namespace LotGD\Core\Models\BattleEvents;
|
namespace LotGD\Core\Models\BattleEvents;
|
||||||
|
|
||||||
use LotGD\Core\Exceptions\BattleEventException;
|
use LotGD\Core\Exceptions\BattleEventException;
|
||||||
|
use LotGD\Core\Game;
|
||||||
use LotGD\Core\Models\FighterInterface;
|
use LotGD\Core\Models\FighterInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +40,7 @@ class MinionDamageEvent extends BattleEvent
|
|||||||
*/
|
*/
|
||||||
public function decorate(Game $game): string
|
public function decorate(Game $game): string
|
||||||
{
|
{
|
||||||
parent::decorate();
|
parent::decorate($game);
|
||||||
|
|
||||||
return str_replace(
|
return str_replace(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
namespace LotGD\Core\Models\BattleEvents;
|
namespace LotGD\Core\Models\BattleEvents;
|
||||||
|
|
||||||
use LotGD\Core\Exceptions\BattleEventException;
|
use LotGD\Core\Exceptions\BattleEventException;
|
||||||
|
use LotGD\Core\Game;
|
||||||
use LotGD\Core\Models\FighterInterface;
|
use LotGD\Core\Models\FighterInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,7 +45,7 @@ class RegenerationBuffEvent extends BattleEvent
|
|||||||
*/
|
*/
|
||||||
public function decorate(Game $game): string
|
public function decorate(Game $game): string
|
||||||
{
|
{
|
||||||
parent::decorate();
|
parent::decorate($game);
|
||||||
|
|
||||||
if ($this->regeneration === 0) {
|
if ($this->regeneration === 0) {
|
||||||
return str_replace(
|
return str_replace(
|
||||||
|
|||||||
+10
-6
@@ -7,6 +7,8 @@ use Doctrine\ORM\Mapping\Entity;
|
|||||||
use Doctrine\ORM\Mapping\Table;
|
use Doctrine\ORM\Mapping\Table;
|
||||||
|
|
||||||
use LotGD\Core\Exceptions\ArgumentException;
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
use Ramsey\Uuid\UuidInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A model representing a buff used to modify the flow of the battle.
|
* A model representing a buff used to modify the flow of the battle.
|
||||||
@@ -23,7 +25,7 @@ class Buff
|
|||||||
const ACTIVATE_NONE = 0b0000;
|
const ACTIVATE_NONE = 0b0000;
|
||||||
const ACTIVATE_ANY = 0b1111;
|
const ACTIVATE_ANY = 0b1111;
|
||||||
|
|
||||||
/** @Id @Column(type="integer") @GeneratedValue */
|
/** @Id @Column(type="uuid", unique=True) */
|
||||||
private $id;
|
private $id;
|
||||||
/**
|
/**
|
||||||
* @ManyToOne(targetEntity="Character", inversedBy="buffs")
|
* @ManyToOne(targetEntity="Character", inversedBy="buffs")
|
||||||
@@ -231,7 +233,7 @@ class Buff
|
|||||||
* Allowed buff values and their type
|
* Allowed buff values and their type
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $buffArrayTemplate = [
|
private static $buffArrayTemplate = [
|
||||||
"slot" => "string",
|
"slot" => "string",
|
||||||
"name" => "string",
|
"name" => "string",
|
||||||
"startMessage" => "string",
|
"startMessage" => "string",
|
||||||
@@ -282,13 +284,15 @@ class Buff
|
|||||||
*/
|
*/
|
||||||
public function __construct(array $buffArray)
|
public function __construct(array $buffArray)
|
||||||
{
|
{
|
||||||
|
$this->id = Uuid::uuid4();
|
||||||
|
|
||||||
foreach ($buffArray as $attribute => $value) {
|
foreach ($buffArray as $attribute => $value) {
|
||||||
// Throw exception if an attribute does not exist (to prevent spelling errors)
|
// Throw exception if an attribute does not exist (to prevent spelling errors)
|
||||||
if (!isset($this->buffArrayTemplate[$attribute])) {
|
if (!isset(self::$buffArrayTemplate[$attribute])) {
|
||||||
throw new ArgumentException("{$attribute} is not a valid key for a buff.");
|
throw new ArgumentException("{$attribute} is not a valid key for a buff.");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($this->buffArrayTemplate[$attribute]) {
|
switch (self::$buffArrayTemplate[$attribute]) {
|
||||||
case "string":
|
case "string":
|
||||||
if (is_string($value) === false) {
|
if (is_string($value) === false) {
|
||||||
throw new ArgumentException("{$attribute} needs to be a string.");
|
throw new ArgumentException("{$attribute} needs to be a string.");
|
||||||
@@ -338,7 +342,7 @@ class Buff
|
|||||||
{
|
{
|
||||||
$buffArray = [];
|
$buffArray = [];
|
||||||
|
|
||||||
foreach ($this->buffArrayTemplate as $attribute => $type) {
|
foreach (self::$buffArrayTemplate as $attribute => $type) {
|
||||||
$buffArray[$attribute] = $buff->$attribute;
|
$buffArray[$attribute] = $buff->$attribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +353,7 @@ class Buff
|
|||||||
* Returns the id of the buff
|
* Returns the id of the buff
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getId(): int
|
public function getId(): UuidInterface
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-18
@@ -7,19 +7,25 @@ use Doctrine\Common\Collections\{
|
|||||||
ArrayCollection,
|
ArrayCollection,
|
||||||
Collection
|
Collection
|
||||||
};
|
};
|
||||||
|
use Doctrine\ORM\Mapping\Column;
|
||||||
use Doctrine\ORM\Mapping\Entity;
|
use Doctrine\ORM\Mapping\Entity;
|
||||||
|
use Doctrine\ORM\Mapping\Id;
|
||||||
|
use Doctrine\ORM\Mapping\JoinColumn;
|
||||||
|
use Doctrine\ORM\Mapping\JoinTable;
|
||||||
|
use Doctrine\ORM\Mapping\ManyToMany;
|
||||||
|
use Doctrine\ORM\Mapping\OneToMany;
|
||||||
|
use Doctrine\ORM\Mapping\OneToOne;
|
||||||
use Doctrine\ORM\Mapping\Table;
|
use Doctrine\ORM\Mapping\Table;
|
||||||
|
|
||||||
use LotGD\Core\{
|
use LotGD\Core\{
|
||||||
BuffList,
|
BuffList, Events\CharacterEventData, Game, GameAwareInterface
|
||||||
Game
|
|
||||||
};
|
};
|
||||||
use LotGD\Core\Tools\Exceptions\BuffSlotOccupiedException;
|
use LotGD\Core\Exceptions\BuffSlotOccupiedException;
|
||||||
use LotGD\Core\Tools\Model\{
|
use LotGD\Core\Tools\Model\{
|
||||||
Creator,
|
Creator, ExtendableModel, GameAware, PropertyManager, SoftDeletable
|
||||||
PropertyManager,
|
|
||||||
SoftDeletable
|
|
||||||
};
|
};
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
use Ramsey\Uuid\UuidInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for a character
|
* Model for a character
|
||||||
@@ -27,18 +33,20 @@ use LotGD\Core\Tools\Model\{
|
|||||||
* @Entity(repositoryClass="LotGD\Core\Models\Repositories\CharacterRepository")
|
* @Entity(repositoryClass="LotGD\Core\Models\Repositories\CharacterRepository")
|
||||||
* @Table(name="characters")
|
* @Table(name="characters")
|
||||||
*/
|
*/
|
||||||
class Character implements CharacterInterface, CreateableInterface
|
class Character implements CharacterInterface, CreateableInterface, GameAwareInterface, ExtendableModelInterface
|
||||||
{
|
{
|
||||||
use Creator;
|
use Creator;
|
||||||
use SoftDeletable;
|
use SoftDeletable;
|
||||||
use PropertyManager;
|
use PropertyManager;
|
||||||
|
use GameAware;
|
||||||
|
use ExtendableModel;
|
||||||
|
|
||||||
/** @Id @Column(type="integer") @GeneratedValue */
|
/** @Id @Column(type="uuid", unique=True) */
|
||||||
private $id;
|
private $id;
|
||||||
/** @Column(type="string", length=50); */
|
/** @Column(type="string", length=50); */
|
||||||
private $name;
|
private $name = "";
|
||||||
/** @Column(type="text"); */
|
/** @Column(type="text"); */
|
||||||
private $displayName;
|
private $displayName = "";
|
||||||
/** @Column(type="integer", options={"default":10}) */
|
/** @Column(type="integer", options={"default":10}) */
|
||||||
private $maxHealth = 10;
|
private $maxHealth = 10;
|
||||||
/** @Column(type="integer", options={"default":10}) */
|
/** @Column(type="integer", options={"default":10}) */
|
||||||
@@ -74,6 +82,8 @@ class Character implements CharacterInterface, CreateableInterface
|
|||||||
"level",
|
"level",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private $propertyClass = CharacterProperty::class;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a character at full health
|
* Creates a character at full health
|
||||||
*/
|
*/
|
||||||
@@ -89,6 +99,8 @@ class Character implements CharacterInterface, CreateableInterface
|
|||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
$this->id = Uuid::uuid4();
|
||||||
|
|
||||||
$this->properties = new ArrayCollection();
|
$this->properties = new ArrayCollection();
|
||||||
$this->buffs = new ArrayCollection();
|
$this->buffs = new ArrayCollection();
|
||||||
$this->messageThreads = new ArrayCollection();
|
$this->messageThreads = new ArrayCollection();
|
||||||
@@ -98,7 +110,7 @@ class Character implements CharacterInterface, CreateableInterface
|
|||||||
* Returns the entity's id
|
* Returns the entity's id
|
||||||
* @return int The id
|
* @return int The id
|
||||||
*/
|
*/
|
||||||
public function getId(): int
|
public function getId(): UuidInterface
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
@@ -142,7 +154,7 @@ class Character implements CharacterInterface, CreateableInterface
|
|||||||
/**
|
/**
|
||||||
* Sets the maximum health of a character to a given value. It also sets the
|
* Sets the maximum health of a character to a given value. It also sets the
|
||||||
* health if none has been set yet.
|
* health if none has been set yet.
|
||||||
* @param int $maxhealth
|
* @param int $maxHealth
|
||||||
*/
|
*/
|
||||||
public function setMaxHealth(int $maxHealth)
|
public function setMaxHealth(int $maxHealth)
|
||||||
{
|
{
|
||||||
@@ -192,7 +204,7 @@ class Character implements CharacterInterface, CreateableInterface
|
|||||||
/**
|
/**
|
||||||
* Heals the enemy
|
* Heals the enemy
|
||||||
* @param int $heal
|
* @param int $heal
|
||||||
* @param type $overheal True if healing bigger than maxhealth is desired.
|
* @param bool $overheal True if healing bigger than maxHealth is desired.
|
||||||
*/
|
*/
|
||||||
public function heal(int $heal, bool $overheal = false)
|
public function heal(int $heal, bool $overheal = false)
|
||||||
{
|
{
|
||||||
@@ -223,18 +235,46 @@ class Character implements CharacterInterface, CreateableInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the character's virtual attribute "attack"
|
* Returns the character's virtual attribute "attack"
|
||||||
|
* @param bool $ignoreBuffs
|
||||||
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getAttack(Game $game, bool $ignoreBuffs = false): int
|
public function getAttack(bool $ignoreBuffs = false): int
|
||||||
{
|
{
|
||||||
return $this->level * 2;
|
$baseAttack = $this->level;
|
||||||
|
|
||||||
|
$hookData = $this->getGame()->getEventManager()->publish(
|
||||||
|
"h/lotgd/core/getCharacterAttack",
|
||||||
|
CharacterEventData::create([
|
||||||
|
"character" => $this,
|
||||||
|
"value" => $baseAttack
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
$modifiedAttack = $hookData->get("value");
|
||||||
|
|
||||||
|
return $modifiedAttack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the character's virtual attribute "defense"
|
* Returns the character's virtual attribute "defense"
|
||||||
|
* @param bool $ignoreBuffs
|
||||||
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getDefense(Game $game, bool $ignoreBuffs = false): int
|
public function getDefense(bool $ignoreBuffs = false): int
|
||||||
{
|
{
|
||||||
return $this->level * 2;
|
$baseDefense = $this->level;
|
||||||
|
|
||||||
|
$hookData = $this->getGame()->getEventManager()->publish(
|
||||||
|
"h/lotgd/core/getCharacterDefense",
|
||||||
|
CharacterEventData::create([
|
||||||
|
"character" => $this,
|
||||||
|
"value" => $baseDefense
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
$modifiedDefense = $hookData->get("value");
|
||||||
|
|
||||||
|
return $modifiedDefense;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -258,7 +298,7 @@ class Character implements CharacterInterface, CreateableInterface
|
|||||||
/**
|
/**
|
||||||
* Sets the current character viewpoint.
|
* Sets the current character viewpoint.
|
||||||
*/
|
*/
|
||||||
public function setViewpoint(Viewpoint $v)
|
public function setViewpoint(?Viewpoint $v)
|
||||||
{
|
{
|
||||||
$this->viewpoint = $v;
|
$this->viewpoint = $v;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core\Models;
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
use Ramsey\Uuid\UuidInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for the character model and all objects that mimick such a model.
|
* Interface for the character model and all objects that mimick such a model.
|
||||||
*/
|
*/
|
||||||
interface CharacterInterface extends FighterInterface
|
interface CharacterInterface extends FighterInterface
|
||||||
{
|
{
|
||||||
public function getId(): int;
|
public function getId(): UuidInterface;
|
||||||
public function getName(): string;
|
public function getName(): string;
|
||||||
public function getDisplayName(): string;
|
public function getDisplayName(): string;
|
||||||
public function getHealth(): int;
|
public function getHealth(): int;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,60 @@
|
|||||||
|
<?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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getWeight(): int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $weight
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function setWeight(int $weight);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
|
||||||
|
interface ExtendableModelInterface
|
||||||
|
{
|
||||||
|
public function __call($method, $arguments);
|
||||||
|
}
|
||||||
@@ -18,8 +18,8 @@ interface FighterInterface
|
|||||||
public function getMaxHealth(): int;
|
public function getMaxHealth(): int;
|
||||||
public function getHealth(): int;
|
public function getHealth(): int;
|
||||||
public function isAlive(): bool;
|
public function isAlive(): bool;
|
||||||
public function getAttack(Game $game, bool $ignoreBuffs = false): int;
|
public function getAttack(bool $ignoreBuffs = false): int;
|
||||||
public function getDefense(Game $game, bool $ignoreBuffs = false): int;
|
public function getDefense(bool $ignoreBuffs = false): int;
|
||||||
public function damage(int $damage);
|
public function damage(int $damage);
|
||||||
public function heal(int $heal);
|
public function heal(int $heal);
|
||||||
public function setHealth(int $amount);
|
public function setHealth(int $amount);
|
||||||
|
|||||||
@@ -18,10 +18,12 @@ class GameConfiguration
|
|||||||
|
|
||||||
/** @var ArrayCollection */
|
/** @var ArrayCollection */
|
||||||
private $properties;
|
private $properties;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
* @param EntityManagerInterface $em
|
* @param EntityManagerInterface $entityManager
|
||||||
*/
|
*/
|
||||||
public function __construct(EntityManagerInterface $entityManager)
|
public function __construct(EntityManagerInterface $entityManager)
|
||||||
{
|
{
|
||||||
@@ -42,7 +44,7 @@ class GameConfiguration
|
|||||||
/**
|
/**
|
||||||
* Sets and overwrites a configuration value saved by the name
|
* Sets and overwrites a configuration value saved by the name
|
||||||
* @param string $configurationName
|
* @param string $configurationName
|
||||||
* @param type $configurationValue
|
* @param mixed $configurationValue
|
||||||
*/
|
*/
|
||||||
public function set(string $configurationName, $configurationValue)
|
public function set(string $configurationName, $configurationValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
<?php
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace LotGD\Core\Models;
|
|
||||||
|
|
||||||
use Doctrine\ORM\Mapping\Entity;
|
|
||||||
use Doctrine\ORM\Mapping\Table;
|
|
||||||
|
|
||||||
use LotGD\Core\Tools\Model\AutoScaleFighter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Monster entity
|
|
||||||
*
|
|
||||||
* @Entity
|
|
||||||
* @Table(name="masters")
|
|
||||||
*/
|
|
||||||
class Master extends BasicEnemy
|
|
||||||
{
|
|
||||||
use AutoScaleFighter;
|
|
||||||
}
|
|
||||||
+6
-36
@@ -11,6 +11,7 @@ use Doctrine\ORM\Mapping\Table;
|
|||||||
|
|
||||||
use LotGD\Core\Exceptions\InvalidModelException;
|
use LotGD\Core\Exceptions\InvalidModelException;
|
||||||
use LotGD\Core\Exceptions\ArgumentException;
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
use LotGD\Core\Exceptions\ParentAlreadySetException;
|
||||||
use LotGD\Core\Tools\Model\Deletor;
|
use LotGD\Core\Tools\Model\Deletor;
|
||||||
use LotGD\Core\Tools\Model\Saveable;
|
use LotGD\Core\Tools\Model\Saveable;
|
||||||
|
|
||||||
@@ -37,48 +38,17 @@ class Message
|
|||||||
/** @Column(type="boolean", nullable=false) */
|
/** @Column(type="boolean", nullable=false) */
|
||||||
private $systemMessage = false;
|
private $systemMessage = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a message to a MessageThread
|
|
||||||
* @param \LotGD\Core\Models\Character $from
|
|
||||||
* @param string $message
|
|
||||||
* @param \LotGD\Core\Models\MessageThread $thread
|
|
||||||
* @param bool $systemMessage
|
|
||||||
* @return \LotGD\Core\Models\Message
|
|
||||||
*/
|
|
||||||
public static function send(
|
|
||||||
Character $from,
|
|
||||||
string $message,
|
|
||||||
MessageThread $thread,
|
|
||||||
bool $systemMessage = false
|
|
||||||
) {
|
|
||||||
$thread->addMessage(new self($from, $message, $thread, $systemMessage));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a system message to a MessageThread
|
|
||||||
* @param string $message
|
|
||||||
* @param \LotGD\Core\Models\MessageThread $thread
|
|
||||||
* @return \LotGD\Core\Models\Message
|
|
||||||
*/
|
|
||||||
public static function sendSystemMessage(
|
|
||||||
string $message,
|
|
||||||
MessageThread $thread
|
|
||||||
) {
|
|
||||||
$thread->addMessage(new self(SystemCharacter::getInstance(), $message, $thread, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the message.
|
* Constructs the message.
|
||||||
*
|
* Use the Message Manager methods send() and sendSystemMessage() instead.
|
||||||
* This method has been made protected to prevent from accessing it directly. Use
|
* @param CharacterInterface $from
|
||||||
* the static methods self::send() and self::sendSystemMessage() instead.
|
|
||||||
* @param \LotGD\Core\Models\Character $from
|
|
||||||
* @param string $message
|
* @param string $message
|
||||||
* @param \LotGD\Core\Models\Thread $thread
|
* @param MessageThread $thread
|
||||||
* @param bool $systemMessage
|
* @param bool $systemMessage
|
||||||
* @throws ArgumentException
|
* @throws ArgumentException
|
||||||
*/
|
*/
|
||||||
protected function __construct(CharacterInterface $from, string $message, MessageThread $thread, bool $systemMessage)
|
public function __construct(CharacterInterface $from, string $message, MessageThread $thread, bool $systemMessage)
|
||||||
{
|
{
|
||||||
if ($from instanceof Character) {
|
if ($from instanceof Character) {
|
||||||
if ($from->isDeleted() === true) {
|
if ($from->isDeleted() === true) {
|
||||||
|
|||||||
@@ -36,10 +36,10 @@ class MessageThread implements SaveableInterface
|
|||||||
/**
|
/**
|
||||||
* Constructor. Sets the (unique) threadKey.
|
* Constructor. Sets the (unique) threadKey.
|
||||||
* @param string $threadKey
|
* @param string $threadKey
|
||||||
* @param type $participants
|
* @param array $participants
|
||||||
* @param type $readonly
|
* @param bool $readonly
|
||||||
*/
|
*/
|
||||||
public function __construct(string $threadKey, array $participants, $readonly = false)
|
public function __construct(string $threadKey, array $participants, bool $readonly = false)
|
||||||
{
|
{
|
||||||
$this->threadKey = $threadKey;
|
$this->threadKey = $threadKey;
|
||||||
$this->readonly = $readonly;
|
$this->readonly = $readonly;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core\Models;
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
use Doctrine\ORM\Mapping\Entity;
|
use Doctrine\ORM\Mapping\Entity;
|
||||||
use Doctrine\ORM\Mapping\Table;
|
use Doctrine\ORM\Mapping\Table;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
@@ -33,13 +34,15 @@ class Module implements SaveableInterface
|
|||||||
/** @OneToMany(targetEntity="ModuleProperty", mappedBy="owner", cascade={"persist", "remove"}) */
|
/** @OneToMany(targetEntity="ModuleProperty", mappedBy="owner", cascade={"persist", "remove"}) */
|
||||||
private $properties;
|
private $properties;
|
||||||
|
|
||||||
|
private $propertyClass = ModuleProperty::class;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new module entry.
|
* Construct a new module entry.
|
||||||
*/
|
*/
|
||||||
public function __construct(string $library)
|
public function __construct(string $library)
|
||||||
{
|
{
|
||||||
$this->properties = new ArrayCollection();
|
$this->properties = new ArrayCollection();
|
||||||
$this->createdAt = new \DateTime();
|
$this->createdAt = new DateTime();
|
||||||
$this->library = $library;
|
$this->library = $library;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +50,7 @@ class Module implements SaveableInterface
|
|||||||
* Returns the time this module was added to the system.
|
* Returns the time this module was added to the system.
|
||||||
* @return DateTime
|
* @return DateTime
|
||||||
*/
|
*/
|
||||||
public function getCreatedAt(): \DateTime
|
public function getCreatedAt(): DateTime
|
||||||
{
|
{
|
||||||
return $this->createdAt;
|
return $this->createdAt;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-5
@@ -8,6 +8,8 @@ use Doctrine\ORM\Mapping\Table;
|
|||||||
|
|
||||||
use LotGD\Core\Tools\Model\Creator;
|
use LotGD\Core\Tools\Model\Creator;
|
||||||
use LotGD\Core\Tools\Model\Deletor;
|
use LotGD\Core\Tools\Model\Deletor;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
use Ramsey\Uuid\UuidInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model for the message of the day
|
* Model for the message of the day
|
||||||
@@ -20,7 +22,7 @@ class MotD implements CreateableInterface
|
|||||||
use Creator;
|
use Creator;
|
||||||
use Deletor;
|
use Deletor;
|
||||||
|
|
||||||
/** @Id @Column(type="integer") @GeneratedValue */
|
/** @Id @Column(type="uuid", unique=True) */
|
||||||
private $id;
|
private $id;
|
||||||
/**
|
/**
|
||||||
* @ManyToOne(targetEntity="Character", cascade={"persist"}, fetch="EAGER")
|
* @ManyToOne(targetEntity="Character", cascade={"persist"}, fetch="EAGER")
|
||||||
@@ -49,6 +51,7 @@ class MotD implements CreateableInterface
|
|||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
$this->id = Uuid::uuid4();
|
||||||
$this->creationTime = new \DateTime("now");
|
$this->creationTime = new \DateTime("now");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +59,7 @@ class MotD implements CreateableInterface
|
|||||||
* Returns the entities ID
|
* Returns the entities ID
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getId(): int
|
public function getId(): UuidInterface
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
@@ -67,7 +70,7 @@ class MotD implements CreateableInterface
|
|||||||
* Returns always the real author of the message, even if it is a
|
* Returns always the real author of the message, even if it is a
|
||||||
* system message. Use $this->getSystemMessage() to check if it is a system
|
* system message. Use $this->getSystemMessage() to check if it is a system
|
||||||
* message or $this->getAppearentAuthor() to get the appearent author.
|
* message or $this->getAppearentAuthor() to get the appearent author.
|
||||||
* @return \LotGD\Core\Models\Character
|
* @return CharacterInterface
|
||||||
*/
|
*/
|
||||||
public function getAuthor(): CharacterInterface
|
public function getAuthor(): CharacterInterface
|
||||||
{
|
{
|
||||||
@@ -76,7 +79,7 @@ class MotD implements CreateableInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the appearent author of this message.
|
* Returns the appearent author of this message.
|
||||||
* @return \LotGD\Core\Models\CharacterInterface
|
* @return CharacterInterface
|
||||||
*/
|
*/
|
||||||
public function getApparantAuthor(): CharacterInterface
|
public function getApparantAuthor(): CharacterInterface
|
||||||
{
|
{
|
||||||
@@ -89,7 +92,7 @@ class MotD implements CreateableInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the author of this motd
|
* Sets the author of this motd
|
||||||
* @param \LotGD\Core\Models\Character $author
|
* @param Character $author
|
||||||
*/
|
*/
|
||||||
public function setAuthor(Character $author)
|
public function setAuthor(Character $author)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping\Entity;
|
||||||
|
use Doctrine\ORM\Mapping\Table;
|
||||||
|
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
use LotGD\Core\Tools\Model\Creator;
|
||||||
|
use LotGD\Core\Tools\Model\Deletor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a permission.
|
||||||
|
*
|
||||||
|
* @Entity()
|
||||||
|
* @Table(name="permissions")
|
||||||
|
*/
|
||||||
|
class Permission implements CreateableInterface
|
||||||
|
{
|
||||||
|
use Creator;
|
||||||
|
use Deletor;
|
||||||
|
|
||||||
|
/** @Id @Column(type="string"); */
|
||||||
|
private $id;
|
||||||
|
/** @Column(type="string") */
|
||||||
|
private $library;
|
||||||
|
/** @Column(type="string") */
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
static $fillable = [
|
||||||
|
"id",
|
||||||
|
"library",
|
||||||
|
"name"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the id of this entity.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId(): string
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this entity's id if it's not set yet.
|
||||||
|
* @param string $id
|
||||||
|
* @throws ArgumentException
|
||||||
|
*/
|
||||||
|
public function setId(string $id)
|
||||||
|
{
|
||||||
|
if (empty($this->id)) {
|
||||||
|
$this->id = $id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new ArgumentException("Cannot reset id.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the library this permission belongs to.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLibrary(): string
|
||||||
|
{
|
||||||
|
return $this->library;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the library this permission belongs to.
|
||||||
|
* @param string $library
|
||||||
|
*/
|
||||||
|
public function setLibrary(string $library)
|
||||||
|
{
|
||||||
|
$this->library = $library;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets this entity's human readable name.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this entity's human readable name.
|
||||||
|
* @param string $name
|
||||||
|
*/
|
||||||
|
public function setName(string $name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend this class to provide an association between an entity and a permission.
|
||||||
|
*/
|
||||||
|
interface PermissionAssociationInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -43,9 +43,9 @@ class CharacterRepository extends EntityRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a character by ID.
|
* Find a character by ID, excluding soft deleted ones.
|
||||||
*/
|
*/
|
||||||
public function find($id, int $deletes = self::SKIP_SOFTDELETED)
|
public function find($id, $lockMode=null, $lockVersion=null)
|
||||||
{
|
{
|
||||||
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
|
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
|
||||||
$queryBuilder->select("c")
|
$queryBuilder->select("c")
|
||||||
@@ -53,7 +53,29 @@ class CharacterRepository extends EntityRepository
|
|||||||
->where($queryBuilder->expr()->eq("c.id", ":id"))
|
->where($queryBuilder->expr()->eq("c.id", ":id"))
|
||||||
->setParameter("id", $id);
|
->setParameter("id", $id);
|
||||||
|
|
||||||
$this->modifyQuery($queryBuilder, $deletes);
|
$this->modifyQuery($queryBuilder, self::SKIP_SOFTDELETED);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $queryBuilder->getQuery()->getSingleResult();
|
||||||
|
} catch (NoResultException $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a character id ID, including soft deleted ones.
|
||||||
|
* @param $id
|
||||||
|
* @return mixed|null
|
||||||
|
* @throws \Doctrine\ORM\NonUniqueResultException
|
||||||
|
*/
|
||||||
|
public function findWithSoftDeleted($id) {
|
||||||
|
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
|
||||||
|
$queryBuilder->select("c")
|
||||||
|
->from(Character::class, "c")
|
||||||
|
->where($queryBuilder->expr()->eq("c.id", ":id"))
|
||||||
|
->setParameter("id", $id);
|
||||||
|
|
||||||
|
$this->modifyQuery($queryBuilder, self::INCLUDE_SOFTDELETED);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return $queryBuilder->getQuery()->getSingleResult();
|
return $queryBuilder->getQuery()->getSingleResult();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types = 1);
|
|||||||
|
|
||||||
namespace LotGD\Core\Models\Repositories;
|
namespace LotGD\Core\Models\Repositories;
|
||||||
|
|
||||||
|
use Doctrine\Common\Util\Debug;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Doctrine\ORM\NoResultException;
|
use Doctrine\ORM\NoResultException;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
|||||||
+217
-80
@@ -7,11 +7,13 @@ use Doctrine\Common\Collections\ArrayCollection;
|
|||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\ORM\Mapping\Entity;
|
use Doctrine\ORM\Mapping\Entity;
|
||||||
use Doctrine\ORM\Mapping\Table;
|
use Doctrine\ORM\Mapping\Table;
|
||||||
use Doctrine\ORM\Mapping\Column;
|
|
||||||
|
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
use LotGD\Core\Tools\Model\Creator;
|
use LotGD\Core\Tools\Model\Creator;
|
||||||
use LotGD\Core\Tools\Model\Deletor;
|
use LotGD\Core\Tools\Model\Deletor;
|
||||||
use LotGD\Core\Tools\Model\SceneBasics;
|
use LotGD\Core\Tools\Model\SceneBasics;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
use Ramsey\Uuid\UuidInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scene is a location within the game, such as the Village or the Tavern. Designed
|
* A scene is a location within the game, such as the Village or the Tavern. Designed
|
||||||
@@ -20,28 +22,29 @@ use LotGD\Core\Tools\Model\SceneBasics;
|
|||||||
* @Entity
|
* @Entity
|
||||||
* @Table(name="scenes")
|
* @Table(name="scenes")
|
||||||
*/
|
*/
|
||||||
class Scene implements CreateableInterface
|
class Scene implements CreateableInterface, SceneConnectable
|
||||||
{
|
{
|
||||||
use Creator;
|
use Creator;
|
||||||
use Deletor;
|
use Deletor;
|
||||||
use SceneBasics;
|
use SceneBasics;
|
||||||
|
|
||||||
/** @Id @Column(type="integer") @GeneratedValue */
|
/** @Id @Column(type="string", length=36, unique=True, name="id", options={"fixed" = true}) */
|
||||||
private $id;
|
protected $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ManyToMany(targetEntity="Scene", mappedBy="children", cascade={"persist"})
|
* @OneToMany(targetEntity="SceneConnectionGroup", mappedBy="scene", cascade={"persist", "remove"})
|
||||||
*/
|
*/
|
||||||
private $parents = null;
|
private $connectionGroups = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ManyToMany(targetEntity="Scene", inversedBy="parents", cascade={"persist", "remove"})
|
* @OneToMany(targetEntity="SceneConnection", mappedBy="outgoingScene", cascade={"persist", "remove"})
|
||||||
* @JoinTable(name="paths",
|
|
||||||
* joinColumns={@JoinColumn(name="scene_id", referencedColumnName="id")},
|
|
||||||
* inverseJoinColumns={@JoinColumn(name="child_scene_id", referencedColumnName="id")}
|
|
||||||
* )
|
|
||||||
*/
|
*/
|
||||||
private $children = [];
|
private $outgoingConnections = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OneToMany(targetEntity="SceneConnection", mappedBy="incomingScene", cascade={"persist", "remove"})
|
||||||
|
*/
|
||||||
|
private $incomingConnections = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
@@ -49,111 +52,245 @@ class Scene implements CreateableInterface
|
|||||||
private static $fillable = [
|
private static $fillable = [
|
||||||
"title",
|
"title",
|
||||||
"description",
|
"description",
|
||||||
"parents",
|
|
||||||
"template"
|
"template"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/* @var ?ArrayCollection */
|
||||||
|
private $connectedScenes = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for a scene.
|
* Constructor for a scene.
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->children = new ArrayCollection();
|
$this->id = Uuid::uuid4()->toString();
|
||||||
$this->parents = new ArrayCollection();
|
|
||||||
|
$this->connectionGroups = new ArrayCollection();
|
||||||
|
$this->outgoingConnections = new ArrayCollection();
|
||||||
|
$this->incomingConnections = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the primary ID for this scene.
|
* Returns the primary ID for this scene.
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getId(): int
|
public function getId(): string
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the parents to the given Collection.
|
* Filters all connection groups for a specific name.
|
||||||
* @param Collection $parents
|
* @param string $name
|
||||||
*/
|
|
||||||
public function setParents(Collection $parents)
|
|
||||||
{
|
|
||||||
// Super slow, but presumably these are short collections :)
|
|
||||||
// We should probably move to a set collection at some point.
|
|
||||||
$oldParents = $this->parents;
|
|
||||||
$additions = $parents->filter(function($element) use ($oldParents) {
|
|
||||||
return !$oldParents->contains($element);
|
|
||||||
});
|
|
||||||
$removals = $this->parents->filter(function($element) use ($parents) {
|
|
||||||
return !$parents->contains($element);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach ($additions as $a) {
|
|
||||||
$this->addParent($a);
|
|
||||||
}
|
|
||||||
foreach ($removals as $r) {
|
|
||||||
$this->removeParent($r);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->parents = $parents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a parent to this scene.
|
|
||||||
* @param \LotGD\Core\Models\Scene $parent
|
|
||||||
*/
|
|
||||||
public function addParent(Scene $parent)
|
|
||||||
{
|
|
||||||
if (!$this->parents->contains($parent)) {
|
|
||||||
$this->parents->add($parent);
|
|
||||||
$parent->addChild($this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a parent from this scene.
|
|
||||||
* @param Scene $parent
|
|
||||||
*/
|
|
||||||
public function removeParent(Scene $parent)
|
|
||||||
{
|
|
||||||
$this->parents->removeElement($parent);
|
|
||||||
$parent->removeChild($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all the possible parents of this scene.
|
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
public function getParents(): Collection
|
private function filterConnectionGroupCollectionByName(string $name): Collection
|
||||||
{
|
{
|
||||||
return $this->parents;
|
return $this->connectionGroups->filter(function(SceneConnectionGroup $group) use ($name) {
|
||||||
|
if ($group->getName() === $name) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of all children registered for this scene.
|
* Returns true if this scene has a connection group with a given name associated.
|
||||||
* @return Collection
|
* @param string $name
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function getChildren(): Collection
|
public function hasConnectionGroup(string $name): bool
|
||||||
{
|
{
|
||||||
return $this->children;
|
return count($this->filterConnectionGroupCollectionByName($name)) === 1 ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a child for this scene.
|
* Returns a connection group entity associated with this scene by a given name.
|
||||||
* @param \LotGD\Core\Models\Scene $child
|
* @param string $name
|
||||||
|
* @return \LotGD\Core\Models\SceneConnectionGroup
|
||||||
*/
|
*/
|
||||||
protected function addChild(Scene $child)
|
public function getConnectionGroup(string $name): SceneConnectionGroup
|
||||||
{
|
{
|
||||||
if (!$this->children->contains($child)) {
|
return $this->filterConnectionGroupCollectionByName($name)->first();
|
||||||
$this->children->add($child);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a connection group to this scene.
|
||||||
|
* @param SceneConnectionGroup $group
|
||||||
|
* @throws ArgumentException
|
||||||
|
*/
|
||||||
|
public function addConnectionGroup(SceneConnectionGroup $group): void
|
||||||
|
{
|
||||||
|
if ($this->connectionGroups->contains($group) === true) {
|
||||||
|
throw new ArgumentException("This entity already owns the given connection group.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($group->getScene()) {
|
||||||
|
throw new ArgumentException("The given connection group is already owned by another scene entity.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$group->setScene($this);
|
||||||
|
$this->connectionGroups->add($group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a connection group from this scene.
|
||||||
|
* @param \LotGD\Core\Models\SceneConnectionGroup $group
|
||||||
|
* @throws ArgumentException
|
||||||
|
*/
|
||||||
|
public function dropConnectionGroup(SceneConnectionGroup $group): void
|
||||||
|
{
|
||||||
|
if ($this->connectionGroups->contains($group) === false) {
|
||||||
|
throw new ArgumentException("This entity does not own the given connection group.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->connectionGroups->removeElement($group);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lazy loading helper function - loads all scenes that are connected to this scene.
|
||||||
|
*/
|
||||||
|
private function loadConnectedScenes(): void
|
||||||
|
{
|
||||||
|
if ($this->connectedScenes === null) {
|
||||||
|
$connectedScenes = new ArrayCollection();
|
||||||
|
|
||||||
|
foreach ($this->outgoingConnections as $connection) {
|
||||||
|
$incomingScene = $connection->getIncomingScene();
|
||||||
|
|
||||||
|
if ($connectedScenes->contains($incomingScene) === false) {
|
||||||
|
$connectedScenes->add($incomingScene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->incomingConnections as $connection) {
|
||||||
|
$outgoingScenes = $connection->getOutgoingScene();
|
||||||
|
|
||||||
|
if ($connectedScenes->contains($outgoingScenes) === false) {
|
||||||
|
$connectedScenes->add($outgoingScenes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->connectedScenes = $connectedScenes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a child from this scene.
|
* Returns a list of scenes that are connected to this scene.
|
||||||
* @param \LotGD\Core\Models\Scene $child
|
*
|
||||||
|
* This procedure can get slow, especially if there are a lot of scenes connected
|
||||||
|
* to one. Use this method only for the installation and removal of modules,
|
||||||
|
* or for administrative purposes (like a scene graph).
|
||||||
|
* @return ArrayCollection
|
||||||
*/
|
*/
|
||||||
protected function removeChild(Scene $child)
|
public function getConnectedScenes(): ArrayCollection
|
||||||
{
|
{
|
||||||
$this->children->removeElement($child);
|
$this->loadConnectedScenes();
|
||||||
|
return $this->connectedScenes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given scene is connected to this entity.
|
||||||
|
* @param \LotGD\Core\Models\Scene $scene
|
||||||
|
* @return bool True if yes.
|
||||||
|
*/
|
||||||
|
public function isConnectedTo(Scene $scene): bool
|
||||||
|
{
|
||||||
|
$this->loadConnectedScenes();
|
||||||
|
|
||||||
|
if ($this->connectedScenes->contains($scene)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all collections of this entity.
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function getConnections(): Collection
|
||||||
|
{
|
||||||
|
return new ArrayCollection(
|
||||||
|
array_merge(
|
||||||
|
$this->outgoingConnections->toArray(),
|
||||||
|
$this->incomingConnections->toArray()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a connection to the outgoing connections.
|
||||||
|
* @param \LotGD\Core\Models\SceneConnection $connection
|
||||||
|
*/
|
||||||
|
public function addOutgoingConnection(SceneConnection $connection): void
|
||||||
|
{
|
||||||
|
$this->outgoingConnections->add($connection);
|
||||||
|
|
||||||
|
// If we already have loaded all connected scenes, we need to add the entry manually.
|
||||||
|
if ($this->connectedScenes !== null) {
|
||||||
|
$this->connectedScenes->add($connection->getIncomingScene());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a connection to the incoming connections.
|
||||||
|
* @param \LotGD\Core\Models\SceneConnection $connection
|
||||||
|
*/
|
||||||
|
public function addIncomingConnection(SceneConnection $connection): void
|
||||||
|
{
|
||||||
|
$this->incomingConnections->add($connection);
|
||||||
|
|
||||||
|
// If we already have loaded all connected scenes, we need to add the entry manually.
|
||||||
|
if ($this->connectedScenes !== null) {
|
||||||
|
$this->connectedScenes->add($connection->getOutgoingScene());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function connect(
|
||||||
|
SceneConnectable $connectable,
|
||||||
|
int $directionality = self::Bidirectional
|
||||||
|
): SceneConnection {
|
||||||
|
if ($connectable instanceof self) {
|
||||||
|
if ($this === $connectable) {
|
||||||
|
throw new ArgumentException("Cannot connect a scene to itself.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isConnectedTo($connectable)) {
|
||||||
|
throw new ArgumentException(
|
||||||
|
"The given scene (ID {$connectable->getId()}) is already connected to this (ID {$this->getId()}) one."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection = new SceneConnection($this, $connectable, $directionality);
|
||||||
|
|
||||||
|
$outgoingScene = $this;
|
||||||
|
$incomingScene = $connectable;
|
||||||
|
} else {
|
||||||
|
if ($this === $connectable->getScene()) {
|
||||||
|
throw new ArgumentException("Cannot connect a scene to itself.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isConnectedTo($connectable->getScene())) {
|
||||||
|
throw new ArgumentException(
|
||||||
|
"The given scene (ID {$connectable->getId()}) is already connected to this (ID {$this->getId()}) one."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection = new SceneConnection($this, $connectable->getScene(), $directionality);
|
||||||
|
$connection->setIncomingConnectionGroupName($connectable->getName());
|
||||||
|
|
||||||
|
$outgoingScene = $this;
|
||||||
|
$incomingScene = $connectable->getScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
$outgoingScene->addOutgoingConnection($connection);
|
||||||
|
$incomingScene->addIncomingConnection($connection);
|
||||||
|
|
||||||
|
return $connection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
interface SceneConnectable
|
||||||
|
{
|
||||||
|
public const Bidirectional = 0;
|
||||||
|
public const Unidirectional = 1;
|
||||||
|
public const Xordirectional = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an outgoing connection for this scene to the given connectable.
|
||||||
|
* @param SceneConnectable $connectable
|
||||||
|
* @param int $directionality
|
||||||
|
* @return SceneConnection
|
||||||
|
*/
|
||||||
|
public function connect(SceneConnectable $connectable, int $directionality): SceneConnection;
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping\Entity;
|
||||||
|
use Doctrine\ORM\Mapping\Table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @Entity
|
||||||
|
* @Table(name="scene_connections")
|
||||||
|
*/
|
||||||
|
class SceneConnection
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Id
|
||||||
|
* @ManyToOne(targetEntity="Scene", inversedBy="outgoingConnections")
|
||||||
|
* @JoinColumn(name="outgoingScene", referencedColumnName="id")
|
||||||
|
*/
|
||||||
|
private $outgoingScene;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Id
|
||||||
|
* @ManyToOne(targetEntity="Scene", inversedBy="incomingConnections")
|
||||||
|
* @JoinColumn(name="incomingScene", referencedColumnName="id")
|
||||||
|
*/
|
||||||
|
private $incomingScene;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column(type="integer", options={"default":0})
|
||||||
|
*/
|
||||||
|
private $directionality = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column(type="string", nullable=True)
|
||||||
|
*/
|
||||||
|
private $outgoingConnectionGroupName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column(type="string", nullable=True)
|
||||||
|
*/
|
||||||
|
private $incomingConnectionGroupName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param \LotGD\Core\Models\Scene $outgoing
|
||||||
|
* @param \LotGD\Core\Models\Scene $incoming
|
||||||
|
* @param int $directionality
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
Scene $outgoing,
|
||||||
|
Scene $incoming,
|
||||||
|
int $directionality
|
||||||
|
) {
|
||||||
|
$this->outgoingScene = $outgoing;
|
||||||
|
$this->incomingScene = $incoming;
|
||||||
|
$this->directionality = $directionality;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the connection group name identifier of the outgoing connection.
|
||||||
|
* @param null|string $name The identifier name of the outgoing connection group.
|
||||||
|
*/
|
||||||
|
public function setOutgoingConnectionGroupName(?string $name): void
|
||||||
|
{
|
||||||
|
$this->outgoingConnectionGroupName = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the connection from name identifier of the outgoing connection.
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public function getOutgoingConnectionGroupName(): ?string
|
||||||
|
{
|
||||||
|
return $this->outgoingConnectionGroupName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the outgoing Scene of this connection.
|
||||||
|
* @return Scene
|
||||||
|
*/
|
||||||
|
public function getOutgoingScene(): Scene
|
||||||
|
{
|
||||||
|
return $this->outgoingScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the connection group name identifier of the incoming connection.
|
||||||
|
* @param null|string $name The identifier name of the incoming connection group.
|
||||||
|
*/
|
||||||
|
public function setIncomingConnectionGroupName(?string $name)
|
||||||
|
{
|
||||||
|
$this->incomingConnectionGroupName = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the connection group name identifier of the incoming connection.
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public function getIncomingConnectionGroupName(): ?string
|
||||||
|
{
|
||||||
|
return $this->incomingConnectionGroupName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the incoming Scene of this connection.
|
||||||
|
* @return Scene
|
||||||
|
*/
|
||||||
|
public function getIncomingScene(): Scene
|
||||||
|
{
|
||||||
|
return $this->incomingScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the directionality of this entity is as given as the first parameter.
|
||||||
|
* @param int $directionality
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDirectionality(int $directionality): bool
|
||||||
|
{
|
||||||
|
if ($this->directionality === $directionality) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping\Entity;
|
||||||
|
use Doctrine\ORM\Mapping\Table;
|
||||||
|
|
||||||
|
use LotGD\Core\Tools\Model\Creator;
|
||||||
|
use LotGD\Core\Tools\Model\Deletor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @Entity
|
||||||
|
* @Table(name="scene_connection_groups")
|
||||||
|
*/
|
||||||
|
class SceneConnectionGroup implements SceneConnectable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Id
|
||||||
|
* @ManyToOne(targetEntity="Scene", inversedBy="outgoingConnections", cascade={"persist"})
|
||||||
|
* @JoinColumn(name="scene", referencedColumnName="id")
|
||||||
|
*/
|
||||||
|
private $scene;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Id
|
||||||
|
* @Column(type="string")
|
||||||
|
*/
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column(type="string", length=255)
|
||||||
|
*/
|
||||||
|
private $title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SceneConnectionGroup constructor.
|
||||||
|
* @param string $name Soft-identifier of the connection group, e.g. lotgd/core
|
||||||
|
* @param string $title
|
||||||
|
*/
|
||||||
|
public function __construct(string $name, string $title)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the scene associated with this connection group.
|
||||||
|
* @return \LotGD\Core\Models\Scene
|
||||||
|
*/
|
||||||
|
public function getScene(): ?Scene
|
||||||
|
{
|
||||||
|
return $this->scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scene associated with this connection group.
|
||||||
|
* @param \LotGD\Core\Models\Scene $scene
|
||||||
|
*/
|
||||||
|
public function setScene(Scene $scene): void
|
||||||
|
{
|
||||||
|
$this->scene = $scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name-identifier of this connection group.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getName(): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the title of this connection group.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function connect(SceneConnectable $connectable, int $directionality = null): SceneConnection
|
||||||
|
{
|
||||||
|
if ($directionality === null) {
|
||||||
|
$connection = $this->scene->connect($connectable);
|
||||||
|
} else {
|
||||||
|
$connection = $this->scene->connect($connectable, $directionality);
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection->setOutgoingConnectionGroupName($this->name);
|
||||||
|
|
||||||
|
return $connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
+132
-10
@@ -3,12 +3,20 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core\Models;
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping\Column;
|
||||||
use Doctrine\ORM\Mapping\Entity;
|
use Doctrine\ORM\Mapping\Entity;
|
||||||
|
use Doctrine\ORM\Mapping\Id;
|
||||||
|
use Doctrine\ORM\Mapping\JoinColumn;
|
||||||
|
use Doctrine\ORM\Mapping\ManyToOne;
|
||||||
|
use Doctrine\ORM\Mapping\OneToOne;
|
||||||
use Doctrine\ORM\Mapping\Table;
|
use Doctrine\ORM\Mapping\Table;
|
||||||
|
|
||||||
use LotGD\Core\Action;
|
use LotGD\Core\Action;
|
||||||
|
use LotGD\Core\ActionGroup;
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
use LotGD\Core\Tools\Model\Creator;
|
use LotGD\Core\Tools\Model\Creator;
|
||||||
use LotGD\Core\Tools\Model\SceneBasics;
|
use LotGD\Core\Tools\Model\SceneBasics;
|
||||||
|
use LotGD\Core\Tools\SceneDescription;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Viewpoint is the current Scene a character is experiencing with
|
* A Viewpoint is the current Scene a character is experiencing with
|
||||||
@@ -21,7 +29,11 @@ class Viewpoint implements CreateableInterface
|
|||||||
use Creator;
|
use Creator;
|
||||||
use SceneBasics;
|
use SceneBasics;
|
||||||
|
|
||||||
/** @Id @OneToOne(targetEntity="Character", inversedBy="viewpoint", cascade="persist") */
|
/**
|
||||||
|
* @Id
|
||||||
|
* @OneToOne(targetEntity="Character", inversedBy="viewpoint", cascade="persist")
|
||||||
|
* @JoinColumn(fieldName="owner_id", referencedColumnName="id")
|
||||||
|
*/
|
||||||
private $owner;
|
private $owner;
|
||||||
/** @Column(type="array") */
|
/** @Column(type="array") */
|
||||||
private $actionGroups = [];
|
private $actionGroups = [];
|
||||||
@@ -29,9 +41,15 @@ class Viewpoint implements CreateableInterface
|
|||||||
private $attachments = [];
|
private $attachments = [];
|
||||||
/** @Column(type="array") */
|
/** @Column(type="array") */
|
||||||
private $data = [];
|
private $data = [];
|
||||||
/** @ManyToOne(targetEntity="Scene") */
|
/**
|
||||||
|
* @ManyToOne(targetEntity="Scene")
|
||||||
|
* @JoinColumn(name="scene_id", referencedColumnName="id")
|
||||||
|
*/
|
||||||
private $scene;
|
private $scene;
|
||||||
|
|
||||||
|
/** @var SceneDescription */
|
||||||
|
private $_description;
|
||||||
|
|
||||||
/** @var array */
|
/** @var array */
|
||||||
private static $fillable = [
|
private static $fillable = [
|
||||||
"owner"
|
"owner"
|
||||||
@@ -56,7 +74,49 @@ class Viewpoint implements CreateableInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies the static data from a scene to this Viewpoint entity
|
* Sets the description of this viewpoint.
|
||||||
|
* @param string $description
|
||||||
|
*/
|
||||||
|
public function setDescription(string $description): void
|
||||||
|
{
|
||||||
|
$this->description = $description;
|
||||||
|
$this->_description = new SceneDescription($description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the description
|
||||||
|
*/
|
||||||
|
public function clearDescription(): void
|
||||||
|
{
|
||||||
|
$this->description = "";
|
||||||
|
$this->_description = new SceneDescription("");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current description as a string
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a paragraph to the existing description
|
||||||
|
* @param string $paragraph
|
||||||
|
*/
|
||||||
|
public function addDescriptionParagraph(string $paragraph)
|
||||||
|
{
|
||||||
|
if ($this->_description === null) {
|
||||||
|
$this->_description = new SceneDescription($this->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_description->addParagraph($paragraph);
|
||||||
|
$this->description = (string)$this->_description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the static data from a scene to this Viewpoint entity.
|
||||||
* @param \LotGD\Core\Models\Scene $scene
|
* @param \LotGD\Core\Models\Scene $scene
|
||||||
*/
|
*/
|
||||||
public function changeFromScene(Scene $scene)
|
public function changeFromScene(Scene $scene)
|
||||||
@@ -71,6 +131,38 @@ class Viewpoint implements CreateableInterface
|
|||||||
$this->setData([]);
|
$this->setData([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a restoration point that can be used to reconstruct the current viewpoint.
|
||||||
|
* @return ViewpointSnapshot
|
||||||
|
*/
|
||||||
|
public function getSnapshot(): ViewpointSnapshot
|
||||||
|
{
|
||||||
|
$snapshot = new ViewpointSnapshot(
|
||||||
|
$this->getTitle(),
|
||||||
|
$this->getDescription(),
|
||||||
|
$this->getTemplate(),
|
||||||
|
$this->getActionGroups(),
|
||||||
|
$this->getAttachments(),
|
||||||
|
$this->getData()
|
||||||
|
);
|
||||||
|
|
||||||
|
return $snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the current viewpoint to the state saved in the given restoration point.
|
||||||
|
* @param ViewpointSnapshot $snapshot
|
||||||
|
*/
|
||||||
|
public function changeFromSnapshot(ViewpointSnapshot $snapshot)
|
||||||
|
{
|
||||||
|
$this->setTitle($snapshot->getTitle());
|
||||||
|
$this->setDescription($snapshot->getDescription());
|
||||||
|
$this->setTemplate($snapshot->getTemplate());
|
||||||
|
$this->setActionGroups($snapshot->getActionGroups());
|
||||||
|
$this->setAttachments($snapshot->getAttachments());
|
||||||
|
$this->setData($snapshot->getData());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the template scene used to create this viewpoint.
|
* Sets the template scene used to create this viewpoint.
|
||||||
* @param Scene $scene
|
* @param Scene $scene
|
||||||
@@ -91,7 +183,7 @@ class Viewpoint implements CreateableInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all action groups.
|
* Returns all action groups.
|
||||||
* @return array
|
* @return ActionGroup[]
|
||||||
*/
|
*/
|
||||||
public function getActionGroups(): array
|
public function getActionGroups(): array
|
||||||
{
|
{
|
||||||
@@ -100,7 +192,7 @@ class Viewpoint implements CreateableInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets action groups.
|
* Sets action groups.
|
||||||
* @param array $actionGroups
|
* @param ActionGroup[] $actionGroups
|
||||||
*/
|
*/
|
||||||
public function setActionGroups(array $actionGroups)
|
public function setActionGroups(array $actionGroups)
|
||||||
{
|
{
|
||||||
@@ -108,11 +200,38 @@ class Viewpoint implements CreateableInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds an action group by id.
|
* Adds a new action group to a viewpoint
|
||||||
|
* @param ActionGroup $group The new group to add.
|
||||||
|
* @param null|string $after, optional group id that comes before.
|
||||||
|
* @throws ArgumentException
|
||||||
|
*/
|
||||||
|
public function addActionGroup(ActionGroup $group, ?string $after = null): void
|
||||||
|
{
|
||||||
|
$groupId = $group->getId();
|
||||||
|
if ($this->findActionGroupById($groupId) == true) {
|
||||||
|
throw new ArgumentException("Group {$group} is already contained in this viewpoint.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($after === null) {
|
||||||
|
$this->actionGroups[] = $group;
|
||||||
|
} else {
|
||||||
|
$groups = [];
|
||||||
|
foreach ($this->actionGroups as $g) {
|
||||||
|
if ($g->getId() == $after) {
|
||||||
|
$groups[] = $group;
|
||||||
|
}
|
||||||
|
$groups[] = $g;
|
||||||
|
}
|
||||||
|
$this->actionGroups = $groups;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an action group by id or fails.
|
||||||
* @param $actionGroupId
|
* @param $actionGroupId
|
||||||
* @return ActionGroup|null
|
* @return ActionGroup|null
|
||||||
*/
|
*/
|
||||||
public function findActionGroupById(string $actionGroupId)
|
public function findActionGroupById(string $actionGroupId): ?ActionGroup
|
||||||
{
|
{
|
||||||
$groups = $this->getActionGroups();
|
$groups = $this->getActionGroups();
|
||||||
foreach ($groups as $g) {
|
foreach ($groups as $g) {
|
||||||
@@ -120,6 +239,7 @@ class Viewpoint implements CreateableInterface
|
|||||||
return $g;
|
return $g;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +302,7 @@ class Viewpoint implements CreateableInterface
|
|||||||
/**
|
/**
|
||||||
* Returns a single data field
|
* Returns a single data field
|
||||||
* @param string $fieldname Fieldname
|
* @param string $fieldname Fieldname
|
||||||
* @param type $default default value
|
* @param mixed $default default value
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getDataField(string $fieldname, $default = null)
|
public function getDataField(string $fieldname, $default = null)
|
||||||
@@ -201,9 +321,10 @@ class Viewpoint implements CreateableInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the action that corresponds to the given ID, if present.
|
* Returns the action that corresponds to the given ID, if present.
|
||||||
|
* @param string $id
|
||||||
* @return Action|null
|
* @return Action|null
|
||||||
*/
|
*/
|
||||||
public function findActionById(string $id)
|
public function findActionById(string $id): ?Action
|
||||||
{
|
{
|
||||||
foreach ($this->getActionGroups() as $group) {
|
foreach ($this->getActionGroups() as $group) {
|
||||||
foreach ($group->getActions() as $a) {
|
foreach ($group->getActions() as $a) {
|
||||||
@@ -212,6 +333,7 @@ class Viewpoint implements CreateableInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +341,7 @@ class Viewpoint implements CreateableInterface
|
|||||||
* Removes any actions that correspond to a given scene ID, if present.
|
* Removes any actions that correspond to a given scene ID, if present.
|
||||||
* @param int $id
|
* @param int $id
|
||||||
*/
|
*/
|
||||||
public function removeActionsWithSceneId(int $id)
|
public function removeActionsWithSceneId(string $id)
|
||||||
{
|
{
|
||||||
foreach ($this->getActionGroups() as $group) {
|
foreach ($this->getActionGroups() as $group) {
|
||||||
$actions = $group->getActions();
|
$actions = $group->getActions();
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Models;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a complete set of viewpoint data used to restore a saved viewpoint.
|
||||||
|
* @package LotGD\Core\Models
|
||||||
|
*/
|
||||||
|
class ViewpointSnapshot
|
||||||
|
{
|
||||||
|
private $title;
|
||||||
|
private $description;
|
||||||
|
private $template;
|
||||||
|
private $actionGroups;
|
||||||
|
private $attachments;
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ViewpointRestorationPoint constructor.
|
||||||
|
* @param string $title
|
||||||
|
* @param string $description
|
||||||
|
* @param string $template
|
||||||
|
* @param array $actionGroups
|
||||||
|
* @param array $attachments
|
||||||
|
* @param array $data
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
string $title,
|
||||||
|
string $description,
|
||||||
|
string $template,
|
||||||
|
array $actionGroups,
|
||||||
|
array $attachments,
|
||||||
|
array $data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->title = $title;
|
||||||
|
$this->description = $description;
|
||||||
|
$this->template = $template;
|
||||||
|
$this->actionGroups = $actionGroups;
|
||||||
|
$this->attachments = $attachments;
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the viewpoint.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of the viewpoint.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template of the viewpoint.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTemplate(): string
|
||||||
|
{
|
||||||
|
return $this->template;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action groups of the viewpoint.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getActionGroups(): array
|
||||||
|
{
|
||||||
|
return $this->actionGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attachements of the viewpoint.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAttachments(): array
|
||||||
|
{
|
||||||
|
return $this->attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date of the viewpoint.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getData(): array
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,18 +9,6 @@ use LotGD\Core\Models\Module as ModuleModel;
|
|||||||
*/
|
*/
|
||||||
interface Module extends EventHandler
|
interface Module extends EventHandler
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Called when an event is published that is handled by this class.
|
|
||||||
*
|
|
||||||
* @param Game $g The game.
|
|
||||||
* @param string $event Name of this event.
|
|
||||||
* @param array $context Arbitrary dictionary representing context around this event.
|
|
||||||
* @return array|null Return an array if you want to make changes to the $context before
|
|
||||||
* the next handler is called. Otherwise, return null. Any changes made will be propogated
|
|
||||||
* to the event publisher as well.
|
|
||||||
*/
|
|
||||||
public static function handleEvent(Game $g, string $event, array &$context);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lifecycle method called when this module is initially installed. Use
|
* Lifecycle method called when this module is initially installed. Use
|
||||||
* this method to perform one-time setup operations like adding tables
|
* this method to perform one-time setup operations like adding tables
|
||||||
|
|||||||
+36
-11
@@ -3,13 +3,13 @@ declare (strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core;
|
namespace LotGD\Core;
|
||||||
|
|
||||||
use Composer\Package\PackageInterface;
|
use Throwable;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
|
|
||||||
use LotGD\Core\PackageConfiguration;
|
use LotGD\Core\Exceptions\ClassNotFoundException;
|
||||||
use LotGD\Core\Exceptions\KeyNotFoundException;
|
|
||||||
use LotGD\Core\Exceptions\ModuleAlreadyExistsException;
|
use LotGD\Core\Exceptions\ModuleAlreadyExistsException;
|
||||||
use LotGD\Core\Exceptions\ModuleDoesNotExistException;
|
use LotGD\Core\Exceptions\ModuleDoesNotExistException;
|
||||||
|
use LotGD\Core\Exceptions\SubscriptionNotFoundException;
|
||||||
|
use LotGD\Core\Exceptions\WrongTypeException;
|
||||||
use LotGD\Core\Models\Module as ModuleModel;
|
use LotGD\Core\Models\Module as ModuleModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,6 +42,7 @@ class ModuleManager
|
|||||||
{
|
{
|
||||||
$name = $library->getName();
|
$name = $library->getName();
|
||||||
$package = $library->getComposerPackage();
|
$package = $library->getComposerPackage();
|
||||||
|
$em = $this->g->getEntityManager();
|
||||||
|
|
||||||
$this->g->getLogger()->debug("Registering module {$name}...");
|
$this->g->getLogger()->debug("Registering module {$name}...");
|
||||||
|
|
||||||
@@ -52,7 +53,8 @@ class ModuleManager
|
|||||||
// TODO: handle error cases here.
|
// TODO: handle error cases here.
|
||||||
$this->g->getLogger()->debug("Creating module model for {$name}");
|
$this->g->getLogger()->debug("Creating module model for {$name}");
|
||||||
$m = new ModuleModel($name);
|
$m = new ModuleModel($name);
|
||||||
$m->save($this->g->getEntityManager());
|
|
||||||
|
$em->beginTransaction();
|
||||||
|
|
||||||
$class = $library->getRootNamespace() . 'Module';
|
$class = $library->getRootNamespace() . 'Module';
|
||||||
try {
|
try {
|
||||||
@@ -70,15 +72,38 @@ class ModuleManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to the module's events.
|
// Subscribe to the module's events.
|
||||||
$subscriptions = $library->getSubscriptionPatterns();
|
try {
|
||||||
foreach ($subscriptions as $s) {
|
$subscriptions = $library->getSubscriptionPatterns();
|
||||||
$this->g->getEventManager()->subscribe($s, $class, $name);
|
foreach ($subscriptions as $s) {
|
||||||
|
$this->g->getEventManager()->subscribe($s, $class, $name);
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$em->rollBack();
|
||||||
|
$em->clear();
|
||||||
|
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the module's onRegister handler.
|
// Run the module's onRegister handler.
|
||||||
$this->g->getLogger()->debug("Calling {$class}::onRegister");
|
$this->g->getLogger()->debug("Calling {$class}::onRegister");
|
||||||
$class::onRegister($this->g, $m);
|
|
||||||
$m->save($this->g->getEntityManager());
|
try {
|
||||||
|
$class::onRegister($this->g, $m);
|
||||||
|
$this->g->getEntityManager()->persist($m);
|
||||||
|
|
||||||
|
$this->g->getEntityManager()->flush();
|
||||||
|
$em->commit();
|
||||||
|
return;
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$em->rollBack();
|
||||||
|
$em->clear();
|
||||||
|
|
||||||
|
$this->g->getLogger()->error("Calling {$class}::onRegister failed with exception: {$e->getMessage()}");
|
||||||
|
unset($m);
|
||||||
|
|
||||||
|
// Propagate the exception.
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +162,7 @@ class ModuleManager
|
|||||||
* @param string $library
|
* @param string $library
|
||||||
* @return Module
|
* @return Module
|
||||||
*/
|
*/
|
||||||
public function getModule(string $library): ModuleModel
|
public function getModule(string $library): ?ModuleModel
|
||||||
{
|
{
|
||||||
return $this->g->getEntityManager()->getRepository(ModuleModel::class)->find($library);
|
return $this->g->getEntityManager()->getRepository(ModuleModel::class)->find($library);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core;
|
||||||
|
|
||||||
|
use LotGD\Core\Exceptions\PermissionIdNotFoundException;
|
||||||
|
use LotGD\Core\Models\Actor;
|
||||||
|
use LotGD\Core\Models\PermissionableInterface;
|
||||||
|
use LotGD\Core\Models\Permission;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The PermissionManager manages (checks and manipulates) permissions of actors.
|
||||||
|
*
|
||||||
|
* The PermissionManager class provides methods to work with permissions and is
|
||||||
|
* the only way to check and manipulate permissions. It can be used to create or
|
||||||
|
* delete permissions, to remove, allow or deny permissions to actors and to
|
||||||
|
* check whether an actor has a certain permission or if it is explicitly
|
||||||
|
* denied to him.
|
||||||
|
*
|
||||||
|
* The wording used in this class is:
|
||||||
|
* - allowed, the actor has a certain permission in the allowed state.
|
||||||
|
* - denied, the actor has a certain permission in the denied state.
|
||||||
|
*
|
||||||
|
* To make this more clear, the following table summarizes how different methods
|
||||||
|
* react.
|
||||||
|
*
|
||||||
|
* Method
|
||||||
|
* State: | Unset | Allowed | Denied
|
||||||
|
* -------------------+-------+---------+---------
|
||||||
|
* isAllowed | False | True | False
|
||||||
|
* isDenied | False | False | True
|
||||||
|
* hasPermissionSet | False | True | True
|
||||||
|
*/
|
||||||
|
class PermissionManager
|
||||||
|
{
|
||||||
|
const Allowed = 1;
|
||||||
|
const Denied = -1;
|
||||||
|
|
||||||
|
const Superuser = "lotgd/core/superuser";
|
||||||
|
const AddScenes = "lotgd/core/scene/add";
|
||||||
|
const EditScenes = "lotgd/core/scene/edit";
|
||||||
|
const DeleteScenes = "lotgd/core/scene/delete";
|
||||||
|
const AddCharacters = "lotgd/core/characters/add";
|
||||||
|
const EditCharacters = "lotgd/core/characters/edit";
|
||||||
|
const DeleteCharacters = "lotgd/core/characters/delete";
|
||||||
|
|
||||||
|
private $game;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a permission manager.
|
||||||
|
* @param Game $g The game.
|
||||||
|
*/
|
||||||
|
public function __construct(Game $game)
|
||||||
|
{
|
||||||
|
$this->game = $game;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an actor has a permission set. No assumption can be made if it's allowed or denied.
|
||||||
|
* @param \LotGD\Core\PermissionableInterface $actor
|
||||||
|
* @param string $permissionId
|
||||||
|
* @return bool True if the permission has been set, be it allowed or denied.
|
||||||
|
*/
|
||||||
|
public function hasPermissionSet(
|
||||||
|
Actor $actor,
|
||||||
|
string $permissionId
|
||||||
|
): bool {
|
||||||
|
if ($actor->hasPermissionSet($permissionId)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an actor is allowed a given permission.
|
||||||
|
* @param \LotGD\Core\PermissionableInterface $actor
|
||||||
|
* @param string $permissionId
|
||||||
|
* @return bool True if the actor has the permission set and it's state is allowed.
|
||||||
|
*/
|
||||||
|
public function isAllowed(
|
||||||
|
Actor $actor,
|
||||||
|
string $permissionId
|
||||||
|
): bool {
|
||||||
|
if ($actor->hasPermissionSet($permissionId)) {
|
||||||
|
return $actor->getPermission($permissionId)->checkState(static::Allowed);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an actor is denied a given permission.
|
||||||
|
* @param \LotGD\Core\PermissionableInterface $actor
|
||||||
|
* @param string $permissionId
|
||||||
|
* @return bool True if the actor has the permission set and it's state is denied.
|
||||||
|
*/
|
||||||
|
public function isDenied(
|
||||||
|
Actor $actor,
|
||||||
|
string $permissionId
|
||||||
|
): bool {
|
||||||
|
if ($actor->hasPermissionSet($permissionId)) {
|
||||||
|
return $actor->getPermission($permissionId)->checkState(static::Denied);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a permission entity from the database by a permission id.
|
||||||
|
* @param string $permissionId
|
||||||
|
* @return Permission
|
||||||
|
* @throws PermissionIdNotFoundException
|
||||||
|
*/
|
||||||
|
private function findPermission(string $permissionId): Permission
|
||||||
|
{
|
||||||
|
$em = $this->game->getEntityManager();
|
||||||
|
$result = $em->getRepository(Permission::class)->find($permissionId);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
return $result;
|
||||||
|
} else {
|
||||||
|
throw new PermissionIdNotFoundException("Permission {$permissionId} was not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows an actor a permission given by the permission id.
|
||||||
|
* @param PermissionableInterface $actor
|
||||||
|
* @param string $permissionId
|
||||||
|
*/
|
||||||
|
public function allow(
|
||||||
|
Actor $actor,
|
||||||
|
string $permissionId
|
||||||
|
) {
|
||||||
|
if ($actor->hasPermissionSet($permissionId)) {
|
||||||
|
if ($this->isAllowed($actor, $permissionId) == false) {
|
||||||
|
$permission = $actor->getPermission($permissionId);
|
||||||
|
$permission->setState(static::Allowed);
|
||||||
|
|
||||||
|
$name = $actor->getActorName();
|
||||||
|
$this->game->getLogger()->debug("Granting permission {$permissionId} to {$name} (from denied).");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$permission = $this->findPermission($permissionId);
|
||||||
|
$actor->addPermission($permission, static::Allowed);
|
||||||
|
|
||||||
|
$name = $actor->getActorName();
|
||||||
|
$this->game->getLogger()->debug("Granting permission {$permissionId} to {$name} (from nothing).");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denies an actor a permission given by the permission id.
|
||||||
|
* @param PermissionableInterface $actor
|
||||||
|
* @param string $permissionId
|
||||||
|
*/
|
||||||
|
public function deny(
|
||||||
|
Actor $actor,
|
||||||
|
string $permissionId
|
||||||
|
) {
|
||||||
|
if ($actor->hasPermissionSet($permissionId)) {
|
||||||
|
if ($this->isDenied($actor, $permissionId) == false) {
|
||||||
|
$permission = $actor->getPermission($permissionId);
|
||||||
|
$permission->setState(static::Denied);
|
||||||
|
|
||||||
|
$name = $actor->getActorName();
|
||||||
|
$this->game->getLogger()->debug("Denying permission {$permissionId} from {$name} (from allowed).");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$permission = $this->findPermission($permissionId);
|
||||||
|
$actor->addPermission($permission, static::Denied);
|
||||||
|
|
||||||
|
$name = $actor->getActorName();
|
||||||
|
$this->game->getLogger()->debug("Denying permission {$permissionId} from {$name} (from nothing).");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a permission from an actor.
|
||||||
|
* @param PermissionableInterface $actor
|
||||||
|
* @param string $permissionId
|
||||||
|
*/
|
||||||
|
public function remove(
|
||||||
|
Actor $actor,
|
||||||
|
string $permissionId
|
||||||
|
) {
|
||||||
|
if ($actor->hasPermissionSet($permissionId)) {
|
||||||
|
$permissionAssoc = $actor->getPermission($permissionId);
|
||||||
|
$actor->removePermission($permissionId);
|
||||||
|
|
||||||
|
$name = $actor->getActorName();
|
||||||
|
$this->game->getLogger()->debug("Removing permission {$permissionId} from {$name}).");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
-16
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
namespace LotGD\Core;
|
namespace LotGD\Core;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
|
use LotGD\Core\Exceptions\ArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configurable way to convert back and forth between real time and game time.
|
* Configurable way to convert back and forth between real time and game time.
|
||||||
@@ -22,18 +23,33 @@ class TimeKeeper
|
|||||||
private $secondsPerGameMinute;
|
private $secondsPerGameMinute;
|
||||||
private $secondsPerGameSecond;
|
private $secondsPerGameSecond;
|
||||||
|
|
||||||
|
private $now;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a TimeKeeper with required configuration.
|
* Construct a TimeKeeper with required configuration.
|
||||||
* @param DateTime $gameEpoch When in real time is game day 0.
|
* @param DateTime $gameEpoch When in real time is game day 0.
|
||||||
|
* @param DateTime $now The current time.
|
||||||
* @param int $gameOffsetSeconds How many seconds from midnight on the epoch should the first game day start.
|
* @param int $gameOffsetSeconds How many seconds from midnight on the epoch should the first game day start.
|
||||||
* @param int $gameDaysPerDay How many game days are in one real day.
|
* @param int $gameDaysPerDay How many game days are in one real day.
|
||||||
*/
|
*/
|
||||||
public function __construct(DateTime $gameEpoch, int $gameOffsetSeconds, int $gameDaysPerDay)
|
public function __construct(
|
||||||
{
|
DateTime $gameEpoch,
|
||||||
|
DateTime $now,
|
||||||
|
int $gameOffsetSeconds,
|
||||||
|
int $gameDaysPerDay
|
||||||
|
) {
|
||||||
$gameEpochCopy = clone($gameEpoch);
|
$gameEpochCopy = clone($gameEpoch);
|
||||||
$this->adjustedEpoch = $gameEpochCopy->add(
|
|
||||||
$this->interval(0, 0, 0, 0, $gameOffsetSeconds)
|
if ($gameOffsetSeconds < 0) {
|
||||||
);
|
$this->adjustedEpoch = $gameEpochCopy->sub(
|
||||||
|
$this->interval(0, 0, 0, 0, $gameOffsetSeconds*-1)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->adjustedEpoch = $gameEpochCopy->add(
|
||||||
|
$this->interval(0, 0, 0, 0, $gameOffsetSeconds)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$this->theBeginning = new DateTime("0000-01-01 UTC");
|
$this->theBeginning = new DateTime("0000-01-01 UTC");
|
||||||
|
|
||||||
$this->secondsPerGameDay = (float) $this->secondsPerDay / $gameDaysPerDay;
|
$this->secondsPerGameDay = (float) $this->secondsPerDay / $gameDaysPerDay;
|
||||||
@@ -41,19 +57,23 @@ class TimeKeeper
|
|||||||
$this->secondsPerGameHour = $this->secondsPerGameDay / 24;
|
$this->secondsPerGameHour = $this->secondsPerGameDay / 24;
|
||||||
$this->secondsPerGameMinute = $this->secondsPerGameHour / 60;
|
$this->secondsPerGameMinute = $this->secondsPerGameHour / 60;
|
||||||
$this->secondsPerGameSecond = $this->secondsPerGameMinute / 60;
|
$this->secondsPerGameSecond = $this->secondsPerGameMinute / 60;
|
||||||
|
|
||||||
|
$this->now = $now;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a user who is interating with the game now and last
|
* Returns whether a user who is interating with the game now and last
|
||||||
* interacted at $lastInteractionTime should experience a New Day event.
|
* interacted at $lastInteractionTime should experience a New Day event.
|
||||||
* @param DateTime $lastInteractionTime
|
* @param DateTime|null $lastInteractionTime
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isNewDay(DateTime $lastInteractionTime): bool
|
public function isNewDay(?DateTime $lastInteractionTime): bool
|
||||||
{
|
{
|
||||||
if ($lastInteractionTime == null) {
|
if ($lastInteractionTime == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$t1 = $this->gameTime();
|
|
||||||
|
$t1 = $this->getGameTime();
|
||||||
$t2 = $this->convertToGameTime($lastInteractionTime);
|
$t2 = $this->convertToGameTime($lastInteractionTime);
|
||||||
$d1 = $t1->format("Y-m-d");
|
$d1 = $t1->format("Y-m-d");
|
||||||
$d2 = $t2->format("Y-m-d");
|
$d2 = $t2->format("Y-m-d");
|
||||||
@@ -65,9 +85,9 @@ class TimeKeeper
|
|||||||
* Return the current game time.
|
* Return the current game time.
|
||||||
* @return DateTime
|
* @return DateTime
|
||||||
*/
|
*/
|
||||||
public function gameTime(): DateTime
|
public function getGameTime(): DateTime
|
||||||
{
|
{
|
||||||
return $this->convertToGameTime(new DateTime());
|
return $this->convertToGameTime($this->now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,9 +95,7 @@ class TimeKeeper
|
|||||||
* @param DateTime $time Game time to convert.
|
* @param DateTime $time Game time to convert.
|
||||||
* @return DateTime Real time corresponding to game time $time.
|
* @return DateTime Real time corresponding to game time $time.
|
||||||
*/
|
*/
|
||||||
public function convertFromGameTime(
|
public function convertFromGameTime(DateTime $time): DateTime {
|
||||||
DateTime $time
|
|
||||||
): DateTime {
|
|
||||||
// Game dates are in the distant past, better not use getTimestamp().
|
// Game dates are in the distant past, better not use getTimestamp().
|
||||||
$i = $this->theBeginning->diff($time);
|
$i = $this->theBeginning->diff($time);
|
||||||
|
|
||||||
@@ -96,9 +114,7 @@ class TimeKeeper
|
|||||||
* @param DateTime $time Real time to convert.
|
* @param DateTime $time Real time to convert.
|
||||||
* @return DateTime Game time corresponding to real time $time.
|
* @return DateTime Game time corresponding to real time $time.
|
||||||
*/
|
*/
|
||||||
public function convertToGameTime(
|
public function convertToGameTime(DateTime $time): DateTime {
|
||||||
DateTime $time
|
|
||||||
): DateTime {
|
|
||||||
$timeUnix = $time->getTimestamp();
|
$timeUnix = $time->getTimestamp();
|
||||||
$epochUnix = $this->adjustedEpoch->getTimestamp();
|
$epochUnix = $this->adjustedEpoch->getTimestamp();
|
||||||
|
|
||||||
|
|||||||
@@ -28,19 +28,21 @@ trait AutoScaleFighter
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the attack value based on the fighter's level
|
* Returns the attack value based on the fighter's level
|
||||||
|
* @param bool $ignoreBuffs
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getAttack(Game $game, bool $ignoreBuffs = false): int
|
public function getAttack(bool $ignoreBuffs = false): int
|
||||||
{
|
{
|
||||||
$level = $this->getLevel();
|
$level = $this->getLevel();
|
||||||
return (int)$level * 2 - 1;
|
return (int)$level * 2 - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the defense value based on the fighter's level
|
* Returns the defense value based on the fighter's level
|
||||||
|
* @param bool $ignoreBuffs
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getDefense(Game $game, bool $ignoreBuffs = false): int
|
public function getDefense(bool $ignoreBuffs = false): int
|
||||||
{
|
{
|
||||||
$level = $this->getlevel();
|
$level = $this->getlevel();
|
||||||
return (int)floor($level*1.45);
|
return (int)floor($level*1.45);
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Tools\Model;
|
||||||
|
|
||||||
|
use LotGD\Core\ModelExtender;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trait to add the __call class required for extendable models.
|
||||||
|
* @package LotGD\Core\Tools\Model
|
||||||
|
*/
|
||||||
|
trait ExtendableModel
|
||||||
|
{
|
||||||
|
public function __call($method, $arguments)
|
||||||
|
{
|
||||||
|
$callback = ModelExtender::get(self::class, $method);
|
||||||
|
|
||||||
|
if ($callback) {
|
||||||
|
return call_user_func_array($callback, array_merge([$this], $arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Tools\Model;
|
||||||
|
|
||||||
|
|
||||||
|
use LotGD\Core\Game;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper trait to implement public setGame from GameAwareInterface and private getGame for internal use.
|
||||||
|
* @package LotGD\Core\Tools\Model
|
||||||
|
*/
|
||||||
|
trait GameAware
|
||||||
|
{
|
||||||
|
private $game;
|
||||||
|
|
||||||
|
public function setGame(Game $game) {
|
||||||
|
$this->game = $game;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGame(): Game {
|
||||||
|
return $this->game;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ use LotGD\Core\{
|
|||||||
};
|
};
|
||||||
use LotGD\Core\Exceptions\IsNullException;
|
use LotGD\Core\Exceptions\IsNullException;
|
||||||
use LotGD\Core\Models\Viewpoint;
|
use LotGD\Core\Models\Viewpoint;
|
||||||
|
use Ramsey\Uuid\UuidInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides basic implementation to mock CharacterInterface.
|
* Provides basic implementation to mock CharacterInterface.
|
||||||
@@ -21,7 +22,7 @@ trait MockCharacter
|
|||||||
throw new IsNullException();
|
throw new IsNullException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId(): int
|
public function getId(): UuidInterface
|
||||||
{
|
{
|
||||||
throw new IsNullException();
|
throw new IsNullException();
|
||||||
}
|
}
|
||||||
@@ -71,12 +72,12 @@ trait MockCharacter
|
|||||||
throw new IsNullException();
|
throw new IsNullException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAttack(Game $game, bool $ignoreBuffs = false): int
|
public function getAttack(bool $ignoreBuffs = false): int
|
||||||
{
|
{
|
||||||
throw new IsNullException();
|
throw new IsNullException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDefense(Game $game, bool $ignoreBuffs = false): int
|
public function getDefense(bool $ignoreBuffs = false): int
|
||||||
{
|
{
|
||||||
throw new IsNullException();
|
throw new IsNullException();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Tools\Model;
|
||||||
|
|
||||||
|
use LotGD\Core\Models\Actor;
|
||||||
|
use LotGD\Core\Models\Permission;
|
||||||
|
use LotGD\Core\Models\PermissionableInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tools to work with a permission type field.
|
||||||
|
*/
|
||||||
|
trait PermissionAssociationable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Id @ManyToOne(targetEntity="LotGD\Core\Models\Permission", inversedBy="permission")
|
||||||
|
* @JoinColumn(name="permission", referencedColumnName="id")
|
||||||
|
*/
|
||||||
|
protected $permission;
|
||||||
|
/** @Column(type="integer") */
|
||||||
|
protected $permissionState;
|
||||||
|
|
||||||
|
public function __construct(Actor $owner, Permission $permission, int $state) {
|
||||||
|
$this->owner = $owner;
|
||||||
|
$this->permission = $permission;
|
||||||
|
$this->permissionState = $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current state of the permission.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getState(): int
|
||||||
|
{
|
||||||
|
return $this->permissionState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current state of the permission.
|
||||||
|
* @param int $state
|
||||||
|
*/
|
||||||
|
public function setState(int $state)
|
||||||
|
{
|
||||||
|
$this->permissionState = $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this permission is set to a given state.
|
||||||
|
* @param int $state
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function checkState(int $state): bool
|
||||||
|
{
|
||||||
|
return $this->permissionState == $state ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the permission id.
|
||||||
|
* @see Permission->getId()
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getId(): string
|
||||||
|
{
|
||||||
|
return $this->permission->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the permission library.
|
||||||
|
* @see Permission->getLibrary()
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLibrary(): string
|
||||||
|
{
|
||||||
|
return $this->permission->getLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Permission entity.
|
||||||
|
* @return Permission
|
||||||
|
*/
|
||||||
|
public function getPermission(): Permission
|
||||||
|
{
|
||||||
|
return $this->permission;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,10 @@ trait PropertyManager
|
|||||||
{
|
{
|
||||||
private $propertyStorage = null;
|
private $propertyStorage = null;
|
||||||
|
|
||||||
public function loadProperties()
|
/**
|
||||||
|
* Loads properties
|
||||||
|
*/
|
||||||
|
public function loadProperties(): void
|
||||||
{
|
{
|
||||||
if ($this->propertyStorage !== null) {
|
if ($this->propertyStorage !== null) {
|
||||||
return;
|
return;
|
||||||
@@ -21,6 +24,12 @@ trait PropertyManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a property with its stored type.
|
||||||
|
* @param string $name
|
||||||
|
* @param mixed $default
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
public function getProperty(string $name, $default = null)
|
public function getProperty(string $name, $default = null)
|
||||||
{
|
{
|
||||||
$this->loadProperties();
|
$this->loadProperties();
|
||||||
@@ -32,7 +41,11 @@ trait PropertyManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function unsetProperty(string $name)
|
/**
|
||||||
|
* Deletes a property.
|
||||||
|
* @param string $name
|
||||||
|
*/
|
||||||
|
public function unsetProperty(string $name): void
|
||||||
{
|
{
|
||||||
$this->loadProperties();
|
$this->loadProperties();
|
||||||
|
|
||||||
@@ -43,14 +56,23 @@ trait PropertyManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setProperty(string $name, $value)
|
/**
|
||||||
|
* Sets a property to a given value
|
||||||
|
* @param string $name
|
||||||
|
* @param mixed $value
|
||||||
|
*/
|
||||||
|
public function setProperty(string $name, $value): void
|
||||||
{
|
{
|
||||||
$this->loadProperties();
|
$this->loadProperties();
|
||||||
|
|
||||||
if (isset($this->propertyStorage[$name])) {
|
if (isset($this->propertyStorage[$name])) {
|
||||||
$this->propertyStorage[$name]->setValue($value);
|
$this->propertyStorage[$name]->setValue($value);
|
||||||
} else {
|
} else {
|
||||||
$className = $this->properties->getTypeClass()->name;
|
if (isset($this->propertyClass)) {
|
||||||
|
$className = $this->propertyClass;
|
||||||
|
} else {
|
||||||
|
$className = $this->properties->getTypeClass()->name;
|
||||||
|
}
|
||||||
$property = new $className();
|
$property = new $className();
|
||||||
if (method_exists($property, "setOwner")) {
|
if (method_exists($property, "setOwner")) {
|
||||||
$property->setOwner($this);
|
$property->setOwner($this);
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace LotGD\Core\Tools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstracts a scene description and provides tools to modify the text more easily.
|
||||||
|
* Class SceneDescription
|
||||||
|
* @package LotGD\Core\Tools
|
||||||
|
*/
|
||||||
|
class SceneDescription
|
||||||
|
{
|
||||||
|
private $description = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SceneDescription constructor.
|
||||||
|
* @param string $description
|
||||||
|
*/
|
||||||
|
public function __construct(string $description)
|
||||||
|
{
|
||||||
|
$this->description = $this->splitIntoParagraphs($description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the description to a string
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return $this->getDescriptionBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the description to a string.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDescriptionBack(): string
|
||||||
|
{
|
||||||
|
return implode("\n\n", $this->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a paragraph to the description. If the paragraph contains \n\n, it gets broken into multiple paragraphs first.
|
||||||
|
* @param string $paragraph
|
||||||
|
*/
|
||||||
|
public function addParagraph(string $paragraph): void
|
||||||
|
{
|
||||||
|
$paragraph = $this->splitIntoParagraphs($paragraph);
|
||||||
|
$this->description = array_merge($this->description, $paragraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits a given string into an array ("paragraphs")
|
||||||
|
*
|
||||||
|
* This method takes a string, normalizes line ends and then splits it at every double line break (\n\n).
|
||||||
|
* @param string $input
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function splitIntoParagraphs(string $input): array
|
||||||
|
{
|
||||||
|
$input = str_replace("\r\n", "\n", $input);
|
||||||
|
$input = str_replace("\r", "\n", $input);
|
||||||
|
|
||||||
|
$parts = explode("\n\n", $input);
|
||||||
|
foreach ($parts as $key => $part) {
|
||||||
|
if (strlen($part) === 0) {
|
||||||
|
unset($parts[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parts;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash -ex
|
#!/bin/bash -ex
|
||||||
phpunit
|
./vendor/bin/phpunit --stop-on-failure
|
||||||
./vendor/bin/phpdoccheck -d src --no-ansi
|
./vendor/bin/phpdoccheck -d src --no-ansi
|
||||||
|
|||||||
+77
-32
@@ -5,6 +5,7 @@ namespace LotGD\Core\Tests\Models;
|
|||||||
|
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
|
||||||
|
use Doctrine\Common\Util\Debug;
|
||||||
use LotGD\Core\{
|
use LotGD\Core\{
|
||||||
Battle,
|
Battle,
|
||||||
DiceBag,
|
DiceBag,
|
||||||
@@ -25,6 +26,9 @@ use LotGD\Core\Models\BattleEvents\{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use LotGD\Core\Tests\CoreModelTestCase;
|
use LotGD\Core\Tests\CoreModelTestCase;
|
||||||
|
use Ramsey\Uuid\Codec\OrderedTimeCodec;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
use Ramsey\Uuid\UuidFactory;
|
||||||
|
|
||||||
class BattleTest extends CoreModelTestCase
|
class BattleTest extends CoreModelTestCase
|
||||||
{
|
{
|
||||||
@@ -33,6 +37,7 @@ class BattleTest extends CoreModelTestCase
|
|||||||
|
|
||||||
public function getMockGame(Character $character): Game
|
public function getMockGame(Character $character): Game
|
||||||
{
|
{
|
||||||
|
mt_srand(0);
|
||||||
$game = $this->getMockBuilder(Game::class)
|
$game = $this->getMockBuilder(Game::class)
|
||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
->getMock();
|
->getMock();
|
||||||
@@ -51,13 +56,13 @@ class BattleTest extends CoreModelTestCase
|
|||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
|
||||||
$character = $em->getRepository(Character::class)->find(1);
|
$character = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$monster = $em->getRepository(Monster::class)->find(1);
|
$monster = $em->getRepository(Monster::class)->find("de84c507-9673-44e7-b665-9e43416b9c2f");
|
||||||
|
|
||||||
$this->assertSame(5, $monster->getLevel());
|
$this->assertSame(5, $monster->getLevel());
|
||||||
$this->assertSame(52, $monster->getMaxHealth());
|
$this->assertSame(52, $monster->getMaxHealth());
|
||||||
$this->assertSame(9, $monster->getAttack($this->getMockGame($character)));
|
$this->assertSame(9, $monster->getAttack());
|
||||||
$this->assertSame(7, $monster->getDefense($this->getMockGame($character)));
|
$this->assertSame(7, $monster->getDefense());
|
||||||
$this->assertSame($monster->getMaxHealth(), $monster->getHealth());
|
$this->assertSame($monster->getMaxHealth(), $monster->getHealth());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,11 +73,14 @@ class BattleTest extends CoreModelTestCase
|
|||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
|
||||||
$character = $em->getRepository(Character::class)->find(1);
|
$character = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$monster = $em->getRepository(Monster::class)->find(1);
|
$monster = $em->getRepository(Monster::class)->find("de84c507-9673-44e7-b665-9e43416b9c2f");
|
||||||
|
|
||||||
$battle = new Battle($this->getMockGame($character), $character, $monster);
|
$battle = new Battle($this->getMockGame($character), $character, $monster);
|
||||||
|
|
||||||
|
$this->assertSame($character, $battle->getPlayer());
|
||||||
|
$this->assertSame($monster, $battle->getMonster());
|
||||||
|
|
||||||
for ($n = 0; $n < 99; $n++) {
|
for ($n = 0; $n < 99; $n++) {
|
||||||
$oldPlayerHealth = $character->getHealth();
|
$oldPlayerHealth = $character->getHealth();
|
||||||
$oldMonsterHealth = $monster->getHealth();
|
$oldMonsterHealth = $monster->getHealth();
|
||||||
@@ -85,12 +93,49 @@ class BattleTest extends CoreModelTestCase
|
|||||||
if ($battle->isOver()) {
|
if ($battle->isOver()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($battle->getEvents() as $event) {
|
||||||
|
$this->assertNotNull($event->decorate($this->getMockGame($character)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->assertTrue($battle->isOver());
|
$this->assertTrue($battle->isOver());
|
||||||
$this->assertTrue($character->isAlive() xor $monster->isAlive());
|
$this->assertTrue($character->isAlive() xor $monster->isAlive());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if a fight can happen if it is serialized between each round.
|
||||||
|
*/
|
||||||
|
public function testFairBattleWithSerializationBetweenRounds()
|
||||||
|
{
|
||||||
|
$em = $this->getEntityManager();
|
||||||
|
|
||||||
|
$character = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
|
$monster = $em->getRepository(Monster::class)->find("de84c507-9673-44e7-b665-9e43416b9c2f");
|
||||||
|
|
||||||
|
$battle = new Battle($this->getMockGame($character), $character, $monster);
|
||||||
|
$battle = $battle->serialize();
|
||||||
|
|
||||||
|
for ($n = 0; $n < 99; $n++) {
|
||||||
|
$battle = Battle::unserialize($this->getMockGame($character), $character, $battle);
|
||||||
|
|
||||||
|
$battle->fightNRounds(1);
|
||||||
|
|
||||||
|
if ($battle->isOver()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($battle->getEvents() as $event) {
|
||||||
|
$this->assertNotNull($event->decorate($this->getMockGame($character)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$battle = $battle->serialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertTrue($battle->isOver());
|
||||||
|
$this->assertTrue($battle->getPlayer()->isAlive() xor $battle->getMonster()->isAlive());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests a fight which the player has to win (lvl 100 vs lvl 1)
|
* Tests a fight which the player has to win (lvl 100 vs lvl 1)
|
||||||
*/
|
*/
|
||||||
@@ -98,8 +143,8 @@ class BattleTest extends CoreModelTestCase
|
|||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
|
||||||
$highLevelPlayer = $em->getRepository(Character::class)->find(2);
|
$highLevelPlayer = $em->getRepository(Character::class)->find("4d01c29b-d825-4bc7-9e6e-63525155fd37");
|
||||||
$lowLevelMonster = $em->getRepository(Monster::class)->find(3);
|
$lowLevelMonster = $em->getRepository(Monster::class)->find("c004bcb6-a7c1-4f9a-abc2-1711c64e23a0");
|
||||||
|
|
||||||
$battle = new Battle($this->getMockGame($highLevelPlayer), $highLevelPlayer, $lowLevelMonster);
|
$battle = new Battle($this->getMockGame($highLevelPlayer), $highLevelPlayer, $lowLevelMonster);
|
||||||
|
|
||||||
@@ -131,8 +176,8 @@ class BattleTest extends CoreModelTestCase
|
|||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
|
||||||
$lowLevelPlayer = $em->getRepository(Character::class)->find(3);
|
$lowLevelPlayer = $em->getRepository(Character::class)->find("c3792b61-4e34-4710-9871-65a68ac30bb4");
|
||||||
$highLevelMonster = $em->getRepository(Monster::class)->find(2);
|
$highLevelMonster = $em->getRepository(Monster::class)->find("b636df29-f72d-4e2d-9850-982e783a9e94");
|
||||||
|
|
||||||
$battle = new Battle($this->getMockGame($lowLevelPlayer), $lowLevelPlayer, $highLevelMonster);
|
$battle = new Battle($this->getMockGame($lowLevelPlayer), $lowLevelPlayer, $highLevelMonster);
|
||||||
|
|
||||||
@@ -164,8 +209,8 @@ class BattleTest extends CoreModelTestCase
|
|||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
|
||||||
$character = $em->getRepository(Character::class)->find(1);
|
$character = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$monster = $em->getRepository(Monster::class)->find(1);
|
$monster = $em->getRepository(Monster::class)->find("de84c507-9673-44e7-b665-9e43416b9c2f");
|
||||||
|
|
||||||
$battle = new Battle($this->getMockGame($character), $character, $monster);
|
$battle = new Battle($this->getMockGame($character), $character, $monster);
|
||||||
|
|
||||||
@@ -179,8 +224,8 @@ class BattleTest extends CoreModelTestCase
|
|||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
|
||||||
$character = $em->getRepository(Character::class)->find(1);
|
$character = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$monster = $em->getRepository(Monster::class)->find(1);
|
$monster = $em->getRepository(Monster::class)->find("de84c507-9673-44e7-b665-9e43416b9c2f");
|
||||||
|
|
||||||
$battle = new Battle($this->getMockGame($character), $character, $monster);
|
$battle = new Battle($this->getMockGame($character), $character, $monster);
|
||||||
|
|
||||||
@@ -195,8 +240,8 @@ class BattleTest extends CoreModelTestCase
|
|||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
|
||||||
$character = $em->getRepository(Character::class)->find(1);
|
$character = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$monster = $em->getRepository(Monster::class)->find(1);
|
$monster = $em->getRepository(Monster::class)->find("de84c507-9673-44e7-b665-9e43416b9c2f");
|
||||||
|
|
||||||
$battle = new Battle($this->getMockGame($character), $character, $monster);
|
$battle = new Battle($this->getMockGame($character), $character, $monster);
|
||||||
|
|
||||||
@@ -216,23 +261,23 @@ class BattleTest extends CoreModelTestCase
|
|||||||
default:
|
default:
|
||||||
case 0:
|
case 0:
|
||||||
// Fair Battle
|
// Fair Battle
|
||||||
$character = $em->getRepository(Character::class)->find(1);
|
$character = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$monster = $em->getRepository(Monster::class)->find(1);
|
$monster = $em->getRepository(Monster::class)->find("de84c507-9673-44e7-b665-9e43416b9c2f");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// very long battle
|
// very long battle
|
||||||
$character = $em->getRepository(Character::class)->find(4);
|
$character = $em->getRepository(Character::class)->find("6565b418-55f5-4a6b-8d92-a9ef81329912");
|
||||||
$monster = $em->getRepository(Monster::class)->find(3);
|
$monster = $em->getRepository(Monster::class)->find("c004bcb6-a7c1-4f9a-abc2-1711c64e23a0");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
// player should win battle
|
// player should win battle
|
||||||
$character = $em->getRepository(Character::class)->find(13);
|
$character = $em->getRepository(Character::class)->find("1a9f63f2-3006-4e12-b272-4fd6be518a93");
|
||||||
$monster = $em->getRepository(Monster::class)->find(11);
|
$monster = $em->getRepository(Monster::class)->find("7ca9c141-aaf8-44a5-9d04-b6f9923f3c66");
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
// player should lose battle
|
// player should lose battle
|
||||||
$character = $em->getRepository(Character::class)->find(11);
|
$character = $em->getRepository(Character::class)->find("24d71c26-f915-401c-8b3e-1932edf650ce");
|
||||||
$monster = $em->getRepository(Monster::class)->find(13);
|
$monster = $em->getRepository(Monster::class)->find("09540b93-63c9-4d82-8501-f569f63dfc4c");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1187,8 +1232,8 @@ class BattleTest extends CoreModelTestCase
|
|||||||
$battle = $this->provideBuffBattleParticipants(new Buff([
|
$battle = $this->provideBuffBattleParticipants(new Buff([
|
||||||
"slot" => "test",
|
"slot" => "test",
|
||||||
"rounds" => 99,
|
"rounds" => 99,
|
||||||
"goodguyAttackModifier" => 2,
|
"goodguyAttackModifier" => 10,
|
||||||
"goodguyDefenseModifier" => 2,
|
"goodguyDefenseModifier" => 10,
|
||||||
"activateAt" => Buff::ACTIVATE_ROUNDSTART,
|
"activateAt" => Buff::ACTIVATE_ROUNDSTART,
|
||||||
]), 3);
|
]), 3);
|
||||||
|
|
||||||
@@ -1290,7 +1335,7 @@ class BattleTest extends CoreModelTestCase
|
|||||||
public function testBufflistGoodguyAttackModifier()
|
public function testBufflistGoodguyAttackModifier()
|
||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
$player = $em->getRepository(Character::class)->find(1);
|
$player = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$game = $this->getMockGame($player);
|
$game = $this->getMockGame($player);
|
||||||
|
|
||||||
$player->addBuff(new Buff([
|
$player->addBuff(new Buff([
|
||||||
@@ -1319,7 +1364,7 @@ class BattleTest extends CoreModelTestCase
|
|||||||
public function testBufflistGoodguyDefenseModifier()
|
public function testBufflistGoodguyDefenseModifier()
|
||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
$player = $em->getRepository(Character::class)->find(1);
|
$player = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$game = $this->getMockGame($player);
|
$game = $this->getMockGame($player);
|
||||||
|
|
||||||
$player->addBuff(new Buff([
|
$player->addBuff(new Buff([
|
||||||
@@ -1348,7 +1393,7 @@ class BattleTest extends CoreModelTestCase
|
|||||||
public function testBufflistGoodguyDamageModifier()
|
public function testBufflistGoodguyDamageModifier()
|
||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
$player = $em->getRepository(Character::class)->find(1);
|
$player = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$game = $this->getMockGame($player);
|
$game = $this->getMockGame($player);
|
||||||
|
|
||||||
$player->addBuff(new Buff([
|
$player->addBuff(new Buff([
|
||||||
@@ -1377,7 +1422,7 @@ class BattleTest extends CoreModelTestCase
|
|||||||
public function testBufflistBadguyAttackModifier()
|
public function testBufflistBadguyAttackModifier()
|
||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
$player = $em->getRepository(Character::class)->find(1);
|
$player = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$game = $this->getMockGame($player);
|
$game = $this->getMockGame($player);
|
||||||
|
|
||||||
$player->addBuff(new Buff([
|
$player->addBuff(new Buff([
|
||||||
@@ -1406,7 +1451,7 @@ class BattleTest extends CoreModelTestCase
|
|||||||
public function testBufflistBadguyDefenseModifier()
|
public function testBufflistBadguyDefenseModifier()
|
||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
$player = $em->getRepository(Character::class)->find(1);
|
$player = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$game = $this->getMockGame($player);
|
$game = $this->getMockGame($player);
|
||||||
|
|
||||||
$player->addBuff(new Buff([
|
$player->addBuff(new Buff([
|
||||||
@@ -1435,7 +1480,7 @@ class BattleTest extends CoreModelTestCase
|
|||||||
public function testBufflistBadguyDamageModifier()
|
public function testBufflistBadguyDamageModifier()
|
||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
$player = $em->getRepository(Character::class)->find(1);
|
$player = $em->getRepository(Character::class)->find("d363c077-234a-433d-834e-f1a1d3b281d8");
|
||||||
$game = $this->getMockGame($player);
|
$game = $this->getMockGame($player);
|
||||||
|
|
||||||
$player->addBuff(new Buff([
|
$player->addBuff(new Buff([
|
||||||
|
|||||||
@@ -89,4 +89,67 @@ class BootstrapTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertInternalType("string", $user->getName());
|
$this->assertInternalType("string", $user->getName());
|
||||||
$this->assertSame("Monthy", $user->getName());
|
$this->assertSame("Monthy", $user->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testIfGameAwareEntitiesHaveAGAmeInstanceAssociatedAfterLoading()
|
||||||
|
{
|
||||||
|
$installationManager = $this->getMockBuilder(InstallationManager::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods(["getInstallPath"])
|
||||||
|
->getMock();
|
||||||
|
$installationManager->method("getInstallPath")->willReturn(__DIR__ . "/FakeModule");
|
||||||
|
|
||||||
|
$composer = $this->getMockBuilder(\Composer\Composer::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods(["getInstallationManager"])
|
||||||
|
->getMock();
|
||||||
|
$composer->method("getInstallationManager")->willReturn($installationManager);
|
||||||
|
|
||||||
|
$fakeModulePackage = $this->getMockBuilder(AliasPackage::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods(["getType", "getAutoload"])
|
||||||
|
->getMock();
|
||||||
|
$fakeModulePackage->method("getType")->willReturn("lotgd-module");
|
||||||
|
$fakeModulePackage->method("getAutoload")->willReturn([
|
||||||
|
"psr-4" => [
|
||||||
|
"LotGD\\Core\\Tests\\FakeModule\\" => "FakeModule/"
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$composerManager = $this->getMockBuilder(ComposerManager::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods(["getPackages", "getComposer", "translateNamespaceToPath"])
|
||||||
|
->getMock();
|
||||||
|
$composerManager->method("getPackages")->willReturn([$fakeModulePackage]);
|
||||||
|
$composerManager->method("getComposer")->willReturn($composer);
|
||||||
|
$composerManager
|
||||||
|
->expects($this->exactly(1))
|
||||||
|
->method("translateNamespaceToPath")
|
||||||
|
->with("LotGD\\Core\\Tests\\FakeModule\\Models\\")
|
||||||
|
->willReturn(__DIR__ . "/FakeModule/Models");
|
||||||
|
|
||||||
|
$bootstrap = $this->getMockBuilder(Bootstrap::class)
|
||||||
|
->setMethods(["createComposerManager"])
|
||||||
|
->getMock();
|
||||||
|
$bootstrap->method("createComposerManager")->willReturn($composerManager);
|
||||||
|
|
||||||
|
// run tests
|
||||||
|
$game = $bootstrap->getGame(implode(DIRECTORY_SEPARATOR, [__DIR__, '..']));
|
||||||
|
|
||||||
|
// A freshly created user entity should not rely
|
||||||
|
$user = new UserEntity();
|
||||||
|
$user->setName("Testus");
|
||||||
|
$user->setGame($game);
|
||||||
|
|
||||||
|
$this->assertSame($game, $user->returnGame());
|
||||||
|
|
||||||
|
$game->getEntityManager()->persist($user);
|
||||||
|
$game->getEntityManager()->flush();
|
||||||
|
$id = $user->getId();
|
||||||
|
$this->assertInternalType("int", $id);
|
||||||
|
$game->getEntityManager()->clear();
|
||||||
|
$user = $game->getEntityManager()->getRepository(UserEntity::class)->find($id);
|
||||||
|
|
||||||
|
$this->assertSame($game, $user->returnGame());
|
||||||
|
$this->assertSame([$user->getName()], $user->getNameAsArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,4 +40,50 @@ class ComposerManagerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$namespace = 'LotGD\\NotFound';
|
$namespace = 'LotGD\\NotFound';
|
||||||
$this->assertNull($manager->translateNamespaceToPath($namespace));
|
$this->assertNull($manager->translateNamespaceToPath($namespace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testListPackageWithRootCwd()
|
||||||
|
{
|
||||||
|
$manager = new ComposerManager(implode(DIRECTORY_SEPARATOR, [__DIR__, '..']));
|
||||||
|
|
||||||
|
$packageCount = count($manager->getPackages());
|
||||||
|
|
||||||
|
$this->assertGreaterThan(1, $packageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testListPackageWithDifferentThanRootCwd()
|
||||||
|
{
|
||||||
|
$oldcwd = getcwd();
|
||||||
|
chdir($oldcwd . DIRECTORY_SEPARATOR . "tests");
|
||||||
|
|
||||||
|
$manager = new ComposerManager(implode(DIRECTORY_SEPARATOR, [__DIR__, '..']));
|
||||||
|
|
||||||
|
$packageCount = count($manager->getPackages());
|
||||||
|
|
||||||
|
$this->assertGreaterThan(1, $packageCount);
|
||||||
|
|
||||||
|
chdir($oldcwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetPackageByLibraryNameWithRootCwd()
|
||||||
|
{
|
||||||
|
$manager = new ComposerManager(implode(DIRECTORY_SEPARATOR, [__DIR__, '..']));
|
||||||
|
|
||||||
|
$package = $manager->getPackageForLibrary("composer/composer");
|
||||||
|
|
||||||
|
$this->assertSame("composer/composer", $package->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetPackageByLibraryNameWithDifferentThanRootCwd()
|
||||||
|
{
|
||||||
|
$oldcwd = getcwd();
|
||||||
|
chdir($oldcwd . DIRECTORY_SEPARATOR . "tests");
|
||||||
|
|
||||||
|
$manager = new ComposerManager(implode(DIRECTORY_SEPARATOR, [__DIR__, '..']));
|
||||||
|
|
||||||
|
$package = $manager->getPackageForLibrary("composer/composer");
|
||||||
|
|
||||||
|
$this->assertSame("composer/composer", $package->getName());
|
||||||
|
|
||||||
|
chdir($oldcwd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user