Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f2f77f7c8 | |||
| 27a5e359f2 | |||
| 53ad63db86 |
@@ -18,6 +18,7 @@
|
|||||||
"gedmo/doctrine-extensions": "^2.3|^3.0",
|
"gedmo/doctrine-extensions": "^2.3|^3.0",
|
||||||
"doctrine/orm": "^2.8",
|
"doctrine/orm": "^2.8",
|
||||||
"doctrine/common": "^3.0",
|
"doctrine/common": "^3.0",
|
||||||
|
"doctrine/dbal": "^2.12 <2.13",
|
||||||
"monolog/monolog": "^2.0",
|
"monolog/monolog": "^2.0",
|
||||||
"symfony/console": "^5.0",
|
"symfony/console": "^5.0",
|
||||||
"symfony/yaml": "^5.0",
|
"symfony/yaml": "^5.0",
|
||||||
|
|||||||
Generated
+194
-200
File diff suppressed because it is too large
Load Diff
+58
-1
@@ -3,13 +3,16 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core;
|
namespace LotGD\Core;
|
||||||
|
|
||||||
|
use LotGD\Core\Models\Viewpoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A representation of an action the user can take to affect the game
|
* A representation of an action the user can take to affect the game
|
||||||
* state. An encapsulation of a navigation menu option.
|
* state. An encapsulation of a navigation menu option.
|
||||||
*/
|
*/
|
||||||
class Action
|
class Action implements \Serializable
|
||||||
{
|
{
|
||||||
protected string $id;
|
protected string $id;
|
||||||
|
private ?Viewpoint $viewpoint = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new action with the specified Scene as its destination.
|
* Construct a new action with the specified Scene as its destination.
|
||||||
@@ -25,6 +28,41 @@ class Action
|
|||||||
$this->id = \bin2hex(\random_bytes(8));
|
$this->id = \bin2hex(\random_bytes(8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function serialize()
|
||||||
|
{
|
||||||
|
return serialize([
|
||||||
|
"id" => $this->id,
|
||||||
|
"destinationSceneId" => $this->destinationSceneId,
|
||||||
|
"title" => $this->title,
|
||||||
|
"parameters" => $this->parameters,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unserialize($serialized)
|
||||||
|
{
|
||||||
|
$data = unserialize($serialized);
|
||||||
|
$this->id = $data["id"];
|
||||||
|
$this->destinationSceneId = $data["destinationSceneId"];
|
||||||
|
$this->title = $data["title"];
|
||||||
|
$this->parameters = $data["parameters"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Viewpoint|null $viewpoint
|
||||||
|
*/
|
||||||
|
public function setViewpoint(?Viewpoint $viewpoint)
|
||||||
|
{
|
||||||
|
$this->viewpoint = $viewpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Viewpoint|null
|
||||||
|
*/
|
||||||
|
public function getViewpoint(): ?Viewpoint
|
||||||
|
{
|
||||||
|
return $this->viewpoint;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the unique, automatically generated identifier for this action.
|
* Returns the unique, automatically generated identifier for this action.
|
||||||
* Use this ID to refer to this action when calling Game::takeAction().
|
* Use this ID to refer to this action when calling Game::takeAction().
|
||||||
@@ -53,6 +91,25 @@ class Action
|
|||||||
return $this->title;
|
return $this->title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rendered action title.
|
||||||
|
* @return string|null
|
||||||
|
* @throws Exceptions\InsecureTwigTemplateError
|
||||||
|
*/
|
||||||
|
public function getRenderedTitle(): ?string
|
||||||
|
{
|
||||||
|
$title = $this->getTitle();
|
||||||
|
$sceneRenderer = $this->getViewpoint()?->getTwigSceneRenderer();
|
||||||
|
|
||||||
|
if (!$title) {
|
||||||
|
return null;
|
||||||
|
} elseif ($sceneRenderer) {
|
||||||
|
return $sceneRenderer->render($title, $this->viewpoint, ignoreErrors: true, templateValues: ["Action" => $this]);
|
||||||
|
} else {
|
||||||
|
return $title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string|null $title
|
* @param string|null $title
|
||||||
*/
|
*/
|
||||||
|
|||||||
+69
-2
@@ -3,15 +3,21 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace LotGD\Core;
|
namespace LotGD\Core;
|
||||||
|
|
||||||
|
use LotGD\Core\Models\Viewpoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A grouping of navigation actions, like a submenu.
|
* A grouping of navigation actions, like a submenu.
|
||||||
*/
|
*/
|
||||||
class ActionGroup implements \Countable
|
class ActionGroup implements \Countable, \Serializable
|
||||||
{
|
{
|
||||||
const DefaultGroup = 'lotgd/core/default';
|
const DefaultGroup = 'lotgd/core/default';
|
||||||
const HiddenGroup = 'lotgd/core/hidden';
|
const HiddenGroup = 'lotgd/core/hidden';
|
||||||
|
|
||||||
private $actions;
|
/**
|
||||||
|
* @var Action[]
|
||||||
|
*/
|
||||||
|
private array $actions;
|
||||||
|
private ?Viewpoint $viewpoint = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new ActionGroup, starting with an empty set of actions.
|
* Create a new ActionGroup, starting with an empty set of actions.
|
||||||
@@ -27,6 +33,45 @@ class ActionGroup implements \Countable
|
|||||||
$this->actions = [];
|
$this->actions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function serialize()
|
||||||
|
{
|
||||||
|
return serialize([
|
||||||
|
"id" => $this->id,
|
||||||
|
"title" => $this->title,
|
||||||
|
"actions" => $this->actions,
|
||||||
|
"sortKey" => $this->sortKey,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unserialize($serialized)
|
||||||
|
{
|
||||||
|
$data = unserialize($serialized);
|
||||||
|
$this->id = $data["id"];
|
||||||
|
$this->title = $data["title"];
|
||||||
|
$this->actions = $data["actions"];
|
||||||
|
$this->sortKey = $data["sortKey"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Viewpoint|null $viewpoint
|
||||||
|
*/
|
||||||
|
public function setViewpoint(?Viewpoint $viewpoint)
|
||||||
|
{
|
||||||
|
$this->viewpoint = $viewpoint;
|
||||||
|
|
||||||
|
foreach ($this->actions as $action) {
|
||||||
|
$action->setViewpoint($viewpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Viewpoint|null
|
||||||
|
*/
|
||||||
|
public function getViewpoint(): ?Viewpoint
|
||||||
|
{
|
||||||
|
return $this->viewpoint;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of registered Actions for this group.
|
* Returns the number of registered Actions for this group.
|
||||||
* @return int
|
* @return int
|
||||||
@@ -54,6 +99,23 @@ class ActionGroup implements \Countable
|
|||||||
return $this->title;
|
return $this->title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rendered title for this group.
|
||||||
|
* @return string
|
||||||
|
* @throws Exceptions\InsecureTwigTemplateError
|
||||||
|
*/
|
||||||
|
public function getRenderedTitle(): string
|
||||||
|
{
|
||||||
|
$title = $this->getTitle();
|
||||||
|
$sceneRenderer = $this->viewpoint?->getTwigSceneRenderer();
|
||||||
|
|
||||||
|
if ($sceneRenderer) {
|
||||||
|
return $sceneRenderer->render($title, $this->viewpoint, ignoreErrors: true);
|
||||||
|
} else {
|
||||||
|
return $title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the sort key for this group. The ordering of the groups in the
|
* Returns the sort key for this group. The ordering of the groups in the
|
||||||
* final menu displayed to users will be sorted by this key. The default
|
* final menu displayed to users will be sorted by this key. The default
|
||||||
@@ -80,6 +142,10 @@ class ActionGroup implements \Countable
|
|||||||
*/
|
*/
|
||||||
public function setActions(array $actions)
|
public function setActions(array $actions)
|
||||||
{
|
{
|
||||||
|
foreach ($actions as $action) {
|
||||||
|
$action->setViewpoint($this->viewpoint);
|
||||||
|
}
|
||||||
|
|
||||||
$this->actions = $actions;
|
$this->actions = $actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +155,7 @@ class ActionGroup implements \Countable
|
|||||||
*/
|
*/
|
||||||
public function addAction(Action $action)
|
public function addAction(Action $action)
|
||||||
{
|
{
|
||||||
|
$action->setViewpoint($this->viewpoint);
|
||||||
$this->actions[] = $action;
|
$this->actions[] = $action;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -288,6 +288,8 @@ class Game
|
|||||||
private function navigateToScene(Scene $scene, array $parameters)
|
private function navigateToScene(Scene $scene, array $parameters)
|
||||||
{
|
{
|
||||||
$viewpoint = $this->getCharacter()->getViewpoint();
|
$viewpoint = $this->getCharacter()->getViewpoint();
|
||||||
|
$viewpoint->setTwigSceneRenderer($this->getSceneRenderer());
|
||||||
|
|
||||||
do {
|
do {
|
||||||
$referrer = $viewpoint->getScene();
|
$referrer = $viewpoint->getScene();
|
||||||
|
|
||||||
@@ -296,7 +298,7 @@ class Game
|
|||||||
$this->getLogger()->debug("Navigating to sceneId={$id} from referrer sceneId={$referrerId}");
|
$this->getLogger()->debug("Navigating to sceneId={$id} from referrer sceneId={$referrerId}");
|
||||||
|
|
||||||
// Copy over the basic structure from the scene database.
|
// Copy over the basic structure from the scene database.
|
||||||
$viewpoint->changeFromScene($scene, $this->getSceneRenderer());
|
$viewpoint->changeFromScene($scene);
|
||||||
|
|
||||||
// Generate the default set of actions: the default group with
|
// Generate the default set of actions: the default group with
|
||||||
// all children.
|
// all children.
|
||||||
|
|||||||
+72
-12
@@ -41,10 +41,16 @@ class Viewpoint implements CreateableInterface
|
|||||||
*/
|
*/
|
||||||
private Character $owner;
|
private Character $owner;
|
||||||
|
|
||||||
/** @Column(type="array") */
|
/**
|
||||||
|
* @var ActionGroup[]
|
||||||
|
* @Column(type="array")
|
||||||
|
*/
|
||||||
private array $actionGroups = [];
|
private array $actionGroups = [];
|
||||||
|
|
||||||
/** @Column(type="array") */
|
/**
|
||||||
|
* @var Attachment[]
|
||||||
|
* @Column(type="array")
|
||||||
|
*/
|
||||||
private array $attachments = [];
|
private array $attachments = [];
|
||||||
|
|
||||||
/** @Column(type="array") */
|
/** @Column(type="array") */
|
||||||
@@ -57,6 +63,7 @@ class Viewpoint implements CreateableInterface
|
|||||||
private ?Scene $scene = null;
|
private ?Scene $scene = null;
|
||||||
|
|
||||||
private ?SceneDescription $_description = null;
|
private ?SceneDescription $_description = null;
|
||||||
|
private ?TwigSceneRenderer $twigSceneRenderer = null;
|
||||||
|
|
||||||
private static array $fillable = [
|
private static array $fillable = [
|
||||||
"owner",
|
"owner",
|
||||||
@@ -80,6 +87,22 @@ class Viewpoint implements CreateableInterface
|
|||||||
$this->owner = $owner;
|
$this->owner = $owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TwigSceneRenderer $twigSceneRenderer
|
||||||
|
*/
|
||||||
|
public function setTwigSceneRenderer(TwigSceneRenderer $twigSceneRenderer)
|
||||||
|
{
|
||||||
|
$this->twigSceneRenderer = $twigSceneRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TwigSceneRenderer|null
|
||||||
|
*/
|
||||||
|
public function getTwigSceneRenderer(): ?TwigSceneRenderer
|
||||||
|
{
|
||||||
|
return $this->twigSceneRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the description of this viewpoint.
|
* Sets the description of this viewpoint.
|
||||||
* @param string $description
|
* @param string $description
|
||||||
@@ -125,15 +148,11 @@ class Viewpoint implements CreateableInterface
|
|||||||
/**
|
/**
|
||||||
* Copies the static data from a scene to this Viewpoint entity.
|
* Copies the static data from a scene to this Viewpoint entity.
|
||||||
* @param Scene $scene
|
* @param Scene $scene
|
||||||
* @param TwigSceneRenderer $renderer Required to parse title and description.
|
|
||||||
*/
|
*/
|
||||||
public function changeFromScene(Scene $scene, TwigSceneRenderer $renderer)
|
public function changeFromScene(Scene $scene)
|
||||||
{
|
{
|
||||||
$title = $renderer->render($scene->getTitle(), $scene, ignoreErrors: true);
|
$this->setTitle($scene->getTitle());
|
||||||
$description = $renderer->render($scene->getDescription(), $scene, ignoreErrors: true);
|
$this->setDescription($scene->getDescription());
|
||||||
|
|
||||||
$this->setTitle($title);
|
|
||||||
$this->setDescription($description);
|
|
||||||
$this->setTemplate($scene->getTemplate());
|
$this->setTemplate($scene->getTemplate());
|
||||||
$this->setScene($scene);
|
$this->setScene($scene);
|
||||||
|
|
||||||
@@ -178,6 +197,10 @@ class Viewpoint implements CreateableInterface
|
|||||||
$this->setActionGroups($snapshot->getActionGroups());
|
$this->setActionGroups($snapshot->getActionGroups());
|
||||||
$this->setAttachments($snapshot->getAttachments());
|
$this->setAttachments($snapshot->getAttachments());
|
||||||
$this->setData($snapshot->getData());
|
$this->setData($snapshot->getData());
|
||||||
|
|
||||||
|
foreach ($this->actionGroups as $actionGroup) {
|
||||||
|
$actionGroup->setViewpoint($this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -213,6 +236,11 @@ class Viewpoint implements CreateableInterface
|
|||||||
*/
|
*/
|
||||||
public function setActionGroups(array $actionGroups)
|
public function setActionGroups(array $actionGroups)
|
||||||
{
|
{
|
||||||
|
foreach ($actionGroups as $actionGroup) {
|
||||||
|
if ($actionGroup instanceof ActionGroup) {
|
||||||
|
$actionGroup->setViewpoint($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
$this->actionGroups = $actionGroups;
|
$this->actionGroups = $actionGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,6 +257,10 @@ class Viewpoint implements CreateableInterface
|
|||||||
throw new ArgumentException("Group {$group} is already contained in this viewpoint.");
|
throw new ArgumentException("Group {$group} is already contained in this viewpoint.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($group->getActions() as $action) {
|
||||||
|
$action->setViewpoint($this);
|
||||||
|
}
|
||||||
|
|
||||||
if ($after === null) {
|
if ($after === null) {
|
||||||
$this->actionGroups[] = $group;
|
$this->actionGroups[] = $group;
|
||||||
} else {
|
} else {
|
||||||
@@ -271,9 +303,7 @@ class Viewpoint implements CreateableInterface
|
|||||||
$actionGroups = $this->getActionGroups();
|
$actionGroups = $this->getActionGroups();
|
||||||
foreach ($actionGroups as $group) {
|
foreach ($actionGroups as $group) {
|
||||||
if ($group->getId() == $actionGroupId) {
|
if ($group->getId() == $actionGroupId) {
|
||||||
$actions = $group->getActions();
|
$group->addAction($action);
|
||||||
$actions[] = $action;
|
|
||||||
$group->setActions($actions);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,4 +411,34 @@ class Viewpoint implements CreateableInterface
|
|||||||
$group->setActions($actions);
|
$group->setActions($actions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rendered version of the title
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRenderedTitle(): string
|
||||||
|
{
|
||||||
|
$title = $this->getTitle();
|
||||||
|
|
||||||
|
if ($this->twigSceneRenderer) {
|
||||||
|
return $this->twigSceneRenderer->render($title, $this, ignoreErrors: true);
|
||||||
|
} else {
|
||||||
|
return $title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rendered version of the description
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRenderedDescription(): string
|
||||||
|
{
|
||||||
|
$description = $this->getDescription();
|
||||||
|
|
||||||
|
if ($this->twigSceneRenderer) {
|
||||||
|
return $this->twigSceneRenderer->render($description, $this, ignoreErrors: true);
|
||||||
|
} else {
|
||||||
|
return $description;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ class ViewpointSnapshot
|
|||||||
private array $attachments,
|
private array $attachments,
|
||||||
private array $data,
|
private array $data,
|
||||||
) {
|
) {
|
||||||
|
foreach ($this->actionGroups as $actionGroup) {
|
||||||
|
$actionGroup->setViewpoint(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,12 +5,17 @@ declare(strict_types=1);
|
|||||||
namespace LotGD\Core\Services;
|
namespace LotGD\Core\Services;
|
||||||
|
|
||||||
|
|
||||||
|
use LotGD\Core\Action;
|
||||||
use LotGD\Core\Events\EventContextData;
|
use LotGD\Core\Events\EventContextData;
|
||||||
|
use LotGD\Core\Exceptions\CharacterNotFoundException;
|
||||||
use LotGD\Core\Exceptions\InsecureTwigTemplateError;
|
use LotGD\Core\Exceptions\InsecureTwigTemplateError;
|
||||||
use LotGD\Core\Game;
|
use LotGD\Core\Game;
|
||||||
use LotGD\Core\Models\Character;
|
use LotGD\Core\Models\Character;
|
||||||
use LotGD\Core\Models\Scene;
|
use LotGD\Core\Models\Scene;
|
||||||
|
use LotGD\Core\Models\Viewpoint;
|
||||||
use Twig\Environment;
|
use Twig\Environment;
|
||||||
|
use Twig\Error\LoaderError;
|
||||||
|
use Twig\Error\SyntaxError;
|
||||||
use Twig\Extension\SandboxExtension;
|
use Twig\Extension\SandboxExtension;
|
||||||
use Twig\Sandbox\SecurityError;
|
use Twig\Sandbox\SecurityError;
|
||||||
use Twig\Sandbox\SecurityPolicy;
|
use Twig\Sandbox\SecurityPolicy;
|
||||||
@@ -18,19 +23,40 @@ use Twig\Sandbox\SecurityPolicy;
|
|||||||
class TwigSceneRenderer
|
class TwigSceneRenderer
|
||||||
{
|
{
|
||||||
private Environment $twig;
|
private Environment $twig;
|
||||||
|
private array $templateValues;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private Game $game
|
private Game $game
|
||||||
) {
|
) {
|
||||||
$this->twig = new Environment(new TwigNullLoader());
|
$this->twig = new Environment(new TwigNullLoader());
|
||||||
|
|
||||||
$securityPolicy = $this->getSecurityPolicy();
|
// Add a hook for additional fields
|
||||||
|
// This is for global changes only. Viewpoint-dependent changes should try to store the important values within
|
||||||
|
// the viewpoint itself.
|
||||||
|
$eventManager = $this->game->getEventManager();
|
||||||
|
$contextData = EventContextData::create(["templateValues" => []]);
|
||||||
|
$newContextData = $eventManager->publish("h/lotgd/core/scene-renderer/templateValues", $contextData);
|
||||||
|
$this->templateValues = $newContextData->get("templateValues") ?? [];
|
||||||
|
|
||||||
# Add Sandbox extension
|
// Add Sandbox extension
|
||||||
|
$securityPolicy = $this->getSecurityPolicy();
|
||||||
$this->twig->addExtension(new SandboxExtension($securityPolicy, sandboxed: true));
|
$this->twig->addExtension(new SandboxExtension($securityPolicy, sandboxed: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(string $string, Scene $scene, bool $ignoreErrors = false): string
|
/**
|
||||||
|
* Renders a given string in the context if a given viewpoint.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @param Viewpoint $viewpoint
|
||||||
|
* @param bool $ignoreErrors If set to true, errors are ignored and the unparsed string will be returned instead.
|
||||||
|
* @param array $templateValues
|
||||||
|
* @return string
|
||||||
|
* @throws InsecureTwigTemplateError
|
||||||
|
* @throws CharacterNotFoundException
|
||||||
|
* @throws LoaderError
|
||||||
|
* @throws SyntaxError
|
||||||
|
*/
|
||||||
|
public function render(string $string, Viewpoint $viewpoint, bool $ignoreErrors = false, array $templateValues = []): string
|
||||||
{
|
{
|
||||||
// We catch here "Tag" errors. If error, we'll exit either by returning the input ($ignoreError === true) or
|
// We catch here "Tag" errors. If error, we'll exit either by returning the input ($ignoreError === true) or
|
||||||
// throwing an exception.
|
// throwing an exception.
|
||||||
@@ -44,16 +70,14 @@ class TwigSceneRenderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$templateValues = [
|
$defaultTemplateValues = [
|
||||||
"Character" => $this->game->getCharacter(),
|
"Character" => $this->game->getCharacter(),
|
||||||
"Scene" => $scene,
|
"Scene" => $viewpoint->getScene(),
|
||||||
|
"Viewpoint" => $viewpoint,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Publish event to change $templateValues
|
// Merges additional template values with important ones.
|
||||||
$eventManager = $this->game->getEventManager();
|
$templateValues = array_merge($this->templateValues, $defaultTemplateValues, $templateValues);
|
||||||
$contextData = EventContextData::create(["templateValues" => $templateValues]);
|
|
||||||
$newContextData = $eventManager->publish("h/lotgd/core/scene-renderer/templateValues", $contextData);
|
|
||||||
$templateValues = $newContextData->get("templateValues");
|
|
||||||
|
|
||||||
// Try to render the template
|
// Try to render the template
|
||||||
try {
|
try {
|
||||||
@@ -70,17 +94,26 @@ class TwigSceneRenderer
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current security policy.
|
||||||
|
* This method provides a hook.
|
||||||
|
* @return SecurityPolicy
|
||||||
|
*/
|
||||||
public function getSecurityPolicy(): SecurityPolicy
|
public function getSecurityPolicy(): SecurityPolicy
|
||||||
{
|
{
|
||||||
$tags = ["if"];
|
$tags = ["if"];
|
||||||
$filters = ["lower", "upper", "escape"];
|
$filters = ["lower", "upper", "escape", "round"];
|
||||||
$functions = ["range"];
|
$functions = ["range"];
|
||||||
$methods = [
|
$methods = [
|
||||||
Character::class => ["getDisplayName", "getLevel", "isAlive", "getHealth", "getMaxHealth", "getProperty"],
|
Character::class => ["getDisplayName", "getLevel", "isAlive", "getHealth", "getMaxHealth", "getProperty"],
|
||||||
Scene::class => ["getProperty"],
|
Scene::class => ["getProperty"],
|
||||||
|
Viewpoint::class => ["getData"],
|
||||||
|
Action::class => ["getParameters"],
|
||||||
];
|
];
|
||||||
$properties = [
|
$properties = [
|
||||||
"Character" => ["displayName", "level", "health", "maxHealth"],
|
"Character" => ["displayName", "level", "alive", "health", "maxHealth", "property"],
|
||||||
|
"Viewpoint" => ["data"],
|
||||||
|
"Action" => ["parameters"],
|
||||||
];
|
];
|
||||||
|
|
||||||
// Publish event to change $templateValues
|
// Publish event to change $templateValues
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ class ViewpointRestorationTest extends CoreModelTestCase
|
|||||||
protected function getActionGroup()
|
protected function getActionGroup()
|
||||||
{
|
{
|
||||||
static $actionGroup = null;
|
static $actionGroup = null;
|
||||||
if ($actionGroup !== null) {
|
if ($actionGroup === null) {
|
||||||
$actionGroup = new ActionGroup("main", "Title", 0);
|
$actionGroup = new ActionGroup("main", "Title", 0);
|
||||||
$actionGroup->addAction(new Action(1));
|
$actionGroup->addAction(new Action("30000000-0000-0000-0000-000000000001"));
|
||||||
$actionGroup->addAction(new Action(2));
|
$actionGroup->addAction(new Action("30000000-0000-0000-0000-000000000002"));
|
||||||
$actionGroup->addAction(new Action(3));
|
$actionGroup->addAction(new Action("30000000-0000-0000-0000-000000000003"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $actionGroup;
|
return $actionGroup;
|
||||||
@@ -102,7 +102,17 @@ class ViewpointRestorationTest extends CoreModelTestCase
|
|||||||
$this->assertSame($viewpoint->getTitle(), $newViewpoint->getTitle());
|
$this->assertSame($viewpoint->getTitle(), $newViewpoint->getTitle());
|
||||||
$this->assertSame($viewpoint->getDescription(), $newViewpoint->getDescription());
|
$this->assertSame($viewpoint->getDescription(), $newViewpoint->getDescription());
|
||||||
$this->assertSame($viewpoint->getTemplate(), $newViewpoint->getTemplate());
|
$this->assertSame($viewpoint->getTemplate(), $newViewpoint->getTemplate());
|
||||||
$this->assertEquals($viewpoint->getActionGroups(), $newViewpoint->getActionGroups());;
|
|
||||||
|
for ($i=0; $i < count($viewpoint->getActionGroups()); $i++) {
|
||||||
|
$should = $viewpoint->getActionGroups()[$i];
|
||||||
|
$is = $newViewpoint->getActionGroups()[$i];
|
||||||
|
|
||||||
|
$this->assertSame($should->getId(), $is->getId());
|
||||||
|
$this->assertSame($should->getTitle(), $is->getTitle());
|
||||||
|
$this->assertSame($should->getSortKey(), $is->getSortKey());
|
||||||
|
$this->assertSame(count($should->getActions()), count($is->getActions()));
|
||||||
|
}
|
||||||
|
|
||||||
$this->assertSame($viewpoint->getData(), $newViewpoint->getData());
|
$this->assertSame($viewpoint->getData(), $newViewpoint->getData());
|
||||||
$this->assertSame($viewpoint->getAttachments(), $newViewpoint->getAttachments());
|
$this->assertSame($viewpoint->getAttachments(), $newViewpoint->getAttachments());
|
||||||
}
|
}
|
||||||
@@ -120,7 +130,17 @@ class ViewpointRestorationTest extends CoreModelTestCase
|
|||||||
$this->assertSame($viewpoint->getTitle(), $newViewpoint->getTitle());
|
$this->assertSame($viewpoint->getTitle(), $newViewpoint->getTitle());
|
||||||
$this->assertSame($viewpoint->getDescription(), $newViewpoint->getDescription());
|
$this->assertSame($viewpoint->getDescription(), $newViewpoint->getDescription());
|
||||||
$this->assertSame($viewpoint->getTemplate(), $newViewpoint->getTemplate());
|
$this->assertSame($viewpoint->getTemplate(), $newViewpoint->getTemplate());
|
||||||
$this->assertEquals($viewpoint->getActionGroups(), $newViewpoint->getActionGroups());;
|
|
||||||
|
for ($i=0; $i < count($viewpoint->getActionGroups()); $i++) {
|
||||||
|
$should = $viewpoint->getActionGroups()[$i];
|
||||||
|
$is = $newViewpoint->getActionGroups()[$i];
|
||||||
|
|
||||||
|
$this->assertSame($should->getId(), $is->getId());
|
||||||
|
$this->assertSame($should->getTitle(), $is->getTitle());
|
||||||
|
$this->assertSame($should->getSortKey(), $is->getSortKey());
|
||||||
|
$this->assertSame(count($should->getActions()), count($is->getActions()));
|
||||||
|
}
|
||||||
|
|
||||||
$this->assertSame($viewpoint->getData(), $newViewpoint->getData());
|
$this->assertSame($viewpoint->getData(), $newViewpoint->getData());
|
||||||
$this->assertSame($viewpoint->getAttachments(), $newViewpoint->getAttachments());
|
$this->assertSame($viewpoint->getAttachments(), $newViewpoint->getAttachments());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,9 +117,18 @@ class ViewpointTest extends CoreModelTestCase
|
|||||||
$em->clear();
|
$em->clear();
|
||||||
|
|
||||||
$output = $em->getRepository(Viewpoint::class)->find("10000000-0000-0000-0000-000000000002");
|
$output = $em->getRepository(Viewpoint::class)->find("10000000-0000-0000-0000-000000000002");
|
||||||
$this->assertEquals($actionGroups, $output->getActionGroups());
|
|
||||||
|
|
||||||
$this->assertEquals($ag2, $input->findActionGroupById('id2'));
|
for ($i=0; $i < count($actionGroups); $i++) {
|
||||||
|
$should = $actionGroups[$i];
|
||||||
|
$is = $output->getActionGroups()[$i];
|
||||||
|
|
||||||
|
$this->assertSame($should->getId(), $is->getId());
|
||||||
|
$this->assertSame($should->getTitle(), $is->getTitle());
|
||||||
|
$this->assertSame($should->getSortKey(), $is->getSortKey());
|
||||||
|
$this->assertSame(count($should->getActions()), count($is->getActions()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals($ag2->getTitle(), $input->findActionGroupById('id2')->getTitle());
|
||||||
$this->assertNull($input->findActionGroupById('not-there'));
|
$this->assertNull($input->findActionGroupById('not-there'));
|
||||||
|
|
||||||
$testAction = new Action("30000000-0000-0000-0000-000000000004");
|
$testAction = new Action("30000000-0000-0000-0000-000000000004");
|
||||||
@@ -186,7 +195,16 @@ class ViewpointTest extends CoreModelTestCase
|
|||||||
|
|
||||||
// Not finding the scene ID should change nothing.
|
// Not finding the scene ID should change nothing.
|
||||||
$output->removeActionsWithSceneId("30000000-0000-0000-0000-000000001000");
|
$output->removeActionsWithSceneId("30000000-0000-0000-0000-000000001000");
|
||||||
$this->assertEquals($actionGroups, $output->getActionGroups());
|
|
||||||
|
for ($i=0; $i < count($actionGroups); $i++) {
|
||||||
|
$should = $actionGroups[$i];
|
||||||
|
$is = $output->getActionGroups()[$i];
|
||||||
|
|
||||||
|
$this->assertSame($should->getId(), $is->getId());
|
||||||
|
$this->assertSame($should->getTitle(), $is->getTitle());
|
||||||
|
$this->assertSame($should->getSortKey(), $is->getSortKey());
|
||||||
|
$this->assertSame(count($should->getActions()), count($is->getActions()));
|
||||||
|
}
|
||||||
|
|
||||||
$ag1_output = new ActionGroup('id1', 'title1', 42);
|
$ag1_output = new ActionGroup('id1', 'title1', 42);
|
||||||
$ag1_output->setActions([
|
$ag1_output->setActions([
|
||||||
@@ -199,7 +217,16 @@ class ViewpointTest extends CoreModelTestCase
|
|||||||
$ag2
|
$ag2
|
||||||
];
|
];
|
||||||
$output->removeActionsWithSceneId("30000000-0000-0000-0000-000000000002");
|
$output->removeActionsWithSceneId("30000000-0000-0000-0000-000000000002");
|
||||||
$this->assertEquals($actionGroupsWithout2, $output->getActionGroups());
|
|
||||||
|
for ($i=0; $i < count($actionGroups); $i++) {
|
||||||
|
$should = $actionGroupsWithout2[$i];
|
||||||
|
$is = $output->getActionGroups()[$i];
|
||||||
|
|
||||||
|
$this->assertSame($should->getId(), $is->getId());
|
||||||
|
$this->assertSame($should->getTitle(), $is->getTitle());
|
||||||
|
$this->assertSame($should->getSortKey(), $is->getSortKey());
|
||||||
|
$this->assertSame(count($should->getActions()), count($is->getActions()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testChangingSceneDescription()
|
public function testChangingSceneDescription()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use LotGD\Core\Exceptions\InsecureTwigTemplateError;
|
|||||||
use LotGD\Core\Game;
|
use LotGD\Core\Game;
|
||||||
use LotGD\Core\Models\Character;
|
use LotGD\Core\Models\Character;
|
||||||
use LotGD\Core\Models\Scene;
|
use LotGD\Core\Models\Scene;
|
||||||
|
use LotGD\Core\Models\Viewpoint;
|
||||||
use LotGD\Core\PHPUnit\LotGDTestCase;
|
use LotGD\Core\PHPUnit\LotGDTestCase;
|
||||||
use LotGD\Core\Services\TwigSceneRenderer;
|
use LotGD\Core\Services\TwigSceneRenderer;
|
||||||
|
|
||||||
@@ -43,12 +44,17 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
->disableOriginalConstructor()
|
->disableOriginalConstructor()
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
return [$game, $scene, $character, $eventManager];
|
$viewpoint = $this->getMockBuilder(Viewpoint::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$viewpoint->method("getScene")->willReturn($scene);
|
||||||
|
|
||||||
|
return [$game, $viewpoint, $character, $eventManager];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIfSceneRendererCanBeConstructed()
|
public function testIfSceneRendererCanBeConstructed()
|
||||||
{
|
{
|
||||||
[$game, $scene, $character, $eventManager] = $this->getMockeries();
|
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
|
||||||
$eventManager->method("publish")->willReturnArgument(1);
|
$eventManager->method("publish")->willReturnArgument(1);
|
||||||
|
|
||||||
$renderer = new TwigSceneRenderer($game);
|
$renderer = new TwigSceneRenderer($game);
|
||||||
@@ -58,7 +64,7 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
|
|
||||||
public function testIfTwigSceneRendererReturnsANonTemplateStringUnmodified()
|
public function testIfTwigSceneRendererReturnsANonTemplateStringUnmodified()
|
||||||
{
|
{
|
||||||
[$game, $scene, $character, $eventManager] = $this->getMockeries();
|
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
|
||||||
$eventManager->method("publish")->willReturnArgument(1);
|
$eventManager->method("publish")->willReturnArgument(1);
|
||||||
|
|
||||||
# Get renderer
|
# Get renderer
|
||||||
@@ -68,7 +74,7 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
$template = "You enter a new location.\n\nA new location.";
|
$template = "You enter a new location.\n\nA new location.";
|
||||||
|
|
||||||
# Create the result
|
# Create the result
|
||||||
$renderResult = $renderer->render($template, $scene);
|
$renderResult = $renderer->render($template, $viewpoint);
|
||||||
|
|
||||||
# Assert result
|
# Assert result
|
||||||
$this->assertSame($template, $renderResult);
|
$this->assertSame($template, $renderResult);
|
||||||
@@ -76,7 +82,7 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
|
|
||||||
public function testIfTwigSceneRendererParsesStringsWithCharacters()
|
public function testIfTwigSceneRendererParsesStringsWithCharacters()
|
||||||
{
|
{
|
||||||
[$game, $scene, $character, $eventManager] = $this->getMockeries();
|
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
|
||||||
$eventManager->method("publish")->willReturnArgument(1);
|
$eventManager->method("publish")->willReturnArgument(1);
|
||||||
|
|
||||||
# Get renderer
|
# Get renderer
|
||||||
@@ -92,7 +98,27 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
."You are alive.";
|
."You are alive.";
|
||||||
|
|
||||||
# Create the result
|
# Create the result
|
||||||
$renderResult = $renderer->render($template, $scene);
|
$renderResult = $renderer->render($template, $viewpoint);
|
||||||
|
|
||||||
|
# Assert result
|
||||||
|
$this->assertSame($result, $renderResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIfViewpointDataCanBeAccessed()
|
||||||
|
{
|
||||||
|
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
|
||||||
|
$eventManager->method("publish")->willReturnArgument(1);
|
||||||
|
$viewpoint->method("getData")->willReturn(["test" => 7, "other" => "Hi"]);
|
||||||
|
|
||||||
|
# Get renderer
|
||||||
|
$renderer = new TwigSceneRenderer($game);
|
||||||
|
|
||||||
|
# Prepare the template string.
|
||||||
|
$template = "Hi {{ Viewpoint.data.test }}! {{ Viewpoint.data.other }}";
|
||||||
|
$result = "Hi 7! Hi";
|
||||||
|
|
||||||
|
# Create the result
|
||||||
|
$renderResult = $renderer->render($template, $viewpoint);
|
||||||
|
|
||||||
# Assert result
|
# Assert result
|
||||||
$this->assertSame($result, $renderResult);
|
$this->assertSame($result, $renderResult);
|
||||||
@@ -100,7 +126,7 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
|
|
||||||
public function testIfRawTemplateGetsReturnedIfTemplateContainsIllegalTokens()
|
public function testIfRawTemplateGetsReturnedIfTemplateContainsIllegalTokens()
|
||||||
{
|
{
|
||||||
[$game, $scene, $character, $eventManager] = $this->getMockeries();
|
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
|
||||||
$eventManager->method("publish")->willReturnArgument(1);
|
$eventManager->method("publish")->willReturnArgument(1);
|
||||||
|
|
||||||
# Get renderer
|
# Get renderer
|
||||||
@@ -110,7 +136,7 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
$template = "Viewpoint: {{ Character.viewpoint }}";
|
$template = "Viewpoint: {{ Character.viewpoint }}";
|
||||||
|
|
||||||
# Try to parse the result
|
# Try to parse the result
|
||||||
$renderResult = $renderer->render($template, $scene, true);
|
$renderResult = $renderer->render($template, $viewpoint, true);
|
||||||
|
|
||||||
# If there was an error, it should have gotten ignored, giving back the raw template.
|
# If there was an error, it should have gotten ignored, giving back the raw template.
|
||||||
$this->assertSame($template, $renderResult);
|
$this->assertSame($template, $renderResult);
|
||||||
@@ -118,7 +144,7 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
|
|
||||||
public function testIfExceptionGetsRaisedIfTemplateContainsIllegalTokens()
|
public function testIfExceptionGetsRaisedIfTemplateContainsIllegalTokens()
|
||||||
{
|
{
|
||||||
[$game, $scene, $character, $eventManager] = $this->getMockeries();
|
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
|
||||||
$eventManager->method("publish")->willReturnArgument(1);
|
$eventManager->method("publish")->willReturnArgument(1);
|
||||||
|
|
||||||
# Get renderer
|
# Get renderer
|
||||||
@@ -131,12 +157,12 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
$this->expectException(InsecureTwigTemplateError::class);
|
$this->expectException(InsecureTwigTemplateError::class);
|
||||||
|
|
||||||
# Try to parse the result
|
# Try to parse the result
|
||||||
$renderResult = $renderer->render($template, $scene, false);
|
$renderResult = $renderer->render($template, $viewpoint, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIfPublishedEventCanModifySecurityPolicy()
|
public function testIfPublishedEventCanModifySecurityPolicy()
|
||||||
{
|
{
|
||||||
[$game, $scene, $character, $eventManager] = $this->getMockeries();
|
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
|
||||||
|
|
||||||
# Set up a more complex "publish" method to emulate a real event.
|
# Set up a more complex "publish" method to emulate a real event.
|
||||||
$eventManager->method("publish")->willReturnCallback(function($event, EventContextData $context) {
|
$eventManager->method("publish")->willReturnCallback(function($event, EventContextData $context) {
|
||||||
@@ -164,15 +190,15 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
|
|
||||||
# Assert that if does not work anymore
|
# Assert that if does not work anymore
|
||||||
$this->expectException(InsecureTwigTemplateError::class);
|
$this->expectException(InsecureTwigTemplateError::class);
|
||||||
$renderer->render("{% if 5*1 %}Hallo{%endif%}", $scene, false);
|
$renderer->render("{% if 5*1 %}Hallo{%endif%}", $viewpoint, false);
|
||||||
|
|
||||||
$this->expectException(InsecureTwigTemplateError::class);
|
$this->expectException(InsecureTwigTemplateError::class);
|
||||||
$renderer->render("{{ Character.name }}", $scene, false);
|
$renderer->render("{{ Character.name }}", $viewpoint, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIfPublishedEventCanModifyValueScope()
|
public function testIfPublishedEventCanModifyValueScope()
|
||||||
{
|
{
|
||||||
[$game, $scene, $character, $eventManager] = $this->getMockeries();
|
[$game, $viewpoint, $character, $eventManager] = $this->getMockeries();
|
||||||
|
|
||||||
# Set up a more complex "publish" method to emulate a real event.
|
# Set up a more complex "publish" method to emulate a real event.
|
||||||
$eventManager->method("publish")->willReturnCallback(function($event, EventContextData $context) {
|
$eventManager->method("publish")->willReturnCallback(function($event, EventContextData $context) {
|
||||||
@@ -192,7 +218,7 @@ class TwigSceneRendererTest extends LotGDTestCase
|
|||||||
$renderer = new TwigSceneRenderer($game);
|
$renderer = new TwigSceneRenderer($game);
|
||||||
|
|
||||||
# Assert result
|
# Assert result
|
||||||
$result = $renderer->render("{{ test }}", $scene, false);
|
$result = $renderer->render("{{ test }}", $viewpoint, false);
|
||||||
$this->assertSame("A test", $result);
|
$this->assertSame("A test", $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user