diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..4265542 --- /dev/null +++ b/.eslintrc.js @@ -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' + ] + } + } + } +} diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..39f4fb3 --- /dev/null +++ b/.vimrc @@ -0,0 +1 @@ +let g:ale_linters = {'perl': ['perl','perlcritic'] } diff --git a/Build.PL b/Build.PL index 95e6c75..a9ff746 100755 --- a/Build.PL +++ b/Build.PL @@ -20,6 +20,7 @@ my $build = Module::Build->new( 'UUID::URandom' => 0, 'Module::Pluggable' => 0, 'Redis' => 0, + 'List::AllUtils' => 0, }, ); $build->create_build_script; diff --git a/dbicdh/PostgreSQL/deploy/5/001-auto.sql b/dbicdh/PostgreSQL/deploy/5/001-auto.sql new file mode 100644 index 0000000..936ff94 --- /dev/null +++ b/dbicdh/PostgreSQL/deploy/5/001-auto.sql @@ -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; + +; diff --git a/dbicdh/PostgreSQL/upgrade/4-5/001-auto.sql b/dbicdh/PostgreSQL/upgrade/4-5/001-auto.sql new file mode 100644 index 0000000..9f8f9db --- /dev/null +++ b/dbicdh/PostgreSQL/upgrade/4-5/001-auto.sql @@ -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; + diff --git a/dbicdh/_source/deploy/5/001-auto.yml b/dbicdh/_source/deploy/5/001-auto.yml new file mode 100644 index 0000000..11bdd1f --- /dev/null +++ b/dbicdh/_source/deploy/5/001-auto.yml @@ -0,0 +1,1432 @@ +--- +schema: + procedures: {} + tables: + equipment: + constraints: + - deferrable: 1 + expression: '' + fields: + - uuid + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + uuid: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: uuid + order: 1 + size: + - 0 + indices: [] + name: equipment + options: [] + order: 1 + equipment_items: + constraints: + - deferrable: 1 + expression: '' + fields: + - kind + - equipment + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - equipment + match_type: '' + name: equipment_items_fk_equipment + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - uuid + reference_table: equipment + type: FOREIGN KEY + fields: + equipment: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: equipment + order: 2 + size: + - 0 + identifier: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: identifier + order: 3 + size: + - 0 + kind: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: kind + order: 1 + size: + - 0 + quantity: + data_type: Integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: quantity + order: 4 + size: + - 0 + indices: + - fields: + - equipment + name: equipment_items_idx_equipment + options: [] + type: NORMAL + name: equipment_items + options: [] + order: 6 + inventories: + constraints: + - deferrable: 1 + expression: '' + fields: + - uuid + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + uuid: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: uuid + order: 1 + size: + - 0 + indices: [] + name: inventories + options: [] + order: 2 + inventory_items: + constraints: + - deferrable: 1 + expression: '' + fields: + - uuid + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - inventory + match_type: '' + name: inventory_items_fk_inventory + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - uuid + reference_table: inventories + type: FOREIGN KEY + fields: + identifier: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: identifier + order: 3 + size: + - 0 + inventory: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: inventory + order: 2 + size: + - 0 + quantity: + data_type: Integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: quantity + order: 4 + size: + - 0 + uuid: + data_type: uuid + default_value: !!perl/ref + =: uuid_generate_v4() + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: uuid + order: 1 + size: + - 0 + indices: + - fields: + - inventory + name: inventory_items_idx_inventory + options: [] + type: NORMAL + name: inventory_items + options: [] + order: 7 + player_companion_npcs: + constraints: + - deferrable: 1 + expression: '' + fields: + - uuid + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - equipment + match_type: '' + name: player_companion_npcs_fk_equipment + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: equipment + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - inventory + match_type: '' + name: player_companion_npcs_fk_inventory + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: inventories + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - owner + match_type: '' + name: player_companion_npcs_fk_owner + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - uuid + reference_table: player_pjs + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - skills + match_type: '' + name: player_companion_npcs_fk_skills + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: skill_like_lists + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - spells + match_type: '' + name: player_companion_npcs_fk_spells + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: skill_like_lists + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - stats + match_type: '' + name: player_companion_npcs_fk_stats + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: stats + type: FOREIGN KEY + fields: + equipment: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: equipment + order: 8 + size: + - 0 + exp: + data_type: integer + default_value: !!perl/ref + =: 1 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: exp + order: 7 + size: + - 0 + identifier: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: identifier + order: 3 + size: + - 0 + inventory: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: inventory + order: 12 + size: + - 0 + level: + data_type: integer + default_value: !!perl/ref + =: 1 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: level + order: 6 + size: + - 0 + nick: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: nick + order: 4 + size: + - 0 + owner: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: owner + order: 2 + size: + - 0 + race: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: race + order: 5 + size: + - 0 + skills: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: skills + order: 10 + size: + - 0 + spells: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: spells + order: 11 + size: + - 0 + stats: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: stats + order: 9 + size: + - 0 + uuid: + data_type: uuid + default_value: !!perl/ref + =: uuid_generate_v4() + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: uuid + order: 1 + size: + - 0 + indices: + - fields: + - equipment + name: player_companion_npcs_idx_equipment + options: [] + type: NORMAL + - fields: + - inventory + name: player_companion_npcs_idx_inventory + options: [] + type: NORMAL + - fields: + - owner + name: player_companion_npcs_idx_owner + options: [] + type: NORMAL + - fields: + - skills + name: player_companion_npcs_idx_skills + options: [] + type: NORMAL + - fields: + - spells + name: player_companion_npcs_idx_spells + options: [] + type: NORMAL + - fields: + - stats + name: player_companion_npcs_idx_stats + options: [] + type: NORMAL + name: player_companion_npcs + options: [] + order: 11 + player_pjs: + constraints: + - deferrable: 1 + expression: '' + fields: + - uuid + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - born_stats + match_type: '' + name: player_pjs_fk_born_stats + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: stats + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - equipment + match_type: '' + name: player_pjs_fk_equipment + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: equipment + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - inventory + match_type: '' + name: player_pjs_fk_inventory + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: inventories + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - owner + match_type: '' + name: player_pjs_fk_owner + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - uuid + reference_table: players + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - skills + match_type: '' + name: player_pjs_fk_skills + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: skill_like_lists + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - spells + match_type: '' + name: player_pjs_fk_spells + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: skill_like_lists + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - team + match_type: '' + name: player_pjs_fk_team + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - uuid + reference_table: teams + type: FOREIGN KEY + - deferrable: 1 + expression: '' + fields: + - training_stats + match_type: '' + name: player_pjs_fk_training_stats + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: stats + type: FOREIGN KEY + fields: + born_stats: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: born_stats + order: 12 + size: + - 0 + creation_date: + data_type: timestamp + default_value: !!perl/ref + =: NOW() + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: creation_date + order: 8 + size: + - 0 + equipment: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: equipment + order: 11 + size: + - 0 + experience: + data_type: integer + default_value: !!perl/ref + =: 1 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: experience + order: 10 + size: + - 0 + full_name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: full_name + order: 3 + size: + - 0 + health: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: health + order: 17 + size: + - 0 + inventory: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: inventory + order: 16 + size: + - 0 + last_activity: + data_type: timestamp + default_value: !!perl/ref + =: NOW() + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: last_activity + order: 9 + size: + - 0 + mana: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: mana + order: 18 + size: + - 0 + nick: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: nick + order: 5 + size: + - 0 + owner: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: owner + order: 2 + size: + - 0 + race: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: race + order: 6 + size: + - 0 + short_name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: short_name + order: 4 + size: + - 0 + skills: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: skills + order: 14 + size: + - 0 + spells: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: spells + order: 15 + size: + - 0 + team: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: team + order: 7 + size: + - 0 + training_stats: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: training_stats + order: 13 + size: + - 0 + uuid: + data_type: uuid + default_value: !!perl/ref + =: uuid_generate_v4() + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: uuid + order: 1 + size: + - 0 + indices: + - fields: + - born_stats + name: player_pjs_idx_born_stats + options: [] + type: NORMAL + - fields: + - equipment + name: player_pjs_idx_equipment + options: [] + type: NORMAL + - fields: + - inventory + name: player_pjs_idx_inventory + options: [] + type: NORMAL + - fields: + - owner + name: player_pjs_idx_owner + options: [] + type: NORMAL + - fields: + - skills + name: player_pjs_idx_skills + options: [] + type: NORMAL + - fields: + - spells + name: player_pjs_idx_spells + options: [] + type: NORMAL + - fields: + - team + name: player_pjs_idx_team + options: [] + type: NORMAL + - fields: + - training_stats + name: player_pjs_idx_training_stats + options: [] + type: NORMAL + name: player_pjs + options: [] + order: 10 + player_pjs_flags: + constraints: + - deferrable: 1 + expression: '' + fields: + - owner + - name + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - owner + match_type: '' + name: player_pjs_flags_fk_owner + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - uuid + reference_table: player_pjs + type: FOREIGN KEY + fields: + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: name + order: 1 + size: + - 0 + owner: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: owner + order: 2 + size: + - 0 + indices: + - fields: + - owner + name: player_pjs_flags_idx_owner + options: [] + type: NORMAL + - fields: + - owner + - name + name: index_flag + options: [] + type: NORMAL + name: player_pjs_flags + options: [] + order: 12 + player_pjs_log: + constraints: + - deferrable: 1 + expression: '' + fields: + - uuid + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - owner + match_type: '' + name: player_pjs_log_fk_owner + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - uuid + reference_table: player_pjs + type: FOREIGN KEY + fields: + content: + data_type: jsonb + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: content + order: 2 + size: + - 0 + date: + data_type: timestamp + default_value: !!perl/ref + =: NOW() + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: date + order: 4 + size: + - 0 + owner: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: owner + order: 3 + size: + - 0 + uuid: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: uuid + order: 1 + size: + - 0 + indices: + - fields: + - owner + name: player_pjs_log_idx_owner + options: [] + type: NORMAL + - fields: + - owner + - date + name: index_log + options: [] + type: NORMAL + name: player_pjs_log + options: [] + order: 13 + players: + constraints: + - deferrable: 1 + expression: '' + fields: + - uuid + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - email + match_type: '' + name: unique_constraint_email + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - username + match_type: '' + name: unique_constraint_username + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + fields: + email: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: email + order: 4 + size: + - 0 + encrypted_password: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: encrypted_password + order: 3 + size: + - 0 + last_activity: + data_type: timestamp + default_value: !!perl/ref + =: NOW() + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: last_activity + order: 8 + size: + - 0 + register_date: + data_type: timestamp + default_value: !!perl/ref + =: NOW() + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: register_date + order: 7 + size: + - 0 + username: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: username + order: 2 + size: + - 0 + uuid: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: uuid + order: 1 + size: + - 0 + verification_token: + data_type: text + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: verification_token + order: 6 + size: + - 0 + verified: + data_type: boolean + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: verified + order: 5 + size: + - 0 + indices: [] + name: players + options: [] + order: 3 + skill_like_items: + constraints: + - deferrable: 1 + expression: '' + fields: + - identifier + - owner_list + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - owner_list + match_type: '' + name: skill_like_items_fk_owner_list + on_delete: CASCADE + on_update: CASCADE + options: [] + reference_fields: + - uuid + reference_table: skill_like_lists + type: FOREIGN KEY + fields: + identifier: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: identifier + order: 1 + size: + - 0 + level: + data_type: integer + default_value: !!perl/ref + =: 1 + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: level + order: 3 + size: + - 0 + owner_list: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: owner_list + order: 2 + size: + - 0 + indices: + - fields: + - owner_list + name: skill_like_items_idx_owner_list + options: [] + type: NORMAL + name: skill_like_items + options: [] + order: 8 + skill_like_lists: + constraints: + - deferrable: 1 + expression: '' + fields: + - uuid + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + uuid: + data_type: uuid + default_value: !!perl/ref + =: uuid_generate_v4() + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: uuid + order: 1 + size: + - 0 + indices: [] + name: skill_like_lists + options: [] + order: 4 + stats: + constraints: + - deferrable: 1 + expression: '' + fields: + - uuid + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + fields: + health: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: health + order: 2 + size: + - 0 + intelligence: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: intelligence + order: 8 + size: + - 0 + magic: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: magic + order: 6 + size: + - 0 + mana: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: mana + order: 3 + size: + - 0 + resistance: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: resistance + order: 5 + size: + - 0 + speed: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: speed + order: 7 + size: + - 0 + strength: + data_type: integer + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: strength + order: 4 + size: + - 0 + uuid: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: uuid + order: 1 + size: + - 0 + indices: [] + name: stats + options: [] + order: 5 + teams: + constraints: + - deferrable: 1 + expression: '' + fields: + - uuid + match_type: '' + name: '' + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: PRIMARY KEY + - deferrable: 1 + expression: '' + fields: + - name + match_type: '' + name: u_name + on_delete: '' + on_update: '' + options: [] + reference_fields: [] + reference_table: '' + type: UNIQUE + - deferrable: 1 + expression: '' + fields: + - leader + match_type: '' + name: teams_fk_leader + on_delete: '' + on_update: '' + options: [] + reference_fields: + - uuid + reference_table: player_pjs + type: FOREIGN KEY + fields: + area: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: area + order: 6 + size: + - 0 + leader: + data_type: uuid + default_value: ~ + is_nullable: 1 + is_primary_key: 0 + is_unique: 0 + name: leader + order: 2 + size: + - 0 + location: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: location + order: 7 + size: + - 0 + name: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 1 + name: name + order: 3 + size: + - 0 + planet: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: planet + order: 4 + size: + - 0 + super_area: + data_type: text + default_value: ~ + is_nullable: 0 + is_primary_key: 0 + is_unique: 0 + name: super_area + order: 5 + size: + - 0 + uuid: + data_type: uuid + default_value: ~ + is_nullable: 0 + is_primary_key: 1 + is_unique: 0 + name: uuid + order: 1 + size: + - 0 + indices: + - fields: + - leader + name: teams_idx_leader + options: [] + type: NORMAL + name: teams + options: [] + order: 9 + triggers: {} + views: {} +translator: + add_drop_table: 0 + filename: ~ + no_comments: 0 + parser_args: + sources: + - CompanionNPC + - Equipment + - EquipmentItem + - Inventory + - InventoryItem + - PJ + - PJFlag + - PJLog + - Player + - SkillLikeItem + - SkillLikeList + - Stats + - Team + parser_type: SQL::Translator::Parser::DBIx::Class + producer_args: {} + producer_type: SQL::Translator::Producer::YAML + show_warnings: 0 + trace: 0 + version: 1.63 diff --git a/js-src/components/game.tsx b/js-src/components/game.tsx index c7ee577..6d9aba5 100644 --- a/js-src/components/game.tsx +++ b/js-src/components/game.tsx @@ -1,10 +1,15 @@ 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 BottomPanel from '@lastres/components/bottom-panel' 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 { setSelectedPJ: (set: PJ | null) => void @@ -16,7 +21,8 @@ export interface GameProps { } export default function Game (props: GameProps): JSX.Element { - if (props.selectedPJ === null) { + const selectedPJ = props.selectedPJ + if (selectedPJ === null) { return ( <> ) } - window.setTimeout(() => { - const locationProtocol = window.location.protocol - if (locationProtocol == null) { - return - } - const protocol = locationProtocol.match(/https:/) != null ? 'wss' : 'ws' - const webSocket = new WebSocket(`${protocol}://${window.location.host}/ws`) - webSocket.onopen = () => { - webSocket.send(JSON.stringify({hola: "mundo"})) - }; - - }, 1); + const [websocket, setWebsocket] = React.useState(null) + const [teamPJs, setTeamPJs] = React.useState(null) + const [currentLocation, setCurrentLocation] = React.useState(null) + const [connectedLocations, setConnectedLocations] = React.useState(null) + const [logLines, setLogLines] = React.useState(null) + if (websocket === null) { + window.setTimeout(() => { + const locationProtocol = window.location.protocol + if (locationProtocol == null) { + return + } + 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 ( <> - + ) diff --git a/js-src/components/pj-list-item.tsx b/js-src/components/pj-list-item.tsx new file mode 100644 index 0000000..f494c9a --- /dev/null +++ b/js-src/components/pj-list-item.tsx @@ -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 <>
+ } + return ( +
+
+ { + avatar() + } +
+
+

{pj.nick}

+ + +
+
+ ) +} diff --git a/js-src/components/pj-list-selection.tsx b/js-src/components/pj-list-selection.tsx index 0cf68da..4503676 100644 --- a/js-src/components/pj-list-selection.tsx +++ b/js-src/components/pj-list-selection.tsx @@ -1,5 +1,5 @@ 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' interface PJListSelectionProps { @@ -7,7 +7,7 @@ interface PJListSelectionProps { setSelectedPJ: (set: PJ | null) => void } -export default function PJListSelection(props: PJListSelectionProps) { +export default function PJListSelection (props: PJListSelectionProps): JSX.Element { const pjs = props.pjs if (pjs === null) { return ( @@ -18,24 +18,21 @@ export default function PJListSelection(props: PJListSelectionProps) { return ( <> { - pjs.map( (item, i) => - { - props.setSelectedPJ(item) - }} - href="#" - key={i}> + pjs.map((item, i) => + { + props.setSelectedPJ(item) + }} href="#" key={i}> {item.full_name} {item.short_name} {item.nick} - ) + ) } ) diff --git a/js-src/components/upper-panel.tsx b/js-src/components/upper-panel.tsx index 46ccdfc..44be36f 100644 --- a/js-src/components/upper-panel.tsx +++ b/js-src/components/upper-panel.tsx @@ -1,7 +1,85 @@ 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 ( + <> +

