112 Commits

Author SHA1 Message Date
Vassyli 0a7f301536 Fix: Adjusted tests. 2021-03-01 20:53:00 +01:00
Vassyli fc8d7be2ef Fix: renamed two events from character-config to scene-config. 2021-03-01 20:53:00 +01:00
Vassyli a9e5647fe0 Adds the missing initialisation of the Scene.properties collection with corresponding tests. 2021-02-26 14:32:59 +01:00
Vassyli 25ccbd8974 Adds default value to type Scene.properties. 2021-02-25 16:46:42 +01:00
Vassyli 2e9f0dc564 Sets cli column width to 120 to standardise testing environment 2021-02-16 22:13:52 +01:00
Vassyli 03fde83fc1 Fixes the actual command to import the correct commands. 2021-02-16 22:13:52 +01:00
Vassyli 669085e65d Added the possibilities to set character and scene settings over cli, with module hooks. 2021-02-16 22:13:52 +01:00
Vassyli f72adb1a38 Adds tests for scene commands. 2021-02-16 22:13:52 +01:00
Vassyli 0292a66252 Adds new commands to manage modules and corresponding tests. 2021-02-16 22:13:52 +01:00
Vassyli eea72f848b Adds tests for all character commands. 2021-02-16 22:13:52 +01:00
Vassyli c2a139d192 Adds a new CharacterEditCommand including a test. 2021-02-16 22:13:52 +01:00
Vassyli d83e437b4a Removed the same wrong assumption from LotGDTestCase, too. 2021-02-04 16:37:07 +01:00
Vassyli 99d554e5d7 Fixes a bug in HasAction->searchAction that caused actions not to be found if no groupTitle was given. 2021-02-04 16:37:07 +01:00
Vassyli 75dd7494c3 Fixes a bug in Action->setTitle() where a return type was expected instead of void. 2021-02-04 12:03:43 +01:00
Vassyli f7504bbb60 Adds a test and the corresponding bugfix. 2021-02-03 20:15:00 +01:00
Vassyli 60a3a8bd2b Adds a trait 'UserAssignable' to mark models as user-assignable. Refactored from SceneTemplates, and applied to SceneAttachments, too. 2021-01-29 20:16:51 +01:00
Vassyli 147692d722 Removes the ability of attachments to add actions. This should be done by modules via scene templates instead. 2021-01-29 20:16:51 +01:00
Vassyli 454248ed0f Game loop now creates attachment instances from SceneAttachments. 2021-01-29 20:16:51 +01:00
Vassyli 27347d0677 Changed SceneAttachment to require the class to implement AttachmentInterface. 2021-01-29 20:16:51 +01:00
Vassyli 69434c7bbf Adds an AttachmentInterface and adjusted the abstract class Attachment. 2021-01-29 20:16:51 +01:00
Vassyli 2a3a3e7bc2 Introduces a SceneAttachment model for registering attachments. 2021-01-29 20:16:51 +01:00
Vassyli 47693f6127 Adds commands to add, show and remove characters. 2021-01-26 21:19:12 +01:00
Vassyli e3534ea88d Adds logs to scene commands. 2021-01-26 21:19:12 +01:00
Vassyli 5dbe8fdca3 Regression fix: Adds composer requirement for d11wtq/boris back in. 2021-01-26 21:19:12 +01:00
Vassyli 31387c1840 Adds a command to remove scenes. 2021-01-26 21:19:12 +01:00
Vassyli dfd39cd1f8 Adds a feature to scene:show command that shows the corresponding group name in the connections. 2021-01-26 21:19:12 +01:00
Vassyli f25bab7af8 Adds commands to add and remove scene connection groups. 2021-01-26 21:19:12 +01:00
Vassyli c0ed663ef4 Adds the possibility to disconnect two scenes. 2021-01-26 21:19:12 +01:00
Vassyli b3b1c4af0a Adds a SceneConnect command to connect two scenes. 2021-01-26 21:19:12 +01:00
Vassyli 2153df5cc8 Small fix to the SceneAdd command. 2021-01-26 21:19:12 +01:00
Vassyli 13dfab2321 Adds improvements to the SceneTemplate object, and integrates them into the console command. 2021-01-26 21:19:12 +01:00
Vassyli 29ad369c88 Adds some additional commands to denerys cli. 2021-01-26 21:19:12 +01:00
Vassyli a576bfd2a0 Moved console commands to subdirectories. 2021-01-26 21:19:12 +01:00
Vassyli aa5b32c03d Fixes typed property to pass tests. 2021-01-18 10:24:17 +01:00
Vassyli c2aaf025f6 Adds a method AddAttachment to the viewpoint. Small changes. 2021-01-18 10:24:17 +01:00
Vassyli 9b60cc0ebb Connects the SceneRenderer to the Game bootstrap process, and parses Scenes in Viewpoint->changeFromScene(). 2021-01-16 18:55:49 +01:00
Vassyli eca1343b5f Adds events to TwigSceneRenderer, and tests to show that they correctly overwrite the data. 2021-01-16 18:55:49 +01:00
Vassyli 1fb2eb023e Adds SceneRenderer class based on twig to convert some logic and variables from Scenes, allowing them to be more flexible. 2021-01-16 18:55:49 +01:00
Vassyli 1a0b6dbe3e Adds tests to check scene properties. 2021-01-14 20:52:19 +01:00
Vassyli 96feb12fb5 Adds the ability to set properties on Scene objects. 2021-01-14 20:52:19 +01:00
Vassyli 512d875609 Updates some documentation in the Game object. 2021-01-14 20:52:19 +01:00
Vassyli 0a2313b5e5 Fixes a bug where phpunit marked tests only running our custom assertions as risky. 2021-01-13 19:37:08 +01:00
Vassyli c4634b90b7 Adds a new common LotGDTestCase providing additional assertions. Adds a HasAction constraint, too. 2021-01-08 20:00:25 +01:00
Vassyli 6325b8bd36 Adds a git add command to the update package workflow. 2021-01-04 19:40:12 +01:00
Vassyli dd074a8bea Fixed a bug that used a misspelled stdout stream for StreamHandler 2021-01-04 19:14:23 +01:00
Vassyli fdb53972d2 Removed travis configuration file 2020-12-31 11:37:50 +01:00
Vassyli ad3ea14bb2 Exchanged the travis badge with a github action badge. 2020-12-31 11:34:08 +01:00
Vassyli bb1ca987b5 Renames test-runner to reflect tests 2020-12-31 11:30:07 +01:00
Vassyli 57b8045c1a Updated composer.json to pass composer validate. 2020-12-31 11:15:27 +01:00
Vassyli f658b421f6 Added a new testrunner github workflow, and changed the update-package to also act on releases. 2020-12-31 10:52:07 +01:00
Vassyli 7ab55c1cb0 Bugfix 2020-12-30 18:11:20 +01:00
Vassyli 05d72a11bb Bugfix 2020-12-30 18:05:05 +01:00
Vassyli d006aa3ded Bugfix 2020-12-30 17:59:05 +01:00
Vassyli 147d449a27 Adds additional credentials for pushing 2020-12-30 17:55:08 +01:00
Vassyli c18cdef3ff Fixes the commit-changes part which wrongly called composer. 2020-12-30 17:34:09 +01:00
Vassyli 3eb538145e Adds github token to composer config. 2020-12-30 17:29:29 +01:00
Vassyli 696a5f3305 Adds authentication steps to github workflow 2020-12-30 17:23:15 +01:00
Vassyli 765b65a9d2 Sets PHP version to 7.4 in worker 2020-12-30 15:07:12 +01:00
Vassyli 96afd4b87e Updated workflow 2020-12-30 15:03:15 +01:00
Vassyli ea6be63bb3 Adds a test github workflow. 2020-12-30 14:58:39 +01:00
Vassyli 126fdee80e Adds additional methods to ModelTestCase for modules to refine their tests. 2020-12-30 14:28:53 +01:00
Vassyli 81c72ca91a Adds an assertDataWasKeptIntact method to ModelTestCase in lieu of the DBUnit features. 2020-12-30 14:11:07 +01:00
Vassyli 29e5ced0f9 Adds a test for null-template scenes. 2020-12-28 13:40:19 +01:00
Vassyli c7dbf33f6e Adds missing return in CharacterResetViewpointCommand 2020-12-26 15:22:57 +01:00
Vassyli d4124a71ef Adds additional typehints to LotGD\Core\Tools\* 2020-12-24 12:47:28 +01:00
Vassyli 28c12a47f1 Collection of fixes to make tests run. 2020-12-24 12:36:26 +01:00
Vassyli 709b96ea52 Adds additional typehints to LotGD\Core\Events\* 2020-12-24 12:20:56 +01:00
Vassyli 363c4678d3 Added typehints do \LotGD\Core\Doctrine\* 2020-12-24 10:00:40 +01:00
Vassyli d8b8fb69d9 Adjusted typehints in LotGD\Core\PermissionManager 2020-12-24 10:00:39 +01:00
Vassyli 0a20c8a968 Adjusted typehints in LotGD\Core\LibraryConfigurationManager 2020-12-24 10:00:37 +01:00
Vassyli f051d72aea Adjusted typehints in LotGD\Core\LibraryConfiguration 2020-12-24 10:00:35 +01:00
Vassyli af17f434d4 Adjusted typehints in LotGD\Core\GameBuilder 2020-12-24 10:00:33 +01:00
Vassyli 2680a41cee Adjusted typehints in LotGD\Core\EventManager 2020-12-24 10:00:32 +01:00
Vassyli c7d91230bd Adjusted typehints in LotGD\Core\DiceBag 2020-12-24 10:00:30 +01:00
Vassyli 541748a168 Adjusted typehints in LotGD\Core\Configuration 2020-12-24 10:00:29 +01:00
Vassyli 42e3f22726 Adjusted typehints in LotGD\Core\ComposerManager 2020-12-24 10:00:27 +01:00
Vassyli 3c64492cde Adjusted typehints in LotGD\Core\BuffList 2020-12-23 16:38:28 +01:00
Vassyli 18ec30ede5 Added default values to Character and TimeKeeper in LotGD\Core\Game to prevent access of uninitialized properties. 2020-12-23 16:29:48 +01:00
Vassyli 4e35fbd6b3 Adjusted typehints in LotGD\Core\Battle 2020-12-23 16:09:48 +01:00
Vassyli 32305238d9 Added typehints to LotGD\Core\Attachment 2020-12-23 15:59:11 +01:00
Vassyli 13082f7b9d Added typehints to LotGD\Core\ActionGroup 2020-12-23 15:58:05 +01:00
Vassyli 272910c3a3 Updated typehints in LotGD\Core\Action 2020-12-23 15:55:58 +01:00
Vassyli 33a7812abe Adds constructor property promotion to Game.php 2020-12-23 15:55:58 +01:00
Vassyli a086fe4b9b Adds property TypeHints to Game 2020-12-23 15:55:51 +01:00
Vassyli 557215bba3 Temporarily removes php-cs-fixer as it does not support PHP8 yet 2020-12-23 13:32:49 +01:00
Vassyli 81a6edc074 Merge branch 'master' of https://github.com/lotgd/core into php8-compability 2020-12-23 12:44:41 +01:00
Vassyli 1cfe1cacba Changed travis to only check for php 8.0 2020-12-23 12:41:52 +01:00
Vassyli f3fee8cc7d Adds a to each console command->execute() 2020-12-21 20:30:05 +01:00
Vassyli 90f187dbf2 Doctrine: Fixed class reference to ClassMetadata 2020-12-21 19:21:25 +01:00
Vassyli 1a6079b270 Monolog: Fixed logging calls from addDebug() to debug() 2020-12-21 18:40:31 +01:00
Vassyli 17b704bec4 Updated packages to newest versions. 2020-12-21 18:12:16 +01:00
Basilius Sauter f6df590cd6 Sets SceneTemplate->userAssignable to true by default. 2019-06-29 12:41:56 +02:00
Basilius Sauter 3338a75f71 Removed PHP 7.4 snapshot. 2019-06-29 12:40:10 +02:00
Basilius Sauter 7fe81a9c5b Fixed a bug in SceneTemplate::__construct that prevented any legal classes to be used. 2019-06-29 12:24:16 +02:00
Basilius Sauter 3ecb7f8e95 Changed a few typehints. 2019-06-27 15:05:34 +02:00
Basilius Sauter 0fcc6dc8b7 Automatic PHP CS Fixer run. 2019-06-27 14:39:03 +02:00
Basilius Sauter 2376696101 Fixed errors related to rebasing. 2019-06-27 14:39:03 +02:00
Basilius Sauter a52de33ed7 Added snapshot back in. 2019-06-27 14:39:03 +02:00
Basilius Sauter cf99395ed3 Removed php 7.4.snapshot from travis due to issues with ReflectionType. 2019-06-27 14:39:03 +02:00
Basilius Sauter 1c53604244 Adjusted tests. 2019-06-27 14:39:03 +02:00
Basilius Sauter c6ecab6ce9 Adds SceneTemplate model and connects it to SceneBasics trait. 2019-06-27 14:39:03 +02:00
Basilius Sauter ff154ccbd9 Merge pull request #129 from lotgd/rebase/phpunit8
Rebase/phpunit8
2019-06-27 14:36:56 +02:00
Basilius Sauter fc73f86ffa Changed PHPUnit dependency to use either 7 or 8. 2019-06-27 14:29:01 +02:00
Basilius Sauter a375cb98cd Removed all Warnings from PHPUnit 8 2019-06-27 09:52:18 +02:00
Basilius Sauter e18cdd21cc Added void return type to setUp/tearDown test methods. 2019-06-27 09:40:12 +02:00
Basilius Sauter c4ff330928 Adds in PHP 7.3 to travis 2019-06-25 20:44:24 +02:00
Basilius Sauter e74dcbdfde Automatic changes from 'php cs fixer' 2019-06-25 20:42:44 +02:00
Basilius Sauter 8612a53538 Replaces style checker with PHP CS Fix 2019-06-25 20:23:22 +02:00
Basilius Sauter e8f2ea56bc Upgrades successfully to PHPUnit 7, removed DBUnit support and integrated custom testing. 2019-06-16 17:54:00 +02:00
Basilius Sauter d0b2d48cc1 Upgrades successfully to PHPUnit 7, removed DBUnit support and integrated custom testing. 2019-06-16 17:50:58 +02:00
Basilius Sauter 14d1c9d582 Adds method getConnectionGroup to Scene model 2019-04-23 14:40:54 +02:00
Basilius Sauter 7725c7faed Adds methods setTitle and setName to SceneConnectionGroup 2019-04-23 14:35:04 +02:00
241 changed files with 12544 additions and 2791 deletions
+39
View File
@@ -0,0 +1,39 @@
name: Tests
on:
push:
branches: [ master ]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Validate composer.json and composer.lock
run: composer validate
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v2
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install dependencies
if: steps.composer-cache.outputs.cache-hit != 'true'
run: composer install --prefer-dist --no-progress --no-suggest
- name: Run test suite
run: vendor/bin/phpunit --stop-on-failure
# Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
# Docs: https://getcomposer.org/doc/articles/scripts.md
# - name: Run test suite
# run: composer run-script test
@@ -0,0 +1,39 @@
name: Package push
on:
push:
branches: [ master ]
release:
types: [ created ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Setup PHP with PECL extension
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
- name: Set git credentials
run: git config --global user.name "Vassyli" && git config --global user.email "basilius.sauter+automated@gmail.com" && git config --global user.password "${{ secrets.GH_TOKEN }}"
- name: Set composer token
run: composer config -g github-oauth.github.com ${{ secrets.GH_TOKEN }}
- name: "Checkouts satis and packages"
run: git clone https://github.com/composer/satis && git clone https://github.com/lotgd/packages
- name: "Install satis"
run: cd satis && composer install && cd ..
- name: "Build satis"
run: satis/bin/satis build packages/satis.json packages/build
- name: Set git url with credentials for pushing
run: cd packages && git config remote.origin.url 'https://Vassyli:${{ secrets.GH_TOKEN }}@github.com/lotgd/packages.git' && cd ..
- name: "Commit changes and push to origin"
run: cd packages && git add build/* && git commit -a -m "Updated packages" && git push origin master && cd ..
+5
View File
@@ -228,3 +228,8 @@ pip-log.txt
#Mr Developer #Mr Developer
.mr.developer.cfg .mr.developer.cfg
dbconfig.php dbconfig.php
composer.phar
clover.xml
.phpunit.result.cache
.php_cs.cache
+142
View File
@@ -0,0 +1,142 @@
<?php
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules([
'align_multiline_comment' => true,
'array_indentation' => true,
'array_syntax' => ['syntax' => 'short'],
'binary_operator_spaces' => true,
'blank_line_after_namespace' => true,
'braces' => [
'position_after_control_structures' => 'same',
'position_after_functions_and_oop_constructs' => 'next',
],
'cast_spaces' => ['space' => 'none'],
'class_definition' => true,
'class_keyword_remove' => false,
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'compact_nullable_typehint' => true,
'declare_strict_types' => true,
'declare_equal_normalize' => true,
'dir_constant' => true,
'doctrine_annotation_array_assignment' => true,
'doctrine_annotation_braces' => true,
'doctrine_annotation_indentation' => true,
'doctrine_annotation_spaces' => [
'after_array_assignments_colon' => false,
'after_array_assignments_equals' => false,
'before_argument_assignments' => false,
'before_array_assignments_colon' => false,
'before_array_assignments_equals' => false,
],
'elseif' => true,
'encoding' => true,
'ereg_to_preg' => true,
'escape_implicit_backslashes' => true,
'explicit_indirect_variable' => true,
'explicit_string_variable' => true,
'full_opening_tag' => true,
'fully_qualified_strict_types' => true,
'function_declaration' => true,
'function_typehint_space' => true,
'general_phpdoc_annotation_remove' => true,
'indentation_type' => true,
'line_ending' => true,
'linebreak_after_opening_tag' => true,
'list_syntax' => ['syntax' => 'short'],
'lowercase_cast' => true,
'lowercase_constants' => true,
'lowercase_static_reference' => true,
'magic_constant_casing' => true,
'magic_method_casing' => true,
'method_argument_space' => true,
'method_chaining_indentation' => true,
'multiline_comment_opening_closing' => true,
'multiline_whitespace_before_semicolons' => ['strategy' => 'new_line_for_chained_calls'],
'native_constant_invocation' => true,
'native_function_invocation' => true,
'native_function_type_declaration_casing' => true,
'new_with_braces' => true,
'no_alias_functions' => true,
'no_alternative_syntax' => true,
'no_blank_lines_after_phpdoc' => true,
'no_break_comment' => true,
'no_closing_tag' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => true,
'no_homoglyph_names' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => ["use" => "print"],
'no_multiline_whitespace_around_double_arrow' => true,
'no_php4_constructor' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_spaces_after_function_name' => true,
'no_spaces_around_offset' => true,
'no_spaces_inside_parenthesis' => true,
'no_trailing_comma_in_list_call' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_trailing_whitespace' => true,
'no_trailing_whitespace_in_comment' => true,
'no_unneeded_control_parentheses' => true,
'no_unneeded_curly_braces' => true,
'no_unneeded_final_method' => true,
'no_unreachable_default_argument_value' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
'non_printable_character' => true,
'normalize_index_brace' => true,
'object_operator_without_whitespace' => true,
'ordered_imports' => true,
'phpdoc_add_missing_param_annotation' => true,
'phpdoc_indent' => true,
'phpdoc_no_access' => true,
'phpdoc_no_alias_tag' => true,
'phpdoc_no_empty_return' => true,
'phpdoc_no_package' => true,
'phpdoc_no_useless_inheritdoc' => true,
'phpdoc_order' => true,
'phpdoc_scalar' => true,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => true,
'phpdoc_to_return_type' => true,
'phpdoc_trim_consecutive_blank_line_separation' => true,
'phpdoc_types' => true,
'phpdoc_types_order' => ['null_adjustment' => 'always_last'],
'phpdoc_var_annotation_correct_order' => true,
'pow_to_exponentiation' => true,
'psr4' => true,
'random_api_migration' => true,
'return_type_declaration' => true,
'self_accessor' => true,
'semicolon_after_instruction' => true,
'set_type_to_cast' => true,
'short_scalar_cast' => true,
'single_blank_line_at_eof' => true,
'single_blank_line_before_namespace' => true,
'single_class_element_per_statement' => true,
'single_import_per_statement' => true,
'single_line_after_imports' => true,
'standardize_not_equals' => true,
'standardize_increment' => true,
'switch_case_semicolon_to_colon' => true,
'switch_case_space' => true,
'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline_array' => true,
'trim_array_spaces' => false,
'unary_operator_spaces' => true,
'visibility_required' => true,
'whitespace_after_comma_in_array' => true,
'yoda_style' => false,
])
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__."/src")
);
-9
View File
@@ -1,9 +0,0 @@
sudo: false
language: php
php:
- '7.1'
- '7.2'
install:
- composer install
script:
- ./t
+1 -1
View File
@@ -1,6 +1,6 @@
# Legend of the Green Dragon (Core) # Legend of the Green Dragon (Core)
[![Build Status](https://travis-ci.org/lotgd/core.svg?branch=master)](https://travis-ci.org/lotgd/core) ![Tests](https://github.com/lotgd/core/workflows/Tests/badge.svg)
Legend of the Green Dragon is a text-based RPG originally developed by Eric Stevens and JT Traub as a remake of and homage to the classic BBS Door game, Legend of the Green Dragon is a text-based RPG originally developed by Eric Stevens and JT Traub as a remake of and homage to the classic BBS Door game,
Legend of the Red Dragon, by Seth Able Robinson. You can play it at numerous sites, including http://www.lotgd.net/. Legend of the Red Dragon, by Seth Able Robinson. You can play it at numerous sites, including http://www.lotgd.net/.
+17 -14
View File
@@ -1,8 +1,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-or-later",
"version": "0.5.0",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"LotGD\\Core\\": "src/", "LotGD\\Core\\": "src/",
@@ -13,15 +12,19 @@
"bin/daenerys" "bin/daenerys"
], ],
"require": { "require": {
"php": "^7.1.0", "php": "^8.0",
"composer/composer": "*", "ext-pdo": "*",
"gedmo/doctrine-extensions": "*", "composer/composer": "^1.10|^2.0",
"doctrine/orm": "^2.5", "gedmo/doctrine-extensions": "^2.3|^3.0",
"monolog/monolog": "^1.12", "doctrine/orm": "^2.8",
"symfony/console": "^3.0|^4.0", "doctrine/common": "^3.0",
"symfony/yaml": "^3.0|^4.0", "monolog/monolog": "^2.0",
"d11wtq/boris": "^1.0", "symfony/console": "^5.0",
"ramsey/uuid-doctrine": "^1.5" "symfony/yaml": "^5.0",
"twig/twig": "^3.0",
"ramsey/uuid-doctrine": "^1.5",
"jetbrains/phpstorm-attributes": "^1.0",
"d11wtq/boris": "^1.0"
}, },
"repositories": [ "repositories": [
{ {
@@ -31,8 +34,8 @@
], ],
"require-dev": { "require-dev": {
"phpunit/phpunit": "^5.0", "phpunit/phpunit": "*",
"phpunit/dbunit": "^2.0", "phpunit/php-code-coverage": "*",
"block8/php-docblock-checker": "2.0.0" "friendsofphp/php-cs-fixer": "*"
} }
} }
Generated
+3572 -1049
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -1,6 +1,7 @@
<phpunit bootstrap="bootstrap/bootstrap.php"> <phpunit bootstrap="bootstrap/bootstrap.php">
<php> <php>
<env name="LOTGD_TESTS_CONFIG_PATH" value="./config/lotgd.yml"/> <env name="LOTGD_TESTS_CONFIG_PATH" value="./config/lotgd.yml"/>
<env name="COLUMNS" value="120" />
</php> </php>
<testsuites> <testsuites>
<testsuite name="All"> <testsuite name="All">
+14 -17
View File
@@ -9,23 +9,20 @@ namespace LotGD\Core;
*/ */
class Action class Action
{ {
protected $id; protected string $id;
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 string $destinationSceneId
* @param string|null $title * @param string|null $title
* @param array $parameters * @param array $parameters
*/ */
public function __construct(string $destinationSceneId, ?string $title = null, array $parameters = []) public function __construct(
{ protected string $destinationSceneId,
$this->id = bin2hex(random_bytes(8)); protected ?string $title = null,
$this->destinationSceneId = $destinationSceneId; protected array $parameters = []
$this->title = $title; ) {
$this->parameters = $parameters; $this->id = \bin2hex(\random_bytes(8));
} }
/** /**
@@ -41,7 +38,7 @@ 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 int * @return string
*/ */
public function getDestinationSceneId(): string public function getDestinationSceneId(): string
{ {
@@ -49,7 +46,7 @@ class Action
} }
/** /**
* @return null|string * @return string|null
*/ */
public function getTitle(): ?string public function getTitle(): ?string
{ {
@@ -57,15 +54,15 @@ class Action
} }
/** /**
* @return null|string * @param string|null $title
*/ */
public function setTitle(?string $title) public function setTitle(?string $title): void
{ {
$this->title = $title; $this->title = $title;
} }
/** /**
* Returns all parameters for this action * Returns all parameters for this action.
* @return array * @return array
*/ */
public function getParameters(): array public function getParameters(): array
@@ -74,7 +71,7 @@ class Action
} }
/** /**
* Sets all parameters for this action * Sets all parameters for this action.
* @param array $parameters * @param array $parameters
*/ */
public function setParameters(array $parameters): void public function setParameters(array $parameters): void
+7 -10
View File
@@ -1,5 +1,5 @@
<?php <?php
declare (strict_types=1); declare(strict_types=1);
namespace LotGD\Core; namespace LotGD\Core;
@@ -11,9 +11,6 @@ class ActionGroup implements \Countable
const DefaultGroup = 'lotgd/core/default'; const DefaultGroup = 'lotgd/core/default';
const HiddenGroup = 'lotgd/core/hidden'; const HiddenGroup = 'lotgd/core/hidden';
private $id;
private $title;
private $sortKey;
private $actions; private $actions;
/** /**
@@ -22,11 +19,11 @@ class ActionGroup implements \Countable
* @param string $title Title to display to the end user. Empty string means no title. * @param string $title Title to display to the end user. Empty string means no title.
* @param int $sortKey Navigation menus are displayed in the order sorted by this integer. * @param int $sortKey Navigation menus are displayed in the order sorted by this integer.
*/ */
public function __construct(string $id, string $title, int $sortKey) public function __construct(
{ private string $id,
$this->id = $id; private string $title,
$this->title = $title; private int $sortKey
$this->sortKey = $sortKey; ) {
$this->actions = []; $this->actions = [];
} }
@@ -36,7 +33,7 @@ class ActionGroup implements \Countable
*/ */
public function count(): int public function count(): int
{ {
return count($this->actions); return \count($this->actions);
} }
/** /**
+15 -17
View File
@@ -3,24 +3,31 @@ declare(strict_types=1);
namespace LotGD\Core; namespace LotGD\Core;
use Exception;
use LotGD\Core\Models\Scene;
/** /**
* An attachment to a scene. This is desigend to be subclasses by modules to * An attachment to a scene. This is desigend to be subclasses by modules to
* provide functinoality like forms or maybe image attachments to go along with a scene. * provide functinoality like forms or maybe image attachments to go along with a scene.
*/ */
abstract class Attachment abstract class Attachment implements AttachmentInterface
{ {
protected $id; protected string $id;
protected $type;
/** /**
* Construct a new attachment of the given type. Randomly assigns it an ID. * Construct a new attachment of the given type. Randomly assigns it an ID.
* @param string $type Type of this attachment, in the vendor/module/type format. * @param Game $game
* @return Attachment * @param Scene $scene
* @throws Exception
*/ */
public function __construct(string $type) public function __construct(Game $game, Scene $scene)
{ {
$this->id = bin2hex(random_bytes(8)); $this->id = \bin2hex(\random_bytes(8));
$this->type = $type; }
public function __toString(): string
{
return "<Attachment#{$this->id} '{". static::class . "}'>";
} }
/** /**
@@ -32,13 +39,4 @@ abstract class Attachment
{ {
return $this->id; return $this->id;
} }
/**
* Returns the type of this attachment, in vendor/module/type format.
* @return string
*/
public function getType(): string
{
return $this->type;
}
} }
+24
View File
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace LotGD\Core;
use LotGD\Core\Models\Scene;
interface AttachmentInterface
{
/**
* AttachmentInterface constructor.
* @param Game $g Should not be saved internally.
* @param Scene $scene Should not be saved internally.
*/
public function __construct(Game $g, Scene $scene);
public function __toString(): string;
public function getId(): string;
/**
* Returns an array with attachment-specific fields.
* @return array
*/
public function getData(): array;
}
+79 -90
View File
@@ -3,21 +3,17 @@ declare(strict_types=1);
namespace LotGD\Core; namespace LotGD\Core;
use Doctrine\Common\Collections\{ use Doctrine\Common\Collections\ArrayCollection;
ArrayCollection, use Doctrine\Common\Collections\Collection;
Collection
};
use LotGD\Core\{ use LotGD\Core\Exceptions\ArgumentException;
DiceBag, use LotGD\Core\Exceptions\BattleIsOverException;
Exceptions\ArgumentException, use LotGD\Core\Exceptions\BattleNotOverException;
Exceptions\BattleIsOverException, use LotGD\Core\Models\BattleEvents\CriticalHitEvent;
Exceptions\BattleNotOverException, use LotGD\Core\Models\BattleEvents\DamageEvent;
Models\FighterInterface use LotGD\Core\Models\BattleEvents\DeathEvent;
}; use LotGD\Core\Models\Buff;
use LotGD\Core\Models\{ use LotGD\Core\Models\FighterInterface;
Buff, BattleEvents\BuffMessageEvent, BattleEvents\CriticalHitEvent, BattleEvents\DamageEvent, BattleEvents\DeathEvent, Scene
};
/** /**
* Class for managing and running battles between 2 participants. * Class for managing and running battles between 2 participants.
@@ -34,18 +30,10 @@ class Battle
const RESULT_PLAYERDEATH = 1; const RESULT_PLAYERDEATH = 1;
const RESULT_MONSTERDEATH = 2; const RESULT_MONSTERDEATH = 2;
protected $player; protected ArrayCollection $events;
protected $monster; protected int $result = 0;
protected $game; protected int $round = 0;
protected $events; protected array $configuration = [
protected $result = 0;
protected $round = 0;
/**
* Battle Configuration
* @var array
*/
protected $configuration = [
"riposteEnabled" => true, "riposteEnabled" => true,
"levelAdjustementEnabled" => true, "levelAdjustementEnabled" => true,
"criticalHitEnabled" => true, "criticalHitEnabled" => true,
@@ -53,15 +41,15 @@ class Battle
/** /**
* Takes a game object and two participants (Player and Monster) to fight a battle. * Takes a game object and two participants (Player and Monster) to fight a battle.
* @param \LotGD\Core\Game $game * @param Game $game
* @param FighterInterface $player * @param FighterInterface $player
* @param FighterInterface $monster * @param FighterInterface|null $monster
*/ */
public function __construct(Game $game, FighterInterface $player, ?FighterInterface $monster) public function __construct(
{ protected Game $game,
$this->game = $game; protected FighterInterface $player,
$this->player = $player; protected ?FighterInterface $monster
$this->monster = $monster; ) {
$this->events = new ArrayCollection(); $this->events = new ArrayCollection();
} }
@@ -71,7 +59,7 @@ class Battle
*/ */
public function serialize(): string public function serialize(): string
{ {
return serialize([ return \serialize([
"monster" => $this->monster, "monster" => $this->monster,
"result" => $this->result, "result" => $this->result,
"round" => $this->round, "round" => $this->round,
@@ -83,14 +71,14 @@ class Battle
* @param Game $game * @param Game $game
* @param FighterInterface $player * @param FighterInterface $player
* @param string $serialized * @param string $serialized
* @return Battle * @return self
*/ */
public static function unserialize(Game $game, FighterInterface $player, string $serialized): self public static function unserialize(Game $game, FighterInterface $player, string $serialized): self
{ {
$battle = new self($game, $player, null); $battle = new self($game, $player, null);
$unserialized = unserialize($serialized); $unserialized = \unserialize($serialized);
$battle->monster = $unserialized["monster"]; $battle->monster = $unserialized["monster"];
$battle->result = $unserialized["result"]; $battle->result = $unserialized["result"];
$battle->round = $unserialized["round"]; $battle->round = $unserialized["round"];
$battle->configuration = $unserialized["configuration"]; $battle->configuration = $unserialized["configuration"];
@@ -99,7 +87,7 @@ class Battle
} }
/** /**
* Returns a list of all battle events * Returns a list of all battle events.
* @return Collection * @return Collection
*/ */
public function getEvents(): Collection public function getEvents(): Collection
@@ -108,23 +96,23 @@ class Battle
} }
/** /**
* Disables ripostes * Disables ripostes.
*/ */
public function disableRiposte() public function disableRiposte(): void
{ {
$this->configuration["riposteEnabled"] = false; $this->configuration["riposteEnabled"] = false;
} }
/** /**
* Enables ripostes * Enables ripostes.
*/ */
public function enableRiposte() public function enableRiposte(): void
{ {
$this->configuration["riposteEnabled"] = true; $this->configuration["riposteEnabled"] = true;
} }
/** /**
* Returns true if ripostes are enabled * Returns true if ripostes are enabled.
* @return bool * @return bool
*/ */
public function isRiposteEnabled(): bool public function isRiposteEnabled(): bool
@@ -133,23 +121,23 @@ class Battle
} }
/** /**
* Enables level adjustement * Enables level adjustement.
*/ */
public function enableLevelAdjustement() public function enableLevelAdjustement(): void
{ {
$this->configuration["levelAdjustementEnabled"] = true; $this->configuration["levelAdjustementEnabled"] = true;
} }
/** /**
* Disables level adjustement * Disables level adjustement.
*/ */
public function disableLevelAdjustement() public function disableLevelAdjustement(): void
{ {
$this->configuration["levelAdjustementEnabled"] = false; $this->configuration["levelAdjustementEnabled"] = false;
} }
/** /**
* Returns true if level adjustements are enabled * Returns true if level adjustements are enabled.
* @return bool * @return bool
*/ */
public function isLevelAdjustementEnabled(): bool public function isLevelAdjustementEnabled(): bool
@@ -158,7 +146,7 @@ class Battle
} }
/** /**
* Returns true if critical hit events are enabled * Returns true if critical hit events are enabled.
* @return bool * @return bool
*/ */
public function isCriticalHitEnabled(): bool public function isCriticalHitEnabled(): bool
@@ -167,17 +155,17 @@ class Battle
} }
/** /**
* Disable critical hits * Disable critical hits.
*/ */
public function disableCriticalHit() public function disableCriticalHit(): void
{ {
$this->configuration["criticalHitEnabled"] = false; $this->configuration["criticalHitEnabled"] = false;
} }
/** /**
* enables critical hits * enables critical hits.
*/ */
public function enableCriticalHit() public function enableCriticalHit(): void
{ {
$this->configuration["criticalHitEnabled"] = true; $this->configuration["criticalHitEnabled"] = true;
} }
@@ -192,7 +180,7 @@ class Battle
} }
/** /**
* Returns the player instance * Returns the player instance.
* @return FighterInterface * @return FighterInterface
*/ */
public function getPlayer(): FighterInterface public function getPlayer(): FighterInterface
@@ -201,7 +189,7 @@ class Battle
} }
/** /**
* Returns the montser instance * Returns the montser instance.
* @return FighterInterface * @return FighterInterface
*/ */
public function getMonster(): FighterInterface public function getMonster(): FighterInterface
@@ -210,9 +198,9 @@ class Battle
} }
/** /**
* Returns the winner of this fight * Returns the winner of this fight.
* @return FighterInterface
* @throws BattleNotOverException if battle is not over. * @throws BattleNotOverException if battle is not over.
* @return FighterInterface
*/ */
public function getWinner(): FighterInterface public function getWinner(): FighterInterface
{ {
@@ -224,9 +212,9 @@ class Battle
} }
/** /**
* Returns the loser of this fight * Returns the loser of this fight.
* @return FighterInterface
* @throws BattleNotOverException if battle is not over. * @throws BattleNotOverException if battle is not over.
* @return FighterInterface
*/ */
public function getLoser(): FighterInterface public function getLoser(): FighterInterface
{ {
@@ -241,10 +229,10 @@ class Battle
* Fights the number of rounds given by the parameter $n and returns the number * Fights the number of rounds given by the parameter $n and returns the number
* of actual rounds fought. * of actual rounds fought.
* @param int $n * @param int $n
* @param bool $firstDamageRound Which damage rounds are calculated. Cannot be 0. * @param int $firstDamageRound Which damage rounds are calculated. Cannot be 0.
* @return int Number of fights fought.
* @throws ArgumentException if firstDamageRound is 0. * @throws ArgumentException if firstDamageRound is 0.
* @throws BattleIsOverException * @throws BattleIsOverException
* @return int Number of fights fought.
*/ */
public function fightNRounds(int $n = 1, int $firstDamageRound = self::DAMAGEROUND_BOTH): int public function fightNRounds(int $n = 1, int $firstDamageRound = self::DAMAGEROUND_BOTH): int
{ {
@@ -265,14 +253,14 @@ class Battle
} }
} }
return $count+1; return $count + 1;
} }
/** /**
* Fights exactly 1 round * Fights exactly 1 round.
* @param int $firstDamageRound * @param int $firstDamageRound
*/ */
protected function fightOneRound(int $firstDamageRound) protected function fightOneRound(int $firstDamageRound): void
{ {
$damageHasBeenDone = false; $damageHasBeenDone = false;
@@ -285,7 +273,7 @@ class Battle
$offenseTurnEvents = $firstDamageRound & self::DAMAGEROUND_PLAYER ? $this->turn($this->player, $this->monster) : new ArrayCollection(); $offenseTurnEvents = $firstDamageRound & self::DAMAGEROUND_PLAYER ? $this->turn($this->player, $this->monster) : new ArrayCollection();
$defenseTurnEvents = $firstDamageRound & self::DAMAGEROUND_MONSTER ? $this->turn($this->monster, $this->player) : new ArrayCollection(); $defenseTurnEvents = $firstDamageRound & self::DAMAGEROUND_MONSTER ? $this->turn($this->monster, $this->player) : new ArrayCollection();
$events = new ArrayCollection(array_merge($offenseTurnEvents->toArray(), $defenseTurnEvents->toArray())); $events = new ArrayCollection([...$offenseTurnEvents->toArray(), ...$defenseTurnEvents->toArray()]);
$eventsToAdd = new ArrayCollection(); $eventsToAdd = new ArrayCollection();
foreach ($events as $event) { foreach ($events as $event) {
@@ -315,17 +303,17 @@ class Battle
$monsterBuffExpiringEvents = $this->monster->getBuffs()->expireOneRound(); $monsterBuffExpiringEvents = $this->monster->getBuffs()->expireOneRound();
$this->events = new ArrayCollection( $this->events = new ArrayCollection(
array_merge( [
$this->events->toArray(), ...$this->events->toArray(),
$playerBuffStartEvents->toArray(), ...$playerBuffStartEvents->toArray(),
$monsterBuffStartEvents->toArray(), ...$monsterBuffStartEvents->toArray(),
$eventsToAdd->toArray(), ...$eventsToAdd->toArray(),
$playerBuffEndEvents->toArray(), ...$playerBuffEndEvents->toArray(),
$monsterBuffEndEvents->toArray(), ...$monsterBuffEndEvents->toArray(),
$playerBuffExpiringEvents->toArray(), ...$playerBuffExpiringEvents->toArray(),
$monsterBuffExpiringEvents->toArray(), ...$monsterBuffExpiringEvents->toArray(),
isset($deathEvent) ? [$deathEvent] : [] ...isset($deathEvent) ? [$deathEvent] : [],
) ]
); );
} }
@@ -333,6 +321,7 @@ class Battle
* Runs one turn. * Runs one turn.
* @param FighterInterface $attacker * @param FighterInterface $attacker
* @param FighterInterface $defender * @param FighterInterface $defender
* @return ArrayCollection
*/ */
protected function turn(FighterInterface $attacker, FighterInterface $defender): ArrayCollection protected function turn(FighterInterface $attacker, FighterInterface $defender): ArrayCollection
{ {
@@ -384,8 +373,8 @@ class Battle
} }
// Conversion from float to int, since the random number generator takes int values. // Conversion from float to int, since the random number generator takes int values.
$attackersAttack = (int) round($attackersAttack, 0); $attackersAttack = (int)\round($attackersAttack, 0);
$defendersDefense = (int) round($defendersDefense, 0); $defendersDefense = (int)\round($defendersDefense, 0);
// Lets roll the // Lets roll the
$attackersAtkRoll = $this->game->getDiceBag()->pseudoBell(0, $attackersAttack); $attackersAtkRoll = $this->game->getDiceBag()->pseudoBell(0, $attackersAttack);
@@ -413,10 +402,10 @@ class Battle
$damage = 0; $damage = 0;
} elseif ($attackerIsInvulnurable) { } elseif ($attackerIsInvulnurable) {
// Attaker is invulnurable, damage is always > 0 (there is no riposte) // Attaker is invulnurable, damage is always > 0 (there is no riposte)
$damage = abs($damage); $damage = \abs($damage);
} elseif ($defenderIsInvulnurable) { } elseif ($defenderIsInvulnurable) {
// Defender is invulnurable, damage is always < 0 (defender always ripostes) // Defender is invulnurable, damage is always < 0 (defender always ripostes)
$damage = - abs($damage); $damage = -\abs($damage);
} }
if ($damage < 0) { if ($damage < 0) {
@@ -438,7 +427,7 @@ class Battle
} }
// Round the damage value and convert to int. // Round the damage value and convert to int.
$damage = (int)round($damage, 0); $damage = (int)\round($damage, 0);
// Add the damage event // Add the damage event
$events->add(new DamageEvent($attacker, $defender, $damage)); $events->add(new DamageEvent($attacker, $defender, $damage));
@@ -454,15 +443,15 @@ class Battle
$defendersDamageDependentBuffEvents = $defendersBuffs->processDamageDependentBuffs(Buff::ACTIVATE_DEFENSE, -$damage, $this->game, $defender, $attacker); $defendersDamageDependentBuffEvents = $defendersBuffs->processDamageDependentBuffs(Buff::ACTIVATE_DEFENSE, -$damage, $this->game, $defender, $attacker);
return new ArrayCollection( return new ArrayCollection(
array_merge( [
$attackersBuffStartEvents->toArray(), ...$attackersBuffStartEvents->toArray(),
$attackersDirectBuffEvents->toArray(), ...$attackersDirectBuffEvents->toArray(),
$defendersBuffStartEvents->toArray(), ...$defendersBuffStartEvents->toArray(),
$defendersDirectBuffEvents->toArray(), ...$defendersDirectBuffEvents->toArray(),
$events->toArray(), ...$events->toArray(),
$attackersDamageDependentBuffEvents->toArray(), ...$attackersDamageDependentBuffEvents->toArray(),
$defendersDamageDependentBuffEvents->toArray() ...$defendersDamageDependentBuffEvents->toArray(),
) ]
); );
} }
} }
+38 -40
View File
@@ -4,28 +4,21 @@ declare(strict_types=1);
namespace LotGD\Core; namespace LotGD\Core;
use Doctrine\Common\Annotations\AnnotationRegistry; use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\Common\EventManager as DoctrineEventManager;
use Doctrine\Common\Util\Debug;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Events as DoctrineEvents; use Doctrine\ORM\Events as DoctrineEvents;
use Doctrine\ORM\ { use Doctrine\ORM\Tools\SchemaTool;
EntityManager, use Doctrine\ORM\Tools\Setup;
EntityManagerInterface, use LotGD\Core\Doctrine\EntityPostLoadEventListener;
Mapping\AnsiQuoteStrategy, use LotGD\Core\Exceptions\InvalidConfigurationException;
Tools\Setup, use Monolog\Handler\RotatingFileHandler;
Tools\SchemaTool use Monolog\Logger;
};
use Monolog\ {
Logger,
Handler\RotatingFileHandler
};
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Application; use Symfony\Component\Console\Application;
use LotGD\Core\{
ComposerManager, BootstrapInterface, Doctrine\EntityPostLoadEventListener, Exceptions\InvalidConfigurationException
};
/** /**
* The entry point for constructing a properly configured LotGD Game object. * The entry point for constructing a properly configured LotGD Game object.
*/ */
@@ -33,24 +26,24 @@ class Bootstrap
{ {
private $logger; private $logger;
private $game; private $game;
/** @var LibraryConfigurationManager */ /** @var LibraryConfigurationManager */
private $libraryConfigurationManager; private $libraryConfigurationManager;
private $annotationDirectories = []; private $annotationDirectories = [];
/** /**
* Create a new Game object, with all the necessary configuration. * Create a new Game object, with all the necessary configuration.
* @param string $cwd * @param string|null $cwd
* @return Game The newly created Game object. * @return Game The newly created Game object.
*/ */
public static function createGame(string $cwd = null): Game public static function createGame(string $cwd = null): Game
{ {
$game = new self(); $game = new self();
$cwd = $cwd ?? getcwd(); $cwd = $cwd ?? \getcwd();
return $game->getGame($cwd); return $game->getGame($cwd);
} }
/** /**
* Starts the game kernel with the most important classes and returns the object * Starts the game kernel with the most important classes and returns the object.
* @param string $cwd * @param string $cwd
* @return Game * @return Game
*/ */
@@ -64,7 +57,7 @@ class Bootstrap
$composer = $this->createComposerManager($cwd); $composer = $this->createComposerManager($cwd);
$this->libraryConfigurationManager = $this->createLibraryConfigurationManager($composer, $cwd); $this->libraryConfigurationManager = $this->createLibraryConfigurationManager($composer, $cwd);
list($dsn, $user, $password) = $config->getDatabaseConnectionDetails($cwd); [$dsn, $user, $password] = $config->getDatabaseConnectionDetails($cwd);
$pdo = $this->connectToDatabase($dsn, $user, $password); $pdo = $this->connectToDatabase($dsn, $user, $password);
$entityManager = $this->createEntityManager($pdo, $config); $entityManager = $this->createEntityManager($pdo, $config);
@@ -73,7 +66,8 @@ class Bootstrap
->withLogger($this->logger) ->withLogger($this->logger)
->withEntityManager($entityManager) ->withEntityManager($entityManager)
->withCwd($cwd) ->withCwd($cwd)
->create(); ->create()
;
// Add Event listener to entity manager // Add Event listener to entity manager
$dem = $entityManager->getEventManager(); $dem = $entityManager->getEventManager();
@@ -86,10 +80,10 @@ class Bootstrap
} }
/** /**
* Creates a library configuration manager * Creates a library configuration manager.
* @param ComposerManager $composerManager * @param ComposerManager $composerManager
* @param string $cwd * @param string $cwd
* @return \LotGD\Core\LibraryConfigurationManager * @return LibraryConfigurationManager
*/ */
protected function createLibraryConfigurationManager( protected function createLibraryConfigurationManager(
ComposerManager $composerManager, ComposerManager $composerManager,
@@ -99,8 +93,10 @@ class Bootstrap
} }
/** /**
* Connects to a database using pdo * Connects to a database using pdo.
* @param \LotGD\Core\Configuration $config * @param string $dsn
* @param string $user
* @param string $password
* @return \PDO * @return \PDO
*/ */
protected function connectToDatabase(string $dsn, string $user, string $password): \PDO protected function connectToDatabase(string $dsn, string $user, string $password): \PDO
@@ -109,7 +105,7 @@ class Bootstrap
} }
/** /**
* Creates and returns an instance of ComposerManager * Creates and returns an instance of ComposerManager.
* @param string $cwd * @param string $cwd
* @return ComposerManager * @return ComposerManager
*/ */
@@ -122,16 +118,16 @@ class Bootstrap
/** /**
* Returns a configuration object reading from the file located at the path stored in $cwd/config/lotgd.yml. * Returns a configuration object reading from the file located at the path stored in $cwd/config/lotgd.yml.
* @param string $cwd * @param string $cwd
* @return \LotGD\Core\Configuration
* @throws InvalidConfigurationException * @throws InvalidConfigurationException
* @return Configuration
*/ */
protected function createConfiguration(string $cwd): Configuration protected function createConfiguration(string $cwd): Configuration
{ {
if (empty($configFilePath)) { if (empty($configFilePath)) {
$configFilePath = implode(DIRECTORY_SEPARATOR, [$cwd, "config", "lotgd.yml"]); $configFilePath = \implode(\DIRECTORY_SEPARATOR, [$cwd, "config", "lotgd.yml"]);
} }
if ($configFilePath === false || strlen($configFilePath) == 0 || is_file($configFilePath) === false) { if ($configFilePath === false || \strlen($configFilePath) == 0 || \is_file($configFilePath) === false) {
throw new InvalidConfigurationException("Invalid or missing configuration file: {$configFilePath}."); throw new InvalidConfigurationException("Invalid or missing configuration file: {$configFilePath}.");
} }
@@ -140,7 +136,7 @@ class Bootstrap
} }
/** /**
* Returns a logger instance * Returns a logger instance.
* @param Configuration $config * @param Configuration $config
* @param string $name * @param string $name
* @return LoggerInterface * @return LoggerInterface
@@ -149,22 +145,23 @@ class Bootstrap
{ {
$logger = new Logger($name); $logger = new Logger($name);
// Add lotgd as the prefix for the log filenames. // Add lotgd as the prefix for the log filenames.
$logger->pushHandler(new RotatingFileHandler($config->getLogPath() . DIRECTORY_SEPARATOR . $name, 14)); $logger->pushHandler(new RotatingFileHandler($config->getLogPath() . \DIRECTORY_SEPARATOR . $name, 14));
return $logger; return $logger;
} }
/** /**
* Creates the EntityManager using the pdo connection given in it's argument * Creates the EntityManager using the pdo connection given in it's argument.
* @param \PDO $pdo * @param \PDO $pdo
* @param Configuration
* @return EntityManagerInterface * @return EntityManagerInterface
*/ */
protected function createEntityManager(\PDO $pdo, Configuration $config): 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->debug("Adding annotation directories:");
foreach ($this->annotationDirectories as $d) { foreach ($this->annotationDirectories as $d) {
$this->logger->addDebug(" {$d}"); $this->logger->debug(" {$d}");
} }
$configuration = Setup::createAnnotationMetadataConfiguration($this->annotationDirectories, true); $configuration = Setup::createAnnotationMetadataConfiguration($this->annotationDirectories, true);
@@ -173,8 +170,9 @@ class Bootstrap
// Register uuid type // Register uuid type
try { try {
\Doctrine\DBAL\Types\Type::addType('uuid', 'Ramsey\Uuid\Doctrine\UuidType'); Type::addType('uuid', 'Ramsey\Uuid\Doctrine\UuidType');
} catch (DBALException $e) {} } catch (DBALException $e) {
}
// Create Schema and update database if needed // Create Schema and update database if needed
if ($config->getDatabaseAutoSchemaUpdate()) { if ($config->getDatabaseAutoSchemaUpdate()) {
@@ -193,12 +191,12 @@ class Bootstrap
protected function generateAnnotationDirectories(): array protected function generateAnnotationDirectories(): array
{ {
// Read db annotations from our own model files. // Read db annotations from our own model files.
$directories = [__DIR__ . DIRECTORY_SEPARATOR . 'Models']; $directories = [__DIR__ . \DIRECTORY_SEPARATOR . 'Models'];
// Get additional annotation directories from library configs. // Get additional annotation directories from library configs.
$libraryDirectories = $this->libraryConfigurationManager->getEntityDirectories(); $libraryDirectories = $this->libraryConfigurationManager->getEntityDirectories();
return array_merge($directories, $libraryDirectories); return \array_merge($directories, $libraryDirectories);
} }
/** /**
+66 -82
View File
@@ -3,73 +3,58 @@ declare(strict_types=1);
namespace LotGD\Core; namespace LotGD\Core;
use Doctrine\Common\Collections\{ use Doctrine\Common\Collections\ArrayCollection;
ArrayCollection, use Doctrine\Common\Collections\Collection;
Collection
};
use LotGD\Core\Exceptions\{
ArgumentException,
BuffListAlreadyActivatedException
};
use LotGD\Core\Models\{
Buff,
Character,
FighterInterface,
BattleEvents\BuffMessageEvent,
BattleEvents\DamageLifetapEvent,
BattleEvents\DamageReflectionEvent,
BattleEvents\RegenerationBuffEvent,
BattleEvents\MinionDamageEvent
};
use LotGD\Core\Exceptions\ArgumentException;
use LotGD\Core\Exceptions\BuffListAlreadyActivatedException;
use LotGD\Core\Exceptions\BuffSlotOccupiedException;
use LotGD\Core\Models\BattleEvents\BuffMessageEvent;
use LotGD\Core\Models\BattleEvents\DamageLifetapEvent;
use LotGD\Core\Models\BattleEvents\DamageReflectionEvent;
use LotGD\Core\Models\BattleEvents\MinionDamageEvent;
use LotGD\Core\Models\BattleEvents\RegenerationBuffEvent;
use LotGD\Core\Models\Buff;
use LotGD\Core\Models\FighterInterface;
/** /**
* Description of BuffList * Description of BuffList.
*/ */
class BuffList class BuffList
{ {
protected $buffs; protected array $buffsBySlot;
protected $buffsBySlot; protected array $activeBuffs = [];
protected $activeBuffs = []; protected ArrayCollection $usedBuffs;
/** @var Doctrine\Common\Collections\ArrayCollection */
protected $usedBuffs;
/** @var boolean True of the modifiers have already been calculated */ /** True of the modifiers have already been calculated */
protected $modifiersCalculated = false; protected bool $modifiersCalculated = false;
/** @var boolean True if the badguy is invulnurable */ /** True if the badguy is invulnurable */
protected $badguyInvulnurable = false; protected bool $badguyInvulnurable = false;
/** @var float */
protected $badguyDamageModifier = 1.;
/** @var float */
protected $badguyAttackModifier = 1.;
/** @var float */
protected $badguyDefenseModifier = 1.;
/** @var boolean True if the goodguy is invulnurable */
protected $goodguyInvulnurable = false;
/** @var float */
protected $goodguyDamageModifier = 1.;
/** @var float */
protected $goodguyAttackModifier = 1.;
/** @var float */
protected $goodguyDefenseModifier = 1.;
protected $events; protected float $badguyDamageModifier = 1.;
protected $loaded = false; protected float $badguyAttackModifier = 1.;
protected float $badguyDefenseModifier = 1.;
protected bool $goodguyInvulnurable = false;
protected float $goodguyDamageModifier = 1.;
protected float $goodguyAttackModifier = 1.;
protected float $goodguyDefenseModifier = 1.;
protected ArrayCollection $events;
protected bool $loaded = false;
/** /**
* Initiates some variables * Initiates some variables.
* @param Collection $buffs * @param Collection $buffs
*/ */
public function __construct(Collection $buffs) public function __construct(
{ protected Collection $buffs
$this->buffs = $buffs; ) {
$this->events = new ArrayCollection(); $this->events = new ArrayCollection();
$this->usedBuffs = new ArrayCollection(); $this->usedBuffs = new ArrayCollection();
} }
/** /**
* Loads all buffs (since it's a lazy correlation) * Loads all buffs (since it's a lazy correlation).
*/ */
public function loadBuffs() public function loadBuffs()
{ {
@@ -97,7 +82,7 @@ class BuffList
} }
/** /**
* Marks the given buff as used * Marks the given buff as used.
* @param Buff $buff * @param Buff $buff
*/ */
protected function useBuff(Buff $buff) protected function useBuff(Buff $buff)
@@ -106,7 +91,7 @@ class BuffList
} }
/** /**
* Returns the buff's start or round message * Returns the buff's start or round message.
* @param Buff $buff * @param Buff $buff
* @return string * @return string
*/ */
@@ -125,7 +110,7 @@ class BuffList
} }
/** /**
* Resets the buff usage for a new round * Resets the buff usage for a new round.
*/ */
public function resetBuffUsage() public function resetBuffUsage()
{ {
@@ -136,22 +121,23 @@ class BuffList
/** /**
* Returns whether any buffs are in use. * Returns whether any buffs are in use.
* @return bool
*/ */
public function hasBuffsInUse(): bool public function hasBuffsInUse(): bool
{ {
return count($this->usedBuffs) > 0 ? true : false; return \count($this->usedBuffs) > 0;
} }
/** /**
* Activates all buffs that activate upon the given activation parameter. * Activates all buffs that activate upon the given activation parameter.
* @param int $activation * @param int $activation
* @return Collection
* @throws ArgumentException * @throws ArgumentException
* @throws BuffListAlreadyActivatedException * @throws BuffListAlreadyActivatedException
* @return Collection
*/ */
public function activate(int $activation): Collection public function activate(int $activation): Collection
{ {
if ($activation%2 !== 0 && $activation !== 1) { if ($activation % 2 !== 0 && $activation !== 1) {
throw new ArgumentException("You can only activate one activation type at a time."); throw new ArgumentException("You can only activate one activation type at a time.");
} }
@@ -186,7 +172,7 @@ class BuffList
} }
/** /**
* Decreases the rounds left on all used buffs * Decreases the rounds left on all used buffs.
* @return Collection A Collection containing expire messages (if there are any) * @return Collection A Collection containing expire messages (if there are any)
*/ */
public function expireOneRound(): Collection public function expireOneRound(): Collection
@@ -261,10 +247,9 @@ class BuffList
} }
/** /**
* Calculates all total modifiers * Calculates all total modifiers.
* @return type
*/ */
protected function calculateModifiers() protected function calculateModifiers(): void
{ {
if ($this->modifiersCalculated === true) { if ($this->modifiersCalculated === true) {
return; return;
@@ -302,14 +287,13 @@ class BuffList
// Only look at buffs that are activated in battle. // Only look at buffs that are activated in battle.
if ($buff->getsActivatedAt(Buff::ACTIVATE_NONE)) { if ($buff->getsActivatedAt(Buff::ACTIVATE_NONE)) {
continue; continue;
} else {
yield $buff;
} }
yield $buff;
} }
} }
/** /**
* Returns the badguy attack modifier calculated over the whole bufflist * Returns the badguy attack modifier calculated over the whole bufflist.
* @return float * @return float
*/ */
public function getBadguyAttackModifier(): float public function getBadguyAttackModifier(): float
@@ -318,8 +302,8 @@ class BuffList
return $this->badguyAttackModifier; return $this->badguyAttackModifier;
} }
/** /**
* Returns the badguy defense modifier calculated over the whole bufflist * Returns the badguy defense modifier calculated over the whole bufflist.
* @return float * @return float
*/ */
public function getBadguyDefenseModifier(): float public function getBadguyDefenseModifier(): float
@@ -329,7 +313,7 @@ class BuffList
} }
/** /**
* Returns the badguy damage modifier calculated over the whole bufflist * Returns the badguy damage modifier calculated over the whole bufflist.
* @return float * @return float
*/ */
public function getBadguyDamageModifier(): float public function getBadguyDamageModifier(): float
@@ -339,7 +323,7 @@ class BuffList
} }
/** /**
* Returns true if the badguy is invulnurable * Returns true if the badguy is invulnurable.
* @return bool * @return bool
*/ */
public function badguyIsInvulnurable(): bool public function badguyIsInvulnurable(): bool
@@ -349,7 +333,7 @@ class BuffList
} }
/** /**
* Returns the badguy attack modifier calculated over the whole bufflist * Returns the badguy attack modifier calculated over the whole bufflist.
* @return float * @return float
*/ */
public function getGoodguyAttackModifier(): float public function getGoodguyAttackModifier(): float
@@ -358,8 +342,8 @@ class BuffList
return $this->goodguyAttackModifier; return $this->goodguyAttackModifier;
} }
/** /**
* Returns the badguy defense modifier calculated over the whole bufflist * Returns the badguy defense modifier calculated over the whole bufflist.
* @return float * @return float
*/ */
public function getGoodguyDefenseModifier(): float public function getGoodguyDefenseModifier(): float
@@ -368,8 +352,8 @@ class BuffList
return $this->goodguyDefenseModifier; return $this->goodguyDefenseModifier;
} }
/** /**
* Returns the badguy damage modifier calculated over the whole bufflist * Returns the badguy damage modifier calculated over the whole bufflist.
* @return float * @return float
*/ */
public function getGoodguyDamageModifier(): float public function getGoodguyDamageModifier(): float
@@ -379,7 +363,7 @@ class BuffList
} }
/** /**
* Returns true if the goodguy is invulnurable * Returns true if the goodguy is invulnurable.
* @return bool * @return bool
*/ */
public function goodguyIsInvulnurable(): bool public function goodguyIsInvulnurable(): bool
@@ -389,9 +373,9 @@ class BuffList
} }
/** /**
* Processes buffs that do direct damage or regeneration * Processes buffs that do direct damage or regeneration.
* @param int $activation * @param int $activation
* @param \LotGD\Core\Game $game * @param Game $game
* @param FighterInterface $goodguy * @param FighterInterface $goodguy
* @param FighterInterface $badguy * @param FighterInterface $badguy
* @return Collection * @return Collection
@@ -477,7 +461,7 @@ class BuffList
$events[] = new MinionDamageEvent( $events[] = new MinionDamageEvent(
$target, $target,
(int)round($damage, 0), (int)\round($damage, 0),
$message $message
); );
} }
@@ -490,10 +474,10 @@ class BuffList
} }
/** /**
* Processes buffs that are dependant on the damage done in one round * Processes buffs that are dependant on the damage done in one round.
* @param int $activation * @param int $activation
* @param int $damage Positive damage is applied to the badguy, negative damage is applied to the goodguy * @param int $damage Positive damage is applied to the badguy, negative damage is applied to the goodguy
* @param \LotGD\Core\Game $game * @param Game $game
* @param FighterInterface $goodguy * @param FighterInterface $goodguy
* @param FighterInterface $badguy * @param FighterInterface $badguy
* @return Collection * @return Collection
@@ -518,7 +502,7 @@ class BuffList
$reflectedDamage = 0; $reflectedDamage = 0;
$message = $buff->getNoEffectMessage(); $message = $buff->getNoEffectMessage();
} else { } else {
$reflectedDamage = (int)round($buff->getGoodguyDamageReflection() * $damage * -1, 0); $reflectedDamage = (int)\round($buff->getGoodguyDamageReflection() * $damage * -1, 0);
if ($reflectedDamage === 0) { if ($reflectedDamage === 0) {
$message = $buff->getNoEffectMessage(); $message = $buff->getNoEffectMessage();
} else { } else {
@@ -536,7 +520,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->getBadguyDamageReflection() * $damage, 0); $reflectedDamage = (int)\round($buff->getBadguyDamageReflection() * $damage, 0);
if ($reflectedDamage === 0) { if ($reflectedDamage === 0) {
$message = $buff->getNoEffectMessage(); $message = $buff->getNoEffectMessage();
} else { } else {
@@ -565,7 +549,7 @@ class BuffList
$message = $buff->getEffectFailsMessage(); $message = $buff->getEffectFailsMessage();
} elseif ($damage < 0) { } elseif ($damage < 0) {
// Damage is < 0, goodguy takes damage. We act upon this. // Damage is < 0, goodguy takes damage. We act upon this.
$healAmount = (int)round($damage * -$buff->getBadguyLifetap(), 0); $healAmount = (int)\round($damage * -$buff->getBadguyLifetap(), 0);
if ($healAmount === 0) { if ($healAmount === 0) {
$message = $buff->getNoEffectMessage(); $message = $buff->getNoEffectMessage();
} else { } else {
@@ -586,7 +570,7 @@ class BuffList
if ($buff->getBadguyLifetap() !== 0.) { if ($buff->getBadguyLifetap() !== 0.) {
if ($damage > 0) { if ($damage > 0) {
// Damage is > 0, badguy takes damage. We act upon this to heal goodguy. // Damage is > 0, badguy takes damage. We act upon this to heal goodguy.
$healAmount = (int)round($damage * $buff->getBadguyLifetap(), 0); $healAmount = (int)\round($damage * $buff->getBadguyLifetap(), 0);
if ($healAmount === 0) { if ($healAmount === 0) {
$message = $buff->getNoEffectMessage(); $message = $buff->getNoEffectMessage();
} else { } else {
+36 -38
View File
@@ -3,33 +3,29 @@ declare(strict_types=1);
namespace LotGD\Core; namespace LotGD\Core;
use Composer\{ use Composer\Composer;
Composer, Factory, IO\NullIO, Package\CompletePackageInterface, Package\PackageInterface use Composer\Factory;
}; use Composer\IO\NullIO;
use Monolog\Logger; use Composer\Package\CompletePackageInterface;
use Composer\Package\PackageInterface;
use Exception;
use LotGD\Core\{ use LotGD\Core\Exceptions\InvalidConfigurationException;
Exceptions\InvalidConfigurationException, use LotGD\Core\Exceptions\LibraryDoesNotExistException;
Exceptions\LibraryDoesNotExistException
};
/** /**
* Helps perform tasks with the composer configuration. * Helps perform tasks with the composer configuration.
*/ */
class ComposerManager class ComposerManager
{ {
private $composer; private ?Composer $composer = null;
private $cwd;
/** /**
* Construct a manager with an optional working directory where composer.json * Construct a manager with an optional working directory where composer.json
* lives. * lives.
* @param string $cwd * @param string $cwd
*/ */
public function __construct(string $cwd) public function __construct(private string $cwd) {}
{
$this->cwd = $cwd;
}
/** /**
* Returns a Composer instance to perform underlying operations on. Be careful. * Returns a Composer instance to perform underlying operations on. Be careful.
@@ -39,8 +35,8 @@ class ComposerManager
{ {
if ($this->composer === null) { if ($this->composer === null) {
// Verify location of composer.json. // Verify location of composer.json.
$composerConfigPath = $this->cwd . DIRECTORY_SEPARATOR . "composer.json"; $composerConfigPath = $this->cwd . \DIRECTORY_SEPARATOR . "composer.json";
if (!file_exists($composerConfigPath)) { if (!\file_exists($composerConfigPath)) {
throw new InvalidConfigurationException("composer.json cannot be found at {$composerConfigPath}."); throw new InvalidConfigurationException("composer.json cannot be found at {$composerConfigPath}.");
} }
@@ -53,8 +49,9 @@ class ComposerManager
/** /**
* Return the Composer package for the corresponding library, in vendor/module format. * Return the Composer package for the corresponding library, in vendor/module format.
* @return PackageInterface Package corresponding to this library. * @param string $library
* @throws LibraryDoesNotExistException * @throws LibraryDoesNotExistException
* @return CompletePackageInterface Package corresponding to this library.
*/ */
public function getPackageForLibrary(string $library): CompletePackageInterface public function getPackageForLibrary(string $library): CompletePackageInterface
{ {
@@ -74,10 +71,10 @@ class ComposerManager
*/ */
public function getPackages(): array public function getPackages(): array
{ {
return array_merge( return [
[$this->getComposer()->getPackage()], $this->getComposer()->getPackage(),
$this->getComposer()->getRepositoryManager()->getLocalRepository()->getPackages() ...$this->getComposer()->getRepositoryManager()->getLocalRepository()->getPackages(),
); ];
} }
/** /**
@@ -86,11 +83,11 @@ class ComposerManager
*/ */
public function getModulePackages(): array public function getModulePackages(): array
{ {
$result = array(); $result = [];
$packages = $this->getComposer()->getRepositoryManager()->getLocalRepository()->getPackages(); $packages = $this->getComposer()->getRepositoryManager()->getLocalRepository()->getPackages();
foreach ($packages as $p) { foreach ($packages as $p) {
if ($p->getType() === 'lotgd-module') { if ($p->getType() === 'lotgd-module') {
array_push($result, $p); \array_push($result, $p);
} }
} }
@@ -103,7 +100,7 @@ class ComposerManager
* @return string|null Path representing $namespace or null if $namespace * @return string|null Path representing $namespace or null if $namespace
* cannot be found or if the path does not exist. * cannot be found or if the path does not exist.
*/ */
public function translateNamespaceToPath(string $namespace) public function translateNamespaceToPath(string $namespace): ?string
{ {
// Find the directory for this namespace by using the autoloader's // Find the directory for this namespace by using the autoloader's
// classmap. // classmap.
@@ -113,32 +110,32 @@ class ComposerManager
// Standardize the namespace to remove any leading \ and add a trailing \ // Standardize the namespace to remove any leading \ and add a trailing \
$n = $namespace; $n = $namespace;
if ('\\' == $n[0]) { if ('\\' == $n[0]) {
$n = substr($n, 1); $n = \substr($n, 1);
} }
if (strlen($n) > 0 && '\\' != $n[strlen($n) - 1]) { if (\strlen($n) > 0 && '\\' != $n[\strlen($n) - 1]) {
$n .= '\\'; $n .= '\\';
} }
$split = explode('\\', $n); $split = \explode('\\', $n);
$suffix = array_splice($split, -1, 1); // starts with [''] $suffix = \array_splice($split, -1, 1); // starts with ['']
$path = null; $path = null;
while (!empty($split)) { while (!empty($split)) {
$key = implode('\\', $split) . '\\'; $key = \implode('\\', $split) . '\\';
$dir = implode(DIRECTORY_SEPARATOR, $suffix); $dir = \implode(\DIRECTORY_SEPARATOR, $suffix);
// Prefix to directory mappings are arrays in Composer's // Prefix to directory mappings are arrays in Composer's
// ClassLoader object. Not sure why. This might break in // ClassLoader object. Not sure why. This might break in
// some unforseen case. // some unforseen case.
if (isset($prefixes[$key]) && is_dir($prefixes[$key][0] . DIRECTORY_SEPARATOR . $dir)) { if (isset($prefixes[$key]) && \is_dir($prefixes[$key][0] . \DIRECTORY_SEPARATOR . $dir)) {
$path = $prefixes[$key][0] . DIRECTORY_SEPARATOR . $dir; $path = $prefixes[$key][0] . \DIRECTORY_SEPARATOR . $dir;
break; break;
} }
$suffix = array_merge($suffix, array_splice($split, -1, 1)); $suffix = \array_merge($suffix, \array_splice($split, -1, 1));
} }
if ($path == null) { if ($path == null) {
return null; return null;
} }
$path = realpath($path); $path = \realpath($path);
if ($path == false) { if ($path == false) {
return null; return null;
} }
@@ -148,19 +145,20 @@ class ComposerManager
/** /**
* Returns a path (could be relative) to the proper autoload.php file in * Returns a path (could be relative) to the proper autoload.php file in
* the current setup. * the current setup.
* @return string
*/ */
public function findAutoloader(): string public function findAutoloader(): string
{ {
// Dance to find the autoloader. // Dance to find the autoloader.
// TOOD: change this to open up the Composer config and use $c['config']['vendor-dir'] instead of "vendor" // TOOD: change this to open up the Composer config and use $c['config']['vendor-dir'] instead of "vendor"
$order = [ $order = [
implode(DIRECTORY_SEPARATOR, [$this->cwd, "vendor", "autoload.php"]), \implode(\DIRECTORY_SEPARATOR, [$this->cwd, "vendor", "autoload.php"]),
implode(DIRECTORY_SEPARATOR, [__DIR__, "..", "vendor", "autoload.php"]), \implode(\DIRECTORY_SEPARATOR, [__DIR__, "..", "vendor", "autoload.php"]),
implode(DIRECTORY_SEPARATOR, [__DIR__, "..", "autoload.php"]), \implode(\DIRECTORY_SEPARATOR, [__DIR__, "..", "autoload.php"]),
]; ];
foreach ($order as $path) { foreach ($order as $path) {
if (file_exists($path)) { if (\file_exists($path)) {
return $path; return $path;
} }
} }
+20 -19
View File
@@ -5,10 +5,10 @@ namespace LotGD\Core;
use DateTime; use DateTime;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
use LotGD\Core\Exceptions\InvalidConfigurationException; use LotGD\Core\Exceptions\InvalidConfigurationException;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
/** /**
* The configuration information for a LotGD game. Configuration is read from * The configuration information for a LotGD game. Configuration is read from
@@ -16,15 +16,15 @@ use LotGD\Core\Exceptions\InvalidConfigurationException;
*/ */
class Configuration class Configuration
{ {
private $databaseDSN; private string $databaseDSN;
private $databaseName; private string $databaseName;
private $databaseUser; private string $databaseUser;
private $databasePassword; private string $databasePassword;
private $databaseAutoSchemaUpdate; private bool $databaseAutoSchemaUpdate;
private $logPath; private string $logPath;
private $gameEpoch; private DateTime $gameEpoch;
private $gameOffsetSeconds; private int $gameOffsetSeconds;
private $gameDaysPerDay; private int $gameDaysPerDay;
/** /**
* Create the configuration object, reading from the specified path. * Create the configuration object, reading from the specified path.
@@ -42,8 +42,8 @@ class Configuration
// Log dir path is relative to config directory. // Log dir path is relative to config directory.
$logPath = $rawConfig['logs']['path'] ?? ''; $logPath = $rawConfig['logs']['path'] ?? '';
$realLogPath = dirname($configFilePath) . DIRECTORY_SEPARATOR . $logPath; $realLogPath = \dirname($configFilePath) . \DIRECTORY_SEPARATOR . $logPath;
if ($realLogPath === false || strlen($realLogPath) == 0 || is_dir($realLogPath) === false) { if ($realLogPath === false || \strlen($realLogPath) == 0 || \is_dir($realLogPath) === false) {
throw new InvalidConfigurationException("Invalid or missing log path: {$realLogPath}"); throw new InvalidConfigurationException("Invalid or missing log path: {$realLogPath}");
} }
$this->logPath = $realLogPath; $this->logPath = $realLogPath;
@@ -53,10 +53,10 @@ class Configuration
$passwd = $rawConfig['database']['password'] ?? ''; $passwd = $rawConfig['database']['password'] ?? '';
$name = $rawConfig['database']['name'] ?? ''; $name = $rawConfig['database']['name'] ?? '';
if ($dsn === false || strlen($dsn) == 0) { if ($dsn === false || \strlen($dsn) == 0) {
throw new InvalidConfigurationException("Invalid or missing data source name: {$dsn}"); throw new InvalidConfigurationException("Invalid or missing data source name: {$dsn}");
} }
if ($user === false || strlen($user) == 0) { if ($user === false || \strlen($user) == 0) {
throw new InvalidConfigurationException("Invalid or missing database user: {$user}"); throw new InvalidConfigurationException("Invalid or missing database user: {$user}");
} }
if ($passwd === false) { if ($passwd === false) {
@@ -105,12 +105,12 @@ class Configuration
*/ */
protected function retrieveRawConfig(string $configFilePath): array protected function retrieveRawConfig(string $configFilePath): array
{ {
return Yaml::parse(file_get_contents($configFilePath)); return Yaml::parse(\file_get_contents($configFilePath));
} }
/** /**
* Returns database connection details needed for pdo to establish a connection. * Returns database connection details needed for pdo to establish a connection.
* *
* This function takes optionally replaces the string %cwd% in the database dsn and * This function takes optionally replaces the string %cwd% in the database dsn and
* replaces it with the first parameter. This is important to normalize the database location * replaces it with the first parameter. This is important to normalize the database location
* across different working directories. Alternatively, SQLite databse names can also directly * across different working directories. Alternatively, SQLite databse names can also directly
@@ -121,7 +121,7 @@ class Configuration
public function getDatabaseConnectionDetails(string $cwd = ""): array public function getDatabaseConnectionDetails(string $cwd = ""): array
{ {
return [ return [
str_replace("%cwd%", $cwd . DIRECTORY_SEPARATOR, $this->getDatabaseDSN()), \str_replace("%cwd%", $cwd . \DIRECTORY_SEPARATOR, $this->getDatabaseDSN()),
$this->getDatabaseUser(), $this->getDatabaseUser(),
$this->getDatabasePassword(), $this->getDatabasePassword(),
]; ];
@@ -213,6 +213,7 @@ class Configuration
/** /**
* Generate a textual representation of the configuration, for debugging * Generate a textual representation of the configuration, for debugging
* purposes. * purposes.
* @return string
*/ */
public function __toString(): string public function __toString(): string
{ {
+22 -3
View File
@@ -3,16 +3,17 @@ declare(strict_types=1);
namespace LotGD\Core\Console\Command; namespace LotGD\Core\Console\Command;
use Symfony\Component\Console\Command\Command;
use LotGD\Core\Game; use LotGD\Core\Game;
use Monolog\Logger;
use Symfony\Component\Console\Command\Command;
/** /**
* Parent class for daenerys tool commands. * Parent class for daenerys tool commands.
*/ */
abstract class BaseCommand extends Command abstract class BaseCommand extends Command
{ {
protected $game; protected Game $game;
protected ?string $namespace = null;
/** /**
* Construct the command, using the provided Game. * Construct the command, using the provided Game.
@@ -23,4 +24,22 @@ abstract class BaseCommand extends Command
parent::__construct(); parent::__construct();
$this->game = $game; $this->game = $game;
} }
/**
* Returns a cloned logger with a different context name.
* @return Logger
*/
public function getCliLogger(): Logger
{
return $this->game->getLogger()->withName("daenerys-cli");
}
protected function namespaced(string $command): string
{
if ($this->namespace) {
return "{$this->namespace}:{$command}";
} else {
return $command;
}
}
} }
@@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Character;
use Exception;
use LotGD\Core\Models\Character;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
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.
*/
class CharacterAddCommand extends CharacterBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("add"))
->setDescription("Add a character.")
->setDefinition(
new InputDefinition([
new InputArgument(
"name",
mode: InputArgument::REQUIRED,
description: "Character name",
),
new InputOption(
"level",
mode: InputOption::VALUE_OPTIONAL,
description: "Character level",
default: 1,
),
new InputOption(
"maxHealth",
mode: InputOption::VALUE_OPTIONAL,
description: "Maximum health of the character. 10*level if not given.",
default: null,
),
])
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$name = $input->getArgument("name");
$level = intval($input->getOption("level"));
$maxHealth = $input->getOption("maxHealth");
if ($level <= 0) {
$io->error("Level must at least be 1.");
return Command::FAILURE;
}
// Set maxHealth in dependence of the level if not given.
if ($maxHealth === null) {
$maxHealth = $level*10;
} else {
$maxHealth = intval($maxHealth);
}
if ($maxHealth < 0) {
$io->error("Maximum health must be at least 0.");
return Command::FAILURE;
} elseif ($maxHealth === 0) {
$io->warning("The character will have 0 max health and will be permanently dead.");
}
$character = Character::createAtFullHealth([
"name" => $name,
"level" => $level,
"maxHealth" => $maxHealth,
]);
try {
$em->persist($character);
// Commit changes
$em->flush();
} catch (Exception $e) {
$io->error("Creating the character was not possible. Reason: {$e->getMessage()}.");
return Command::FAILURE;
}
$io->success("{$character} was successfully created.");
$logger->info("Character was created.", ["character" => $character]);
return Command::SUCCESS;
}
}
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Character;
use LotGD\Core\Console\Command\BaseCommand;
use LotGD\Core\Models\Character;
use Symfony\Component\Console\Input\InputArgument;
class CharacterBaseCommand extends BaseCommand
{
protected ?string $namespace = "character";
/**
* @return InputArgument
*/
protected function getCharacterIdArgumentDefinition(): InputArgument
{
return new InputArgument(
name: "id",
mode: InputArgument::REQUIRED,
description: "Character ID",
);
}
/**
* @param string $id
* @return Character|null
*/
protected function getCharacter(string $id): ?Character
{
/** @var Character|null $character */
$character = $this->game->getEntityManager()->getRepository(Character::class)->find($id);
return $character;
}
}
@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Character;
use LotGD\Core\Events\EventContextData;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class CharacterConfigListCommand extends CharacterBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("config:list"))
->setDescription('List available settings for a character')
->setDefinition([
$this->getCharacterIdArgumentDefinition(),
])
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$character = $this->getCharacter($input->getArgument("id"));
if (!$character) {
$io->error("Character was not found.");
return Command::FAILURE;
}
// Create hook
$context = EventContextData::create([
"character" => $character,
"io" => $io,
"settings" => [],
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/character-config-list",
contextData: $context
);
$settings = $newContext->get("settings");
$io->title("Character ".$character->getDisplayName());
if (count($settings) === 0) {
$io->note("There are no character settings available.");
} else {
$io->table(["setting", "value", "description"], $settings);
}
return Command::SUCCESS;
}
}
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Character;
use LotGD\Core\Events\EventContextData;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class CharacterConfigResetCommand extends CharacterBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("config:reset"))
->setDescription('Reset a character setting')
->setDefinition([
$this->getCharacterIdArgumentDefinition(),
new InputArgument(
"setting",
mode: InputArgument::REQUIRED,
description: "Name of setting, see {$this->namespaced('config:list')}.",
),
])
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$character = $this->getCharacter($input->getArgument("id"));
if (!$character) {
$io->error("Module was not found.");
return Command::FAILURE;
}
$io->title("Character {$character->getDisplayName()}");
// Create hook
$context = EventContextData::create([
"character" => $character,
"io" => $io,
"setting" => $input->getArgument("setting"),
"return" => Command::FAILURE,
"reason" => "Setting does not exist.",
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/character-config-reset",
contextData: $context
);
if ($newContext->get("return") != Command::SUCCESS) {
$io->error($newContext->get("reason"));
return Command::FAILURE;
}
$this->game->getEntityManager()->flush();
return Command::SUCCESS;
}
}
@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Character;
use LotGD\Core\Events\EventContextData;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class CharacterConfigSetCommand extends CharacterBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("config:set"))
->setDescription('Change a character setting')
->setDefinition([
$this->getCharacterIdArgumentDefinition(),
new InputArgument(
"setting",
mode: InputArgument::REQUIRED,
description: "Name of setting, see {$this->namespaced('config:list')}.",
),
new InputArgument(
"value",
InputArgument::REQUIRED,
description: "New value for the given setting.",
),
])
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$character = $this->getCharacter($input->getArgument("id"));
if (!$character) {
$io->error("Module was not found.");
return Command::FAILURE;
}
$io->title("Character {$character->getDisplayName()}");
// Create hook
$context = EventContextData::create([
"character" => $character,
"io" => $io,
"setting" => $input->getArgument("setting"),
"value" => $input->getArgument("value"),
"return" => Command::FAILURE,
"reason" => "Setting does not exist.",
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/character-config-set",
contextData: $context
);
if ($newContext->get("return") != Command::SUCCESS) {
$io->error($newContext->get("reason"));
return Command::FAILURE;
}
$this->game->getEntityManager()->flush();
return Command::SUCCESS;
}
}
@@ -0,0 +1,227 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Character;
use Exception;
use Symfony\Component\Console\Command\Command;
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.
*/
class CharacterEditCommand extends CharacterBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("edit"))
->setDescription("Edit a given character.")
->setDefinition(
new InputDefinition([
$this->getCharacterIdArgumentDefinition(),
new InputOption(
"level",
mode: InputOption::VALUE_REQUIRED,
description: "Changes the level"
),
new InputOption(
"maxHealth",
mode: InputOption::VALUE_REQUIRED,
description: "Change maximum amount of health points. Health will be adjusted accordingly."
),
new InputOption(
"heal",
mode: InputOption::VALUE_NONE,
description: "Restores full health"
),
new InputOption(
"revive",
mode: InputOption::VALUE_OPTIONAL,
description: "Revives at full health. Give a number between 0 and 1 to revive fractionally.",
default: false,
),
new InputOption(
"kill",
mode: InputOption::VALUE_NONE,
description: "Kills"
),
])
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$id = $input->getArgument("id");
$level = $input->getOption("level");
$heal = $input->getOption("heal");
$revive = $input->getOption("revive");
$kill = $input->getOption("kill");
$maxHealth = $input->getOption("maxHealth");
$changed = false;
// Find character
$character = $this->getCharacter($id);
if (!$character) {
$io->error("The character with the id {$id} was not found.");
return Command::FAILURE;
}
// Change level
if ($level !== null) {
$level = intval($level);
if ($level <= 0) {
$io->error("Cannot set the level below 1.");
return Command::FAILURE;
}
// Only change level if necessary
if ($character->getLevel() !== $level) {
// Log
$logger->info("Character level changed", [
"for" => $character,
"from" => $character->getLevel(),
"to" => $level
]);
// Change
$character->setLevel($level);
$changed = true;
}
}
// Heal
if ($heal) {
if ($character->getHealth() >= $character->getMaxHealth()) {
$io->note("Character is already at full health.");
} elseif ($character->isAlive()) {
$oldHealth = $character->getHealth();
// Log
$logger->info("Character health changed", [
"for" => $character,
"from" => $oldHealth,
"to" => $character->getMaxHealth()
]);
// Change
$character->setHealth($character->getMaxHealth());
$io->success("Character was restored to full health ({$oldHealth} to {$character->getMaxHealth()}).");
$changed = true;
} else {
$io->error("Cannot heal a dead character. Use --revive instead.");
return Command::FAILURE;
}
}
// Revive the character
if ($revive !== false) {
// Make sure we revive between 0 and 1
if ($revive === null) {
$revive = 1;
} elseif (str_ends_with($revive, "%")) {
$revive = min(floatval($revive)/100, 1);
} else {
$revive = min(floatval($revive), 1);
}
if ($character->isAlive()) {
$io->error("Character is already alive. Use --heal instead.");
return Command::FAILURE;
} else {
// Make sure we heal at least by 1.
$reviveAmount = (int)round(max($revive * $character->getMaxHealth(), 1), 0);
// Log
$logger->info("Character was revived", [
"for" => $character,
"to" => $reviveAmount
]);
// Change
$character->setHealth($reviveAmount);
$io->success("Character was revived with {$reviveAmount} of health points "
."(max: {$character->getMaxHealth()}).");
$changed = true;
}
}
if ($kill) {
if (!$character->isAlive()) {
$io->error("What is dead may never die.");
return Command::FAILURE;
} else {
// Log
$logger->info("Character was killed", ["for" => $character]);
// Change
$character->setHealth(0);
$io->success("Character was killed.");
$changed = true;
}
}
if ($maxHealth) {
$maxHealth = intval($maxHealth);
if ($maxHealth < 0) {
$io->error("Cannot set maximum health below 0.");
return Command::FAILURE;
}
if ($character->getMaxHealth() === 0) {
$healthProportion = 0;
} else {
$healthProportion = $character->getHealth() / $character->getMaxHealth();
}
// Log
$logger->info("Character maxHealth changed", [
"for" => $character,
"from" => $character->getMaxHealth(),
"to" => $maxHealth
]);
// Change
$character->setMaxHealth($maxHealth);
$character->setHealth((int)round($healthProportion*$maxHealth, 0));
$io->success("Character has new maximum health of {$maxHealth} (current health is {$character->getHealth()}).");
$changed = true;
}
// Save changes
if ($changed) {
try {
$em->flush();
$io->success("The character was successfully changed.");
// Log
$logger->info("Changed committed.");
} catch (Exception $e) {
$io->error("Character could not be saved. Reason: {$e}");
$logger->error("Changes rolled back.", ["exception" => $e]);
return Command::FAILURE;
}
} else {
$io->note("Nothing was changed.");
}
return Command::SUCCESS;
}
}
@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Character;
use LotGD\Core\Models\Character;
use LotGD\Core\Models\Repositories\CharacterRepository;
use Symfony\Component\Console\Command\Command;
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;
/**
* Command to list all characters.
*/
class CharacterListCommand extends CharacterBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("list"))
->setDescription('Lists all characters')
->setDefinition(
new InputDefinition([
new InputOption(
"includeSoftDeleted",
mode: InputOption::VALUE_NONE,
description: "Includes soft-deleted characters",
),
new InputOption(
"onlySoftDeleted",
mode: InputOption::VALUE_NONE,
description: "Displays only soft-deleted characters",
),
])
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$io = new SymfonyStyle($input, $output);
/** @var CharacterRepository $repository */
$repository = $em->getRepository(Character::class);
$marker = "";
if ($input->getOption("includeSoftDeleted")) {
$io->writeln("* marks soft-deleted characters");
$marker = "*";
$characters = $repository->findAll(CharacterRepository::INCLUDE_SOFTDELETED);
} elseif ($input->getOption("onlySoftDeleted")) {
$io->writeln("Only soft-deleted characters are shown");
$characters = $repository->findAll(CharacterRepository::ONLY_SOFTDELETED);
} else {
$characters = $repository->findAll();
}
$table = [["id", "name", "level"], []];
foreach ($characters as $character) {
$table[1][] = [
$character->getId(),
$marker.$character->getName(),
$character->getLevel(),
];
}
$io->table(...$table);
return Command::SUCCESS;
}
}
@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Character;
use Exception;
use LotGD\Core\Models\Character;
use LotGD\Core\Models\Repositories\CharacterRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
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.
*/
class CharacterRemoveCommand extends CharacterBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("remove"))
->setDescription("Definitely removes a character (no soft delete).")
->setDefinition(
new InputDefinition([
$this->getCharacterIdArgumentDefinition(),
new InputOption(
name: "soft",
mode: InputOption::VALUE_NONE,
description: "Only removes the character softly (soft delete)."
),
])
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
/** @var CharacterRepository $characterRepository */
$characterRepository = $em->getRepository(Character::class);
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$id = $input->getArgument("id");
// Find character
/** @var Character $character */
$character = $characterRepository->findWithSoftDeleted($id);
if (!$character) {
$io->error("The character with the id {$id} was not found.");
return Command::FAILURE;
}
if ($character->isDeleted()) {
$io->info("Character was marked as soft-deleted.");
}
try {
if ($input->getOption("soft")) {
// Only soft-delete if requested
$character->delete($em);
// Commit changes
$em->flush();
$io->success("{$character} was successfully soft-deleted.");
$logger->info("Character was soft-deleted.", ["character" => $character]);
} else {
$em->remove($character);
// Commit changes
$em->flush();
$io->success("{$character} was successfully removed.");
$logger->info("Character was removed.", ["character" => $character]);
}
} catch (Exception $e) {
$io->error("Removing {$character} was not possible. Reason: {$e}.");
return Command::FAILURE;
}
return Command::SUCCESS;
}
}
@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Character;
use Exception;
use LotGD\Core\Models\Character;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Resets the viewpoint of a given character.
*/
class CharacterResetViewpointCommand extends CharacterBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("resetViewpoint"))
->setDescription("Resets the viewpoint of a given character.")
->setDefinition(
new InputDefinition([
$this->getCharacterIdArgumentDefinition(),
]),
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$id = $input->getArgument("id");
/* @var $character Character */
$character = $em->getRepository(Character::class)->find($id);
if ($character === null) {
$io->error("Character not found.");
return Command::FAILURE;
}
if ($character->getViewpoint() === null) {
$io->info("Character does not have a viewpoint yet.");
} else {
try {
$em->remove($character->getViewpoint());
$character->setViewpoint(null);
$io->success("Viewpoint was successfully reset.");
# Save
$em->flush();
} catch (Exception $e) {
$io->error("Resetting the viewpoint was not possible. Reason: {$e}");
return Command::FAILURE;
}
}
return Command::SUCCESS;
}
}
@@ -0,0 +1,113 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Character;
use Exception;
use LotGD\Core\Console\Command\BaseCommand;
use LotGD\Core\Models\Character;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputArgument;
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.
*/
class CharacterShowCommand extends CharacterBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("show"))
->setDescription("Shows details about character.")
->setDefinition(
new InputDefinition([
$this->getCharacterIdArgumentDefinition(),
new InputOption(
"onlyViewpoint",
mode: InputOption::VALUE_NONE,
description: "Set to only display viewpoint",
)
])
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$logger = $this->game->getLogger();
$io = new SymfonyStyle($input, $output);
$id = $input->getArgument("id");
$onlyViewpoint = $input->getOption("onlyViewpoint");
// Find character
/** @var Character $character */
$character = $em->getRepository(Character::class)->find($id);
if (!$character) {
$io->error("The character with the id {$id} was not found.");
return Command::FAILURE;
}
if (!$onlyViewpoint) {
$io->title("About Character {$character->getName()}");
$io->listing([
"ID: {$character->getId()}",
"Display name: {$character->getDisplayName()}",
"Level: {$character->getLevel()}",
"Health: {$character->getHealth()}/{$character->getMaxHealth()}",
"Alive: ".($character->isAlive()?"yes":"no"),
"Attack: {$character->getAttack()}",
"Defense: {$character->getDefense()}",
]);
$io->section("Viewpoint");
} else {
$io->title("Viewpoint of {$character->getName()}");
}
$viewpoint = $character->getViewpoint();
if (!$viewpoint) {
$io->text("No viewpoint yet");
} else {
$io->text($viewpoint->getTitle() . "\n");
$io->text($viewpoint->getDescription());
$io->section("Viewpoint actions");
$actionGroups = $viewpoint->getActionGroups();
$rows = [];
foreach ($actionGroups as $actionGroup) {
$rows[] = [$actionGroup->getId(), $actionGroup->getTitle(), "", "", ""];
foreach ($actionGroup->getActions() as $action) {
$rows[] = ["", "", $action->getId(), $action->getTitle(), $action->getDestinationSceneId()];
}
if (count($actionGroup->getActions())) {
$rows[] = new TableSeparator();
}
}
$io->table(["Group id", "Group name", "Action id", "Action name", "Destination"], $rows);
}
return Command::SUCCESS;
}
}
@@ -1,47 +0,0 @@
<?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);
}
}
@@ -1,56 +0,0 @@
<?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();
}
}
+16 -11
View File
@@ -3,6 +3,8 @@ declare(strict_types=1);
namespace LotGD\Core\Console\Command; namespace LotGD\Core\Console\Command;
use LotGD\Core\Game;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
@@ -17,26 +19,29 @@ class ConsoleCommand extends BaseCommand
protected function configure() protected function configure()
{ {
$this->setName('console') $this->setName('console')
->setDescription('Start a shell to interact with the game'); ->setDescription('Start a shell to interact with the game')
;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output): int
{ {
print("Daenerys console, the dragon prompt. lotgd/core " . \LotGD\Core\Game::getVersion() . ".\n"); print "Daenerys console, the dragon prompt. lotgd/core " . Game::getVersion() . ".\n";
print("Enter some PHP, but be careful, this is live and attached to your currently configured setup:\n\n"); print "Enter some PHP, but be careful, this is live and attached to your currently configured setup:\n\n";
print($this->game->getConfiguration()); print $this->game->getConfiguration();
print("\n"); print "\n";
print("Try things like `\$g::getVersion()`. To quit, ^D or `exit();`.\n"); print "Try things like `\$g::getVersion()`. To quit, ^D or `exit();`.\n";
print("\n"); print "\n";
$boris = new \Boris\Boris('🐲 > '); $boris = new \Boris\Boris('🐲 > ');
$boris->setLocal(array( $boris->setLocal([
'g' => $this->game 'g' => $this->game,
)); ]);
$boris->start(); $boris->start();
return Command::SUCCESS;
} }
} }
@@ -1,15 +1,13 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace LotGD\Core\Console\Command; namespace LotGD\Core\Console\Command\Database;
use LotGD\Core\Console\Command\BaseCommand;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
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\Console\Main;
use LotGD\Core\Game;
/** /**
* Danerys command to initiate the database with default values. * Danerys command to initiate the database with default values.
*/ */
@@ -21,14 +19,17 @@ class DatabaseInitCommand extends BaseCommand
protected function configure() protected function configure()
{ {
$this->setName('database:init') $this->setName('database:init')
->setDescription('Initiates database with default values.'); ->setDescription('Initiates database with default values.')
;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$this->game->getEntityManager()->flush(); $this->game->getEntityManager()->flush();
return Command::SUCCESS;
} }
} }
@@ -1,16 +1,14 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace LotGD\Core\Console\Command; namespace LotGD\Core\Console\Command\Database;
use LotGD\Core\Console\Command\BaseCommand;
use Doctrine\ORM\Tools\SchemaTool; use Doctrine\ORM\Tools\SchemaTool;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
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\Console\Main;
use LotGD\Core\Game;
/** /**
* Danerys command to initiate the database with default values. * Danerys command to initiate the database with default values.
*/ */
@@ -22,13 +20,14 @@ class DatabaseSchemaUpdateCommand extends BaseCommand
protected function configure() protected function configure()
{ {
$this->setName('database:schemaUpdate') $this->setName('database:schemaUpdate')
->setDescription('Updates the database schema manually.'); ->setDescription('Updates the database schema manually.')
;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$entityManager = $this->game->getEntityManager(); $entityManager = $this->game->getEntityManager();
$metaData = $entityManager->getMetadataFactory()->getAllMetadata(); $metaData = $entityManager->getMetadataFactory()->getAllMetadata();
@@ -36,5 +35,7 @@ class DatabaseSchemaUpdateCommand extends BaseCommand
$schemaTool->updateSchema($metaData); $schemaTool->updateSchema($metaData);
$entityManager->flush(); $entityManager->flush();
return Command::SUCCESS;
} }
} }
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Module;
use Doctrine\Persistence\ObjectRepository;
use LotGD\Core\Console\Command\BaseCommand;
use LotGD\Core\Models\Module;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
class ModuleBaseCommand extends BaseCommand
{
protected ?string $namespace = "module";
/**
* @return InputArgument
*/
protected function getModuleNameArgumentDefinition(): InputArgument
{
return new InputArgument(
name: "moduleName",
mode: InputArgument::REQUIRED,
description: "Name of the module, in vendor/package format",
);
}
protected function getModuleRepository(): ObjectRepository
{
return $this->game->getEntityManager()->getRepository(Module::class);
}
protected function getModuleModel(InputInterface $input): ?Module
{
return $this->game->getModuleManager()->getModule($input->getArgument("moduleName"));
}
}
@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Module;
use LotGD\Core\Events\EventContextData;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class ModuleConfigListCommand extends ModuleBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("config:list"))
->setDescription('List available configuration option for a module')
->setDefinition([
$this->getModuleNameArgumentDefinition(),
])
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$module = $this->getModuleModel($input);
if (!$module) {
$io->error("Module was not found.");
return Command::FAILURE;
}
// Create hook
$context = EventContextData::create([
"module" => $module,
"io" => $io,
"settings" => [],
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/module-config-list/".$module->getLibrary(),
contextData: $context
);
$settings = $newContext->get("settings");
$io->title("Module ".$module->getLibrary());
if (count($settings) === 0) {
$io->note("This module does not provide any settings.");
} else {
$io->table(["setting", "value", "description"], $settings);
}
return Command::SUCCESS;
}
}
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Module;
use LotGD\Core\Events\EventContextData;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class ModuleConfigResetCommand extends ModuleBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("config:reset"))
->setDescription('Reset a module setting')
->setDefinition([
$this->getModuleNameArgumentDefinition(),
new InputArgument(
"setting",
mode: InputArgument::REQUIRED,
description: "Name of setting, see {$this->namespaced('config:list')}.",
),
])
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$module = $this->getModuleModel($input);
if (!$module) {
$io->error("Module was not found.");
return Command::FAILURE;
}
$io->title("Module {$module->getLibrary()}");
// Create hook
$context = EventContextData::create([
"module" => $module,
"io" => $io,
"setting" => $input->getArgument("setting"),
"return" => Command::FAILURE,
"reason" => "Setting does not exist.",
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/module-config-reset/{$module->getLibrary()}",
contextData: $context
);
if ($newContext->get("return") != Command::SUCCESS) {
$io->error($newContext->get("reason"));
return Command::FAILURE;
}
$this->game->getEntityManager()->flush();
return Command::SUCCESS;
}
}
@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Module;
use LotGD\Core\Events\EventContextData;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class ModuleConfigSetCommand extends ModuleBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("config:set"))
->setDescription('Change a module setting')
->setDefinition([
$this->getModuleNameArgumentDefinition(),
new InputArgument(
"setting",
mode: InputArgument::REQUIRED,
description: "Name of setting, see {$this->namespaced('config:list')}.",
),
new InputArgument(
"value",
InputArgument::REQUIRED,
description: "New value for the given setting.",
),
])
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$module = $this->getModuleModel($input);
if (!$module) {
$io->error("Module was not found.");
return Command::FAILURE;
}
$io->title("Module {$module->getLibrary()}");
// Create hook
$context = EventContextData::create([
"module" => $module,
"io" => $io,
"setting" => $input->getArgument("setting"),
"value" => $input->getArgument("value"),
"return" => Command::FAILURE,
"reason" => "Setting does not exist.",
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/module-config-set/{$module->getLibrary()}",
contextData: $context
);
if ($newContext->get("return") != Command::SUCCESS) {
$io->error($newContext->get("reason"));
return Command::FAILURE;
}
$this->game->getEntityManager()->flush();
return Command::SUCCESS;
}
}
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Module;
use LotGD\Core\Models\Module;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class ModuleListCommand extends ModuleBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("list"))
->setDescription('List all installed modules.')
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
/** @var Module[] $modules */
$modules = $this->game->getModuleManager()->getModules();
$io->title("Installed modules");
if (count($modules) > 0) {
$listing = [];
foreach ($modules as $module) {
$listing[] = [$module->getLibrary() => $module->getCreatedAt()->format("d M Y, H:i")];
}
$io->definitionList(...$listing);
} else {
$io->note("No modules installed.");
}
return Command::SUCCESS;
}
}
@@ -1,77 +1,111 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace LotGD\Core\Console\Command; namespace LotGD\Core\Console\Command\Module;
use Composer\Repository\RepositoryInterface; use Exception;
use LotGD\Core\ModuleManager; use LotGD\Core\Console\Command\BaseCommand;
use LotGD\Core\Exceptions\ClassNotFoundException;
use LotGD\Core\Exceptions\InvalidConfigurationException;
use LotGD\Core\Exceptions\ModuleAlreadyExistsException;
use LotGD\Core\Exceptions\WrongTypeException;
use LotGD\Core\LibraryConfiguration;
use Symfony\Component\Console\Command\Command;
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\ModuleAlreadyExistsException;
use LotGD\Core\LibraryConfiguration;
use Symfony\Component\Console\Style\SymfonyStyle; 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.
*/ */
class ModuleRegisterCommand extends BaseCommand class ModuleRegisterCommand extends ModuleBaseCommand
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function configure() protected function configure()
{ {
$this->setName('module:register') $this->setName($this->namespaced("register"))
->setDescription('Register and initialize any newly installed modules'); ->setDescription('Register and initialize any newly installed modules')
;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$io = new SymfonyStyle($input, $output); $io = new SymfonyStyle($input, $output);
$modules = $this->game->getComposerManager()->getModulePackages(); $modules = $this->game->getComposerManager()->getModulePackages();
$globalFlawless = true;
$registered = []; $registered = [];
foreach ($modules as $p) { foreach ($modules as $p) {
$this->registerModule($p->getName(), $io, $registered); $flawless = $this->registerModule($p->getName(), $io, $registered);
$globalFlawless &= $flawless;
} }
if (!$globalFlawless) {
$io->warning("Some module were not registered properly.");
return Command::FAILURE;
}
return Command::SUCCESS;
} }
/** /**
* Register a given package as a module if it is of type lotdg-module. Resolves dependencies and skips already registered packages. * 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 string $packageName
* @param OutputInterface $output * @param SymfonyStyle $io
* @param array $registered * @param array $registered
* @throws \LotGD\Core\Exceptions\InvalidConfigurationException * @return bool True if registering was flawless
* @throws \LotGD\Core\Exceptions\WrongTypeException * @throws InvalidConfigurationException
* @throws WrongTypeException
* @throws Exception
*/ */
protected function registerModule( protected function registerModule(
string $packageName, string $packageName,
SymfonyStyle $io, SymfonyStyle $io,
array &$registered array &$registered
) { ): bool {
$composerRepository = $this->game->getComposerManager()->getComposer() $composerRepository = $this->game->getComposerManager()->getComposer()
->getRepositoryManager()->getLocalRepository(); ->getRepositoryManager()->getLocalRepository();
$package = $composerRepository->findPackage($packageName, "*"); $package = $composerRepository->findPackage($packageName, "*");
# Skip if not a lotgd-module
if ($package->getType() !== "lotgd-module") { if ($package->getType() !== "lotgd-module") {
return; return true;
} }
# Skip if already registered
if (!empty($registered[$packageName])) { if (!empty($registered[$packageName])) {
return; return true;
} }
$io->text("Reading module {$packageName} {$package->getPrettyVersion()}"); $io->text("Reading module {$packageName} {$package->getPrettyVersion()}");
$library = new LibraryConfiguration($this->game->getComposerManager(), $package, $this->game->getCWD()); # Try to load module configuration ($moduleRoot/lotgd.yml)
try {
$library = new LibraryConfiguration($this->game->getComposerManager(), $package, $this->game->getCWD());
} catch (InvalidConfigurationException) {
$io->error("\tModule {$packageName} does not have a valid lotgd.yml in its root.");
return false;
}
# Register dependencies first.
$dependencyFlawless = true;
$dependencies = $package->getRequires(); $dependencies = $package->getRequires();
foreach ($dependencies as $dependency) { foreach ($dependencies as $dependency) {
$this->registerModule($dependency->getTarget(), $io, $registered); $dependencyFlawless &= $this->registerModule($dependency->getTarget(), $io, $registered);
}
# If $dependencyFlawless is not true anymore (as true & false == 0), we should abort as a dependency was not met.
if (!$dependencyFlawless) {
$io->warning("\t{$packageName} was not completely installed, as one of its dependencies had an "
."error during registration.");
return false;
} }
try { try {
@@ -81,8 +115,11 @@ class ModuleRegisterCommand extends BaseCommand
$io->note("\tSkipping already registered module {$packageName}"); $io->note("\tSkipping already registered module {$packageName}");
} catch (ClassNotFoundException $e) { } catch (ClassNotFoundException $e) {
$io->error("\tError installing module {$packageName}: {$e->getMessage()}"); $io->error("\tError installing module {$packageName}: {$e->getMessage()}");
return false;
} }
$registered[$packageName] = true; $registered[$packageName] = true;
return true;
} }
} }
@@ -1,40 +1,44 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace LotGD\Core\Console\Command; namespace LotGD\Core\Console\Command\Module;
use LotGD\Core\Console\Command\BaseCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
/** /**
* Danerys command to validate installed modules. * Danerys command to validate installed modules.
*/ */
class ModuleValidateCommand extends BaseCommand class ModuleValidateCommand extends ModuleBaseCommand
{ {
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function configure() protected function configure()
{ {
$this->setName('module:validate') $this->setName($this->namespaced("validate"))
->setDescription('Validate installed modules'); ->setDescription('Validate installed modules')
;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function execute(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$results = $this->game->getModuleManager()->validate(); $results = $this->game->getModuleManager()->validate();
if (count($results) > 0) { if (\count($results) > 0) {
foreach ($results as $r) { foreach ($results as $r) {
$output->writeln($r); $output->writeln($r);
} }
return 1;
} else { return Command::FAILURE;
$output->writeln("<info>LotGD modules validated</info>");
return 0;
} }
$output->writeln("<info>LotGD modules validated</info>");
return Command::SUCCESS;
} }
} }
@@ -0,0 +1,99 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use Exception;
use LotGD\Core\Models\Scene;
use LotGD\Core\Models\SceneTemplate;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
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.
*/
class SceneAddCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("add"))
->setDescription("Add a scene.")
->setDefinition(
new InputDefinition([
new InputArgument(
"title",
mode: InputArgument::REQUIRED,
description: "Scene title",
),
new InputArgument(
"description",
mode: InputArgument::OPTIONAL,
description: "Scene description",
default: "",
),
new InputOption(
"template",
mode: InputOption::VALUE_OPTIONAL,
description: "A valid, user-assignable scene template. Check sceneTemplate:list to get all available scenes.",
default: null,
)
])
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$title = $input->getArgument("title");
$description = $input->getArgument("description");
$templateClass = $input->getOption("template");
/* @var $template SceneTemplate */
if ($templateClass) {
$template = $em->getRepository(SceneTemplate::class)->find($templateClass);
if (!$template) {
$io->warning("Template '$template' has not been found. Set to NULL instead.");
}
} else {
$template = $templateClass;
}
$scene = new Scene(
title: $title,
description: $description,
template: $template
);
try {
$em->persist($scene);
// Commit changes
$em->flush();
} catch (Exception $e) {
$io->error("Persisting of the scene was not possible. Reason: {$e->getMessage()}.");
return Command::FAILURE;
}
$io->success("Scene was successfully created. ID: {$scene->getId()}.");
$logger->info("{$scene} was created.");
return Command::SUCCESS;
}
}
@@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use Exception;
use LotGD\Core\Exceptions\ArgumentException;
use LotGD\Core\Models\Scene;
use LotGD\Core\Models\SceneConnectionGroup;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Resets the viewpoint of a given character.
*/
class SceneAddConnectionGroupCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced('addConnectionGroup'))
->setDescription("Add a connection group to an existing scene.")
->setDefinition(
new InputDefinition([
$this->getSceneIdArgumentDefinition(),
new InputArgument("groupName", InputArgument::REQUIRED, "Internal id of the group."),
new InputArgument("groupTitle", InputArgument::REQUIRED, "Title of the group (what the character can see"),
]),
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$sceneId = $input->getArgument("id");
$groupName = $input->getArgument("groupName");
$groupTitle = $input->getArgument("groupTitle");
// Search scene
/** @var ?Scene $scene */
$scene = $em->getRepository(Scene::class)->find($sceneId);
if (!$scene) {
$io->error("The requested scene with the ID {$sceneId} was not found.");
return Command::FAILURE;
}
// Make scene connection group
$connectionGroup = new SceneConnectionGroup($groupName, $groupTitle);
// Add
try {
$scene->addConnectionGroup($connectionGroup);
// Commit changes
$em->flush();
} catch(ArgumentException $e) {
// Catches the error if a group already exists.
$io->error($e->getMessage());
return Command::FAILURE;
} catch (Exception $e) {
$io->error("An unknown error occurred: {$e->getMessage()}");
return Command::FAILURE;
}
$io->success("{$connectionGroup} successfully added.");
$logger->info("{$connectionGroup} was added to {$scene}.");
return Command::SUCCESS;
}
}
@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use LotGD\Core\Console\Command\BaseCommand;
use LotGD\Core\Models\Scene;
use LotGD\Core\SceneTemplates\SceneTemplateInterface;
use Symfony\Component\Console\Input\InputArgument;
class SceneBaseCommand extends BaseCommand
{
protected ?string $namespace = "scene";
/**
* @return InputArgument
*/
protected function getSceneIdArgumentDefinition(): InputArgument
{
return new InputArgument(
name: "id",
mode: InputArgument::REQUIRED,
description: "Scene ID",
);
}
/**
* @param string $id
* @return Scene|null
*/
protected function getScene(string $id): ?Scene
{
/** @var Scene|null $scene */
$scene = $this->game->getEntityManager()->getRepository(Scene::class)->find($id);
return $scene;
}
/**
* @param Scene $scene
* @return string
*/
protected function getSceneTemplatePath(Scene $scene)
{
$sceneTemplate = "no-template";
if ($scene->getTemplate()) {
/** @var SceneTemplateInterface $templateClass */
$templateClass = $scene->getTemplate()->getClass();
$sceneTemplate = $templateClass::getNavigationEvent();
}
return $sceneTemplate;
}
}
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use LotGD\Core\Events\EventContextData;
use LotGD\Core\SceneTemplates\SceneTemplateInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class SceneConfigListCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("config:list"))
->setDescription('List available settings for a scene')
->setDefinition([
$this->getSceneIdArgumentDefinition(),
])
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$scene = $this->getScene($input->getArgument("id"));
if (!$scene) {
$io->error("Scene was not found.");
return Command::FAILURE;
}
$sceneTemplate = $this->getSceneTemplatePath($scene);
// Create hook
$context = EventContextData::create([
"scene" => $scene,
"io" => $io,
"settings" => [],
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/scene-config-list/$sceneTemplate",
contextData: $context
);
$settings = $newContext->get("settings");
$io->title("Scene ".$scene->getTitle());
if (count($settings) === 0) {
$io->note("There are no scene settings available.");
} else {
$io->table(["setting", "value", "description"], $settings);
}
return Command::SUCCESS;
}
}
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use LotGD\Core\Events\EventContextData;
use LotGD\Core\SceneTemplates\SceneTemplateInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class SceneConfigResetCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("config:reset"))
->setDescription('Reset a scene setting')
->setDefinition([
$this->getSceneIdArgumentDefinition(),
new InputArgument(
"setting",
mode: InputArgument::REQUIRED,
description: "Name of setting, see {$this->namespaced('config:list')}.",
),
])
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$scene = $this->getScene($input->getArgument("id"));
if (!$scene) {
$io->error("Scene was not found.");
return Command::FAILURE;
}
$sceneTemplate = $this->getSceneTemplatePath($scene);
$io->title("Scene {$scene->getTitle()}");
// Create hook
$context = EventContextData::create([
"scene" => $scene,
"io" => $io,
"setting" => $input->getArgument("setting"),
"return" => Command::FAILURE,
"reason" => "Setting does not exist.",
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/scene-config-reset/{$sceneTemplate}",
contextData: $context
);
if ($newContext->get("return") != Command::SUCCESS) {
$io->error($newContext->get("reason"));
return Command::FAILURE;
}
$this->game->getEntityManager()->flush();
return Command::SUCCESS;
}
}
@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use LotGD\Core\Events\EventContextData;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class SceneConfigSetCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("config:set"))
->setDescription('Change a scene setting')
->setDefinition([
$this->getSceneIdArgumentDefinition(),
new InputArgument(
"setting",
mode: InputArgument::REQUIRED,
description: "Name of setting, see {$this->namespaced('config:list')}.",
),
new InputArgument(
"value",
InputArgument::REQUIRED,
description: "New value for the given setting.",
),
])
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$scene = $this->getScene($input->getArgument("id"));
if (!$scene) {
$io->error("Scene was not found.");
return Command::FAILURE;
}
$sceneTemplate = $this->getSceneTemplatePath($scene);
$io->title("Scene {$scene->getTitle()}");
// Create hook
$context = EventContextData::create([
"scene" => $scene,
"io" => $io,
"setting" => $input->getArgument("setting"),
"value" => $input->getArgument("value"),
"return" => Command::FAILURE,
"reason" => "Setting does not exist.",
]);
$newContext = $this->game->getEventManager()->publish(
event: "h/lotgd/core/cli/scene-config-set/{$sceneTemplate}",
contextData: $context
);
if ($newContext->get("return") != Command::SUCCESS) {
$io->error($newContext->get("reason"));
return Command::FAILURE;
}
$this->game->getEntityManager()->flush();
return Command::SUCCESS;
}
}
@@ -0,0 +1,155 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use Exception;
use LotGD\Core\Exceptions\ArgumentException;
use LotGD\Core\Models\Scene;
use LotGD\Core\Models\SceneConnectable;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
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.
*/
class SceneConnectCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("connect"))
->setDescription("Connects two scenes.")
->setDefinition(
new InputDefinition([
new InputArgument(
"outgoing",
mode: InputArgument::REQUIRED,
description: "Outgoing scene ID",
),
new InputArgument(
"incoming",
mode: InputArgument::REQUIRED,
description: "Incoming scene ID",
),
new InputOption(
"outgoingGroupName",
shortcut: "o",
mode: InputOption::VALUE_OPTIONAL,
description: "A valid, user-assignable scene template. Check sceneTemplate:list to get all available scenes.",
default: null,
),
new InputOption(
"incomingGroupName",
shortcut: "i",
mode: InputOption::VALUE_OPTIONAL,
description: "A valid, user-assignable scene template. Check sceneTemplate:list to get all available scenes.",
default: null,
),
new InputOption(
"directionality",
shortcut: "d",
mode: InputOption::VALUE_OPTIONAL,
description: "0 for bidirectional, 1 for unidirectional (outgoing->incoming)",
default: 0,
)
])
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$logger = $this->getCliLogger();
$sceneRepository = $em->getRepository(Scene::class);
$io = new SymfonyStyle($input, $output);
/** @var ?Scene $outgoingScene */
$outgoingScene = $sceneRepository->find($input->getArgument("outgoing"));
/** @var ?Scene $incomingScene */
$incomingScene = $sceneRepository->find($input->getArgument("incoming"));
// Check of scenes actually exist
if (!$outgoingScene) {
$io->error("The outgoing scene was not found.");
return Command::FAILURE;
}
if (!$incomingScene) {
$io->error("The incoming scene was not found");
return Command::FAILURE;
}
// Get group names
$outgoingGroupName = $input->getOption("outgoingGroupName");
$incomingGroupName = $input->getOption("incomingGroupName");
/** @var SceneConnectable $outgoing */
$outgoing = null;
/** @var SceneConnectable $outgoing */
$incoming = null;
// Determine the outgoing Connectable
if ($outgoingGroupName) {
if (!$outgoingScene->hasConnectionGroup($outgoingGroupName)) {
$io->error("The outgoing scene does not have a connection group with the id {$outgoingGroupName}");
return Command::FAILURE;
} else {
$outgoing = $outgoingScene->getConnectionGroup($outgoingGroupName);
}
} else {
$outgoing = $outgoingScene;
}
// Determine the incoming Connectable
if ($incomingGroupName) {
if (!$incomingScene->hasConnectionGroup($incomingGroupName)) {
$io->error("The incoming scene does not have a connection group with the id {$incomingGroupName}");
return Command::FAILURE;
} else {
$incoming = $incomingScene->getConnectionGroup($incomingGroupName);
}
} else {
$incoming = $incomingScene;
}
// Get directionality
$directionality = intval($input->getOption("directionality"));
if ($directionality < 0 or $directionality > 1) {
$io->warning("Directionality was not either 0 or 1. It was forced to 0.");
$directionality = 0;
}
// Connect the connectables
try {
$outgoing->connect($incoming, $directionality);
// Commit changes
$em->flush();
} catch (ArgumentException $e) {
$io->error("Scenes were not connected. Reason: {$e->getMessage()}.");
return Command::FAILURE;
} catch (Exception $e) {
$io->error("An unknown error occurred: {$e}");
return Command::FAILURE;
}
$io->success("The two scenes were successfully connected.");
$logger->info("Connected {$outgoingScene} to {$incomingScene}.");
return Command::SUCCESS;
}
}
@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use Exception;
use LotGD\Core\Models\Scene;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Resets the viewpoint of a given character.
*/
class SceneDisconnectCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("disconnect"))
->setDescription("Disconnects two scenes.")
->setDefinition(
new InputDefinition([
new InputArgument(
"scene1",
mode: InputArgument::REQUIRED,
description: "One scene ID",
),
new InputArgument(
"scene2",
mode: InputArgument::REQUIRED,
description: "The other scene ID",
),
])
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$logger = $this->getCliLogger();
$sceneRepository = $em->getRepository(Scene::class);
$io = new SymfonyStyle($input, $output);
/** @var Scene $scene1 */
$scene1 = $sceneRepository->find($input->getArgument("scene1"));
/** @var Scene $scene2 */
$scene2 = $sceneRepository->find($input->getArgument("scene2"));
if (!$scene1) {
$io->error("Scene with id {$input->getArgument('scene1')} was not found.");
return Command::FAILURE;
}
if (!$scene2) {
$io->error("Scene with id {$input->getArgument('scene2')} was not found.");
return Command::FAILURE;
}
$connection = $scene1->getConnectionTo($scene2);
if (!$connection) {
$io->error("The given scenes do not share a connection.");
return Command::FAILURE;
}
try {
// Commit changes
$em->remove($connection);
$em->flush();
} catch (Exception $e) {
$io->error("An unknown error occurred: {$e->getMessage()}");
return Command::FAILURE;
}
$io->success("The connections between the two given scenes was removed.");
$logger->info("Disconnected {$connection->getOutgoingScene()} and {$connection->getIncomingScene()}.");
return Command::SUCCESS;
}
}
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use LotGD\Core\Console\Command\BaseCommand;
use LotGD\Core\Models\Scene;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class SceneListCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("list"))
->setDescription("Lists all scenes")
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$io = new SymfonyStyle($input, $output);
/** @var Scene[] $scenes */
$scenes = $em->getRepository(Scene::class)->findAll();
$table = [["id", "title", "connections", "template"], []];
foreach ($scenes as $scene) {
$table[1][] = [
$scene->getId(),
$scene->getTitle(),
count($scene->getConnectedScenes()),
$scene->getTemplate()?->getClass(),
];
}
$io->table(...$table);
return Command::SUCCESS;
}
}
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use LotGD\Core\Models\Scene;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Resets the viewpoint of a given character.
*/
class SceneRemoveCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("remove"))
->setDescription("Removes a scene.")
->setDefinition(
new InputDefinition([
$this->getSceneIdArgumentDefinition(),
])
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$io = new SymfonyStyle($input, $output);
$sceneId = $input->getArgument("id");
// Get scene
/** @var Scene $scene */
$scene = $em->getRepository(Scene::class)->find($sceneId);
if (!$scene) {
$io->error("The scene with the ID {$sceneId} was not found.");
return Command::FAILURE;
}
if (!$scene->isRemovable()) {
$io->error("The scene with the ID {$sceneId} was marked as not removable. Please remove the responsible module instead.");
return Command::FAILURE;
}
// Mark for removal and flush
try {
$em->remove($scene);
$em->flush();
} catch (\Exception $e) {
$io->error("Removal of {$sceneId} was not possible: {$e->getMessage()}");
return Command::FAILURE;
}
$io->success("{$scene} was successfully removed.");
return Command::SUCCESS;
}
}
@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use LotGD\Core\Models\Scene;
use LotGD\Core\Models\SceneConnection;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Resets the viewpoint of a given character.
*/
class SceneRemoveConnectionGroupCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("removeConnectionGroup"))
->setDescription("Removes a connection group from an existing scene.")
->setDefinition(
new InputDefinition([
$this->getSceneIdArgumentDefinition(),
new InputArgument("groupName", InputArgument::REQUIRED, "Internal id of the group."),
]),
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$logger = $this->getCliLogger();
$io = new SymfonyStyle($input, $output);
$sceneId = $input->getArgument("id");
$groupName = $input->getArgument("groupName");
// Search scene
/** @var ?Scene $scene */
$scene = $em->getRepository(Scene::class)->find($sceneId);
if (!$scene) {
$io->error("The scene with the ID {$sceneId} was not found.");
return Command::FAILURE;
}
if (!$scene->hasConnectionGroup($groupName)) {
$io->error("The scene {$sceneId} does not have a connection group with the name {$groupName}");
return Command::FAILURE;
}
$connectionGroup = $scene->getConnectionGroup($groupName);
# Mark for removal
$em->remove($connectionGroup);
# Update outgoing connections if they refer to the deleted connectionGroup
$connections = $scene->getConnections();
/** @var SceneConnection $connection */
foreach ($connections as $connection) {
if ($connection->getIncomingScene() === $scene and $connection->getIncomingConnectionGroupName() === $groupName) {
$connection->setIncomingConnectionGroupName(null);
$io->comment("Updated connection to {$connection->getOutgoingScene()->getTitle()}");
}
if ($connection->getOutgoingScene() === $scene and $connection->getOutgoingConnectionGroupName() === $groupName) {
$connection->setOutgoingConnectionGroupName(null);
$io->comment("Updated connection to {$connection->getIncomingScene()->getTitle()}");
}
}
try {
$em->flush();
} catch (\Exception $e) {
$io->error("An unknown error occurred: {$e->getMessage()}");
return Command::FAILURE;
}
$io->success("{$connectionGroup} was successfully removed");
$logger->info("Removed {$connectionGroup} from {$scene}.");
return Command::SUCCESS;
}
}
@@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\Scene;
use LotGD\Core\Models\Scene;
use LotGD\Core\Models\SceneConnectable;
use LotGD\Core\Models\SceneConnection;
use LotGD\Core\Models\SceneConnectionGroup;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Resets the viewpoint of a given character.
*/
class SceneShowCommand extends SceneBaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName($this->namespaced("show"))
->setDescription("Show details about a specific scene.")
->setDefinition(
new InputDefinition([
$this->getSceneIdArgumentDefinition(),
])
)
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$io = new SymfonyStyle($input, $output);
$id = $input->getArgument("id");
/* @var $scene Scene */
$scene = $em->getRepository(Scene::class)->find($id);
if ($scene === null) {
$io->error("Scene not found.");
return Command::FAILURE;
}
$io->title("About scene '{$scene->getTitle()}'");
$io->listing([
"ID: {$scene->getId()}",
"Title: {$scene->getTitle()}",
"Template: {$scene->getTemplate()?->getClass()}",
]);
$io->text($scene->getDescription());
$io->section("Connection groups");
/** @var SceneConnectionGroup[] $connectionGroups */
$connectionGroups = $scene->getConnectionGroups();
$list = [];
foreach ($connectionGroups as $connectionGroup) {
$list[] = "{$connectionGroup->getTitle()} (id={$connectionGroup->getName()})";
}
$io->listing($list);
$io->section("Connected Scenes");
/** @var SceneConnection[] $connections */
$connections = $scene->getConnections();
$list = [];
foreach ($connections as $connection) {
# Get formatting for outgoing scene connection group name
$outgoingSceneConnectionGroup = $connection->getOutgoingConnectionGroupName();
if ($outgoingSceneConnectionGroup) {
$outgoingSceneConnectionGroup = " (on $outgoingSceneConnectionGroup)";
} else {
$outgoingSceneConnectionGroup = "";
}
# Get formatting for incoming scene connection group name
$incomingSceneConnectionGroup = $connection->getIncomingConnectionGroupName();
if ($incomingSceneConnectionGroup) {
$incomingSceneConnectionGroup = " (on $incomingSceneConnectionGroup)";
} else {
$incomingSceneConnectionGroup = " ";
}
# Treat outgoing and incoming connections slightly differently
if ($connection->getOutgoingScene() === $scene) {
$other = $connection->getIncomingScene();
# Check if the connection is bidirectional (only out (this)->in)
if ($connection->isDirectionality(SceneConnectable::Bidirectional)) {
$list[] = "this$outgoingSceneConnectionGroup <=> {$other->getTitle()}$incomingSceneConnectionGroup(id={$other->getId()})";
} else {
$list[] = "this$outgoingSceneConnectionGroup => {$other->getTitle()}$incomingSceneConnectionGroup(id={$other->getId()})";
}
} else {
$other = $connection->getOutgoingScene();
# Check if the connection is bidirectional (only out->in (this))
if ($connection->isDirectionality(SceneConnectable::Bidirectional)) {
$list[] = "this$incomingSceneConnectionGroup <=> {$other->getTitle()}$outgoingSceneConnectionGroup (id={$other->getId()})";
} else {
$list[] = "this$incomingSceneConnectionGroup <= {$other->getTitle()}$outgoingSceneConnectionGroup (id={$other->getId()})";
}
}
}
$io->listing($list);
return Command::SUCCESS;
}
}
@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Console\Command\SceneTemplates;
use LotGD\Core\Console\Command\BaseCommand;
use LotGD\Core\Models\SceneTemplate;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
class SceneTemplateListCommand extends BaseCommand
{
/**
* @inheritDoc
*/
protected function configure()
{
$this->setName('sceneTemplate:list')
->setDescription('Lists all registered scene templates')
;
}
/**
* @inheritDoc
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->game->getEntityManager();
$io = new SymfonyStyle($input, $output);
/** @var SceneTemplate[] $templates */
$templates = $em->getRepository(SceneTemplate::class)->findAll();
$table = [["class", "module", "assignable", "# scenes", "# viewpoints"], []];
foreach ($templates as $template) {
$table[1][] = [
$template->getClass(),
$template->getModule(),
$template->isUserAssignable()?"X":"-",
count($template->getOwningScenes()),
count($template->getOwningViewpoints()),
];
}
$io->table(...$table);
return Command::SUCCESS;
}
}
+76 -19
View File
@@ -3,28 +3,49 @@ declare(strict_types=1);
namespace LotGD\Core\Console; namespace LotGD\Core\Console;
use Symfony\Component\Console\Application;
use LotGD\Core\Bootstrap; use LotGD\Core\Bootstrap;
use LotGD\Core\Console\Command\Character\CharacterAddCommand;
use LotGD\Core\Console\Command\Character\CharacterConfigListCommand;
use LotGD\Core\Console\Command\Character\CharacterConfigResetCommand;
use LotGD\Core\Console\Command\Character\CharacterConfigSetCommand;
use LotGD\Core\Console\Command\Character\CharacterEditCommand;
use LotGD\Core\Console\Command\Character\CharacterListCommand;
use LotGD\Core\Console\Command\Character\CharacterRemoveCommand;
use LotGD\Core\Console\Command\Character\CharacterResetViewpointCommand;
use LotGD\Core\Console\Command\Character\CharacterShowCommand;
use LotGD\Core\Console\Command\ConsoleCommand;
use LotGD\Core\Console\Command\Database\DatabaseInitCommand;
use LotGD\Core\Console\Command\Database\DatabaseSchemaUpdateCommand;
use LotGD\Core\Console\Command\Module\ModuleConfigListCommand;
use LotGD\Core\Console\Command\Module\ModuleConfigResetCommand;
use LotGD\Core\Console\Command\Module\ModuleConfigSetCommand;
use LotGD\Core\Console\Command\Module\ModuleListCommand;
use LotGD\Core\Console\Command\Module\ModuleRegisterCommand;
use LotGD\Core\Console\Command\Module\ModuleValidateCommand;
use LotGD\Core\Console\Command\Scene\SceneConfigListCommand;
use LotGD\Core\Console\Command\Scene\SceneConfigResetCommand;
use LotGD\Core\Console\Command\Scene\SceneConfigSetCommand;
use LotGD\Core\Console\Command\SceneTemplates\SceneTemplateListCommand;
use LotGD\Core\Console\Command\Scene\SceneAddCommand;
use LotGD\Core\Console\Command\Scene\SceneAddConnectionGroupCommand;
use LotGD\Core\Console\Command\Scene\SceneConnectCommand;
use LotGD\Core\Console\Command\Scene\SceneDisconnectCommand;
use LotGD\Core\Console\Command\Scene\SceneListCommand;
use LotGD\Core\Console\Command\Scene\SceneRemoveCommand;
use LotGD\Core\Console\Command\Scene\SceneRemoveConnectionGroupCommand;
use LotGD\Core\Console\Command\Scene\SceneShowCommand;
use LotGD\Core\Game; use LotGD\Core\Game;
use LotGD\Core\Console\Command\{ use Symfony\Component\Console\Application;
CharacterListCommand,
CharacterResetViewpointCommand,
DatabaseInitCommand,
DatabaseSchemaUpdateCommand,
ModuleValidateCommand,
ModuleRegisterCommand,
ConsoleCommand
};
/** /**
* Main execution class for the daenerys tool. * Main execution class for the daenerys tool.
*/ */
class Main class Main
{ {
private $application; private Application $application;
private $bootstrap; private Bootstrap $bootstrap;
private $game; private Game $game;
/** /**
* Construct a new daenerys tool instance. * Construct a new daenerys tool instance.
@@ -34,7 +55,7 @@ class Main
$this->application = new Application(); $this->application = new Application();
$this->application->setName("daenerys 🐲 "); $this->application->setName("daenerys 🐲 ");
$this->application->setVersion("0.0.1 (lotgd/core version " . \LotGD\Core\Game::getVersion() . ")"); $this->application->setVersion("lotgd/core version " . Game::getVersion() . "");
} }
/** /**
@@ -42,26 +63,62 @@ class Main
*/ */
protected function addCommands() protected function addCommands()
{ {
$this->application->add(new ModuleValidateCommand($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 DatabaseSchemaUpdateCommand($this->game));
$this->application->add(new ConsoleCommand($this->game)); $this->application->add(new ConsoleCommand($this->game));
// Module commands
$this->application->add(new ModuleConfigListCommand($this->game));
$this->application->add(new ModuleConfigResetCommand($this->game));
$this->application->add(new ModuleConfigSetCommand($this->game));
$this->application->add(new ModuleListCommand($this->game));
$this->application->add(new ModuleRegisterCommand($this->game));
$this->application->add(new ModuleValidateCommand($this->game));
// Character commands
$this->application->add(new CharacterAddCommand($this->game));
$this->application->add(new CharacterConfigListCommand($this->game));
$this->application->add(new CharacterConfigResetCommand($this->game));
$this->application->add(new CharacterConfigSetCommand($this->game));
$this->application->add(new CharacterEditCommand($this->game));
$this->application->add(new CharacterListCommand($this->game)); $this->application->add(new CharacterListCommand($this->game));
$this->application->add(new CharacterRemoveCommand($this->game));
$this->application->add(new CharacterResetViewpointCommand($this->game)); $this->application->add(new CharacterResetViewpointCommand($this->game));
$this->application->add(new CharacterShowCommand($this->game));
// Scene commands
$this->application->add(new SceneAddCommand($this->game));
$this->application->add(new SceneConfigListCommand($this->game));
$this->application->add(new SceneConfigResetCommand($this->game));
$this->application->add(new SceneConfigSetCommand($this->game));
$this->application->add(new SceneListCommand($this->game));
$this->application->add(new SceneRemoveCommand($this->game));
$this->application->add(new SceneShowCommand($this->game));
// Scene connections
$this->application->add(new SceneConnectCommand($this->game));
$this->application->add(new SceneDisconnectCommand($this->game));
// Scene connection group
$this->application->add(new SceneAddConnectionGroupCommand($this->game));
$this->application->add(new SceneRemoveConnectionGroupCommand($this->game));
// Scene templates
$this->application->add(new SceneTemplateListCommand($this->game));
// Add additional ones // Add additional ones
$this->bootstrap->addDaenerysCommands($this->application); $this->bootstrap->addDaenerysCommands($this->application);
} }
/** /**
* Run the danerys tool. * Run the Daenerys tool.
*/ */
public function run() public function run()
{ {
// Bootstrap application // Bootstrap application
$this->bootstrap = new Bootstrap(); $this->bootstrap = new Bootstrap();
$this->game = $this->bootstrap->getGame(getcwd()); $this->game = $this->bootstrap->getGame(\getcwd());
// Add commands // Add commands
$this->addCommands(); $this->addCommands();
+15 -16
View File
@@ -28,7 +28,7 @@ class DiceBag
*/ */
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;
} }
/** /**
@@ -49,7 +49,7 @@ class DiceBag
$max = $a; $max = $a;
} }
return mt_rand($min, $max); return \mt_rand($min, $max);
} }
/** /**
@@ -71,9 +71,9 @@ class DiceBag
$mean = ($max - $min) / 2; $mean = ($max - $min) / 2;
$r = 0; $r = 0;
do { do {
$u1 = mt_rand() / mt_getrandmax(); $u1 = \mt_rand() / \mt_getrandmax();
$u2 = mt_rand() / mt_getrandmax(); $u2 = \mt_rand() / \mt_getrandmax();
$r = sqrt(-2 * log($u1)) * cos(2 * pi() * $u2) + $mean; $r = \sqrt(-2 * \log($u1)) * \cos(2 * \pi() * $u2) + $mean;
} while ($r < $min || $r > $max); } while ($r < $min || $r > $max);
return $r; return $r;
@@ -82,31 +82,30 @@ class DiceBag
/** /**
* This function has uniform distribution except for the extreme values, which are * This function has uniform distribution except for the extreme values, which are
* half as likely to happen. * half as likely to happen.
* The code for this function was taken from LotGD in version 0.9.7 * The code for this function was taken from LotGD in version 0.9.7.
* @author MightyE, JT * @author MightyE, JT
* @param int $min * @param int|null $min
* @param int $max * @param int|null $max
* @return int * @return int
*/ */
public function pseudoBell(int $min = null, int $max = null): int public function pseudoBell(int $min = null, int $max = null): int
{ {
if (is_null($min)) { if (\is_null($min)) {
return mt_rand(); return \mt_rand();
} }
$min *= 1000; $min *= 1000;
if (is_null($max)) { if (\is_null($max)) {
return (int)round(mt_rand($min)/1000, 0); return (int)\round(\mt_rand($min) / 1000, 0);
} }
$max *= 1000; $max *= 1000;
if ($min === $max) { if ($min === $max) {
return (int)round($min/1000, 0); return (int)\round($min / 1000, 0);
} elseif ($min < $max) { } elseif ($min < $max) {
return (int)round(mt_rand($min, $max)/1000, 0); return (int)\round(\mt_rand($min, $max) / 1000, 0);
} else {
return (int)round(mt_rand($max, $min)/1000, 0);
} }
return (int)\round(\mt_rand($max, $min) / 1000, 0);
} }
} }
+8 -9
View File
@@ -4,38 +4,37 @@ declare(strict_types=1);
namespace LotGD\Core\Doctrine\Annotations; namespace LotGD\Core\Doctrine\Annotations;
use Doctrine\Common\Annotations\Annotation; use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Annotation\Attributes;
use Doctrine\Common\Annotations\Annotation\Attribute; use Doctrine\Common\Annotations\Annotation\Attribute;
use Doctrine\Common\Annotations\Annotation\Attributes;
use LotGD\Core\Exceptions\ArgumentException; use LotGD\Core\Exceptions\ArgumentException;
use LotGD\Core\Models\ExtendableModelInterface; use LotGD\Core\Models\ExtendableModelInterface;
/** /**
* Annotation that is used to flag which entity a class extends. * Annotation that is used to flag which entity a class extends.
* @package LotGD\Core\Doctrine
* @Annotation * @Annotation
* @Target("CLASS") * @Target("CLASS")
* @Attributes({ * @Attributes({
* @Attribute("of", type = "string") * @Attribute("of", type="string")
* }) * })
*/ */
class Extension class Extension
{ {
/** @var string */ private string $modelClass;
private $modelClass;
/** /**
* Extension constructor. * Extension constructor.
* @param array $attributes * @param array $attributes
* @throws ArgumentException * @throws ArgumentException
*/ */
public function __construct(array $attributes) { public function __construct(array $attributes)
{
$this->modelClass = $attributes["of"]; $this->modelClass = $attributes["of"];
if (!class_exists($this->modelClass)) { if (!\class_exists($this->modelClass)) {
throw new ArgumentException("The class given in of must be a valid class."); throw new ArgumentException("The class given in of must be a valid class.");
} }
if (!in_array(ExtendableModelInterface::class, class_implements($this->modelClass))) { if (!\in_array(ExtendableModelInterface::class, \class_implements($this->modelClass))) {
throw new ArgumentException("The class given in of must implement the ExtendableModelInterface."); throw new ArgumentException("The class given in of must implement the ExtendableModelInterface.");
} }
} }
@@ -48,4 +47,4 @@ class Extension
{ {
return $this->modelClass; return $this->modelClass;
} }
} }
+8 -9
View File
@@ -4,37 +4,36 @@ declare(strict_types=1);
namespace LotGD\Core\Doctrine\Annotations; namespace LotGD\Core\Doctrine\Annotations;
use Doctrine\Common\Annotations\Annotation; use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Annotation\Attributes;
use Doctrine\Common\Annotations\Annotation\Attribute; use Doctrine\Common\Annotations\Annotation\Attribute;
use Doctrine\Common\Annotations\Annotation\Attributes;
use LotGD\Core\Exceptions\ArgumentException; use LotGD\Core\Exceptions\ArgumentException;
/** /**
* Annotation that is used to link a static method to a model entity. * Annotation that is used to link a static method to a model entity.
* @package LotGD\Core\Doctrine\Annotations
* @Annotation * @Annotation
* @Target("METHOD") * @Target("METHOD")
* @Attributes({ * @Attributes({
* @Attribute("as", type = "string") * @Attribute("as", type="string")
* }) * })
*/ */
class ExtensionMethod class ExtensionMethod
{ {
/** @var string */ private string $methodName = "";
private $methodName = "";
/** /**
* ExtensionMethod constructor. * ExtensionMethod constructor.
* @param array $attributes * @param array $attributes
* @throws ArgumentException * @throws ArgumentException
*/ */
public function __construct(array $attributes) { public function __construct(array $attributes)
{
$this->methodName = $attributes["as"]; $this->methodName = $attributes["as"];
if (!is_string($this->methodName)) { if (!\is_string($this->methodName)) {
throw new ArgumentException("Property 'as' must be a string."); throw new ArgumentException("Property 'as' must be a string.");
} }
if (strlen($this->methodName) == 0) { if (\strlen($this->methodName) == 0) {
throw new ArgumentException("Property 'as' must not be an empty string."); throw new ArgumentException("Property 'as' must not be an empty string.");
} }
} }
@@ -47,4 +46,4 @@ class ExtensionMethod
{ {
return $this->methodName; return $this->methodName;
} }
} }
+4 -11
View File
@@ -3,28 +3,21 @@ declare(strict_types=1);
namespace LotGD\Core\Doctrine; namespace LotGD\Core\Doctrine;
use Doctrine\Common\Util\Debug;
use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\ORM\Event\LifecycleEventArgs;
use LotGD\Core\Game; use LotGD\Core\Game;
use LotGD\Core\GameAwareInterface; use LotGD\Core\GameAwareInterface;
/** /**
* Class EntityPostLoadEventListener * Class EntityPostLoadEventListener.
* @package LotGD\Core\Doctrine
*/ */
class EntityPostLoadEventListener class EntityPostLoadEventListener
{ {
/** @var Game $game */
private $game;
/** /**
* EntityPostLoadEventListener constructor. * EntityPostLoadEventListener constructor.
* @param Game $g * @param Game $game
*/ */
public function __construct(Game $g) public function __construct(private Game $game) {}
{
$this->game = $g;
}
/** /**
* Called upon event postLoad. * Called upon event postLoad.
@@ -37,4 +30,4 @@ class EntityPostLoadEventListener
$entity->setGame($this->game); $entity->setGame($this->game);
} }
} }
} }
+1
View File
@@ -2,6 +2,7 @@
declare(strict_types=1); declare(strict_types=1);
namespace LotGD\Core; namespace LotGD\Core;
use LotGD\Core\Events\EventContext; use LotGD\Core\Events\EventContext;
interface EventHandler interface EventHandler
+14 -21
View File
@@ -3,31 +3,23 @@ declare(strict_types=1);
namespace LotGD\Core; namespace LotGD\Core;
use Doctrine\ORM\EntityManagerInterface;
use LotGD\Core\Events\EventContext; use LotGD\Core\Events\EventContext;
use LotGD\Core\Models\EventSubscription; use LotGD\Core\Events\EventContextData;
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; use LotGD\Core\Models\EventSubscription;
/** /**
* Manages a simple publish/subscribe system based on regular expressions * Manages a simple publish/subscribe system based on regular expressions
* matching event names and running a fixed * matching event names and running a fixed.
*/ */
class EventManager class EventManager
{ {
private $g;
/** /**
* @param Game $g The game. * @param Game $g The game.
*/ */
public function __construct(Game $g) public function __construct(private Game $g) {}
{
$this->g = $g;
}
/** /**
* Publish an event. Will immediately cause handleEvent() to be called on all * Publish an event. Will immediately cause handleEvent() to be called on all
@@ -46,13 +38,13 @@ class EventManager
// TODO: Add an in-memory cache here. Will likely only be in the 1000s of // TODO: Add an in-memory cache here. Will likely only be in the 1000s of
// patterns, so no need to go to the remote key-value store. // patterns, so no need to go to the remote key-value store.
$this->g->getLogger()->addDebug("Publishing event {$event}."); $this->g->getLogger()->debug("Publishing event {$event}.");
$subscriptions = $this->getSubscriptions(); $subscriptions = $this->getSubscriptions();
foreach ($subscriptions as $s) { foreach ($subscriptions as $s) {
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()->debug(" Handling with {$class}.");
$eventContext = new EventContext($event, $s->getPattern(), $contextData); $eventContext = new EventContext($event, $s->getPattern(), $contextData);
@@ -82,7 +74,7 @@ class EventManager
*/ */
public function subscribe(string $pattern, string $class, string $library) public function subscribe(string $pattern, string $class, string $library)
{ {
$this->g->getLogger()->addDebug("Subscribing event pattern={$pattern} class={$class} library={$library}"); $this->g->getLogger()->debug("Subscribing event pattern={$pattern} class={$class} library={$library}");
try { try {
// Can we resolve this class? // Can we resolve this class?
@@ -102,14 +94,14 @@ class EventManager
} }
// Validate the regular expression. // Validate the regular expression.
if (@preg_match($pattern, '') === false) { if (@\preg_match($pattern, '') === false) {
throw new WrongTypeException("Invalid regular expression: {$pattern}"); throw new WrongTypeException("Invalid regular expression: {$pattern}");
} }
$e = EventSubscription::create([ $e = EventSubscription::create([
'pattern' => $pattern, 'pattern' => $pattern,
'class' => $class, 'class' => $class,
'library' => $library 'library' => $library,
]); ]);
$this->g->getEntityManager()->persist($e); $this->g->getEntityManager()->persist($e);
@@ -122,15 +114,16 @@ class EventManager
* @param string $pattern Regular expression, in PHP format, to match against * @param string $pattern Regular expression, in PHP format, to match against
* published event names. * published event names.
* @param string $class Fully qualified class name. * @param string $class Fully qualified class name.
* @param string $library
* @throws SubscriptionNotFoundException if the specified subscription does not exist. * @throws SubscriptionNotFoundException if the specified subscription does not exist.
*/ */
public function unsubscribe(string $pattern, string $class, string $library) public function unsubscribe(string $pattern, string $class, string $library)
{ {
$e = $this->g->getEntityManager()->getRepository(EventSubscription::class)->find(array( $e = $this->g->getEntityManager()->getRepository(EventSubscription::class)->find([
'pattern' => $pattern, 'pattern' => $pattern,
'class' => $class, 'class' => $class,
'library' => $library 'library' => $library,
)); ]);
if (!$e) { if (!$e) {
throw new SubscriptionNotFoundException("Subscription not found with pattern={$pattern} class={$class} library={$library}."); throw new SubscriptionNotFoundException("Subscription not found with pattern={$pattern} class={$class} library={$library}.");
} }
+16 -7
View File
@@ -1,19 +1,28 @@
<?php <?php
declare(strict_types=1);
namespace LotGD\Core\Events; namespace LotGD\Core\Events;
use JetBrains\PhpStorm\ArrayShape;
use LotGD\Core\Exceptions\ArgumentException;
use LotGD\Core\Models\Character; use LotGD\Core\Models\Character;
/** /**
* Class CharacterEventData * Class CharacterEventData.
* @package LotGD\Core\Events
*/ */
class CharacterEventData extends EventContextData class CharacterEventData extends EventContextData
{ {
protected static $argumentConfig = [ #[ArrayShape([
"character" => [
"type" => Character::class,
"required" => "bool",
],
"value" => [
"type" => "mixed",
"required" => "bool",
],
])]
protected static ?array $argumentConfig = [
"character" => ["type" => Character::class, "required" => true], "character" => ["type" => Character::class, "required" => true],
"value" => ["type" => "mixed", "required" => false] "value" => ["type" => "mixed", "required" => false],
]; ];
} }
+7 -16
View File
@@ -3,18 +3,12 @@ declare(strict_types=1);
namespace LotGD\Core\Events; namespace LotGD\Core\Events;
/** /**
* Class EventContext * Class EventContext.
* @package LotGD\Core
* @immutable * @immutable
*/ */
class EventContext class EventContext
{ {
private $matchingPattern;
private $event;
private $data;
/** /**
* EventContext constructor. * EventContext constructor.
* @param string $event The published event * @param string $event The published event
@@ -22,13 +16,10 @@ class EventContext
* @param EventContextData $data * @param EventContextData $data
*/ */
public function __construct( public function __construct(
string $event, private string $event,
string $matchingPattern, private string $matchingPattern,
EventContextData $data private EventContextData $data
) { ) {
$this->event = $event;
$this->matchingPattern = $matchingPattern;
$this->data = $data;
} }
/** /**
@@ -69,7 +60,7 @@ class EventContext
} }
/** /**
* Returns a data field * Returns a data field.
* @param $field * @param $field
* @return mixed * @return mixed
*/ */
@@ -79,7 +70,7 @@ class EventContext
} }
/** /**
* Sets a data field * Sets a data field.
* @param $field * @param $field
* @param $value * @param $value
*/ */
@@ -106,4 +97,4 @@ class EventContext
{ {
return $this->data === $originalData ? false : true; return $this->data === $originalData ? false : true;
} }
} }
+41 -37
View File
@@ -9,12 +9,18 @@ use LotGD\Core\Exceptions\ArgumentException;
* EventContextData to provide a basic structure for managing contextual data of an event. * 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. * This class must be immutable and returns always a new instance of itself for any change.
* @package LotGD\Core\Events
* @immutable * @immutable
*/ */
class EventContextData class EventContextData
{ {
private $data; protected static ?array $argumentConfig = null;
/**
* protected constructor..
* @see self::create
* @param array $data
*/
protected function __construct(private array $data) {}
/** /**
* Creates a new instance of a data container. * Creates a new instance of a data container.
@@ -34,53 +40,53 @@ class EventContextData
/** /**
* Checks a field configuration given in self::$argumentConfig. * Checks a field configuration given in self::$argumentConfig.
* @param $data * @param array $data
* @throws ArgumentException * @throws ArgumentException
*/ */
public static function checkConfiguration($data) public static function checkConfiguration(array $data)
{ {
$configuration = static::$argumentConfig; $configuration = static::$argumentConfig;
$types = [ $types = [
"mixed" => function ($x) {return true;}, "mixed" => function ($x) {
"int" => function ($x) {return is_int($x);}, return true;
"float" => function ($x) {return is_float($x);}, },
"numeric" => function($x) {return is_numeric($x);}, "int" => function ($x) {
"string" => function($x) {return is_string($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); $keys = \array_keys($data);
foreach ($keys as $key) { foreach ($keys as $key) {
if (!isset($configuration[$key])) { if (!isset($configuration[$key])) {
throw new ArgumentException(sprintf("%s does not accept a field called %s", static::class, $key)); throw new ArgumentException(\sprintf("%s does not accept a field called %s", static::class, $key));
} }
} }
foreach ($configuration as $key => $config) { foreach ($configuration as $key => $config) {
if ($config["required"] === true and !isset($data[$key])) { if ($config["required"] === true and !isset($data[$key])) {
throw new ArgumentException(sprintf("%s must have a field called %s.", static::class, $key)); throw new ArgumentException(\sprintf("%s must have a field called %s.", static::class, $key));
} }
if (isset($types[$config["type"]])) { if (isset($types[$config["type"]])) {
if ($types[$config["type"]]($data[$key]) === false) { 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"])); throw new ArgumentException(\sprintf("The field %s of %s must be of type %s.", $key, static::class, $config["type"]));
} }
} else { } else {
if (!$data[$key] instanceof $config["type"]) { 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"])); 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. * Returns true if container has a certain field.
* @param string $field * @param string $field
@@ -88,7 +94,7 @@ class EventContextData
*/ */
public function has(string $field): bool public function has(string $field): bool
{ {
return array_key_exists($field, $this->data); return \array_key_exists($field, $this->data);
} }
/** /**
@@ -100,31 +106,29 @@ class EventContextData
{ {
if ($this->has($field)) { if ($this->has($field)) {
return $this->data[$field]; return $this->data[$field];
} else {
$this->throwException($field);
} }
$this->throwException($field);
} }
/** /**
* Sets a field to a new value and returns a new data container * Sets a field to a new value and returns a new data container.
* @param string $field * @param string $field
* @param $value * @param mixed $value
* @return EventContextData * @return EventContextData
*/ */
public function set(string $field, $value): self public function set(string $field, mixed $value): self
{ {
if ($this->has($field)) { if ($this->has($field)) {
$data = $this->data; $data = $this->data;
$data[$field] = $value; $data[$field] = $value;
return new static($data); return new static($data);
} else {
$this->throwException($field);
} }
$this->throwException($field);
} }
/** /**
* Sets multiple fields at once * Sets multiple fields at once.
* @param array $data array of $field=>$value pairs * @param array $data array of $field=>$value pairs
* @return EventContextData * @return EventContextData
*/ */
@@ -144,12 +148,12 @@ class EventContextData
} }
/** /**
* Returns a list of fields in this context * Returns a list of fields in this context.
* @return array * @return array
*/ */
private function getListOfFields(): array private function getListOfFields(): array
{ {
return array_keys($this->data); return \array_keys($this->data);
} }
/** /**
@@ -158,8 +162,8 @@ class EventContextData
*/ */
private function getFormattedListOfFields(): string private function getFormattedListOfFields(): string
{ {
return substr( return \substr(
implode(", ", $this->getListOfFields()), \implode(", ", $this->getListOfFields()),
0, 0,
-2 -2
); );
+21 -17
View File
@@ -3,15 +3,11 @@ declare(strict_types=1);
namespace LotGD\Core\Events; namespace LotGD\Core\Events;
use JetBrains\PhpStorm\ArrayShape;
use Doctrine\Common\Util\Debug;
use Doctrine\DBAL\Schema\View;
use LotGD\Core\Exceptions\ArgumentException; use LotGD\Core\Exceptions\ArgumentException;
use LotGD\Core\Models\Character;
use LotGD\Core\Models\Scene; use LotGD\Core\Models\Scene;
use LotGD\Core\Models\Viewpoint; use LotGD\Core\Models\Viewpoint;
/** /**
* NavigateToScene data container which can be used for navigational events. * NavigateToScene data container which can be used for navigational events.
* *
@@ -21,7 +17,6 @@ use LotGD\Core\Models\Viewpoint;
* scene Scene * scene Scene
* parameters array * parameters array
* redirect Scene|null * redirect Scene|null
* @package LotGD\Core\Events
*/ */
class NavigateToSceneData extends EventContextData class NavigateToSceneData extends EventContextData
{ {
@@ -30,40 +25,49 @@ class NavigateToSceneData extends EventContextData
* @param array $data Must contain fields referrer, viewpoint, scene, parameters and redirect; none more. * @param array $data Must contain fields referrer, viewpoint, scene, parameters and redirect; none more.
* @throws ArgumentException * @throws ArgumentException
*/ */
protected function __construct(array $data) protected function __construct(
{ #[ArrayShape([
"referrer" => Scene::class . "|null",
"viewpoint" => Viewpoint::class,
"scene" => Scene::class,
"parameters" => "array",
"reddirect" => Scene::class . "|null",
])]
array $data,
) {
$mustHaveForm = ["referrer", "viewpoint", "scene", "parameters", "redirect"]; $mustHaveForm = ["referrer", "viewpoint", "scene", "parameters", "redirect"];
$doesHaveForm = array_keys($data); $doesHaveForm = \array_keys($data);
sort($mustHaveForm); sort($doesHaveForm); \sort($mustHaveForm);
\sort($doesHaveForm);
if ($doesHaveForm !== $mustHaveForm) { if ($doesHaveForm !== $mustHaveForm) {
throw new ArgumentException("A new NavigateToScene event must have referrer, viewpoint, scene, parameters and redirect."); 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) { if ($data["referrer"] instanceof Scene === false and $data["referrer"] !== null) {
throw new ArgumentException(sprintf( throw new ArgumentException(\sprintf(
"data[referrer] must be an instance of %s, %s given.", "data[referrer] must be an instance of %s, %s given.",
Scene::class, Scene::class,
get_class($data["referrer"]) \get_class($data["referrer"])
)); ));
} }
if ($data["scene"] instanceof Scene === false) { if ($data["scene"] instanceof Scene === false) {
throw new ArgumentException(sprintf( throw new ArgumentException(\sprintf(
"data[scene] must be an instance of %s, %s given.", "data[scene] must be an instance of %s, %s given.",
Scene::class, Scene::class,
get_class($data["scene"]) \get_class($data["scene"])
)); ));
} }
if ($data["viewpoint"] instanceof Viewpoint === false) { if ($data["viewpoint"] instanceof Viewpoint === false) {
throw new ArgumentException(sprintf( throw new ArgumentException(\sprintf(
"data[viewpoint] must be an instance of %s, %s given.", "data[viewpoint] must be an instance of %s, %s given.",
Viewpoint::class, Viewpoint::class,
get_class($data["viewpoint"]) \get_class($data["viewpoint"])
)); ));
} }
parent::__construct($data); parent::__construct($data);
} }
} }
+14 -10
View File
@@ -3,7 +3,7 @@ declare(strict_types=1);
namespace LotGD\Core\Events; namespace LotGD\Core\Events;
use JetBrains\PhpStorm\ArrayShape;
use LotGD\Core\Exceptions\ArgumentException; use LotGD\Core\Exceptions\ArgumentException;
use LotGD\Core\Models\Character; use LotGD\Core\Models\Character;
use LotGD\Core\Models\Scene; use LotGD\Core\Models\Scene;
@@ -14,7 +14,6 @@ use LotGD\Core\Models\Scene;
* Fields are: * Fields are:
* character Character * character Character
* scene Scene|null * scene Scene|null
* @package LotGD\Core\Events
*/ */
class NewViewpointData extends EventContextData class NewViewpointData extends EventContextData
{ {
@@ -23,28 +22,33 @@ class NewViewpointData extends EventContextData
* @param array $data * @param array $data
* @throws ArgumentException In case $data contains invalid data. * @throws ArgumentException In case $data contains invalid data.
*/ */
protected function __construct(array $data) protected function __construct(
{ #[ArrayShape([
if (array_keys($data) !== ["character", "scene"]) { "character" => Character::class,
"scene" => Scene::class . "|null",
])]
array $data,
) {
if (\array_keys($data) !== ["character", "scene"]) {
throw new ArgumentException("A NewViewpoint event must have only character and scene."); throw new ArgumentException("A NewViewpoint event must have only character and scene.");
} }
if (!$data["character"] instanceof Character) { if (!$data["character"] instanceof Character) {
throw new ArgumentException(sprintf( throw new ArgumentException(\sprintf(
"NewViewpoint data[character] must be an instance of %s, %s given.", "NewViewpoint data[character] must be an instance of %s, %s given.",
Character::class, Character::class,
get_class($data) \get_class($data)
)); ));
} }
if ($data["scene"] !== null and !$data["scene"] instanceof Scene) { if ($data["scene"] !== null and !$data["scene"] instanceof Scene) {
throw new ArgumentException(sprintf( throw new ArgumentException(\sprintf(
"NewViewpoint data[scene] must be an instance of %s or null, %s given.", "NewViewpoint data[scene] must be an instance of %s or null, %s given.",
Scene::class, Scene::class,
get_class($data) \get_class($data)
)); ));
} }
parent::__construct($data); parent::__construct($data);
} }
} }
+11 -6
View File
@@ -3,16 +3,21 @@ declare(strict_types=1);
namespace LotGD\Core\Events; namespace LotGD\Core\Events;
use LotGD\Core\Exceptions\ArgumentException; use JetBrains\PhpStorm\ArrayShape;
use LotGD\Core\Models\Viewpoint; use LotGD\Core\Models\Viewpoint;
/** /**
* Class ViewpointDecorationEventData * Class ViewpointDecorationEventData.
* @package LotGD\Core\Events
*/ */
class ViewpointDecorationEventData extends EventContextData class ViewpointDecorationEventData extends EventContextData
{ {
protected static $argumentConfig = [ #[ArrayShape([
"viewpoint" => ["type" => Viewpoint::class, "required" => true] "viewpoint" => [
"type" => Viewpoint::class,
"required" => "bool",
],
])]
protected static ?array $argumentConfig = [
"viewpoint" => ["type" => Viewpoint::class, "required" => true],
]; ];
} }
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class ActionNotFoundException extends CoreException class ActionNotFoundException extends CoreException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class ArgumentEmptyException extends ArgumentException class ArgumentEmptyException extends ArgumentException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class ArgumentException extends CoreException class ArgumentException extends CoreException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class AttributeMissingException extends CoreException class AttributeMissingException extends CoreException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class BattleEventException extends BattleException class BattleEventException extends BattleException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class BattleException extends CoreException class BattleException extends CoreException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class BattleIsOverException extends BattleException class BattleIsOverException extends BattleException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class BattleNotOverException extends BattleException class BattleNotOverException extends BattleException
{ {
} }
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class BuffListAlreadyActivatedException extends CoreException class BuffListAlreadyActivatedException extends CoreException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class BuffSlotOccupiedException extends CoreException class BuffSlotOccupiedException extends CoreException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a builder is missing an argument * Exception if a builder is missing an argument.
*/ */
class BuilderException extends CoreException class BuilderException extends CoreException
{ {
} }
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class CharacterNotFoundException extends CoreException class CharacterNotFoundException extends CoreException
{ {
} }
+2 -6
View File
@@ -1,15 +1,11 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Class CharacterStatException * Class CharacterStatException.
* @package LotGD\Core\Exceptions
*/ */
class CharacterStatException extends CoreException class CharacterStatException extends CoreException
{ {
}
}
@@ -1,15 +1,11 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Class CharacterStatExistsException * Class CharacterStatExistsException.
* @package LotGD\Core\Exceptions
*/ */
class CharacterStatExistsException extends CharacterStatException class CharacterStatExistsException extends CharacterStatException
{ {
}
}
@@ -1,15 +1,11 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Class CharacterStatGroupExistsException * Class CharacterStatGroupExistsException.
* @package LotGD\Core\Exceptions
*/ */
class CharacterStatGroupExistsException extends CharacterStatException class CharacterStatGroupExistsException extends CharacterStatException
{ {
}
}
@@ -1,15 +1,11 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Class CharacterStatGroupNotFoundException * Class CharacterStatGroupNotFoundException.
* @package LotGD\Core\Exceptions
*/ */
class CharacterStatGroupNotFoundException extends CharacterStatException class CharacterStatGroupNotFoundException extends CharacterStatException
{ {
}
}
@@ -1,15 +1,11 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Class CharacterStatNotFoundException * Class CharacterStatNotFoundException.
* @package LotGD\Core\Exceptions
*/ */
class CharacterStatNotFoundException extends CharacterStatException class CharacterStatNotFoundException extends CharacterStatException
{ {
}
}
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class ClassNotFoundException extends CoreException class ClassNotFoundException extends CoreException
{ {
} }
-1
View File
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class CoreException extends \Exception class CoreException extends \Exception
{ {
} }
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class EntityAlreadyExistsException extends EntityException class EntityAlreadyExistsException extends EntityException
{ {
} }
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class EntityDoesNotExistException extends EntityException class EntityDoesNotExistException extends EntityException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* A basic entity exception * A basic entity exception.
*/ */
class EntityException extends CoreException class EntityException extends CoreException
{ {
} }
@@ -0,0 +1,8 @@
<?php
declare(strict_types=1);
namespace LotGD\Core\Exceptions;
class InsecureTwigTemplateError extends CoreException
{
}
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class InvalidConfigurationException extends CoreException class InvalidConfigurationException extends CoreException
{ {
} }
-1
View File
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class InvalidModelException extends CoreException class InvalidModelException extends CoreException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class IsNullException extends CoreException class IsNullException extends CoreException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class KeyNotFoundException extends CoreException class KeyNotFoundException extends CoreException
{ {
} }
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class LibraryDoesNotExistException extends CoreException class LibraryDoesNotExistException extends CoreException
{ {
} }
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class ModuleAlreadyExistsException extends CoreException class ModuleAlreadyExistsException extends CoreException
{ {
} }
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class ModuleDoesNotExistException extends CoreException class ModuleDoesNotExistException extends CoreException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class NotImplementedException extends CoreException class NotImplementedException extends CoreException
{ {
} }
+1 -2
View File
@@ -4,9 +4,8 @@ declare(strict_types=1);
namespace LotGD\Core\Exceptions; namespace LotGD\Core\Exceptions;
/** /**
* Exception if a specific, required argument is missing * Exception if a specific, required argument is missing.
*/ */
class ParentAlreadySetException extends CoreException class ParentAlreadySetException extends CoreException
{ {
} }
@@ -8,5 +8,4 @@ namespace LotGD\Core\Exceptions;
*/ */
class PermissionAlreadyExistsException extends EntityAlreadyExistsException class PermissionAlreadyExistsException extends EntityAlreadyExistsException
{ {
} }

Some files were not shown because too many files have changed in this diff Show More