From d2924a0c6145717eb0c03a75250eb661508ef02a Mon Sep 17 00:00:00 2001 From: sergiotarxz Date: Sun, 2 Jul 2023 06:35:14 +0200 Subject: [PATCH] Adding the ability of execute pj actions. --- js-src/components/bottom-panel.tsx | 14 +++++- js-src/output-packet/execute_action.ts | 23 ++++++++++ lib/LasTres/Battle.pm | 4 +- .../Controller/Websocket/InputPacket.pm | 3 ++ .../Websocket/InputPacket/ExecuteAction.pm | 45 +++++++++++++++++++ .../InputPacket/MoveBetweenLocations.pm | 4 +- lib/LasTres/Location.pm | 2 + lib/LasTres/PJAction/DefaultHeal.pm | 1 - lib/LasTres/Schema/Result/Team.pm | 6 ++- public/css/styles.css | 7 ++- public/css/styles.scss | 3 +- public/js/bundle.js | 12 ++++- start_docker.sh | 5 +-- 13 files changed, 110 insertions(+), 19 deletions(-) create mode 100644 js-src/output-packet/execute_action.ts create mode 100644 lib/LasTres/Controller/Websocket/InputPacket/ExecuteAction.pm diff --git a/js-src/components/bottom-panel.tsx b/js-src/components/bottom-panel.tsx index 758bd78..a8e3d21 100644 --- a/js-src/components/bottom-panel.tsx +++ b/js-src/components/bottom-panel.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import type { Action, ActionHash } from '@lastres/action' +import OutputPacketExecuteAction from '@lastres/output-packet/execute_action' import PresentationItem from '@lastres/components/presentation-item' import Presentation from '@lastres/components/presentation' @@ -51,12 +52,21 @@ export default function BottomPanel (props: BottomPanelProps): JSX.Element { if (action.is_disabled) { style.background = 'lightgray' } - return
+ function onClick (): void { + if (action.is_disabled) { + return + } + if (props.websocket !== null) { + new OutputPacketExecuteAction(action.identifier) + .send(props.websocket) + } + } + return

{action.name}

{ printDisabledReason(action) } -
+ }) } diff --git a/js-src/output-packet/execute_action.ts b/js-src/output-packet/execute_action.ts new file mode 100644 index 0000000..8db95c5 --- /dev/null +++ b/js-src/output-packet/execute_action.ts @@ -0,0 +1,23 @@ +import OutputPacket from '@lastres/output-packet' + +export interface OutputPacketExecuteActionData { + action: string +} + +export default class OutputPacketExecuteAction extends OutputPacket { + action: string + constructor (action: string) { + super() + this.action = action + } + + command (): string { + return 'execute_action' + } + + data (): OutputPacketExecuteActionData { + return { + action: this.action + } + } +} diff --git a/lib/LasTres/Battle.pm b/lib/LasTres/Battle.pm index 90229cb..dc5a64b 100644 --- a/lib/LasTres/Battle.pm +++ b/lib/LasTres/Battle.pm @@ -107,8 +107,6 @@ sub loser ($self) { sub end ($self) { require LasTres::Redis; my $redis = LasTres::Redis->new; - $self->team1->on_end_combat; - $self->team2->on_end_combat; $self->team1->current_battle(undef); $self->team1->update; if ( defined $self->team2 ) { @@ -116,6 +114,8 @@ sub end ($self) { $self->team2->update; } $redis->db->expire( $redis->battle_key( $self->uuid ), 0 ); + $self->team1->on_end_combat; + $self->team2->on_end_combat; } sub _build_uuid { diff --git a/lib/LasTres/Controller/Websocket/InputPacket.pm b/lib/LasTres/Controller/Websocket/InputPacket.pm index d7acb8c..52635c2 100644 --- a/lib/LasTres/Controller/Websocket/InputPacket.pm +++ b/lib/LasTres/Controller/Websocket/InputPacket.pm @@ -10,4 +10,7 @@ use feature 'signatures'; use Moo::Role; requires qw/new handle identifier/; + +## IMPLEMENTORS MUST IMPLEMENT +# sub handle ( $self, $ws, $session, $data ); 1; diff --git a/lib/LasTres/Controller/Websocket/InputPacket/ExecuteAction.pm b/lib/LasTres/Controller/Websocket/InputPacket/ExecuteAction.pm new file mode 100644 index 0000000..aabba59 --- /dev/null +++ b/lib/LasTres/Controller/Websocket/InputPacket/ExecuteAction.pm @@ -0,0 +1,45 @@ +package LasTres::Controller::Websocket::InputPacket::ExecuteAction; + +use v5.36.0; +use strict; +use warnings; +use utf8; + +use Moo; +use List::AllUtils; + +sub identifier { + return 'execute_action'; +} + +sub handle ( $self, $ws, $session, $data ) { + if ( ref $data ne 'HASH' ) { + return $ws->send( to_json( { error => "Data should be a hashref." } ) ); + } + if ( !defined $session->{pj} ) { + return $ws->send( + to_json( { error => 'The pj for this session does not exist.' } ) ); + } + $session->{pj} = $session->{pj}->get_from_storage; + my $pj = $session->{pj}; + my $action_id = $data->{action}; + if ( !defined $action_id ) { + return $ws->send( to_json( { error => 'No action set.' } ) ); + } + my @actions = $pj->actions->@*; + my ($action) = List::AllUtils::onlyres { $_->identifier eq $action_id && $_ } @actions; + if (!defined $action) { + return $ws->send( to_json( { error => "Could not find action $action_id." } ) ); + } + if ( $action->is_disabled($pj) ) { + return $ws->send( to_json( { error => "@{[$action->identifier]} is disabled." } ) ); + } + $action->callback($pj); + my $team = $pj->team; + for my $member ( $team->combat_members->@* ) { + $member->update_team_sprites; + $member->update_location; + $member->update_actions; + } +} +1; diff --git a/lib/LasTres/Controller/Websocket/InputPacket/MoveBetweenLocations.pm b/lib/LasTres/Controller/Websocket/InputPacket/MoveBetweenLocations.pm index 9ba4976..f17f150 100644 --- a/lib/LasTres/Controller/Websocket/InputPacket/MoveBetweenLocations.pm +++ b/lib/LasTres/Controller/Websocket/InputPacket/MoveBetweenLocations.pm @@ -44,14 +44,14 @@ sub handle ( $self, $ws, $session, $data ) { return $ws->send( to_json( { error => "The location is malformed" } ) ); } $session->{pj} = $session->{pj}->get_from_storage; - my $pj = $session->{pj}; - if ( !defined $pj ) { + if ( !defined $session->{pj} ) { return $ws->send( to_json( { error => 'You have not set a pj yet for this websocket.' } ) ); } + my $pj = $session->{pj}; my $team = $pj->team; my $leader = $team->leader; if ( $leader->uuid ne $pj->uuid ) { diff --git a/lib/LasTres/Location.pm b/lib/LasTres/Location.pm index 807d3d0..0db6d88 100644 --- a/lib/LasTres/Location.pm +++ b/lib/LasTres/Location.pm @@ -103,6 +103,7 @@ sub on_pj_arrival ( $self, $pj ) { } $self->show_intro($pj); $pj->update_location; + $pj->update_team_sprites; $pj->update_actions; } @@ -170,6 +171,7 @@ sub on_pj_moving ( $self, $pj ) { ); $pj->update_location; $pj->update_actions; + $pj->update_team_sprites; } ## DO NOT EXTEND NOT SUPPORTED. diff --git a/lib/LasTres/PJAction/DefaultHeal.pm b/lib/LasTres/PJAction/DefaultHeal.pm index b88f447..4700a8b 100644 --- a/lib/LasTres/PJAction/DefaultHeal.pm +++ b/lib/LasTres/PJAction/DefaultHeal.pm @@ -67,7 +67,6 @@ sub callback($self, $pj) { $member->health($member->max_health); $member->mana($member->max_mana); $member->update; - $member->update_team_sprites; } if (Scalar::Util::blessed($self) eq __PACKAGE__) { $self->_callback_unique_sleep($pj); diff --git a/lib/LasTres/Schema/Result/Team.pm b/lib/LasTres/Schema/Result/Team.pm index 74ce178..497503a 100644 --- a/lib/LasTres/Schema/Result/Team.pm +++ b/lib/LasTres/Schema/Result/Team.pm @@ -137,6 +137,7 @@ sub on_blackout ($self) { for my $pj ( $self->members ) { $pj->update_team_sprites; $pj->update_location; + $pj->update_actions; } } @@ -213,8 +214,9 @@ sub on_end_combat ($self) { require LasTres::Redis; my $redis = LasTres::Redis->new; for my $pj ( $self->members ) { - $redis->publish( $redis->pj_subscription($pj), - to_json( { command => 'update-team-sprites' } ) ); + $pj->update_team_sprites; + $pj->update_location; + $pj->update_actions; } } diff --git a/public/css/styles.css b/public/css/styles.css index 05cc650..172ba52 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -20,7 +20,7 @@ body { body label.bar-container div.bar div.filled { background: lightgreen; height: 100%; } - body div.action { + body a.action { border: solid 1px black; text-decoration: underline; display: flex; @@ -28,9 +28,8 @@ body { align-content: center; justify-content: center; align-items: center; - flex-direction: column; - width: 100%; } - body div.action div.disabled-reason { + flex-direction: column; } + body a.action div.disabled-reason { text-decoration: none; } body div.pj-list-item { display: flex; diff --git a/public/css/styles.scss b/public/css/styles.scss index 0c53485..437215f 100644 --- a/public/css/styles.scss +++ b/public/css/styles.scss @@ -26,7 +26,7 @@ body { } } } - div.action { + a.action { border: solid 1px black; text-decoration: underline; display: flex; @@ -35,7 +35,6 @@ body { justify-content: center; align-items: center; flex-direction: column; - width: 100%; div.disabled-reason { text-decoration: none; } diff --git a/public/js/bundle.js b/public/js/bundle.js index e4c924d..529a979 100644 --- a/public/js/bundle.js +++ b/public/js/bundle.js @@ -86,7 +86,7 @@ eval("\n\nif (false) {} else {\n module.exports = __webpack_require__(/*! ./cjs \********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ BottomPanel)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/presentation-item */ \"./js-src/components/presentation-item.tsx\");\n/* harmony import */ var _lastres_components_presentation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @lastres/components/presentation */ \"./js-src/components/presentation.tsx\");\n\n\n\nfunction BottomPanel(props) {\n const actionHash = props.actionHash;\n function printListActions() {\n if (actionHash === null) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n const listOfActionKeys = Object.keys(actionHash).sort((a, b) => {\n const isDisabledComparisionValue = +actionHash[a].is_disabled - +actionHash[b].is_disabled;\n if (isDisabledComparisionValue !== 0) {\n return isDisabledComparisionValue;\n }\n if (actionHash[a].name < actionHash[b].name) {\n return -1;\n }\n if (actionHash[a].name > actionHash[b].name) {\n return 1;\n }\n return 0;\n });\n function printDisabledReason(action) {\n if (!action.is_disabled || action.disabled_reason === null) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", { className: \"disabled-reason\", style: { color: 'red' } }, action.disabled_reason));\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, \"Acciones disponibles.\"),\n listOfActionKeys.map((key) => {\n const style = {};\n const action = actionHash[key];\n if (action.is_disabled) {\n style.background = 'lightgray';\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"action\", style: style, key: action.identifier },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, action.name),\n printDisabledReason(action));\n }));\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null, printListActions()),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null)));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/bottom-panel.tsx?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ BottomPanel)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _lastres_output_packet_execute_action__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/output-packet/execute_action */ \"./js-src/output-packet/execute_action.ts\");\n/* harmony import */ var _lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @lastres/components/presentation-item */ \"./js-src/components/presentation-item.tsx\");\n/* harmony import */ var _lastres_components_presentation__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @lastres/components/presentation */ \"./js-src/components/presentation.tsx\");\n\n\n\n\nfunction BottomPanel(props) {\n const actionHash = props.actionHash;\n function printListActions() {\n if (actionHash === null) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n const listOfActionKeys = Object.keys(actionHash).sort((a, b) => {\n const isDisabledComparisionValue = +actionHash[a].is_disabled - +actionHash[b].is_disabled;\n if (isDisabledComparisionValue !== 0) {\n return isDisabledComparisionValue;\n }\n if (actionHash[a].name < actionHash[b].name) {\n return -1;\n }\n if (actionHash[a].name > actionHash[b].name) {\n return 1;\n }\n return 0;\n });\n function printDisabledReason(action) {\n if (!action.is_disabled || action.disabled_reason === null) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", { className: \"disabled-reason\", style: { color: 'red' } }, action.disabled_reason));\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, \"Acciones disponibles.\"),\n listOfActionKeys.map((key) => {\n const style = {};\n const action = actionHash[key];\n if (action.is_disabled) {\n style.background = 'lightgray';\n }\n function onClick() {\n if (action.is_disabled) {\n return;\n }\n if (props.websocket !== null) {\n new _lastres_output_packet_execute_action__WEBPACK_IMPORTED_MODULE_1__[\"default\"](action.identifier)\n .send(props.websocket);\n }\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { onClick: onClick, className: \"action\", style: style, key: action.identifier },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, action.name),\n printDisabledReason(action));\n }));\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation__WEBPACK_IMPORTED_MODULE_3__[\"default\"], null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null, printListActions()),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null)));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/bottom-panel.tsx?"); /***/ }), @@ -290,6 +290,16 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ }), +/***/ "./js-src/output-packet/execute_action.ts": +/*!************************************************!*\ + !*** ./js-src/output-packet/execute_action.ts ***! + \************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ OutputPacketExecuteAction)\n/* harmony export */ });\n/* harmony import */ var _lastres_output_packet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @lastres/output-packet */ \"./js-src/output-packet.ts\");\n\nclass OutputPacketExecuteAction extends _lastres_output_packet__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor(action) {\n super();\n this.action = action;\n }\n command() {\n return 'execute_action';\n }\n data() {\n return {\n action: this.action\n };\n }\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/output-packet/execute_action.ts?"); + +/***/ }), + /***/ "./js-src/output-packet/init.ts": /*!**************************************!*\ !*** ./js-src/output-packet/init.ts ***! diff --git a/start_docker.sh b/start_docker.sh index b0d5012..09b67d2 100644 --- a/start_docker.sh +++ b/start_docker.sh @@ -8,9 +8,8 @@ DOCKER_BUILD_PARAMS="$CURRENT_DIR -t $DOCKER_TAG" DOCKER_RUN_PARAMS="run -it -v /var/run/postgresql/:/var/run/postgresql/ -v $CURRENT_DIR:/var/lib/las_tres/LasTres -v /var/run/redis/:/var/run/redis --name LasTresDocker -p 3000:3000 $DOCKER_TAG" CHECKSUM_DOCKER_FILE="$CURRENT_DIR/.dockerfile_checksum" -perl -pe 's/\{\{UID\}\}/'"$UID/" Dockerfile.template > Dockerfile - OLD_CHECKSUM_DOCKER="$(cat $CHECKSUM_DOCKER_FILE 2> /dev/null)" +perl -pe 's/\{\{UID\}\}/'"$UID/" Dockerfile.template > Dockerfile CURRENT_CHECKSUM_DOCKER="$(sha512sum Dockerfile | awk '{ print $1 }')" if ! [ -f las_tres.yml ]; then @@ -37,7 +36,7 @@ if [[ $OLD_CHECKSUM_DOCKER != $CURRENT_CHECKSUM_DOCKER ]]; then echo "$OLD_CHECKSUM_DOCKER != $CURRENT_CHECKSUM_DOCKER rebuilding docker"; echo $SUDO docker container rm LasTresDocker - $SUDO docker container rm LasTresDocker + $SUDO docker container rm LasTresDocker ; echo $SUDO docker build $DOCKER_BUILD_PARAMS $SUDO docker build $DOCKER_BUILD_PARAMS echo $CURRENT_CHECKSUM_DOCKER > $CHECKSUM_DOCKER_FILE