Esperando datos...

+ + ) + } + function generateLog (): React.ReactNode { + if (logLines === null || logLines.length < 1) { + return ( + <>No log + ) + } + return logLines.map((item, i) => { + return <> + {item.date} { + 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 {item.text} + }) + }
+ + }) + } return ( - <> - +
+
+ { + teamPJs.map((item, i) => { + return + }) + } +
+
+
+                    {
+                        generateLog()
+                    }
+                
+
+
+

Estás en {currentLocation.area.name}/{currentLocation.location.name}.

+

Puedes ir a:

+ +
+
) } diff --git a/js-src/input-packet.ts b/js-src/input-packet.ts new file mode 100644 index 0000000..b73a38a --- /dev/null +++ b/js-src/input-packet.ts @@ -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) + } + } +} diff --git a/js-src/input-packet/info.ts b/js-src/input-packet/info.ts new file mode 100644 index 0000000..2efefb2 --- /dev/null +++ b/js-src/input-packet/info.ts @@ -0,0 +1,6 @@ +import InputPacket from '@lastres/input-packet' +export default class InputPacketInfo extends InputPacket { + identifier (): string { + return 'info' + } +} diff --git a/js-src/input-packet/pong.ts b/js-src/input-packet/pong.ts new file mode 100644 index 0000000..77804b9 --- /dev/null +++ b/js-src/input-packet/pong.ts @@ -0,0 +1,6 @@ +import InputPacket from '@lastres/input-packet'; +export default class InputPacketPong extends InputPacket { + identifier() { + return 'pong' + } +} diff --git a/js-src/input-packets.ts b/js-src/input-packets.ts new file mode 100644 index 0000000..ced2015 --- /dev/null +++ b/js-src/input-packets.ts @@ -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 +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 + } +} diff --git a/js-src/location.ts b/js-src/location.ts new file mode 100644 index 0000000..e32e0a1 --- /dev/null +++ b/js-src/location.ts @@ -0,0 +1,10 @@ +export interface NameIdentifierHash { + name: string + identifier: string +} +export interface Location { + location: NameIdentifierHash + area: NameIdentifierHash + super_area: NameIdentifierHash + planet: NameIdentifierHash +} diff --git a/js-src/log-line.ts b/js-src/log-line.ts new file mode 100644 index 0000000..62cf23e --- /dev/null +++ b/js-src/log-line.ts @@ -0,0 +1,7 @@ +import type { LogSection } from '@lastres/log-section' + +export interface LogLine { + content: LogSection[] + date: string + uuid: string +} diff --git a/js-src/log-section.ts b/js-src/log-section.ts new file mode 100644 index 0000000..2aaee32 --- /dev/null +++ b/js-src/log-section.ts @@ -0,0 +1,5 @@ +export interface LogSection { + color?: string + background?: string + text: string +} diff --git a/js-src/output-packet.ts b/js-src/output-packet.ts new file mode 100644 index 0000000..d259dd5 --- /dev/null +++ b/js-src/output-packet.ts @@ -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 +} diff --git a/js-src/output-packet/init.ts b/js-src/output-packet/init.ts new file mode 100644 index 0000000..b3ede85 --- /dev/null +++ b/js-src/output-packet/init.ts @@ -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 + } + } +} diff --git a/js-src/output-packet/ping.ts b/js-src/output-packet/ping.ts new file mode 100644 index 0000000..3dc3173 --- /dev/null +++ b/js-src/output-packet/ping.ts @@ -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 + } +} diff --git a/js-src/pj.ts b/js-src/pj.ts index b6c7c9f..d591ff1 100644 --- a/js-src/pj.ts +++ b/js-src/pj.ts @@ -2,21 +2,22 @@ export interface PJ { full_name: string short_name: string nick: string - health: number - mana: number + health: number + mana: number max_mana: number - max_health: number + max_health: number race: string uuid: string + image?: string } -export async function fetchMyPjs(setError: (set: string | null) => void): Promise { +export async function fetchMyPjs (setError: (set: string | null) => void): Promise { const response = await fetch('/my/pjs', { method: 'GET', mode: 'same-origin', cache: 'no-cache' }).catch((error) => { - console.log(error); + console.log(error) setError('Error recuperando tus pjs') }) if (response === undefined) { diff --git a/lib/LasTres/Area.pm b/lib/LasTres/Area.pm index fb795ab..54f7ae7 100644 --- a/lib/LasTres/Area.pm +++ b/lib/LasTres/Area.pm @@ -5,7 +5,22 @@ use v5.36.0; use strict; use warnings; +use feature 'signatures'; + use Moo::Role; 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; diff --git a/lib/LasTres/Controller/PJ.pm b/lib/LasTres/Controller/PJ.pm index 909771e..e782ec2 100644 --- a/lib/LasTres/Controller/PJ.pm +++ b/lib/LasTres/Controller/PJ.pm @@ -39,17 +39,7 @@ sub list_my_pjs ($self) { my @pjs = $user->pjs; my @pjs_hash = ( map { - { - 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, - } + $_->hash; } @pjs ); return $self->render( diff --git a/lib/LasTres/Controller/Websocket.pm b/lib/LasTres/Controller/Websocket.pm index 78f8a19..7c20b5a 100644 --- a/lib/LasTres/Controller/Websocket.pm +++ b/lib/LasTres/Controller/Websocket.pm @@ -12,13 +12,13 @@ use Mojo::Base 'Mojolicious::Controller', -signatures; use Data::Dumper; use LasTres::Redis; -use LasTres::DAO::PJs; use LasTres::Controller::Websocket::InputPackets; my %sessions; +use LasTres::DAO::PJs; 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; sub ws ($self) { @@ -46,6 +46,7 @@ sub ws ($self) { $self->on( finish => sub ( $self, $code, $reason ) { delete $sessions{$session_uuid}; + $reason ||= "No reason"; say STDERR "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 ) { my $command = $hash->{command}; if ( !defined $command ) { @@ -60,7 +62,7 @@ sub ws ($self) { $self->send( encode_json( { error => "No command" } ) ); return; } - my $input_packet = $input_packets->hash->{$command) + my $input_packet = $input_packets->hash->{$command}; if ( !defined $input_packet ) { say STDERR "Unknown command $command."; diff --git a/lib/LasTres/Controller/Websocket/InputPacket/Init.pm b/lib/LasTres/Controller/Websocket/InputPacket/Init.pm index d3b79f0..547e730 100644 --- a/lib/LasTres/Controller/Websocket/InputPacket/Init.pm +++ b/lib/LasTres/Controller/Websocket/InputPacket/Init.pm @@ -5,21 +5,31 @@ use v5.36.0; use strict; use warnings; +use feature 'signatures'; + +use Data::Dumper; + use Moo; +use JSON; + +use LasTres::Flags; 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 'init'; } -my $redis = LasTres::Redis->new; - sub handle ( $self, $ws, $session, $data ) { - if (ref $data ne 'HASH') { - return $ws->send( encode_json( { error => "Data should be a hashref." } ) ); + if ( ref $data ne 'HASH' ) { + return $ws->send( + encode_json( { error => "Data should be a hashref." } ) ); } my $pj_uuid = $data->{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.' } ) ); } $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; diff --git a/lib/LasTres/Controller/Websocket/InputPacket/Ping.pm b/lib/LasTres/Controller/Websocket/InputPacket/Ping.pm new file mode 100644 index 0000000..269e681 --- /dev/null +++ b/lib/LasTres/Controller/Websocket/InputPacket/Ping.pm @@ -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; diff --git a/lib/LasTres/Controller/Websocket/OutputPacket.pm b/lib/LasTres/Controller/Websocket/OutputPacket.pm index e58ea56..3b2ae89 100644 --- a/lib/LasTres/Controller/Websocket/OutputPacket.pm +++ b/lib/LasTres/Controller/Websocket/OutputPacket.pm @@ -7,16 +7,16 @@ use warnings; use Moo::Role; +use JSON qw/encode_json/; + requires qw/new identifier data/; sub send ( $self, $ws ) { - return $ws->send( - encode_json( - { - command => $self->identifier, - data => $self->data - } - ) - ); + return $ws->send({json => + { + command => $self->identifier, + data => $self->data + } + }); } 1; diff --git a/lib/LasTres/Controller/Websocket/OutputPacket/Info.pm b/lib/LasTres/Controller/Websocket/OutputPacket/Info.pm index c1a8b21..705998b 100644 --- a/lib/LasTres/Controller/Websocket/OutputPacket/Info.pm +++ b/lib/LasTres/Controller/Websocket/OutputPacket/Info.pm @@ -7,6 +7,10 @@ use warnings; use feature 'signatures'; +use Data::Dumper; + +use Moo; + with 'LasTres::Controller::Websocket::OutputPacket'; has clear => ( @@ -21,6 +25,10 @@ has location_data => ( is => 'rw', ); +has set_log => ( + is => 'rw', +); + sub identifier { return 'info'; } @@ -29,6 +37,7 @@ sub data($self) { my $clear = $self->clear; my $team_pjs = $self->team_pjs; my $location_data = $self->location_data; + my $set_log = $self->set_log; return { ( (defined $clear) @@ -44,6 +53,11 @@ sub data($self) { (defined $location_data) ? (location_data => $location_data) : () + ), + ( + (defined $set_log) + ? (set_log => [map { $_->hash } @$set_log]) + : () ) }; } diff --git a/lib/LasTres/Controller/Websocket/OutputPacket/Pong.pm b/lib/LasTres/Controller/Websocket/OutputPacket/Pong.pm new file mode 100644 index 0000000..410aaaf --- /dev/null +++ b/lib/LasTres/Controller/Websocket/OutputPacket/Pong.pm @@ -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; diff --git a/lib/LasTres/DAO/PJs.pm b/lib/LasTres/DAO/PJs.pm index d26ffe8..fb1afcb 100644 --- a/lib/LasTres/DAO/PJs.pm +++ b/lib/LasTres/DAO/PJs.pm @@ -7,17 +7,15 @@ use warnings; use feature 'signatures'; -use Moo; +use Data::Dumper; -use Params::ValidationCompiler qw/validation_for/; -use Types::Standard qw/Str Bool/; +use Moo; use LasTres::Schema; -my $schema = LasTres::Schema->Schema; -my $result_set = $schema->resultset('PJ'); - sub ResultSet { + my $schema = LasTres::Schema->Schema; + my $result_set = $schema->resultset('PJ'); return $result_set; } 1; diff --git a/lib/LasTres/DAO/Players.pm b/lib/LasTres/DAO/Players.pm index 3f746ee..9ca0259 100644 --- a/lib/LasTres/DAO/Players.pm +++ b/lib/LasTres/DAO/Players.pm @@ -11,10 +11,10 @@ use Moo; use LasTres::Schema; -my $schema = LasTres::Schema->Schema; -my $result_set = $schema->resultset('Player'); sub ResultSet { + my $schema = LasTres::Schema->Schema; + my $result_set = $schema->resultset('Player'); return $result_set; } 1; diff --git a/lib/LasTres/Flags.pm b/lib/LasTres/Flags.pm new file mode 100644 index 0000000..ae12ff4 --- /dev/null +++ b/lib/LasTres/Flags.pm @@ -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; diff --git a/lib/LasTres/Location.pm b/lib/LasTres/Location.pm index 026f961..b9dd257 100644 --- a/lib/LasTres/Location.pm +++ b/lib/LasTres/Location.pm @@ -5,7 +5,69 @@ use v5.36.0; use strict; use warnings; +use feature 'signatures'; + +use LasTres::Planets; use Moo::Role; 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; diff --git a/lib/LasTres/PJ.pm b/lib/LasTres/PJ.pm deleted file mode 100644 index b1c2eb7..0000000 --- a/lib/LasTres/PJ.pm +++ /dev/null @@ -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; diff --git a/lib/LasTres/Planet/Bahdder.pm b/lib/LasTres/Planet/Bahdder.pm index 4a01c45..9396c2f 100644 --- a/lib/LasTres/Planet/Bahdder.pm +++ b/lib/LasTres/Planet/Bahdder.pm @@ -7,7 +7,13 @@ use warnings; 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 => ( is => 'ro', diff --git a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe.pm b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe.pm index 47a8218..61d8b30 100644 --- a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe.pm +++ b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe.pm @@ -7,6 +7,8 @@ use warnings; use feature 'signatures'; +use utf8; + use Moo; use Module::Pluggable search_path => ['LasTres::Planet::Bahdder::BosqueDelHeroe'], diff --git a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI.pm b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI.pm index 61a36ca..cd21e1a 100644 --- a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI.pm +++ b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI.pm @@ -7,6 +7,8 @@ use warnings; use feature 'signatures'; +use utf8; + use Module::Pluggable search_path => ['LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI'], instantiate => 'instance', on_require_error => sub ($plugin, $error) { diff --git a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI/TribuDeLaLima.pm b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI/TribuDeLaLima.pm index a51c042..a68c61d 100644 --- a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI/TribuDeLaLima.pm +++ b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI/TribuDeLaLima.pm @@ -4,6 +4,7 @@ use v5.36.0; use strict; use warnings; +use utf8; use Moo; @@ -67,6 +68,12 @@ sub _build_npcs { return []; } +sub connected_places { + return [ + LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima::Entrada->instance, + ]; +} + my $singleton; sub instance { my $class = shift; diff --git a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima.pm b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima.pm new file mode 100644 index 0000000..cfa8529 --- /dev/null +++ b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima.pm @@ -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; diff --git a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/Entrada.pm b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/Entrada.pm new file mode 100644 index 0000000..2deafb8 --- /dev/null +++ b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/Entrada.pm @@ -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; diff --git a/lib/LasTres/Planets.pm b/lib/LasTres/Planets.pm new file mode 100644 index 0000000..17aba84 --- /dev/null +++ b/lib/LasTres/Planets.pm @@ -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; diff --git a/lib/LasTres/Race/Aldimor.pm b/lib/LasTres/Race/Aldimor.pm index 97fbc36..60cf36c 100644 --- a/lib/LasTres/Race/Aldimor.pm +++ b/lib/LasTres/Race/Aldimor.pm @@ -51,6 +51,10 @@ has is_playable => ( with 'LasTres::Race'; +sub image { + return '/img/aldimor.png'; +} + sub _build_spawn { return LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI::TribuDeLaLima diff --git a/lib/LasTres/Schema.pm b/lib/LasTres/Schema.pm index 251c203..3353065 100644 --- a/lib/LasTres/Schema.pm +++ b/lib/LasTres/Schema.pm @@ -1,11 +1,12 @@ package LasTres::Schema; -our $VERSION = 4; use v5.36.0; use strict; use warnings; +our $VERSION = 5; + use feature 'signatures'; use LasTres; @@ -15,29 +16,33 @@ use parent 'DBIx::Class::Schema'; __PACKAGE__->load_namespaces(); my $schema; -sub Schema($class) { - if (!defined $schema) { - my $app = LasTres->new; - my $config = $app->{config}; + +sub Schema ($class) { + if ( !defined $schema ) { + my $app = LasTres->new; + my $config = $app->{config}; my $database_config = $config->{database}; - my $dbname = $database_config->{dbname}; - my $host = $database_config->{host}; - my $port = $database_config->{port}; - my $user = $database_config->{user}; - my $password = $database_config->{password}; - my $dsn = 'dbi:Pg:'; - if (!defined $dbname) { + my $dbname = $database_config->{dbname}; + my $host = $database_config->{host}; + my $port = $database_config->{port}; + my $user = $database_config->{user}; + my $password = $database_config->{password}; + my $dsn = 'dbi:Pg:'; + + if ( !defined $dbname ) { die "The key database/dbname must be configured."; } $dsn .= "dbname=$dbname"; - if (defined $host) { + if ( defined $host ) { $dsn .= ";host=$host"; } - if (defined $port) { + if ( defined $port ) { $dsn .= ";port=$port"; } + # 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; } diff --git a/lib/LasTres/Schema/Result/PJ.pm b/lib/LasTres/Schema/Result/PJ.pm index ba63a93..1a2c2de 100644 --- a/lib/LasTres/Schema/Result/PJ.pm +++ b/lib/LasTres/Schema/Result/PJ.pm @@ -9,9 +9,11 @@ use feature 'signatures'; use parent 'DBIx::Class::Core'; +use UUID::URandom qw/create_uuid_string/; +use List::AllUtils; use Data::Dumper; -use LasTres::Schema; +use JSON qw/to_json/; use Moo; @@ -43,6 +45,7 @@ __PACKAGE__->add_columns( race => { data_type => 'text', is_nullable => 0, + accessor => "_race", }, team => { data_type => 'uuid', @@ -94,12 +97,12 @@ __PACKAGE__->add_columns( }, health => { data_type => 'integer', - accessor => '_health', + accessor => '_health', is_nullable => 0, }, mana => { data_type => 'integer', - accessor => '_mana', + accessor => '_mana', is_nullable => 0, } ); @@ -108,6 +111,8 @@ __PACKAGE__->set_primary_key('uuid'); __PACKAGE__->has_many( 'npcs', 'LasTres::Schema::Result::CompanionNPC', '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( 'training_stats', 'LasTres::Schema::Result::Stats' ); __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( '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; -for my $column_name (keys %$columns) { - my $column = $columns->{$column_name}; +for my $column_name ( keys %$columns ) { + my $column = $columns->{$column_name}; my $is_nullable = $column->{is_nullable}; $is_nullable //= 0; my $required = !$is_nullable; + if ( defined $column->{default_value} ) { + $required = 0; + } has $column_name => ( - is => 'rw', + is => 'rw', required => $required, accessor => "_moo_$column_name", ); @@ -132,73 +164,151 @@ for my $column_name (keys %$columns) { sub max_health ($self) { 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_born = $self->born_stats->health; my $health_training = $self->training_stats->health; my $health_mix = 2 * $health_base_race + $health_born + ( $health_training / 4 ); 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) { - my $races = LasTres::Races->new; - my $race = $races->hash_playable->{$self->race}; + my $races = LasTres::Races->new; + my $race = $self->race; my $mana_base_race = $race->base_stats->mana; my $mana_born = $self->born_stats->mana; my $mana_training = $self->training_stats->mana; - my $mana_mix = - 2 * $mana_base_race + $mana_born + ( $mana_training / 4 ); + my $mana_mix = 2 * $mana_base_race + $mana_born + ( $mana_training / 4 ); my $mana_scaled = ( ( $mana_mix * $self->level ) / 100 ); - return int($mana_scaled + $self->level + 10); + return int( $mana_scaled + $self->level + 10 ); } sub health { - my $self = shift; + my $self = shift; my $health_to_set = shift; + require LasTres::Schema; my $schema = LasTres::Schema->Schema; - $schema->txn_do(sub { - if (defined $health_to_set) { - $self->_health($health_to_set); - $self->update; + $schema->txn_do( + sub { + if ( defined $health_to_set ) { + $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; } sub mana { - my $self = shift; + my $self = shift; my $mana_to_set = shift; + require LasTres::Schema; my $schema = LasTres::Schema->Schema; - $schema->txn_do(sub { - if (defined $mana_to_set) { - $self->_mana($mana_to_set); - $self->update; + $schema->txn_do( + sub { + if ( defined $mana_to_set ) { + $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; } +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) { 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; diff --git a/lib/LasTres/Schema/Result/PJFlag.pm b/lib/LasTres/Schema/Result/PJFlag.pm new file mode 100644 index 0000000..7133d16 --- /dev/null +++ b/lib/LasTres/Schema/Result/PJFlag.pm @@ -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; diff --git a/lib/LasTres/Schema/Result/PJLog.pm b/lib/LasTres/Schema/Result/PJLog.pm new file mode 100644 index 0000000..5855b4e --- /dev/null +++ b/lib/LasTres/Schema/Result/PJLog.pm @@ -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; diff --git a/lib/LasTres/Schema/Result/Team.pm b/lib/LasTres/Schema/Result/Team.pm index bcae2c5..05b510e 100644 --- a/lib/LasTres/Schema/Result/Team.pm +++ b/lib/LasTres/Schema/Result/Team.pm @@ -7,6 +7,8 @@ use warnings; use parent 'DBIx::Class::Core'; +use LasTres::Location; + __PACKAGE__->table('teams'); __PACKAGE__->add_columns( @@ -45,22 +47,27 @@ __PACKAGE__->add_columns( }, ); +# May throw error, it is needed to handle. sub location { my $self = shift; my $location = shift; + my $planet; + my $super_area; + my $area; if (defined $location) { $self->_location($location->identifier); - my $area = $location->parent; + $area = $location->parent; $self->_area($area->identifier); - my $super_area = $area->parent; - $self->_super_area($super_area->identifier) - my $planet = $super_area->parent; + $super_area = $area->parent; + $self->_super_area($super_area->identifier); + $planet = $super_area->parent; $self->_planet($planet->identifier); } - my $location = $self->_location; - my $area = $self->_area; - my $super_area = $self->_super_area; - my $planet = $self->_planet; + $location = $self->_location; + $area = $self->_area; + $super_area = $self->_super_area; + $planet = $self->_planet; + $location = LasTres::Location::get($planet, $super_area, $area, $location); return $location; } __PACKAGE__->set_primary_key('uuid'); diff --git a/public/css/styles.css b/public/css/styles.css index 886993a..b9dbe3a 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -1,8 +1,66 @@ +@keyframes move-avatar { + 0% { + padding-bottom: 0rem; } + 50% { + padding-bottom: 0.3rem; } + 100% { + padding-bottom: 0rem; } } + body { margin: 0px; padding: 0px; min-height: 100%; 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 { width: max-content; } body div#game-container { @@ -74,21 +132,12 @@ body { body div.pj-selection-menu div.pj-selection-menu-container div.pj-list a:hover { color: yellow; 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 { display: flex; justify-content: center; align-items: center; height: 100%; - background: url("/img/wallpaper.jpg") no-repeat center black; + background: url() no-repeat center black; flex-direction: column; } body div.login-container div.login-contained { background: #001e8b; diff --git a/public/css/styles.scss b/public/css/styles.scss index bd550b8..21e38a9 100644 --- a/public/css/styles.scss +++ b/public/css/styles.scss @@ -1,4 +1,80 @@ +@keyframes move-avatar { + 0% { + padding-bottom: 0rem; + } + 50% { + padding-bottom: 0.3rem; + } + 100% { + padding-bottom: 0rem; + } +} 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; padding: 0px; min-height: 100%; @@ -83,19 +159,7 @@ body { background: gray; } 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; align-items: center; height: 100%; - background: url('/img/wallpaper.jpg') no-repeat center black; + background: url() no-repeat center black; flex-direction: column; div.login-contained { background: rgba(0, 30, 139, 1); diff --git a/public/img/aldimor.png b/public/img/aldimor.png new file mode 100644 index 0000000..a8f2fd8 Binary files /dev/null and b/public/img/aldimor.png differ diff --git a/public/js/bundle.js b/public/js/bundle.js index a6e81b8..76153cf 100644 --- a/public/js/bundle.js +++ b/public/js/bundle.js @@ -96,7 +96,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac \************************************/ /***/ ((__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 ***! \*************************************************/ /***/ ((__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__) => { -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 ***! @@ -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 ***!