Adding first screen with pj list, log and list of available locations.
This commit is contained in:
parent
aa9c652fcb
commit
206f2c48a2
37
.eslintrc.js
Normal file
37
.eslintrc.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es2021: true
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'plugin:react/recommended',
|
||||||
|
'standard-with-typescript'
|
||||||
|
],
|
||||||
|
overrides: [
|
||||||
|
],
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 'latest',
|
||||||
|
sourceType: 'module',
|
||||||
|
project: 'tsconfig.json'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
'react',
|
||||||
|
'no-relative-import-paths'
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
indent: ['error', 4, { SwitchCase: 1 }],
|
||||||
|
'no-relative-import-paths/no-relative-import-paths': ['warn', { allowSameFolder: true }],
|
||||||
|
'@typescript-eslint/indent': ['error', 4],
|
||||||
|
'react/jsx-indent': ['error', 4],
|
||||||
|
'react/jsx-indent-props': ['error', 4]
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
'import/resolver': {
|
||||||
|
typescript: {
|
||||||
|
project: [
|
||||||
|
'tsconfig.json'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
Build.PL
1
Build.PL
@ -20,6 +20,7 @@ my $build = Module::Build->new(
|
|||||||
'UUID::URandom' => 0,
|
'UUID::URandom' => 0,
|
||||||
'Module::Pluggable' => 0,
|
'Module::Pluggable' => 0,
|
||||||
'Redis' => 0,
|
'Redis' => 0,
|
||||||
|
'List::AllUtils' => 0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
$build->create_build_script;
|
$build->create_build_script;
|
||||||
|
292
dbicdh/PostgreSQL/deploy/5/001-auto.sql
Normal file
292
dbicdh/PostgreSQL/deploy/5/001-auto.sql
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
--
|
||||||
|
-- Created by SQL::Translator::Producer::PostgreSQL
|
||||||
|
-- Created on Tue Jun 13 00:53:45 2023
|
||||||
|
--
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: equipment
|
||||||
|
--
|
||||||
|
CREATE TABLE "equipment" (
|
||||||
|
"uuid" uuid NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid")
|
||||||
|
);
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: inventories
|
||||||
|
--
|
||||||
|
CREATE TABLE "inventories" (
|
||||||
|
"uuid" uuid NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid")
|
||||||
|
);
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: players
|
||||||
|
--
|
||||||
|
CREATE TABLE "players" (
|
||||||
|
"uuid" uuid NOT NULL,
|
||||||
|
"username" text NOT NULL,
|
||||||
|
"encrypted_password" text NOT NULL,
|
||||||
|
"email" text NOT NULL,
|
||||||
|
"verified" boolean NOT NULL,
|
||||||
|
"verification_token" text,
|
||||||
|
"register_date" timestamp DEFAULT NOW() NOT NULL,
|
||||||
|
"last_activity" timestamp DEFAULT NOW() NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid"),
|
||||||
|
CONSTRAINT "unique_constraint_email" UNIQUE ("email"),
|
||||||
|
CONSTRAINT "unique_constraint_username" UNIQUE ("username")
|
||||||
|
);
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: skill_like_lists
|
||||||
|
--
|
||||||
|
CREATE TABLE "skill_like_lists" (
|
||||||
|
"uuid" uuid DEFAULT uuid_generate_v4() NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid")
|
||||||
|
);
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: stats
|
||||||
|
--
|
||||||
|
CREATE TABLE "stats" (
|
||||||
|
"uuid" uuid NOT NULL,
|
||||||
|
"health" integer NOT NULL,
|
||||||
|
"mana" integer NOT NULL,
|
||||||
|
"strength" integer NOT NULL,
|
||||||
|
"resistance" integer NOT NULL,
|
||||||
|
"magic" integer NOT NULL,
|
||||||
|
"speed" integer NOT NULL,
|
||||||
|
"intelligence" integer NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid")
|
||||||
|
);
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: equipment_items
|
||||||
|
--
|
||||||
|
CREATE TABLE "equipment_items" (
|
||||||
|
"kind" text NOT NULL,
|
||||||
|
"equipment" uuid NOT NULL,
|
||||||
|
"identifier" text NOT NULL,
|
||||||
|
"quantity" integer NOT NULL,
|
||||||
|
PRIMARY KEY ("kind", "equipment")
|
||||||
|
);
|
||||||
|
CREATE INDEX "equipment_items_idx_equipment" on "equipment_items" ("equipment");
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: inventory_items
|
||||||
|
--
|
||||||
|
CREATE TABLE "inventory_items" (
|
||||||
|
"uuid" uuid DEFAULT uuid_generate_v4() NOT NULL,
|
||||||
|
"inventory" uuid NOT NULL,
|
||||||
|
"identifier" text NOT NULL,
|
||||||
|
"quantity" integer NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid")
|
||||||
|
);
|
||||||
|
CREATE INDEX "inventory_items_idx_inventory" on "inventory_items" ("inventory");
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: skill_like_items
|
||||||
|
--
|
||||||
|
CREATE TABLE "skill_like_items" (
|
||||||
|
"identifier" text NOT NULL,
|
||||||
|
"owner_list" uuid NOT NULL,
|
||||||
|
"level" integer DEFAULT 1 NOT NULL,
|
||||||
|
PRIMARY KEY ("identifier", "owner_list")
|
||||||
|
);
|
||||||
|
CREATE INDEX "skill_like_items_idx_owner_list" on "skill_like_items" ("owner_list");
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: teams
|
||||||
|
--
|
||||||
|
CREATE TABLE "teams" (
|
||||||
|
"uuid" uuid NOT NULL,
|
||||||
|
"leader" uuid,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"planet" text NOT NULL,
|
||||||
|
"super_area" text NOT NULL,
|
||||||
|
"area" text NOT NULL,
|
||||||
|
"location" text NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid"),
|
||||||
|
CONSTRAINT "u_name" UNIQUE ("name")
|
||||||
|
);
|
||||||
|
CREATE INDEX "teams_idx_leader" on "teams" ("leader");
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: player_pjs
|
||||||
|
--
|
||||||
|
CREATE TABLE "player_pjs" (
|
||||||
|
"uuid" uuid DEFAULT uuid_generate_v4() NOT NULL,
|
||||||
|
"owner" uuid NOT NULL,
|
||||||
|
"full_name" text NOT NULL,
|
||||||
|
"short_name" text NOT NULL,
|
||||||
|
"nick" text NOT NULL,
|
||||||
|
"race" text NOT NULL,
|
||||||
|
"team" uuid NOT NULL,
|
||||||
|
"creation_date" timestamp DEFAULT NOW() NOT NULL,
|
||||||
|
"last_activity" timestamp DEFAULT NOW() NOT NULL,
|
||||||
|
"experience" integer DEFAULT 1 NOT NULL,
|
||||||
|
"equipment" uuid NOT NULL,
|
||||||
|
"born_stats" uuid NOT NULL,
|
||||||
|
"training_stats" uuid NOT NULL,
|
||||||
|
"skills" uuid NOT NULL,
|
||||||
|
"spells" uuid NOT NULL,
|
||||||
|
"inventory" uuid NOT NULL,
|
||||||
|
"health" integer NOT NULL,
|
||||||
|
"mana" integer NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid")
|
||||||
|
);
|
||||||
|
CREATE INDEX "player_pjs_idx_born_stats" on "player_pjs" ("born_stats");
|
||||||
|
CREATE INDEX "player_pjs_idx_equipment" on "player_pjs" ("equipment");
|
||||||
|
CREATE INDEX "player_pjs_idx_inventory" on "player_pjs" ("inventory");
|
||||||
|
CREATE INDEX "player_pjs_idx_owner" on "player_pjs" ("owner");
|
||||||
|
CREATE INDEX "player_pjs_idx_skills" on "player_pjs" ("skills");
|
||||||
|
CREATE INDEX "player_pjs_idx_spells" on "player_pjs" ("spells");
|
||||||
|
CREATE INDEX "player_pjs_idx_team" on "player_pjs" ("team");
|
||||||
|
CREATE INDEX "player_pjs_idx_training_stats" on "player_pjs" ("training_stats");
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: player_companion_npcs
|
||||||
|
--
|
||||||
|
CREATE TABLE "player_companion_npcs" (
|
||||||
|
"uuid" uuid DEFAULT uuid_generate_v4() NOT NULL,
|
||||||
|
"owner" uuid NOT NULL,
|
||||||
|
"identifier" text NOT NULL,
|
||||||
|
"nick" text,
|
||||||
|
"race" text NOT NULL,
|
||||||
|
"level" integer DEFAULT 1 NOT NULL,
|
||||||
|
"exp" integer DEFAULT 1 NOT NULL,
|
||||||
|
"equipment" uuid NOT NULL,
|
||||||
|
"stats" uuid NOT NULL,
|
||||||
|
"skills" uuid NOT NULL,
|
||||||
|
"spells" uuid NOT NULL,
|
||||||
|
"inventory" uuid NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid")
|
||||||
|
);
|
||||||
|
CREATE INDEX "player_companion_npcs_idx_equipment" on "player_companion_npcs" ("equipment");
|
||||||
|
CREATE INDEX "player_companion_npcs_idx_inventory" on "player_companion_npcs" ("inventory");
|
||||||
|
CREATE INDEX "player_companion_npcs_idx_owner" on "player_companion_npcs" ("owner");
|
||||||
|
CREATE INDEX "player_companion_npcs_idx_skills" on "player_companion_npcs" ("skills");
|
||||||
|
CREATE INDEX "player_companion_npcs_idx_spells" on "player_companion_npcs" ("spells");
|
||||||
|
CREATE INDEX "player_companion_npcs_idx_stats" on "player_companion_npcs" ("stats");
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: player_pjs_flags
|
||||||
|
--
|
||||||
|
CREATE TABLE "player_pjs_flags" (
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"owner" uuid NOT NULL,
|
||||||
|
PRIMARY KEY ("name", "owner")
|
||||||
|
);
|
||||||
|
CREATE INDEX "player_pjs_flags_idx_owner" on "player_pjs_flags" ("owner");
|
||||||
|
CREATE INDEX "index_flag" on "player_pjs_flags" ("owner", "name");
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Table: player_pjs_log
|
||||||
|
--
|
||||||
|
CREATE TABLE "player_pjs_log" (
|
||||||
|
"uuid" uuid NOT NULL,
|
||||||
|
"content" jsonb NOT NULL,
|
||||||
|
"owner" uuid NOT NULL,
|
||||||
|
"date" timestamp DEFAULT NOW() NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid")
|
||||||
|
);
|
||||||
|
CREATE INDEX "player_pjs_log_idx_owner" on "player_pjs_log" ("owner");
|
||||||
|
CREATE INDEX "index_log" on "player_pjs_log" ("owner", "date");
|
||||||
|
|
||||||
|
;
|
||||||
|
--
|
||||||
|
-- Foreign Key Definitions
|
||||||
|
--
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "equipment_items" ADD CONSTRAINT "equipment_items_fk_equipment" FOREIGN KEY ("equipment")
|
||||||
|
REFERENCES "equipment" ("uuid") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "inventory_items" ADD CONSTRAINT "inventory_items_fk_inventory" FOREIGN KEY ("inventory")
|
||||||
|
REFERENCES "inventories" ("uuid") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "skill_like_items" ADD CONSTRAINT "skill_like_items_fk_owner_list" FOREIGN KEY ("owner_list")
|
||||||
|
REFERENCES "skill_like_lists" ("uuid") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "teams" ADD CONSTRAINT "teams_fk_leader" FOREIGN KEY ("leader")
|
||||||
|
REFERENCES "player_pjs" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs" ADD CONSTRAINT "player_pjs_fk_born_stats" FOREIGN KEY ("born_stats")
|
||||||
|
REFERENCES "stats" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs" ADD CONSTRAINT "player_pjs_fk_equipment" FOREIGN KEY ("equipment")
|
||||||
|
REFERENCES "equipment" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs" ADD CONSTRAINT "player_pjs_fk_inventory" FOREIGN KEY ("inventory")
|
||||||
|
REFERENCES "inventories" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs" ADD CONSTRAINT "player_pjs_fk_owner" FOREIGN KEY ("owner")
|
||||||
|
REFERENCES "players" ("uuid") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs" ADD CONSTRAINT "player_pjs_fk_skills" FOREIGN KEY ("skills")
|
||||||
|
REFERENCES "skill_like_lists" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs" ADD CONSTRAINT "player_pjs_fk_spells" FOREIGN KEY ("spells")
|
||||||
|
REFERENCES "skill_like_lists" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs" ADD CONSTRAINT "player_pjs_fk_team" FOREIGN KEY ("team")
|
||||||
|
REFERENCES "teams" ("uuid") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs" ADD CONSTRAINT "player_pjs_fk_training_stats" FOREIGN KEY ("training_stats")
|
||||||
|
REFERENCES "stats" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_companion_npcs" ADD CONSTRAINT "player_companion_npcs_fk_equipment" FOREIGN KEY ("equipment")
|
||||||
|
REFERENCES "equipment" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_companion_npcs" ADD CONSTRAINT "player_companion_npcs_fk_inventory" FOREIGN KEY ("inventory")
|
||||||
|
REFERENCES "inventories" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_companion_npcs" ADD CONSTRAINT "player_companion_npcs_fk_owner" FOREIGN KEY ("owner")
|
||||||
|
REFERENCES "player_pjs" ("uuid") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_companion_npcs" ADD CONSTRAINT "player_companion_npcs_fk_skills" FOREIGN KEY ("skills")
|
||||||
|
REFERENCES "skill_like_lists" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_companion_npcs" ADD CONSTRAINT "player_companion_npcs_fk_spells" FOREIGN KEY ("spells")
|
||||||
|
REFERENCES "skill_like_lists" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_companion_npcs" ADD CONSTRAINT "player_companion_npcs_fk_stats" FOREIGN KEY ("stats")
|
||||||
|
REFERENCES "stats" ("uuid") DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs_flags" ADD CONSTRAINT "player_pjs_flags_fk_owner" FOREIGN KEY ("owner")
|
||||||
|
REFERENCES "player_pjs" ("uuid") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs_log" ADD CONSTRAINT "player_pjs_log_fk_owner" FOREIGN KEY ("owner")
|
||||||
|
REFERENCES "player_pjs" ("uuid") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
37
dbicdh/PostgreSQL/upgrade/4-5/001-auto.sql
Normal file
37
dbicdh/PostgreSQL/upgrade/4-5/001-auto.sql
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
-- Convert schema '/home/sergio/LasTres/script/../dbicdh/_source/deploy/4/001-auto.yml' to '/home/sergio/LasTres/script/../dbicdh/_source/deploy/5/001-auto.yml':;
|
||||||
|
|
||||||
|
;
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
;
|
||||||
|
CREATE TABLE "player_pjs_flags" (
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"owner" uuid NOT NULL,
|
||||||
|
PRIMARY KEY ("name", "owner")
|
||||||
|
);
|
||||||
|
CREATE INDEX "player_pjs_flags_idx_owner" on "player_pjs_flags" ("owner");
|
||||||
|
CREATE INDEX "index_flag" on "player_pjs_flags" ("owner", "name");
|
||||||
|
|
||||||
|
;
|
||||||
|
CREATE TABLE "player_pjs_log" (
|
||||||
|
"uuid" uuid NOT NULL,
|
||||||
|
"content" jsonb NOT NULL,
|
||||||
|
"owner" uuid NOT NULL,
|
||||||
|
"date" timestamp DEFAULT NOW() NOT NULL,
|
||||||
|
PRIMARY KEY ("uuid")
|
||||||
|
);
|
||||||
|
CREATE INDEX "player_pjs_log_idx_owner" on "player_pjs_log" ("owner");
|
||||||
|
CREATE INDEX "index_log" on "player_pjs_log" ("owner", "date");
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs_flags" ADD CONSTRAINT "player_pjs_flags_fk_owner" FOREIGN KEY ("owner")
|
||||||
|
REFERENCES "player_pjs" ("uuid") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
ALTER TABLE "player_pjs_log" ADD CONSTRAINT "player_pjs_log_fk_owner" FOREIGN KEY ("owner")
|
||||||
|
REFERENCES "player_pjs" ("uuid") ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE;
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
1432
dbicdh/_source/deploy/5/001-auto.yml
Normal file
1432
dbicdh/_source/deploy/5/001-auto.yml
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,15 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
|
||||||
import { PJ } from '@lastres/pj'
|
import type { PJ } from '@lastres/pj'
|
||||||
|
import type { Location } from '@lastres/location'
|
||||||
|
import type { LogLine } from '@lastres/log-line'
|
||||||
|
|
||||||
import UpperPanel from '@lastres/components/upper-panel'
|
import UpperPanel from '@lastres/components/upper-panel'
|
||||||
import BottomPanel from '@lastres/components/bottom-panel'
|
import BottomPanel from '@lastres/components/bottom-panel'
|
||||||
import PJSelectionMenu from '@lastres/components/pj-selection-menu'
|
import PJSelectionMenu from '@lastres/components/pj-selection-menu'
|
||||||
|
import OutputPacketInit from '@lastres/output-packet/init'
|
||||||
|
import OutputPacketPing from '@lastres/output-packet/ping'
|
||||||
|
import InputPackets from '@lastres/input-packets'
|
||||||
|
|
||||||
export interface GameProps {
|
export interface GameProps {
|
||||||
setSelectedPJ: (set: PJ | null) => void
|
setSelectedPJ: (set: PJ | null) => void
|
||||||
@ -16,7 +21,8 @@ export interface GameProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Game (props: GameProps): JSX.Element {
|
export default function Game (props: GameProps): JSX.Element {
|
||||||
if (props.selectedPJ === null) {
|
const selectedPJ = props.selectedPJ
|
||||||
|
if (selectedPJ === null) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PJSelectionMenu
|
<PJSelectionMenu
|
||||||
@ -28,21 +34,47 @@ export default function Game (props: GameProps): JSX.Element {
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
window.setTimeout(() => {
|
const [websocket, setWebsocket] = React.useState<WebSocket | null>(null)
|
||||||
const locationProtocol = window.location.protocol
|
const [teamPJs, setTeamPJs] = React.useState<PJ[] | null>(null)
|
||||||
if (locationProtocol == null) {
|
const [currentLocation, setCurrentLocation] = React.useState<Location | null>(null)
|
||||||
return
|
const [connectedLocations, setConnectedLocations] = React.useState<Location[] | null>(null)
|
||||||
}
|
const [logLines, setLogLines] = React.useState<LogLine[] | null>(null)
|
||||||
const protocol = locationProtocol.match(/https:/) != null ? 'wss' : 'ws'
|
if (websocket === null) {
|
||||||
const webSocket = new WebSocket(`${protocol}://${window.location.host}/ws`)
|
window.setTimeout(() => {
|
||||||
webSocket.onopen = () => {
|
const locationProtocol = window.location.protocol
|
||||||
webSocket.send(JSON.stringify({hola: "mundo"}))
|
if (locationProtocol == null) {
|
||||||
};
|
return
|
||||||
|
}
|
||||||
}, 1);
|
const protocol = locationProtocol.match(/https:/) != null ? 'wss' : 'ws'
|
||||||
|
const webSocket = new WebSocket(`${protocol}://${window.location.host}/ws`)
|
||||||
|
webSocket.onopen = () => {
|
||||||
|
new OutputPacketInit(selectedPJ.uuid).send(webSocket)
|
||||||
|
let interval: number = 0
|
||||||
|
interval = window.setInterval(() => {
|
||||||
|
if (webSocket.readyState === WebSocket.OPEN) {
|
||||||
|
new OutputPacketPing().send(webSocket)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
window.clearInterval(interval)
|
||||||
|
}, 10000)
|
||||||
|
}
|
||||||
|
const inputPackets = new InputPackets(setTeamPJs, setCurrentLocation, setConnectedLocations, setLogLines)
|
||||||
|
webSocket.onmessage = (event) => {
|
||||||
|
const packet = JSON.parse(event.data)
|
||||||
|
inputPackets.handle(packet)
|
||||||
|
}
|
||||||
|
webSocket.onerror = (event) => {
|
||||||
|
console.log(event)
|
||||||
|
}
|
||||||
|
setWebsocket(webSocket)
|
||||||
|
}, 1)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<UpperPanel/>
|
<UpperPanel teamPJs={teamPJs}
|
||||||
|
currentLocation={currentLocation}
|
||||||
|
connectedLocations={connectedLocations}
|
||||||
|
logLines={logLines}/>
|
||||||
<BottomPanel/>
|
<BottomPanel/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
35
js-src/components/pj-list-item.tsx
Normal file
35
js-src/components/pj-list-item.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import * as React from 'react'
|
||||||
|
import type { PJ } from '@lastres/pj'
|
||||||
|
import PJHealthLikeBar from '@lastres/components/pj-health-like-bar'
|
||||||
|
export interface PJListItemProps {
|
||||||
|
pj: PJ
|
||||||
|
}
|
||||||
|
export default function PJListItem (props: PJListItemProps): JSX.Element {
|
||||||
|
const pj = props.pj
|
||||||
|
function avatar (): React.ReactNode {
|
||||||
|
if (pj.image === undefined) {
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
return <><img src={pj.image}/><div className="shadow"/></>
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="pj-list-item">
|
||||||
|
<div className="avatar">
|
||||||
|
{
|
||||||
|
avatar()
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className="data">
|
||||||
|
<p>{pj.nick}</p>
|
||||||
|
<label className="bar-container">
|
||||||
|
Salud
|
||||||
|
<PJHealthLikeBar value={pj.health} max={pj.max_health}/>
|
||||||
|
</label>
|
||||||
|
<label className="bar-container">
|
||||||
|
Mana
|
||||||
|
<PJHealthLikeBar value={pj.mana} max={pj.max_mana}/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { PJ } from '@lastres/pj'
|
import type { PJ } from '@lastres/pj'
|
||||||
import PJHealthLikeBar from '@lastres/components/pj-health-like-bar'
|
import PJHealthLikeBar from '@lastres/components/pj-health-like-bar'
|
||||||
|
|
||||||
interface PJListSelectionProps {
|
interface PJListSelectionProps {
|
||||||
@ -7,7 +7,7 @@ interface PJListSelectionProps {
|
|||||||
setSelectedPJ: (set: PJ | null) => void
|
setSelectedPJ: (set: PJ | null) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PJListSelection(props: PJListSelectionProps) {
|
export default function PJListSelection (props: PJListSelectionProps): JSX.Element {
|
||||||
const pjs = props.pjs
|
const pjs = props.pjs
|
||||||
if (pjs === null) {
|
if (pjs === null) {
|
||||||
return (
|
return (
|
||||||
@ -18,24 +18,21 @@ export default function PJListSelection(props: PJListSelectionProps) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{
|
{
|
||||||
pjs.map( (item, i) =>
|
pjs.map((item, i) =>
|
||||||
<a onClick={() => {
|
<a onClick={() => {
|
||||||
props.setSelectedPJ(item)
|
props.setSelectedPJ(item)
|
||||||
}}
|
}} href="#" key={i}>
|
||||||
href="#"
|
|
||||||
key={i}>
|
|
||||||
<span>{item.full_name}</span>
|
<span>{item.full_name}</span>
|
||||||
<span>{item.short_name}</span>
|
<span>{item.short_name}</span>
|
||||||
<span>{item.nick}</span>
|
<span>{item.nick}</span>
|
||||||
<label>
|
<label className="bar-container">
|
||||||
Salud
|
|
||||||
<PJHealthLikeBar value={item.health} max={item.max_health}/>
|
<PJHealthLikeBar value={item.health} max={item.max_health}/>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label className="bar-container">
|
||||||
Mana
|
Mana
|
||||||
<PJHealthLikeBar value={item.mana} max={item.max_mana}/>
|
<PJHealthLikeBar value={item.mana} max={item.max_mana}/>
|
||||||
</label>
|
</label>
|
||||||
</a> )
|
</a>)
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,85 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
export default function UpperPanel (): JSX.Element {
|
import type { Location } from '@lastres/location'
|
||||||
|
import type { PJ } from '@lastres/pj'
|
||||||
|
import type { LogLine } from '@lastres/log-line'
|
||||||
|
import PJListItem from '@lastres/components/pj-list-item'
|
||||||
|
|
||||||
|
interface UpperPanelProps {
|
||||||
|
connectedLocations: Location[] | null
|
||||||
|
teamPJs: PJ[] | null
|
||||||
|
currentLocation: Location | null
|
||||||
|
logLines: LogLine[] | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Style {
|
||||||
|
color?: string;
|
||||||
|
background?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function UpperPanel (props: UpperPanelProps): JSX.Element {
|
||||||
|
const connectedLocations = props.connectedLocations
|
||||||
|
const teamPJs = props.teamPJs
|
||||||
|
const currentLocation = props.currentLocation
|
||||||
|
const logLines = props.logLines
|
||||||
|
if (!(teamPJs !== null && currentLocation !== null && connectedLocations !== null)) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>Esperando datos...</p>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
function generateLog (): React.ReactNode {
|
||||||
|
if (logLines === null || logLines.length < 1) {
|
||||||
|
return (
|
||||||
|
<>No log</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return logLines.map((item, i) => {
|
||||||
|
return <>
|
||||||
|
<b>{item.date}</b> {
|
||||||
|
item.content.map((item, i) => {
|
||||||
|
const style: Style = {}
|
||||||
|
if (item.color !== undefined) {
|
||||||
|
style.color = item.color
|
||||||
|
}
|
||||||
|
if (item.background !== undefined) {
|
||||||
|
style.background = item.background
|
||||||
|
}
|
||||||
|
return <span key={i} style={style}>{item.text}</span>
|
||||||
|
})
|
||||||
|
} <br/>
|
||||||
|
</>
|
||||||
|
})
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="presentation">
|
||||||
</>
|
<div className="presentation-item">
|
||||||
|
{
|
||||||
|
teamPJs.map((item, i) => {
|
||||||
|
return <PJListItem key={i} pj={item}/>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className="presentation-item">
|
||||||
|
<code><pre>
|
||||||
|
{
|
||||||
|
generateLog()
|
||||||
|
}
|
||||||
|
</pre></code>
|
||||||
|
</div>
|
||||||
|
<div className="presentation-item">
|
||||||
|
<p>Estás en {currentLocation.area.name}/{currentLocation.location.name}.</p>
|
||||||
|
<p>Puedes ir a:</p>
|
||||||
|
<ul>
|
||||||
|
{
|
||||||
|
connectedLocations.map((item, i) => {
|
||||||
|
return <li key={i}>
|
||||||
|
<a href="#">{item.area.name}/{item.location.name}</a>
|
||||||
|
</li>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
20
js-src/input-packet.ts
Normal file
20
js-src/input-packet.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
interface InputPacketJSONDecoded {
|
||||||
|
command: string
|
||||||
|
data: any
|
||||||
|
}
|
||||||
|
|
||||||
|
type onReceiveCallback = (data: any) => void
|
||||||
|
export default abstract class InputPacket {
|
||||||
|
onreceive: onReceiveCallback | null = null
|
||||||
|
|
||||||
|
onReceive (callback: onReceiveCallback): void {
|
||||||
|
this.onreceive = callback
|
||||||
|
}
|
||||||
|
abstract identifier (): string
|
||||||
|
|
||||||
|
recv (packet: InputPacketJSONDecoded): void {
|
||||||
|
if (this.onreceive !== null) {
|
||||||
|
this.onreceive(packet.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
js-src/input-packet/info.ts
Normal file
6
js-src/input-packet/info.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import InputPacket from '@lastres/input-packet'
|
||||||
|
export default class InputPacketInfo extends InputPacket {
|
||||||
|
identifier (): string {
|
||||||
|
return 'info'
|
||||||
|
}
|
||||||
|
}
|
6
js-src/input-packet/pong.ts
Normal file
6
js-src/input-packet/pong.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import InputPacket from '@lastres/input-packet';
|
||||||
|
export default class InputPacketPong extends InputPacket {
|
||||||
|
identifier() {
|
||||||
|
return 'pong'
|
||||||
|
}
|
||||||
|
}
|
64
js-src/input-packets.ts
Normal file
64
js-src/input-packets.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import type { PJ } from '@lastres/pj'
|
||||||
|
import type { Location } from '@lastres/location'
|
||||||
|
import type InputPacket from '@lastres/input-packet'
|
||||||
|
import type { LogLine } from '@lastres/log-line'
|
||||||
|
import InputPacketInfo from '@lastres/input-packet/info'
|
||||||
|
import InputPacketPong from '@lastres/input-packet/pong'
|
||||||
|
type SetTeamPJs = (set: PJ[] | null) => void
|
||||||
|
type SetCurrentLocation = (set: Location | null) => void
|
||||||
|
type SetConnectedLocations = (set: Location[] | null) => void
|
||||||
|
type DispatchHash = Record<string, any>
|
||||||
|
type SetLogLines = (set: LogLine[] | null) => void
|
||||||
|
interface Packet {
|
||||||
|
command: string
|
||||||
|
data: any
|
||||||
|
}
|
||||||
|
export default class InputPackets {
|
||||||
|
setTeamPJs: SetTeamPJs
|
||||||
|
setCurrentLocation: SetCurrentLocation
|
||||||
|
setConnectedLocations: SetConnectedLocations
|
||||||
|
setLogLines: SetLogLines
|
||||||
|
cachedHash: DispatchHash | null = null
|
||||||
|
cachedArray: InputPacket[] | null = null
|
||||||
|
constructor (setTeamPJs: SetTeamPJs,
|
||||||
|
setCurrentLocation: SetCurrentLocation,
|
||||||
|
setConnectedLocations: SetConnectedLocations,
|
||||||
|
setLogLines: SetLogLines) {
|
||||||
|
this.setTeamPJs = setTeamPJs
|
||||||
|
this.setCurrentLocation = setCurrentLocation
|
||||||
|
this.setConnectedLocations = setConnectedLocations
|
||||||
|
this.setLogLines = setLogLines
|
||||||
|
}
|
||||||
|
|
||||||
|
handle (packet: Packet): void {
|
||||||
|
const hash = this.hashAvailablePackets()
|
||||||
|
const identifier = packet.command
|
||||||
|
const inputPacket = hash[identifier]
|
||||||
|
inputPacket.recv(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
listAvailablePackets (): InputPacket[] {
|
||||||
|
if (this.cachedArray === null) {
|
||||||
|
const infoPacket = new InputPacketInfo()
|
||||||
|
const pongPacket = new InputPacketPong()
|
||||||
|
infoPacket.onReceive((data) => {
|
||||||
|
this.setTeamPJs(data.team_pjs)
|
||||||
|
this.setConnectedLocations(data.location_data.connected_places)
|
||||||
|
this.setCurrentLocation(data.location_data.current)
|
||||||
|
this.setLogLines(data.set_log)
|
||||||
|
})
|
||||||
|
this.cachedArray = [infoPacket, pongPacket]
|
||||||
|
}
|
||||||
|
return this.cachedArray
|
||||||
|
}
|
||||||
|
|
||||||
|
hashAvailablePackets (): DispatchHash {
|
||||||
|
if (this.cachedHash === null) {
|
||||||
|
this.cachedHash = {}
|
||||||
|
for (const inputPacket of this.listAvailablePackets()) {
|
||||||
|
this.cachedHash[inputPacket.identifier()] = inputPacket
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.cachedHash
|
||||||
|
}
|
||||||
|
}
|
10
js-src/location.ts
Normal file
10
js-src/location.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export interface NameIdentifierHash {
|
||||||
|
name: string
|
||||||
|
identifier: string
|
||||||
|
}
|
||||||
|
export interface Location {
|
||||||
|
location: NameIdentifierHash
|
||||||
|
area: NameIdentifierHash
|
||||||
|
super_area: NameIdentifierHash
|
||||||
|
planet: NameIdentifierHash
|
||||||
|
}
|
7
js-src/log-line.ts
Normal file
7
js-src/log-line.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import type { LogSection } from '@lastres/log-section'
|
||||||
|
|
||||||
|
export interface LogLine {
|
||||||
|
content: LogSection[]
|
||||||
|
date: string
|
||||||
|
uuid: string
|
||||||
|
}
|
5
js-src/log-section.ts
Normal file
5
js-src/log-section.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export interface LogSection {
|
||||||
|
color?: string
|
||||||
|
background?: string
|
||||||
|
text: string
|
||||||
|
}
|
11
js-src/output-packet.ts
Normal file
11
js-src/output-packet.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export default abstract class OutputPacket {
|
||||||
|
send(ws: WebSocket): void {
|
||||||
|
const data = this.data();
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
command: this.command(),
|
||||||
|
data: this.data(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
abstract data(): any
|
||||||
|
abstract command(): string
|
||||||
|
}
|
22
js-src/output-packet/init.ts
Normal file
22
js-src/output-packet/init.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import OutputPacket from '@lastres/output-packet';
|
||||||
|
interface OutputPacketInitData {
|
||||||
|
pj_uuid: string
|
||||||
|
}
|
||||||
|
export default class OutputPacketInit extends OutputPacket {
|
||||||
|
pj_uuid: string
|
||||||
|
|
||||||
|
constructor(pj_uuid: string) {
|
||||||
|
super()
|
||||||
|
this.pj_uuid = pj_uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
command(): string {
|
||||||
|
return 'init'
|
||||||
|
}
|
||||||
|
|
||||||
|
data(): OutputPacketInitData {
|
||||||
|
return {
|
||||||
|
pj_uuid: this.pj_uuid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
js-src/output-packet/ping.ts
Normal file
16
js-src/output-packet/ping.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import OutputPacket from '@lastres/output-packet';
|
||||||
|
export default class OutputPacketPing extends OutputPacket {
|
||||||
|
pj_uuid: string
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
command(): string {
|
||||||
|
return 'ping'
|
||||||
|
}
|
||||||
|
|
||||||
|
data(): null {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
11
js-src/pj.ts
11
js-src/pj.ts
@ -2,21 +2,22 @@ export interface PJ {
|
|||||||
full_name: string
|
full_name: string
|
||||||
short_name: string
|
short_name: string
|
||||||
nick: string
|
nick: string
|
||||||
health: number
|
health: number
|
||||||
mana: number
|
mana: number
|
||||||
max_mana: number
|
max_mana: number
|
||||||
max_health: number
|
max_health: number
|
||||||
race: string
|
race: string
|
||||||
uuid: string
|
uuid: string
|
||||||
|
image?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchMyPjs(setError: (set: string | null) => void): Promise<PJ[]> {
|
export async function fetchMyPjs (setError: (set: string | null) => void): Promise<PJ[]> {
|
||||||
const response = await fetch('/my/pjs', {
|
const response = await fetch('/my/pjs', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
mode: 'same-origin',
|
mode: 'same-origin',
|
||||||
cache: 'no-cache'
|
cache: 'no-cache'
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.log(error);
|
console.log(error)
|
||||||
setError('Error recuperando tus pjs')
|
setError('Error recuperando tus pjs')
|
||||||
})
|
})
|
||||||
if (response === undefined) {
|
if (response === undefined) {
|
||||||
|
@ -5,7 +5,22 @@ use v5.36.0;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
use feature 'signatures';
|
||||||
|
|
||||||
use Moo::Role;
|
use Moo::Role;
|
||||||
|
|
||||||
requires qw/identifier locations name parent/;
|
requires qw/identifier locations name parent/;
|
||||||
|
|
||||||
|
has children => (
|
||||||
|
is => 'ro',
|
||||||
|
lazy => 1,
|
||||||
|
builder => \&_build_children,
|
||||||
|
);
|
||||||
|
|
||||||
|
sub _build_children($self) {
|
||||||
|
my $locations = $self->locations;
|
||||||
|
my @locations = map { $locations->{$_} } keys %$locations;
|
||||||
|
@locations = sort { $a->name cmp $b->name } @locations;
|
||||||
|
return \@locations;
|
||||||
|
}
|
||||||
1;
|
1;
|
||||||
|
@ -39,17 +39,7 @@ sub list_my_pjs ($self) {
|
|||||||
my @pjs = $user->pjs;
|
my @pjs = $user->pjs;
|
||||||
my @pjs_hash = (
|
my @pjs_hash = (
|
||||||
map {
|
map {
|
||||||
{
|
$_->hash;
|
||||||
uuid => $_->uuid,
|
|
||||||
full_name => $_->full_name,
|
|
||||||
short_name => $_->short_name,
|
|
||||||
nick => $_->nick,
|
|
||||||
race => $_->race,
|
|
||||||
health => $_->health,
|
|
||||||
max_health => $_->max_health,
|
|
||||||
mana => $_->mana,
|
|
||||||
max_mana => $_->max_mana,
|
|
||||||
}
|
|
||||||
} @pjs
|
} @pjs
|
||||||
);
|
);
|
||||||
return $self->render(
|
return $self->render(
|
||||||
|
@ -12,13 +12,13 @@ use Mojo::Base 'Mojolicious::Controller', -signatures;
|
|||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
use LasTres::Redis;
|
use LasTres::Redis;
|
||||||
use LasTres::DAO::PJs;
|
|
||||||
use LasTres::Controller::Websocket::InputPackets;
|
use LasTres::Controller::Websocket::InputPackets;
|
||||||
|
|
||||||
my %sessions;
|
my %sessions;
|
||||||
|
use LasTres::DAO::PJs;
|
||||||
my $result_set_pjs = LasTres::DAO::PJs->ResultSet;
|
my $result_set_pjs = LasTres::DAO::PJs->ResultSet;
|
||||||
|
|
||||||
my $redis = LasTres::Redis->new;
|
my $redis = LasTres::Redis->new;
|
||||||
my $input_packets = LasTres::Controller::Websocket::InputPackets->new;
|
my $input_packets = LasTres::Controller::Websocket::InputPackets->new;
|
||||||
|
|
||||||
sub ws ($self) {
|
sub ws ($self) {
|
||||||
@ -46,6 +46,7 @@ sub ws ($self) {
|
|||||||
$self->on(
|
$self->on(
|
||||||
finish => sub ( $self, $code, $reason ) {
|
finish => sub ( $self, $code, $reason ) {
|
||||||
delete $sessions{$session_uuid};
|
delete $sessions{$session_uuid};
|
||||||
|
$reason ||= "No reason";
|
||||||
say STDERR
|
say STDERR
|
||||||
"Websocket for user @{[$user->username]} closed with status $code and reason $reason.";
|
"Websocket for user @{[$user->username]} closed with status $code and reason $reason.";
|
||||||
}
|
}
|
||||||
@ -53,6 +54,7 @@ sub ws ($self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
sub _handle_packet ( $self, $session, $hash ) {
|
sub _handle_packet ( $self, $session, $hash ) {
|
||||||
my $command = $hash->{command};
|
my $command = $hash->{command};
|
||||||
if ( !defined $command ) {
|
if ( !defined $command ) {
|
||||||
@ -60,7 +62,7 @@ sub ws ($self) {
|
|||||||
$self->send( encode_json( { error => "No command" } ) );
|
$self->send( encode_json( { error => "No command" } ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
my $input_packet = $input_packets->hash->{$command)
|
my $input_packet = $input_packets->hash->{$command};
|
||||||
|
|
||||||
if ( !defined $input_packet ) {
|
if ( !defined $input_packet ) {
|
||||||
say STDERR "Unknown command $command.";
|
say STDERR "Unknown command $command.";
|
||||||
|
@ -5,21 +5,31 @@ use v5.36.0;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
|
use JSON;
|
||||||
|
|
||||||
|
use LasTres::Flags;
|
||||||
use LasTres::Redis;
|
use LasTres::Redis;
|
||||||
|
use LasTres::DAO::PJs;
|
||||||
|
|
||||||
with 'LasTres::Controller::Websocket::InputPacket';
|
with 'LasTres::Controller::Websocket::InputPacket';
|
||||||
|
|
||||||
|
my $redis = LasTres::Redis->new;
|
||||||
|
my $result_set_pjs = LasTres::DAO::PJs->ResultSet;
|
||||||
|
|
||||||
sub identifier {
|
sub identifier {
|
||||||
return 'init';
|
return 'init';
|
||||||
}
|
}
|
||||||
|
|
||||||
my $redis = LasTres::Redis->new;
|
|
||||||
|
|
||||||
sub handle ( $self, $ws, $session, $data ) {
|
sub handle ( $self, $ws, $session, $data ) {
|
||||||
if (ref $data ne 'HASH') {
|
if ( ref $data ne 'HASH' ) {
|
||||||
return $ws->send( encode_json( { error => "Data should be a hashref." } ) );
|
return $ws->send(
|
||||||
|
encode_json( { error => "Data should be a hashref." } ) );
|
||||||
}
|
}
|
||||||
my $pj_uuid = $data->{pj_uuid};
|
my $pj_uuid = $data->{pj_uuid};
|
||||||
if ( !defined $pj_uuid ) {
|
if ( !defined $pj_uuid ) {
|
||||||
@ -37,6 +47,55 @@ sub handle ( $self, $ws, $session, $data ) {
|
|||||||
encode_json( { error => 'You are not the owner of this pj.' } ) );
|
encode_json( { error => 'You are not the owner of this pj.' } ) );
|
||||||
}
|
}
|
||||||
$session->{pj} = $pj;
|
$session->{pj} = $pj;
|
||||||
|
my $team = $pj->team;
|
||||||
|
my @team_members = $team->members;
|
||||||
|
my @friends = grep { $pj->uuid ne $_->uuid } @team_members;
|
||||||
|
my $team_pjs = [ map { $_->hash } ( $pj, @friends ) ];
|
||||||
|
my $location = $team->location;
|
||||||
|
my $connected_places = $self->_get_connected_places($pj);
|
||||||
|
|
||||||
|
$pj->append_log_line(
|
||||||
|
[
|
||||||
|
{ text => 'Nueva conexion a este pj.', color => 'red' },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( !$pj->get_flag( LasTres::Flags::INTRO_MESSAGE_SENT_FLAG() ) ) {
|
||||||
|
$pj->set_flag(LasTres::Flags::INTRO_MESSAGE_SENT_FLAG);
|
||||||
|
$pj->append_log_line(
|
||||||
|
[
|
||||||
|
{ text => 'Bienvenido a ' },
|
||||||
|
{ text => 'LasTres', color => 'green' },
|
||||||
|
{ text => '. Esperamos que disfrutes del juego.' }
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
my $info_packet_to_send =
|
||||||
|
LasTres::Controller::Websocket::OutputPacket::Info->new(
|
||||||
|
set_log => [$pj->last_50_log],
|
||||||
|
team_pjs => $team_pjs,
|
||||||
|
location_data => {
|
||||||
|
current => $location->hash,
|
||||||
|
connected_places => $connected_places,
|
||||||
|
},
|
||||||
|
clear => $JSON::true,
|
||||||
|
);
|
||||||
|
$info_packet_to_send->send($ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub _get_connected_places ( $self, $pj ) {
|
||||||
|
my $team = $pj->team;
|
||||||
|
my $location = $team->location;
|
||||||
|
|
||||||
|
my $connected_places = [];
|
||||||
|
if ( $location->can('connected_places') ) {
|
||||||
|
@$connected_places = ( @{ $team->location->connected_places } );
|
||||||
|
}
|
||||||
|
@$connected_places =
|
||||||
|
( @$connected_places, @{ $location->parent->children } );
|
||||||
|
@$connected_places =
|
||||||
|
grep { $_->identifier ne $location->identifier } @$connected_places;
|
||||||
|
@$connected_places = map { $_->hash } @$connected_places;
|
||||||
|
return $connected_places;
|
||||||
|
}
|
||||||
1;
|
1;
|
||||||
|
32
lib/LasTres/Controller/Websocket/InputPacket/Ping.pm
Normal file
32
lib/LasTres/Controller/Websocket/InputPacket/Ping.pm
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package LasTres::Controller::Websocket::InputPacket::Ping;
|
||||||
|
|
||||||
|
use v5.36.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
use Moo;
|
||||||
|
|
||||||
|
use JSON;
|
||||||
|
|
||||||
|
use LasTres::Redis;
|
||||||
|
use LasTres::DAO::PJs;
|
||||||
|
|
||||||
|
with 'LasTres::Controller::Websocket::InputPacket';
|
||||||
|
|
||||||
|
|
||||||
|
my $redis = LasTres::Redis->new;
|
||||||
|
my $result_set_pjs = LasTres::DAO::PJs->ResultSet;
|
||||||
|
|
||||||
|
sub identifier {
|
||||||
|
return 'ping';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle ( $self, $ws, $session, $data ) {
|
||||||
|
LasTres::Controller::Websocket::OutputPacket::Pong->new->send($ws);
|
||||||
|
}
|
||||||
|
1;
|
@ -7,16 +7,16 @@ use warnings;
|
|||||||
|
|
||||||
use Moo::Role;
|
use Moo::Role;
|
||||||
|
|
||||||
|
use JSON qw/encode_json/;
|
||||||
|
|
||||||
requires qw/new identifier data/;
|
requires qw/new identifier data/;
|
||||||
|
|
||||||
sub send ( $self, $ws ) {
|
sub send ( $self, $ws ) {
|
||||||
return $ws->send(
|
return $ws->send({json =>
|
||||||
encode_json(
|
{
|
||||||
{
|
command => $self->identifier,
|
||||||
command => $self->identifier,
|
data => $self->data
|
||||||
data => $self->data
|
}
|
||||||
}
|
});
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
1;
|
1;
|
||||||
|
@ -7,6 +7,10 @@ use warnings;
|
|||||||
|
|
||||||
use feature 'signatures';
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
use Moo;
|
||||||
|
|
||||||
with 'LasTres::Controller::Websocket::OutputPacket';
|
with 'LasTres::Controller::Websocket::OutputPacket';
|
||||||
|
|
||||||
has clear => (
|
has clear => (
|
||||||
@ -21,6 +25,10 @@ has location_data => (
|
|||||||
is => 'rw',
|
is => 'rw',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
has set_log => (
|
||||||
|
is => 'rw',
|
||||||
|
);
|
||||||
|
|
||||||
sub identifier {
|
sub identifier {
|
||||||
return 'info';
|
return 'info';
|
||||||
}
|
}
|
||||||
@ -29,6 +37,7 @@ sub data($self) {
|
|||||||
my $clear = $self->clear;
|
my $clear = $self->clear;
|
||||||
my $team_pjs = $self->team_pjs;
|
my $team_pjs = $self->team_pjs;
|
||||||
my $location_data = $self->location_data;
|
my $location_data = $self->location_data;
|
||||||
|
my $set_log = $self->set_log;
|
||||||
return {
|
return {
|
||||||
(
|
(
|
||||||
(defined $clear)
|
(defined $clear)
|
||||||
@ -44,6 +53,11 @@ sub data($self) {
|
|||||||
(defined $location_data)
|
(defined $location_data)
|
||||||
? (location_data => $location_data)
|
? (location_data => $location_data)
|
||||||
: ()
|
: ()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(defined $set_log)
|
||||||
|
? (set_log => [map { $_->hash } @$set_log])
|
||||||
|
: ()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
21
lib/LasTres/Controller/Websocket/OutputPacket/Pong.pm
Normal file
21
lib/LasTres/Controller/Websocket/OutputPacket/Pong.pm
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package LasTres::Controller::Websocket::OutputPacket::Pong;
|
||||||
|
|
||||||
|
use v5.36.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use Moo;
|
||||||
|
|
||||||
|
with 'LasTres::Controller::Websocket::OutputPacket';
|
||||||
|
|
||||||
|
sub identifier {
|
||||||
|
return 'pong';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub data($self) {
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
1;
|
@ -7,17 +7,15 @@ use warnings;
|
|||||||
|
|
||||||
use feature 'signatures';
|
use feature 'signatures';
|
||||||
|
|
||||||
use Moo;
|
use Data::Dumper;
|
||||||
|
|
||||||
use Params::ValidationCompiler qw/validation_for/;
|
use Moo;
|
||||||
use Types::Standard qw/Str Bool/;
|
|
||||||
|
|
||||||
use LasTres::Schema;
|
use LasTres::Schema;
|
||||||
|
|
||||||
my $schema = LasTres::Schema->Schema;
|
|
||||||
my $result_set = $schema->resultset('PJ');
|
|
||||||
|
|
||||||
sub ResultSet {
|
sub ResultSet {
|
||||||
|
my $schema = LasTres::Schema->Schema;
|
||||||
|
my $result_set = $schema->resultset('PJ');
|
||||||
return $result_set;
|
return $result_set;
|
||||||
}
|
}
|
||||||
1;
|
1;
|
||||||
|
@ -11,10 +11,10 @@ use Moo;
|
|||||||
|
|
||||||
use LasTres::Schema;
|
use LasTres::Schema;
|
||||||
|
|
||||||
my $schema = LasTres::Schema->Schema;
|
|
||||||
my $result_set = $schema->resultset('Player');
|
|
||||||
|
|
||||||
sub ResultSet {
|
sub ResultSet {
|
||||||
|
my $schema = LasTres::Schema->Schema;
|
||||||
|
my $result_set = $schema->resultset('Player');
|
||||||
return $result_set;
|
return $result_set;
|
||||||
}
|
}
|
||||||
1;
|
1;
|
||||||
|
11
lib/LasTres/Flags.pm
Normal file
11
lib/LasTres/Flags.pm
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package LasTres::Flags;
|
||||||
|
|
||||||
|
use v5.36.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
sub INTRO_MESSAGE_SENT_FLAG {
|
||||||
|
return 'INTRO_MESSAGE_FLAG_SENT';
|
||||||
|
}
|
||||||
|
1;
|
@ -5,7 +5,69 @@ use v5.36.0;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use LasTres::Planets;
|
||||||
use Moo::Role;
|
use Moo::Role;
|
||||||
|
|
||||||
requires qw/identifier name description parent actions npcs/;
|
requires qw/identifier name description parent actions npcs/;
|
||||||
|
|
||||||
|
my $planets = LasTres::Planets->new;
|
||||||
|
sub get($planet_id, $super_area_id, $area_id, $location_id) {
|
||||||
|
my $planet = $planets->hash->{$planet_id};
|
||||||
|
if (!defined $planet) {
|
||||||
|
die "No such planet $planet_id.";
|
||||||
|
}
|
||||||
|
my $super_area = $planet->super_areas->{$super_area_id};
|
||||||
|
if (!defined $super_area) {
|
||||||
|
die "No such super_area $super_area_id in planet $planet_id.";
|
||||||
|
}
|
||||||
|
my $area = $super_area->areas->{$area_id};
|
||||||
|
if (!defined $area) {
|
||||||
|
die "No such area $area_id in super_area $super_area_id in planet $planet_id.";
|
||||||
|
}
|
||||||
|
my $location = $area->locations->{$location_id};
|
||||||
|
if (!defined $location) {
|
||||||
|
die "No such location $location_id in area $area_id in super_area $super_area_id in planet $planet_id.";
|
||||||
|
|
||||||
|
}
|
||||||
|
return $location;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub hash($self) {
|
||||||
|
my $location = $self;
|
||||||
|
if (!Moo::Role::does_role($location, 'LasTres::Location')) {
|
||||||
|
die "$location does not implement LasTres::Location.";
|
||||||
|
}
|
||||||
|
my $area = $location->parent;
|
||||||
|
if (!Moo::Role::does_role($area, 'LasTres::Area')) {
|
||||||
|
die "$area does not implement LasTres::Area.";
|
||||||
|
}
|
||||||
|
my $super_area = $area->parent;
|
||||||
|
if (!Moo::Role::does_role($super_area, 'LasTres::SuperArea')) {
|
||||||
|
die "$super_area does not implement LasTres::SuperArea.";
|
||||||
|
}
|
||||||
|
my $planet = $super_area->parent;
|
||||||
|
if (!Moo::Role::does_role($planet, 'LasTres::Planet')) {
|
||||||
|
die "$planet does not implement LasTres::Planet.";
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
planet => {
|
||||||
|
name => $planet->name,
|
||||||
|
identifier => $planet->identifier,
|
||||||
|
},
|
||||||
|
super_area => {
|
||||||
|
name => $super_area->name,
|
||||||
|
identifier => $super_area->identifier,
|
||||||
|
},
|
||||||
|
area => {
|
||||||
|
name => $area->name,
|
||||||
|
identifier => $area->identifier,
|
||||||
|
},
|
||||||
|
location => {
|
||||||
|
name => $location->name,
|
||||||
|
identifier => $location->identifier,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
1;
|
1;
|
||||||
|
@ -1,137 +0,0 @@
|
|||||||
package LasTres::PJ;
|
|
||||||
|
|
||||||
use v5.36.0;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use feature 'signatures';
|
|
||||||
|
|
||||||
use Scalar::Util qw/blessed/;
|
|
||||||
use LasTres::DAO::PJs;
|
|
||||||
|
|
||||||
my $result_set = LasTres::DAO::PJs->ResultSet;
|
|
||||||
|
|
||||||
use Moo;
|
|
||||||
|
|
||||||
has uuid => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
has owner => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
has full_name => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
has short_name => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
has nick => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
has race => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
has team => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
has creation_date => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
has last_activity => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
has experience => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
has equipment => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
sub _coerce_stats($attr) {
|
|
||||||
if (blessed($attr) eq 'LasTres::Schema::Result::Stats') {
|
|
||||||
return $attr->model;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
has born_stats => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
coerce => \&_coerce_stats,
|
|
||||||
);
|
|
||||||
|
|
||||||
has training_stats => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
coerce => \&_coerce_stats,
|
|
||||||
);
|
|
||||||
|
|
||||||
sub _coerce_skills($attr) {
|
|
||||||
if (blessed($attr) eq 'LasTres::Schema::Result::SkillLikeList') {
|
|
||||||
return $attr->model;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
has skills => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
coerce => \&_coerce_skills,
|
|
||||||
);
|
|
||||||
|
|
||||||
has spells => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
coerce => \&_coerce_skills,
|
|
||||||
);
|
|
||||||
|
|
||||||
has inventory => (
|
|
||||||
is => 'rw',
|
|
||||||
required => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
sub hash ($self) {
|
|
||||||
return {
|
|
||||||
uuid => $self->uuid,
|
|
||||||
owner => $self->owner,
|
|
||||||
full_name => $self->full_name,
|
|
||||||
short_name => $self->short_name,
|
|
||||||
nick => $self->nick,
|
|
||||||
race => $self->race,
|
|
||||||
team => $self->team,
|
|
||||||
creation_date => $self->creation_date,
|
|
||||||
last_activity => $self->last_activity,
|
|
||||||
experience => $self->experience,
|
|
||||||
equipment => $self->equipment,
|
|
||||||
born_stats => $self->born_stats,
|
|
||||||
training_stats => $self->training_stats,
|
|
||||||
skills => $self->skills,
|
|
||||||
spells => $self->spells,
|
|
||||||
inventory => $self->inventory,
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub result_set ($self) {
|
|
||||||
return $result_set->new( %{ $self->hash } );
|
|
||||||
}
|
|
||||||
1;
|
|
@ -7,7 +7,13 @@ use warnings;
|
|||||||
|
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
use Module::Pluggable search_path => ['LasTres::Planet::Bahdder'];
|
use utf8;
|
||||||
|
|
||||||
|
use Module::Pluggable search_path => ['LasTres::Planet::Bahdder'],
|
||||||
|
instantiate => 'instance',
|
||||||
|
on_require_error => sub ($plugin, $error) {
|
||||||
|
die $error;
|
||||||
|
};
|
||||||
|
|
||||||
has super_areas => (
|
has super_areas => (
|
||||||
is => 'ro',
|
is => 'ro',
|
||||||
|
@ -7,6 +7,8 @@ use warnings;
|
|||||||
|
|
||||||
use feature 'signatures';
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use utf8;
|
||||||
|
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
use Module::Pluggable search_path => ['LasTres::Planet::Bahdder::BosqueDelHeroe'],
|
use Module::Pluggable search_path => ['LasTres::Planet::Bahdder::BosqueDelHeroe'],
|
||||||
|
@ -7,6 +7,8 @@ use warnings;
|
|||||||
|
|
||||||
use feature 'signatures';
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use utf8;
|
||||||
|
|
||||||
use Module::Pluggable search_path => ['LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI'],
|
use Module::Pluggable search_path => ['LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI'],
|
||||||
instantiate => 'instance',
|
instantiate => 'instance',
|
||||||
on_require_error => sub ($plugin, $error) {
|
on_require_error => sub ($plugin, $error) {
|
||||||
|
@ -4,6 +4,7 @@ use v5.36.0;
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use utf8;
|
||||||
|
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
@ -67,6 +68,12 @@ sub _build_npcs {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub connected_places {
|
||||||
|
return [
|
||||||
|
LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima::Entrada->instance,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
my $singleton;
|
my $singleton;
|
||||||
sub instance {
|
sub instance {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
|
72
lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima.pm
Normal file
72
lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima.pm
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima;
|
||||||
|
|
||||||
|
use v5.36.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use Module::Pluggable search_path => ['LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima'],
|
||||||
|
instantiate => 'instance',
|
||||||
|
on_require_error => sub ($plugin, $error) {
|
||||||
|
die $error;
|
||||||
|
};
|
||||||
|
|
||||||
|
use Moo;
|
||||||
|
use LasTres::Planet::Bahdder::BosqueDelHeroe;
|
||||||
|
|
||||||
|
has locations => (
|
||||||
|
is => 'ro',
|
||||||
|
builder => \&_build_locations,
|
||||||
|
lazy => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
has identifier => (
|
||||||
|
is => 'ro',
|
||||||
|
builder => \&_build_identifier,
|
||||||
|
);
|
||||||
|
|
||||||
|
has name => (
|
||||||
|
is => 'ro',
|
||||||
|
builder => \&_build_name,
|
||||||
|
);
|
||||||
|
|
||||||
|
has parent => (
|
||||||
|
is => 'ro',
|
||||||
|
builder => \&_build_parent,
|
||||||
|
);
|
||||||
|
|
||||||
|
with 'LasTres::Area';
|
||||||
|
|
||||||
|
sub _build_identifier {
|
||||||
|
return 'tribu_de_la_lima';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _build_locations {
|
||||||
|
my $self = shift;
|
||||||
|
my $hash = {};
|
||||||
|
my @locations = $self->plugins();
|
||||||
|
for my $location (@locations) {
|
||||||
|
$hash->{$location->identifier} = $location;
|
||||||
|
}
|
||||||
|
return $hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _build_name {
|
||||||
|
return 'Tribu de la Lima';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _build_parent {
|
||||||
|
return LasTres::Planet::Bahdder::BosqueDelHeroe->instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $singleton;
|
||||||
|
sub instance {
|
||||||
|
my $class = shift;
|
||||||
|
if (!defined $singleton) {
|
||||||
|
$singleton = $class->new(@_);
|
||||||
|
}
|
||||||
|
return $singleton;
|
||||||
|
}
|
||||||
|
1;
|
@ -0,0 +1,88 @@
|
|||||||
|
package LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima::Entrada;
|
||||||
|
|
||||||
|
use v5.36.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use utf8;
|
||||||
|
|
||||||
|
use Moo;
|
||||||
|
|
||||||
|
use LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima;
|
||||||
|
|
||||||
|
has identifier => (
|
||||||
|
is => 'ro',
|
||||||
|
builder => \&_build_identifier,
|
||||||
|
);
|
||||||
|
|
||||||
|
has name => (
|
||||||
|
is => 'ro',
|
||||||
|
builder => \&_build_name,
|
||||||
|
);
|
||||||
|
|
||||||
|
has description => (
|
||||||
|
is => 'ro',
|
||||||
|
builder => \&_build_description,
|
||||||
|
);
|
||||||
|
|
||||||
|
has parent => (
|
||||||
|
is => 'ro',
|
||||||
|
builder => \&_build_parent,
|
||||||
|
);
|
||||||
|
|
||||||
|
has actions => (
|
||||||
|
is => 'ro',
|
||||||
|
builder => \&_build_actions,
|
||||||
|
);
|
||||||
|
|
||||||
|
has npcs => (
|
||||||
|
is => 'ro',
|
||||||
|
builder => \&_build_npcs,
|
||||||
|
);
|
||||||
|
|
||||||
|
with 'LasTres::Location';
|
||||||
|
|
||||||
|
sub _build_identifier {
|
||||||
|
return 'entrada';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _build_name {
|
||||||
|
return 'Entrada';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _build_description {
|
||||||
|
return 'Un cartel reza. "Tribu de la Lima. Considerate bienvenido si '
|
||||||
|
. 'no eres un ladrón o un maleante, '
|
||||||
|
. 'en caso contrario recorre en sentido inverso el sendero de tus pisadas."';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _build_parent {
|
||||||
|
return LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima->instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _build_actions {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _build_npcs {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
sub connected_places {
|
||||||
|
return [
|
||||||
|
LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI::TribuDeLaLima->instance,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
my $singleton;
|
||||||
|
sub instance {
|
||||||
|
my $class = shift;
|
||||||
|
if (!defined $singleton) {
|
||||||
|
$singleton = $class->new(@_);
|
||||||
|
}
|
||||||
|
return $singleton;
|
||||||
|
}
|
||||||
|
1;
|
32
lib/LasTres/Planets.pm
Normal file
32
lib/LasTres/Planets.pm
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package LasTres::Planets;
|
||||||
|
|
||||||
|
use v5.36.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use Moo;
|
||||||
|
|
||||||
|
use Module::Pluggable search_path => ['LasTres::Planet'],
|
||||||
|
instantiate => 'instance',
|
||||||
|
on_require_error => sub ($plugin, $error) {
|
||||||
|
die $error;
|
||||||
|
};
|
||||||
|
|
||||||
|
has hash => (
|
||||||
|
is => 'rw',
|
||||||
|
lazy => 1,
|
||||||
|
builder => \&_build_hash,
|
||||||
|
);
|
||||||
|
|
||||||
|
sub _build_hash($self) {
|
||||||
|
my @planets = $self->plugins();
|
||||||
|
my %hash;
|
||||||
|
for my $planet (@planets) {
|
||||||
|
$hash{$planet->identifier} = $planet;
|
||||||
|
}
|
||||||
|
return \%hash;
|
||||||
|
}
|
||||||
|
1;
|
@ -51,6 +51,10 @@ has is_playable => (
|
|||||||
|
|
||||||
with 'LasTres::Race';
|
with 'LasTres::Race';
|
||||||
|
|
||||||
|
sub image {
|
||||||
|
return '/img/aldimor.png';
|
||||||
|
}
|
||||||
|
|
||||||
sub _build_spawn {
|
sub _build_spawn {
|
||||||
return
|
return
|
||||||
LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI::TribuDeLaLima
|
LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI::TribuDeLaLima
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package LasTres::Schema;
|
package LasTres::Schema;
|
||||||
our $VERSION = 4;
|
|
||||||
|
|
||||||
use v5.36.0;
|
use v5.36.0;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
our $VERSION = 5;
|
||||||
|
|
||||||
use feature 'signatures';
|
use feature 'signatures';
|
||||||
|
|
||||||
use LasTres;
|
use LasTres;
|
||||||
@ -15,29 +16,33 @@ use parent 'DBIx::Class::Schema';
|
|||||||
__PACKAGE__->load_namespaces();
|
__PACKAGE__->load_namespaces();
|
||||||
|
|
||||||
my $schema;
|
my $schema;
|
||||||
sub Schema($class) {
|
|
||||||
if (!defined $schema) {
|
sub Schema ($class) {
|
||||||
my $app = LasTres->new;
|
if ( !defined $schema ) {
|
||||||
my $config = $app->{config};
|
my $app = LasTres->new;
|
||||||
|
my $config = $app->{config};
|
||||||
my $database_config = $config->{database};
|
my $database_config = $config->{database};
|
||||||
my $dbname = $database_config->{dbname};
|
my $dbname = $database_config->{dbname};
|
||||||
my $host = $database_config->{host};
|
my $host = $database_config->{host};
|
||||||
my $port = $database_config->{port};
|
my $port = $database_config->{port};
|
||||||
my $user = $database_config->{user};
|
my $user = $database_config->{user};
|
||||||
my $password = $database_config->{password};
|
my $password = $database_config->{password};
|
||||||
my $dsn = 'dbi:Pg:';
|
my $dsn = 'dbi:Pg:';
|
||||||
if (!defined $dbname) {
|
|
||||||
|
if ( !defined $dbname ) {
|
||||||
die "The key database/dbname must be configured.";
|
die "The key database/dbname must be configured.";
|
||||||
}
|
}
|
||||||
$dsn .= "dbname=$dbname";
|
$dsn .= "dbname=$dbname";
|
||||||
if (defined $host) {
|
if ( defined $host ) {
|
||||||
$dsn .= ";host=$host";
|
$dsn .= ";host=$host";
|
||||||
}
|
}
|
||||||
if (defined $port) {
|
if ( defined $port ) {
|
||||||
$dsn .= ";port=$port";
|
$dsn .= ";port=$port";
|
||||||
}
|
}
|
||||||
|
|
||||||
# Undef is perfectly fine for username and password.
|
# Undef is perfectly fine for username and password.
|
||||||
$schema = $class->connect($dsn, $user, $password, {auto_savepoint => 1});
|
$schema =
|
||||||
|
$class->connect( $dsn, $user, $password, { auto_savepoint => 1 } );
|
||||||
}
|
}
|
||||||
return $schema;
|
return $schema;
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,11 @@ use feature 'signatures';
|
|||||||
|
|
||||||
use parent 'DBIx::Class::Core';
|
use parent 'DBIx::Class::Core';
|
||||||
|
|
||||||
|
use UUID::URandom qw/create_uuid_string/;
|
||||||
|
use List::AllUtils;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
use LasTres::Schema;
|
use JSON qw/to_json/;
|
||||||
|
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
@ -43,6 +45,7 @@ __PACKAGE__->add_columns(
|
|||||||
race => {
|
race => {
|
||||||
data_type => 'text',
|
data_type => 'text',
|
||||||
is_nullable => 0,
|
is_nullable => 0,
|
||||||
|
accessor => "_race",
|
||||||
},
|
},
|
||||||
team => {
|
team => {
|
||||||
data_type => 'uuid',
|
data_type => 'uuid',
|
||||||
@ -94,12 +97,12 @@ __PACKAGE__->add_columns(
|
|||||||
},
|
},
|
||||||
health => {
|
health => {
|
||||||
data_type => 'integer',
|
data_type => 'integer',
|
||||||
accessor => '_health',
|
accessor => '_health',
|
||||||
is_nullable => 0,
|
is_nullable => 0,
|
||||||
},
|
},
|
||||||
mana => {
|
mana => {
|
||||||
data_type => 'integer',
|
data_type => 'integer',
|
||||||
accessor => '_mana',
|
accessor => '_mana',
|
||||||
is_nullable => 0,
|
is_nullable => 0,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -108,6 +111,8 @@ __PACKAGE__->set_primary_key('uuid');
|
|||||||
|
|
||||||
__PACKAGE__->has_many( 'npcs', 'LasTres::Schema::Result::CompanionNPC',
|
__PACKAGE__->has_many( 'npcs', 'LasTres::Schema::Result::CompanionNPC',
|
||||||
'owner' );
|
'owner' );
|
||||||
|
__PACKAGE__->has_many( 'logs', 'LasTres::Schema::Result::PJLog', 'owner' );
|
||||||
|
__PACKAGE__->has_many( 'flags', 'LasTres::Schema::Result::PJFlag', 'owner' );
|
||||||
__PACKAGE__->belongs_to( 'born_stats', 'LasTres::Schema::Result::Stats' );
|
__PACKAGE__->belongs_to( 'born_stats', 'LasTres::Schema::Result::Stats' );
|
||||||
__PACKAGE__->belongs_to( 'training_stats', 'LasTres::Schema::Result::Stats' );
|
__PACKAGE__->belongs_to( 'training_stats', 'LasTres::Schema::Result::Stats' );
|
||||||
__PACKAGE__->belongs_to( 'inventory', 'LasTres::Schema::Result::Inventory' );
|
__PACKAGE__->belongs_to( 'inventory', 'LasTres::Schema::Result::Inventory' );
|
||||||
@ -117,14 +122,41 @@ __PACKAGE__->belongs_to( 'equipment', 'LasTres::Schema::Result::Equipment' );
|
|||||||
__PACKAGE__->belongs_to( 'team', 'LasTres::Schema::Result::Team' );
|
__PACKAGE__->belongs_to( 'team', 'LasTres::Schema::Result::Team' );
|
||||||
__PACKAGE__->belongs_to( 'owner', 'LasTres::Schema::Result::Player' );
|
__PACKAGE__->belongs_to( 'owner', 'LasTres::Schema::Result::Player' );
|
||||||
|
|
||||||
|
sub hash ($self) {
|
||||||
|
my $image;
|
||||||
|
my $race = $self->race;
|
||||||
|
if ( $race->can('image') ) {
|
||||||
|
$image = $race->image;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
uuid => $self->uuid,
|
||||||
|
full_name => $self->full_name,
|
||||||
|
short_name => $self->short_name,
|
||||||
|
nick => $self->nick,
|
||||||
|
race => $self->race,
|
||||||
|
health => $self->health,
|
||||||
|
max_health => $self->max_health,
|
||||||
|
mana => $self->mana,
|
||||||
|
max_mana => $self->max_mana,
|
||||||
|
(
|
||||||
|
( defined $image )
|
||||||
|
? ( image => $image )
|
||||||
|
: ()
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
my $columns = __PACKAGE__->columns_info;
|
my $columns = __PACKAGE__->columns_info;
|
||||||
for my $column_name (keys %$columns) {
|
for my $column_name ( keys %$columns ) {
|
||||||
my $column = $columns->{$column_name};
|
my $column = $columns->{$column_name};
|
||||||
my $is_nullable = $column->{is_nullable};
|
my $is_nullable = $column->{is_nullable};
|
||||||
$is_nullable //= 0;
|
$is_nullable //= 0;
|
||||||
my $required = !$is_nullable;
|
my $required = !$is_nullable;
|
||||||
|
if ( defined $column->{default_value} ) {
|
||||||
|
$required = 0;
|
||||||
|
}
|
||||||
has $column_name => (
|
has $column_name => (
|
||||||
is => 'rw',
|
is => 'rw',
|
||||||
required => $required,
|
required => $required,
|
||||||
accessor => "_moo_$column_name",
|
accessor => "_moo_$column_name",
|
||||||
);
|
);
|
||||||
@ -132,73 +164,151 @@ for my $column_name (keys %$columns) {
|
|||||||
|
|
||||||
sub max_health ($self) {
|
sub max_health ($self) {
|
||||||
my $races = LasTres::Races->new;
|
my $races = LasTres::Races->new;
|
||||||
my $race = $races->hash_playable->{$self->race};
|
my $race = $self->race;
|
||||||
my $health_base_race = $race->base_stats->health;
|
my $health_base_race = $race->base_stats->health;
|
||||||
my $health_born = $self->born_stats->health;
|
my $health_born = $self->born_stats->health;
|
||||||
my $health_training = $self->training_stats->health;
|
my $health_training = $self->training_stats->health;
|
||||||
my $health_mix =
|
my $health_mix =
|
||||||
2 * $health_base_race + $health_born + ( $health_training / 4 );
|
2 * $health_base_race + $health_born + ( $health_training / 4 );
|
||||||
my $health_scaled = ( ( $health_mix * $self->level ) / 100 );
|
my $health_scaled = ( ( $health_mix * $self->level ) / 100 );
|
||||||
return int($health_scaled + $self->level + 10);
|
return int( $health_scaled + $self->level + 10 );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub max_mana ($self) {
|
sub max_mana ($self) {
|
||||||
my $races = LasTres::Races->new;
|
my $races = LasTres::Races->new;
|
||||||
my $race = $races->hash_playable->{$self->race};
|
my $race = $self->race;
|
||||||
my $mana_base_race = $race->base_stats->mana;
|
my $mana_base_race = $race->base_stats->mana;
|
||||||
my $mana_born = $self->born_stats->mana;
|
my $mana_born = $self->born_stats->mana;
|
||||||
my $mana_training = $self->training_stats->mana;
|
my $mana_training = $self->training_stats->mana;
|
||||||
my $mana_mix =
|
my $mana_mix = 2 * $mana_base_race + $mana_born + ( $mana_training / 4 );
|
||||||
2 * $mana_base_race + $mana_born + ( $mana_training / 4 );
|
|
||||||
my $mana_scaled = ( ( $mana_mix * $self->level ) / 100 );
|
my $mana_scaled = ( ( $mana_mix * $self->level ) / 100 );
|
||||||
return int($mana_scaled + $self->level + 10);
|
return int( $mana_scaled + $self->level + 10 );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub health {
|
sub health {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $health_to_set = shift;
|
my $health_to_set = shift;
|
||||||
|
require LasTres::Schema;
|
||||||
my $schema = LasTres::Schema->Schema;
|
my $schema = LasTres::Schema->Schema;
|
||||||
$schema->txn_do(sub {
|
$schema->txn_do(
|
||||||
if (defined $health_to_set) {
|
sub {
|
||||||
$self->_health($health_to_set);
|
if ( defined $health_to_set ) {
|
||||||
$self->update;
|
$self->_health($health_to_set);
|
||||||
|
$self->update;
|
||||||
|
}
|
||||||
|
my $health = $self->_health;
|
||||||
|
if ( $health < 0 ) {
|
||||||
|
$self->_health(0);
|
||||||
|
$self->update;
|
||||||
|
}
|
||||||
|
if ( $health > $self->max_health ) {
|
||||||
|
$self->_health( $self->max_health );
|
||||||
|
$self->update;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
my $health = $self->_health;
|
);
|
||||||
if ($health < 0) {
|
|
||||||
$self->_health(0);
|
|
||||||
$self->update;
|
|
||||||
}
|
|
||||||
if ($health > $self->max_health) {
|
|
||||||
$self->_health($self->max_health);
|
|
||||||
$self->update;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return $self->_health;
|
return $self->_health;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub mana {
|
sub mana {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $mana_to_set = shift;
|
my $mana_to_set = shift;
|
||||||
|
require LasTres::Schema;
|
||||||
my $schema = LasTres::Schema->Schema;
|
my $schema = LasTres::Schema->Schema;
|
||||||
$schema->txn_do(sub {
|
$schema->txn_do(
|
||||||
if (defined $mana_to_set) {
|
sub {
|
||||||
$self->_mana($mana_to_set);
|
if ( defined $mana_to_set ) {
|
||||||
$self->update;
|
$self->_mana($mana_to_set);
|
||||||
|
$self->update;
|
||||||
|
}
|
||||||
|
my $mana = $self->_mana;
|
||||||
|
if ( $mana < 0 ) {
|
||||||
|
$self->_mana(0);
|
||||||
|
$self->update;
|
||||||
|
}
|
||||||
|
if ( $mana > $self->max_mana ) {
|
||||||
|
$self->_mana( $self->max_mana );
|
||||||
|
$self->update;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
my $mana = $self->_mana;
|
);
|
||||||
if ($mana < 0) {
|
|
||||||
$self->_mana(0);
|
|
||||||
$self->update;
|
|
||||||
}
|
|
||||||
if ($mana > $self->max_mana) {
|
|
||||||
$self->_mana($self->max_mana);
|
|
||||||
$self->update;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return $self->_mana;
|
return $self->_mana;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub race ($self) {
|
||||||
|
my $hash = LasTres::Races->new->hash_playable;
|
||||||
|
my $race = $hash->{ $self->_race };
|
||||||
|
if ( !defined $race ) {
|
||||||
|
die "Not valid race for pj " . $self->uuid;
|
||||||
|
}
|
||||||
|
return $race;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub last_50_log ($self) {
|
||||||
|
return $self->logs->search( {},
|
||||||
|
{ limit => 50, order_by => { -desc => 'date' } } );
|
||||||
|
}
|
||||||
|
|
||||||
|
sub append_log_line ( $self, $content ) {
|
||||||
|
require LasTres::Schema;
|
||||||
|
if ( ref $content ne 'ARRAY' ) {
|
||||||
|
die 'Bad log content, not a arrayref.';
|
||||||
|
}
|
||||||
|
for my $section (@$content) {
|
||||||
|
if ( ref $section ne 'HASH' ) {
|
||||||
|
die 'Invalid section, not a hashref.';
|
||||||
|
}
|
||||||
|
my @recognized_log_keys = qw/color background text/;
|
||||||
|
if (
|
||||||
|
List::AllUtils::any {
|
||||||
|
my $key = $_;
|
||||||
|
(
|
||||||
|
List::AllUtils::none {
|
||||||
|
$key eq $_
|
||||||
|
}
|
||||||
|
@recognized_log_keys
|
||||||
|
)
|
||||||
|
}
|
||||||
|
keys %$section
|
||||||
|
)
|
||||||
|
{
|
||||||
|
die 'The section '
|
||||||
|
. ( Data::Dumper::Dumper $section)
|
||||||
|
. ' has an unrecognized key';
|
||||||
|
}
|
||||||
|
if ( !defined $section->{text} ) {
|
||||||
|
die 'The section has no text.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my $uuid = create_uuid_string;
|
||||||
|
LasTres::Schema->Schema->resultset('PJLog')
|
||||||
|
->new(
|
||||||
|
{ uuid => $uuid, owner => $self->uuid, content => to_json($content) } )
|
||||||
|
->insert;
|
||||||
|
}
|
||||||
|
|
||||||
sub level ($self) {
|
sub level ($self) {
|
||||||
return $self->experience**( 1 / 3 );
|
return $self->experience**( 1 / 3 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub set_flag ( $self, $name ) {
|
||||||
|
require LasTres::Schema;
|
||||||
|
my $schema = LasTres::Schema->Schema;
|
||||||
|
my $result_set_flags = $schema->resultset('PJFlag');
|
||||||
|
my $flag = $result_set_flags->new({name => $name, owner => $self->uuid})
|
||||||
|
->update_or_insert;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_flag ( $self, $name ) {
|
||||||
|
my @flags = $self->flags->search({name => $name});
|
||||||
|
if ( scalar @flags ) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub clear_flag ( $self, $name ) {
|
||||||
|
$self->flags->search( name => $name )->delete;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
36
lib/LasTres/Schema/Result/PJFlag.pm
Normal file
36
lib/LasTres/Schema/Result/PJFlag.pm
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package LasTres::Schema::Result::PJFlag;
|
||||||
|
|
||||||
|
use v5.36.0;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use parent 'DBIx::Class::Core';
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
use Moo;
|
||||||
|
|
||||||
|
__PACKAGE__->table('player_pjs_flags');
|
||||||
|
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
name => {
|
||||||
|
data_type => 'text',
|
||||||
|
is_nullable => 0,
|
||||||
|
},
|
||||||
|
owner => {
|
||||||
|
data_type => 'uuid',
|
||||||
|
is_nullable => 0,
|
||||||
|
is_foreign_key => 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
__PACKAGE__->set_primary_key( 'owner', 'name' );
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to( 'owner', 'LasTres::Schema::Result::PJ' );
|
||||||
|
|
||||||
|
sub sqlt_deploy_hook ( $self, $sqlt_table ) {
|
||||||
|
$sqlt_table->add_index( name => 'index_flag', fields => [qw/owner name/] );
|
||||||
|
}
|
||||||
|
1;
|
60
lib/LasTres/Schema/Result/PJLog.pm
Normal file
60
lib/LasTres/Schema/Result/PJLog.pm
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package LasTres::Schema::Result::PJLog;
|
||||||
|
|
||||||
|
use v5.36.0;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use feature 'signatures';
|
||||||
|
|
||||||
|
use parent 'DBIx::Class::Core';
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
use JSON qw/from_json/;
|
||||||
|
|
||||||
|
use Moo;
|
||||||
|
|
||||||
|
__PACKAGE__->table('player_pjs_log');
|
||||||
|
|
||||||
|
__PACKAGE__->add_columns(
|
||||||
|
uuid => {
|
||||||
|
data_type => 'uuid',
|
||||||
|
is_nullable => 0,
|
||||||
|
},
|
||||||
|
content => {
|
||||||
|
data_type => 'jsonb',
|
||||||
|
accessor => '_content',
|
||||||
|
is_nullable => 0,
|
||||||
|
},
|
||||||
|
owner => {
|
||||||
|
data_type => 'uuid',
|
||||||
|
is_foreign_key => 1,
|
||||||
|
is_nullable => 0,
|
||||||
|
},
|
||||||
|
date => {
|
||||||
|
data_type => 'timestamp',
|
||||||
|
default_value => \'NOW()',
|
||||||
|
is_nullable => 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
sub content($self) {
|
||||||
|
return from_json($self->_content);
|
||||||
|
}
|
||||||
|
|
||||||
|
__PACKAGE__->set_primary_key('uuid');
|
||||||
|
|
||||||
|
__PACKAGE__->belongs_to( 'owner', 'LasTres::Schema::Result::PJ' );
|
||||||
|
|
||||||
|
sub hash ($self) {
|
||||||
|
return {
|
||||||
|
uuid => $self->uuid,
|
||||||
|
content => $self->content,
|
||||||
|
date => $self->date,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub sqlt_deploy_hook ( $self, $sqlt_table ) {
|
||||||
|
$sqlt_table->add_index( name => 'index_log', fields => [qw/owner date/] );
|
||||||
|
}
|
||||||
|
1;
|
@ -7,6 +7,8 @@ use warnings;
|
|||||||
|
|
||||||
use parent 'DBIx::Class::Core';
|
use parent 'DBIx::Class::Core';
|
||||||
|
|
||||||
|
use LasTres::Location;
|
||||||
|
|
||||||
__PACKAGE__->table('teams');
|
__PACKAGE__->table('teams');
|
||||||
|
|
||||||
__PACKAGE__->add_columns(
|
__PACKAGE__->add_columns(
|
||||||
@ -45,22 +47,27 @@ __PACKAGE__->add_columns(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# May throw error, it is needed to handle.
|
||||||
sub location {
|
sub location {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $location = shift;
|
my $location = shift;
|
||||||
|
my $planet;
|
||||||
|
my $super_area;
|
||||||
|
my $area;
|
||||||
if (defined $location) {
|
if (defined $location) {
|
||||||
$self->_location($location->identifier);
|
$self->_location($location->identifier);
|
||||||
my $area = $location->parent;
|
$area = $location->parent;
|
||||||
$self->_area($area->identifier);
|
$self->_area($area->identifier);
|
||||||
my $super_area = $area->parent;
|
$super_area = $area->parent;
|
||||||
$self->_super_area($super_area->identifier)
|
$self->_super_area($super_area->identifier);
|
||||||
my $planet = $super_area->parent;
|
$planet = $super_area->parent;
|
||||||
$self->_planet($planet->identifier);
|
$self->_planet($planet->identifier);
|
||||||
}
|
}
|
||||||
my $location = $self->_location;
|
$location = $self->_location;
|
||||||
my $area = $self->_area;
|
$area = $self->_area;
|
||||||
my $super_area = $self->_super_area;
|
$super_area = $self->_super_area;
|
||||||
my $planet = $self->_planet;
|
$planet = $self->_planet;
|
||||||
|
$location = LasTres::Location::get($planet, $super_area, $area, $location);
|
||||||
return $location;
|
return $location;
|
||||||
}
|
}
|
||||||
__PACKAGE__->set_primary_key('uuid');
|
__PACKAGE__->set_primary_key('uuid');
|
||||||
|
@ -1,8 +1,66 @@
|
|||||||
|
@keyframes move-avatar {
|
||||||
|
0% {
|
||||||
|
padding-bottom: 0rem; }
|
||||||
|
50% {
|
||||||
|
padding-bottom: 0.3rem; }
|
||||||
|
100% {
|
||||||
|
padding-bottom: 0rem; } }
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
background: ghostwhite; }
|
background: ghostwhite; }
|
||||||
|
body label.bar-container {
|
||||||
|
width: 90%; }
|
||||||
|
body label.bar-container div.bar {
|
||||||
|
width: 100%;
|
||||||
|
height: 1em;
|
||||||
|
border: solid 1px black; }
|
||||||
|
body label.bar-container div.bar div.filled {
|
||||||
|
background: lightgreen;
|
||||||
|
height: 100%; }
|
||||||
|
body div.pj-list-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center; }
|
||||||
|
body div.pj-list-item div.avatar {
|
||||||
|
width: 30%;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: gray;
|
||||||
|
margin-right: 2%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative; }
|
||||||
|
body div.pj-list-item div.avatar img {
|
||||||
|
animation-name: move-avatar;
|
||||||
|
animation-duration: 0.5s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
width: 80%;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
z-index: 1; }
|
||||||
|
body div.pj-list-item div.avatar div.shadow {
|
||||||
|
top: 78%;
|
||||||
|
position: absolute;
|
||||||
|
width: 60%;
|
||||||
|
aspect-ratio: 7/2;
|
||||||
|
background: black;
|
||||||
|
border-radius: 50%; }
|
||||||
|
body div.pj-list-item div.data {
|
||||||
|
width: 60%; }
|
||||||
|
body div.presentation {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 95%;
|
||||||
|
justify-content: center;
|
||||||
|
height: 50vh; }
|
||||||
|
body div.presentation div.presentation-item {
|
||||||
|
margin: 1%;
|
||||||
|
width: 30%;
|
||||||
|
overflow-y: scroll; }
|
||||||
|
body div.presentation div.presentation-item code pre {
|
||||||
|
white-space: pre-wrap; }
|
||||||
body div.width-max-content {
|
body div.width-max-content {
|
||||||
width: max-content; }
|
width: max-content; }
|
||||||
body div#game-container {
|
body div#game-container {
|
||||||
@ -74,21 +132,12 @@ body {
|
|||||||
body div.pj-selection-menu div.pj-selection-menu-container div.pj-list a:hover {
|
body div.pj-selection-menu div.pj-selection-menu-container div.pj-list a:hover {
|
||||||
color: yellow;
|
color: yellow;
|
||||||
background: gray; }
|
background: gray; }
|
||||||
body div.pj-selection-menu div.pj-selection-menu-container div.pj-list a label {
|
|
||||||
width: 90%; }
|
|
||||||
body div.pj-selection-menu div.pj-selection-menu-container div.pj-list a label div.bar {
|
|
||||||
width: 100%;
|
|
||||||
height: 1em;
|
|
||||||
border: solid 1px black; }
|
|
||||||
body div.pj-selection-menu div.pj-selection-menu-container div.pj-list a label div.bar div.filled {
|
|
||||||
background: lightgreen;
|
|
||||||
height: 100%; }
|
|
||||||
body div.login-container {
|
body div.login-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: url("/img/wallpaper.jpg") no-repeat center black;
|
background: url() no-repeat center black;
|
||||||
flex-direction: column; }
|
flex-direction: column; }
|
||||||
body div.login-container div.login-contained {
|
body div.login-container div.login-contained {
|
||||||
background: #001e8b;
|
background: #001e8b;
|
||||||
|
@ -1,4 +1,80 @@
|
|||||||
|
@keyframes move-avatar {
|
||||||
|
0% {
|
||||||
|
padding-bottom: 0rem;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
padding-bottom: 0.3rem;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
padding-bottom: 0rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
body {
|
body {
|
||||||
|
label.bar-container {
|
||||||
|
width: 90%;
|
||||||
|
div.bar {
|
||||||
|
width: 100%;
|
||||||
|
height: 1em;
|
||||||
|
border: solid 1px black;
|
||||||
|
div.filled {
|
||||||
|
background: lightgreen;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.pj-list-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
div.avatar {
|
||||||
|
width: 30%;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: gray;
|
||||||
|
margin-right: 2%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
img {
|
||||||
|
animation-name: move-avatar;
|
||||||
|
animation-duration: 0.5s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
width: 80%;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
div.shadow {
|
||||||
|
top: 78%;
|
||||||
|
position: absolute;
|
||||||
|
width: 60%;
|
||||||
|
aspect-ratio: 7/2;
|
||||||
|
background: black;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.data {
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.presentation {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
width: 95%;
|
||||||
|
justify-content: center;
|
||||||
|
div.presentation-item {
|
||||||
|
code {
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
margin: 1%;
|
||||||
|
width: 30%;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
height: 50vh;
|
||||||
|
}
|
||||||
|
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
@ -83,19 +159,7 @@ body {
|
|||||||
background: gray;
|
background: gray;
|
||||||
}
|
}
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
label {
|
}
|
||||||
width: 90%;
|
|
||||||
div.bar {
|
|
||||||
width: 100%;
|
|
||||||
height: 1em;
|
|
||||||
border: solid 1px black;
|
|
||||||
div.filled {
|
|
||||||
background: lightgreen;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +168,7 @@ body {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: url('/img/wallpaper.jpg') no-repeat center black;
|
background: url() no-repeat center black;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
div.login-contained {
|
div.login-contained {
|
||||||
background: rgba(0, 30, 139, 1);
|
background: rgba(0, 30, 139, 1);
|
||||||
|
BIN
public/img/aldimor.png
Normal file
BIN
public/img/aldimor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
@ -96,7 +96,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|||||||
\************************************/
|
\************************************/
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
/***/ ((__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 */ Game)\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_upper_panel__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/upper-panel */ \"./js-src/components/upper-panel.tsx\");\n/* harmony import */ var _lastres_components_bottom_panel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @lastres/components/bottom-panel */ \"./js-src/components/bottom-panel.tsx\");\n/* harmony import */ var _lastres_components_pj_selection_menu__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @lastres/components/pj-selection-menu */ \"./js-src/components/pj-selection-menu.tsx\");\n\n\n\n\nfunction Game(props) {\n if (props.selectedPJ === null) {\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_selection_menu__WEBPACK_IMPORTED_MODULE_3__[\"default\"], { setSelectedPJ: props.setSelectedPJ, userWantsToCreatePJ: props.userWantsToCreatePJ, setUserWantsToCreatePJ: props.setUserWantsToCreatePJ, error: props.error, setError: props.setError })));\n }\n window.setTimeout(() => {\n const locationProtocol = window.location.protocol;\n if (locationProtocol == null) {\n return;\n }\n const protocol = locationProtocol.match(/https:/) != null ? 'wss' : 'ws';\n const webSocket = new WebSocket(`${protocol}://${window.location.host}/ws`);\n webSocket.onopen = () => {\n webSocket.send(JSON.stringify({ hola: \"mundo\" }));\n };\n }, 1);\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_upper_panel__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_bottom_panel__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null)));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/game.tsx?");
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Game)\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_upper_panel__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/upper-panel */ \"./js-src/components/upper-panel.tsx\");\n/* harmony import */ var _lastres_components_bottom_panel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @lastres/components/bottom-panel */ \"./js-src/components/bottom-panel.tsx\");\n/* harmony import */ var _lastres_components_pj_selection_menu__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @lastres/components/pj-selection-menu */ \"./js-src/components/pj-selection-menu.tsx\");\n/* harmony import */ var _lastres_output_packet_init__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @lastres/output-packet/init */ \"./js-src/output-packet/init.ts\");\n/* harmony import */ var _lastres_output_packet_ping__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @lastres/output-packet/ping */ \"./js-src/output-packet/ping.ts\");\n/* harmony import */ var _lastres_input_packets__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @lastres/input-packets */ \"./js-src/input-packets.ts\");\n\n\n\n\n\n\n\nfunction Game(props) {\n const selectedPJ = props.selectedPJ;\n if (selectedPJ === null) {\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_selection_menu__WEBPACK_IMPORTED_MODULE_3__[\"default\"], { setSelectedPJ: props.setSelectedPJ, userWantsToCreatePJ: props.userWantsToCreatePJ, setUserWantsToCreatePJ: props.setUserWantsToCreatePJ, error: props.error, setError: props.setError })));\n }\n const [websocket, setWebsocket] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [teamPJs, setTeamPJs] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [currentLocation, setCurrentLocation] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [connectedLocations, setConnectedLocations] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [logLines, setLogLines] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n if (websocket === null) {\n window.setTimeout(() => {\n const locationProtocol = window.location.protocol;\n if (locationProtocol == null) {\n return;\n }\n const protocol = locationProtocol.match(/https:/) != null ? 'wss' : 'ws';\n const webSocket = new WebSocket(`${protocol}://${window.location.host}/ws`);\n webSocket.onopen = () => {\n new _lastres_output_packet_init__WEBPACK_IMPORTED_MODULE_4__[\"default\"](selectedPJ.uuid).send(webSocket);\n let interval = 0;\n interval = window.setInterval(() => {\n if (webSocket.readyState === WebSocket.OPEN) {\n new _lastres_output_packet_ping__WEBPACK_IMPORTED_MODULE_5__[\"default\"]().send(webSocket);\n return;\n }\n window.clearInterval(interval);\n }, 10000);\n };\n const inputPackets = new _lastres_input_packets__WEBPACK_IMPORTED_MODULE_6__[\"default\"](setTeamPJs, setCurrentLocation, setConnectedLocations, setLogLines);\n webSocket.onmessage = (event) => {\n const packet = JSON.parse(event.data);\n inputPackets.handle(packet);\n };\n webSocket.onerror = (event) => {\n console.log(event);\n };\n setWebsocket(webSocket);\n }, 1);\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_upper_panel__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { teamPJs: teamPJs, currentLocation: currentLocation, connectedLocations: connectedLocations, logLines: logLines }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_bottom_panel__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null)));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/game.tsx?");
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
@ -140,13 +140,23 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./js-src/components/pj-list-item.tsx":
|
||||||
|
/*!********************************************!*\
|
||||||
|
!*** ./js-src/components/pj-list-item.tsx ***!
|
||||||
|
\********************************************/
|
||||||
|
/***/ ((__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 */ PJListItem)\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_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/pj-health-like-bar */ \"./js-src/components/pj-health-like-bar.tsx\");\n\n\nfunction PJListItem(props) {\n const pj = props.pj;\n function avatar() {\n if (pj.image === undefined) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"img\", { src: pj.image }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"shadow\" }));\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"pj-list-item\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"avatar\" }, avatar()),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"data\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, pj.nick),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"label\", { className: \"bar-container\" },\n \"Salud\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { value: pj.health, max: pj.max_health })),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"label\", { className: \"bar-container\" },\n \"Mana\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { value: pj.mana, max: pj.max_mana })))));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/pj-list-item.tsx?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
/***/ "./js-src/components/pj-list-selection.tsx":
|
/***/ "./js-src/components/pj-list-selection.tsx":
|
||||||
/*!*************************************************!*\
|
/*!*************************************************!*\
|
||||||
!*** ./js-src/components/pj-list-selection.tsx ***!
|
!*** ./js-src/components/pj-list-selection.tsx ***!
|
||||||
\*************************************************/
|
\*************************************************/
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
/***/ ((__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 */ PJListSelection)\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_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/pj-health-like-bar */ \"./js-src/components/pj-health-like-bar.tsx\");\n\n\nfunction PJListSelection(props) {\n const pjs = props.pjs;\n if (pjs === 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(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, pjs.map((item, i) => react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { onClick: () => {\n props.setSelectedPJ(item);\n }, href: \"#\", key: i },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", null, item.full_name),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", null, item.short_name),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", null, item.nick),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"label\", null,\n \"Salud\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { value: item.health, max: item.max_health })),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"label\", null,\n \"Mana\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { value: item.mana, max: item.max_mana }))))));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/pj-list-selection.tsx?");
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ PJListSelection)\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_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/pj-health-like-bar */ \"./js-src/components/pj-health-like-bar.tsx\");\n\n\nfunction PJListSelection(props) {\n const pjs = props.pjs;\n if (pjs === 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(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, pjs.map((item, i) => react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { onClick: () => {\n props.setSelectedPJ(item);\n }, href: \"#\", key: i },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", null, item.full_name),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", null, item.short_name),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", null, item.nick),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"label\", { className: \"bar-container\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { value: item.health, max: item.max_health })),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"label\", { className: \"bar-container\" },\n \"Mana\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { value: item.mana, max: item.max_mana }))))));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/pj-list-selection.tsx?");
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
@ -176,7 +186,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|||||||
\*******************************************/
|
\*******************************************/
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
/***/ ((__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 */ UpperPanel)\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\nfunction UpperPanel() {\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/upper-panel.tsx?");
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ UpperPanel)\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_pj_list_item__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/pj-list-item */ \"./js-src/components/pj-list-item.tsx\");\n\n\nfunction UpperPanel(props) {\n const connectedLocations = props.connectedLocations;\n const teamPJs = props.teamPJs;\n const currentLocation = props.currentLocation;\n const logLines = props.logLines;\n if (!(teamPJs !== null && currentLocation !== null && connectedLocations !== null)) {\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, \"Esperando datos...\")));\n }\n function generateLog() {\n if (logLines === null || logLines.length < 1) {\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, \"No log\"));\n }\n return logLines.map((item, i) => {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"b\", null, item.date),\n \" \",\n item.content.map((item, i) => {\n const style = {};\n if (item.color !== undefined) {\n style.color = item.color;\n }\n if (item.background !== undefined) {\n style.background = item.background;\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", { key: i, style: style }, item.text);\n }),\n \" \",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"br\", null));\n });\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"presentation\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"presentation-item\" }, teamPJs.map((item, i) => {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_list_item__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { key: i, pj: item });\n })),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"presentation-item\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"code\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"pre\", null, generateLog()))),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"presentation-item\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null,\n \"Est\\u00E1s en \",\n currentLocation.area.name,\n \"/\",\n currentLocation.location.name,\n \".\"),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, \"Puedes ir a:\"),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"ul\", null, connectedLocations.map((item, i) => {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", { key: i },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { href: \"#\" },\n item.area.name,\n \"/\",\n item.location.name));\n })))));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/upper-panel.tsx?");
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
@ -190,6 +200,46 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var reac
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./js-src/input-packet.ts":
|
||||||
|
/*!********************************!*\
|
||||||
|
!*** ./js-src/input-packet.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 */ InputPacket)\n/* harmony export */ });\nclass InputPacket {\n constructor() {\n this.onreceive = null;\n }\n onReceive(callback) {\n this.onreceive = callback;\n }\n recv(packet) {\n if (this.onreceive !== null) {\n this.onreceive(packet.data);\n }\n }\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/input-packet.ts?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./js-src/input-packet/info.ts":
|
||||||
|
/*!*************************************!*\
|
||||||
|
!*** ./js-src/input-packet/info.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 */ InputPacketInfo)\n/* harmony export */ });\n/* harmony import */ var _lastres_input_packet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @lastres/input-packet */ \"./js-src/input-packet.ts\");\n\nclass InputPacketInfo extends _lastres_input_packet__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n identifier() {\n return 'info';\n }\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/input-packet/info.ts?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./js-src/input-packet/pong.ts":
|
||||||
|
/*!*************************************!*\
|
||||||
|
!*** ./js-src/input-packet/pong.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 */ InputPacketPong)\n/* harmony export */ });\n/* harmony import */ var _lastres_input_packet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @lastres/input-packet */ \"./js-src/input-packet.ts\");\n\nclass InputPacketPong extends _lastres_input_packet__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n identifier() {\n return 'pong';\n }\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/input-packet/pong.ts?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./js-src/input-packets.ts":
|
||||||
|
/*!*********************************!*\
|
||||||
|
!*** ./js-src/input-packets.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 */ InputPackets)\n/* harmony export */ });\n/* harmony import */ var _lastres_input_packet_info__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @lastres/input-packet/info */ \"./js-src/input-packet/info.ts\");\n/* harmony import */ var _lastres_input_packet_pong__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/input-packet/pong */ \"./js-src/input-packet/pong.ts\");\n\n\nclass InputPackets {\n constructor(setTeamPJs, setCurrentLocation, setConnectedLocations, setLogLines) {\n this.cachedHash = null;\n this.cachedArray = null;\n this.setTeamPJs = setTeamPJs;\n this.setCurrentLocation = setCurrentLocation;\n this.setConnectedLocations = setConnectedLocations;\n this.setLogLines = setLogLines;\n }\n handle(packet) {\n const hash = this.hashAvailablePackets();\n const identifier = packet.command;\n const inputPacket = hash[identifier];\n inputPacket.recv(packet);\n }\n listAvailablePackets() {\n if (this.cachedArray === null) {\n const infoPacket = new _lastres_input_packet_info__WEBPACK_IMPORTED_MODULE_0__[\"default\"]();\n const pongPacket = new _lastres_input_packet_pong__WEBPACK_IMPORTED_MODULE_1__[\"default\"]();\n infoPacket.onReceive((data) => {\n this.setTeamPJs(data.team_pjs);\n this.setConnectedLocations(data.location_data.connected_places);\n this.setCurrentLocation(data.location_data.current);\n this.setLogLines(data.set_log);\n });\n this.cachedArray = [infoPacket, pongPacket];\n }\n return this.cachedArray;\n }\n hashAvailablePackets() {\n if (this.cachedHash === null) {\n this.cachedHash = {};\n for (const inputPacket of this.listAvailablePackets()) {\n this.cachedHash[inputPacket.identifier()] = inputPacket;\n }\n }\n return this.cachedHash;\n }\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/input-packets.ts?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
/***/ "./js-src/login.ts":
|
/***/ "./js-src/login.ts":
|
||||||
/*!*************************!*\
|
/*!*************************!*\
|
||||||
!*** ./js-src/login.ts ***!
|
!*** ./js-src/login.ts ***!
|
||||||
@ -200,6 +250,36 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./js-src/output-packet.ts":
|
||||||
|
/*!*********************************!*\
|
||||||
|
!*** ./js-src/output-packet.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 */ OutputPacket)\n/* harmony export */ });\nclass OutputPacket {\n send(ws) {\n const data = this.data();\n ws.send(JSON.stringify({\n command: this.command(),\n data: this.data(),\n }));\n }\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/output-packet.ts?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./js-src/output-packet/init.ts":
|
||||||
|
/*!**************************************!*\
|
||||||
|
!*** ./js-src/output-packet/init.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 */ OutputPacketInit)\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 OutputPacketInit extends _lastres_output_packet__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor(pj_uuid) {\n super();\n this.pj_uuid = pj_uuid;\n }\n command() {\n return 'init';\n }\n data() {\n return {\n pj_uuid: this.pj_uuid\n };\n }\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/output-packet/init.ts?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./js-src/output-packet/ping.ts":
|
||||||
|
/*!**************************************!*\
|
||||||
|
!*** ./js-src/output-packet/ping.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 */ OutputPacketPing)\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 OutputPacketPing extends _lastres_output_packet__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor() {\n super();\n }\n command() {\n return 'ping';\n }\n data() {\n return null;\n }\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/output-packet/ping.ts?");
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
/***/ "./js-src/pj.ts":
|
/***/ "./js-src/pj.ts":
|
||||||
/*!**********************!*\
|
/*!**********************!*\
|
||||||
!*** ./js-src/pj.ts ***!
|
!*** ./js-src/pj.ts ***!
|
||||||
|
Loading…
Reference in New Issue
Block a user