From f4f5c331e41a609a71d35541b00d338d2bc154eb Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 18 Nov 2024 01:37:24 -0800 Subject: [PATCH 1/7] feat: initial support for total_stationed_gmax --- packages/types/lib/scanner.d.ts | 1 + server/src/graphql/typeDefs/scanner.graphql | 1 + server/src/models/Station.js | 1 + src/features/station/StationPopup.jsx | 8 ++++++-- src/services/queries/station.js | 1 + 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/types/lib/scanner.d.ts b/packages/types/lib/scanner.d.ts index b07ef6df1..11fb72acc 100644 --- a/packages/types/lib/scanner.d.ts +++ b/packages/types/lib/scanner.d.ts @@ -368,6 +368,7 @@ export interface Station { battle_pokemon_move_2: number total_stationed_pokemon: number + total_stationed_gmax: number stationed_pokemon: Parsed extends true ? StationPokemon[] : string | StationPokemon[] diff --git a/server/src/graphql/typeDefs/scanner.graphql b/server/src/graphql/typeDefs/scanner.graphql index b77e293ab..eee547c89 100644 --- a/server/src/graphql/typeDefs/scanner.graphql +++ b/server/src/graphql/typeDefs/scanner.graphql @@ -275,6 +275,7 @@ type Station { end_time: Int cooldown_complete: Int total_stationed_pokemon: Int + total_stationed_gmax: Int is_battle_available: Boolean is_inactive: Boolean battle_level: Int diff --git a/server/src/models/Station.js b/server/src/models/Station.js index 1f0092e96..aedbf0495 100644 --- a/server/src/models/Station.js +++ b/server/src/models/Station.js @@ -35,6 +35,7 @@ class Station extends Model { 'start_time', 'end_time', 'total_stationed_pokemon', + 'total_stationed_gmax', ] const query = this.query() diff --git a/src/features/station/StationPopup.jsx b/src/features/station/StationPopup.jsx index abcc891ff..961afd42b 100644 --- a/src/features/station/StationPopup.jsx +++ b/src/features/station/StationPopup.jsx @@ -348,7 +348,7 @@ function StationMedia({ } /** @param {import('@rm/types').Station} station */ -function StationAttackBonus({ total_stationed_pokemon }) { +function StationAttackBonus({ total_stationed_pokemon, total_stationed_gmax }) { const { t } = useTranslation() return ( @@ -360,7 +360,11 @@ function StationAttackBonus({ total_stationed_pokemon }) { max={4} /> - {t('battle_bonus')}  ({total_stationed_pokemon} / 40) + {t('battle_bonus')}  ( + {total_stationed_gmax === undefined || total_stationed_gmax === null + ? '' + : `${total_stationed_gmax} / `} + {total_stationed_pokemon} / 40) ) diff --git a/src/services/queries/station.js b/src/services/queries/station.js index 9ca9a2182..fdf426ded 100644 --- a/src/services/queries/station.js +++ b/src/services/queries/station.js @@ -12,6 +12,7 @@ const core = gql` start_time end_time total_stationed_pokemon + total_stationed_gmax } ` From 38b563a973d3a4a5b78991bbfa98f23ecf3804de Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 18 Nov 2024 14:17:14 -0800 Subject: [PATCH 2/7] fix: show battle bonus when inactive --- src/features/station/StationPopup.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/features/station/StationPopup.jsx b/src/features/station/StationPopup.jsx index 961afd42b..49b939a12 100644 --- a/src/features/station/StationPopup.jsx +++ b/src/features/station/StationPopup.jsx @@ -57,8 +57,7 @@ export function StationPopup(station) { )} - {!!station.is_battle_available && - station.battle_start < Date.now() / 1000 && + {station.battle_start < Date.now() / 1000 && station.battle_end > Date.now() / 1000 && ( From dcb00ab4d3addc2b0beb83858c12b858189c15f0 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 18 Nov 2024 14:20:11 -0800 Subject: [PATCH 3/7] fix: show active battle pokemon during inactive hours This is more consistent with the in-game experience. --- server/src/models/Station.js | 5 +---- src/features/station/useStationMarker.js | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/server/src/models/Station.js b/server/src/models/Station.js index aedbf0495..3da881db4 100644 --- a/server/src/models/Station.js +++ b/server/src/models/Station.js @@ -66,10 +66,7 @@ class Station extends Model { ) if (!onlyAllStations) { - query - .whereNotNull('battle_pokemon_id') - .andWhere('is_battle_available', true) - .andWhere('battle_end', '>', ts) + query.whereNotNull('battle_pokemon_id').andWhere('battle_end', '>', ts) if (onlyBattleTier === 'all') { const battleBosses = new Set() diff --git a/src/features/station/useStationMarker.js b/src/features/station/useStationMarker.js index db2f70de0..3f9bfd84f 100644 --- a/src/features/station/useStationMarker.js +++ b/src/features/station/useStationMarker.js @@ -17,7 +17,6 @@ export function useStationMarker({ battle_pokemon_form, battle_pokemon_gender, battle_pokemon_id, - is_battle_available, battle_pokemon_bread_mode, start_time, end_time, @@ -54,7 +53,7 @@ export function useStationMarker({ return divIcon({ popupAnchor: [ 0 + stationMod.popupX + stationMod.offsetX, - (-baseSize - (is_battle_available && isActive ? battleSize : 0)) * 0.67 + + (-baseSize - (isActive ? battleSize : 0)) * 0.67 + stationMod.popupY + stationMod.offsetY + (-5 + battleMod.offsetY + battleMod.popupY), @@ -75,7 +74,7 @@ export function useStationMarker({ " /> ${ - is_battle_available && isActive + isActive ? /* html */ ` Date: Mon, 18 Nov 2024 15:28:00 -0800 Subject: [PATCH 4/7] feat: filter by Gigantamax Stationed --- config/default.json | 3 +- server/src/filters/builder/base.js | 3 ++ server/src/models/Station.js | 79 ++++++++++++++++------------- server/src/ui/drawer.js | 1 + src/pages/map/hooks/usePermCheck.js | 3 +- src/services/queries/index.js | 2 +- src/services/queries/station.js | 4 +- 7 files changed, 55 insertions(+), 40 deletions(-) diff --git a/config/default.json b/config/default.json index 647206103..da49bc6ee 100644 --- a/config/default.json +++ b/config/default.json @@ -579,7 +579,8 @@ "enabled": false, "pokemon": false, "battleTier": "all", - "battles": false + "battles": false, + "gmaxStationed": false }, "s2cells": { "enabled": false, diff --git a/server/src/filters/builder/base.js b/server/src/filters/builder/base.js index 61585baaa..a800ba163 100644 --- a/server/src/filters/builder/base.js +++ b/server/src/filters/builder/base.js @@ -126,6 +126,9 @@ function buildDefaultFilters(perms) { ? defaultFilters.stations.battles : undefined, filter: pokemon.stations, + gmaxStationed: perms.dynamax + ? defaultFilters.stations.gmaxStationed + : undefined, } : undefined, pokemon: diff --git a/server/src/models/Station.js b/server/src/models/Station.js index 3da881db4..838cca0d5 100644 --- a/server/src/models/Station.js +++ b/server/src/models/Station.js @@ -22,8 +22,13 @@ class Station extends Model { static async getAll(perms, args, { isMad }) { const { areaRestrictions } = perms const { stationUpdateLimit } = config.getSafe('api') - const { onlyAreas, onlyAllStations, onlyMaxBattles, onlyBattleTier } = - args.filters + const { + onlyAreas, + onlyAllStations, + onlyMaxBattles, + onlyBattleTier, + onlyGmaxStationed, + } = args.filters const ts = getEpoch() const select = [ @@ -34,8 +39,6 @@ class Station extends Model { 'updated', 'start_time', 'end_time', - 'total_stationed_pokemon', - 'total_stationed_gmax', ] const query = this.query() @@ -49,7 +52,7 @@ class Station extends Model { ) // .where('is_inactive', false) - if (perms.dynamax && onlyMaxBattles) { + if (perms.dynamax && (onlyMaxBattles || onlyGmaxStationed)) { select.push( 'is_battle_available', 'battle_level', @@ -63,45 +66,51 @@ class Station extends Model { 'battle_pokemon_bread_mode', 'battle_pokemon_move_1', 'battle_pokemon_move_2', + 'total_stationed_pokemon', + 'total_stationed_gmax', ) if (!onlyAllStations) { query.whereNotNull('battle_pokemon_id').andWhere('battle_end', '>', ts) - if (onlyBattleTier === 'all') { - const battleBosses = new Set() - const battleForms = new Set() - const battleLevels = new Set() + query.andWhere((station) => { + station.where((battle) => { + if (onlyBattleTier === 'all') { + const battleBosses = new Set() + const battleForms = new Set() + const battleLevels = new Set() - Object.keys(args.filters).forEach((key) => { - switch (key.charAt(0)) { - case 'o': - break - case 'j': - battleLevels.add(key.slice(1)) - break - default: - { - const [id, form] = key.split('-') - if (id) battleBosses.add(id) - if (form) battleForms.add(form) + Object.keys(args.filters).forEach((key) => { + switch (key.charAt(0)) { + case 'o': + break + case 'j': + battleLevels.add(key.slice(1)) + break + default: + { + const [id, form] = key.split('-') + if (id) battleBosses.add(id) + if (form) battleForms.add(form) + } + break } - break + }) + if (battleBosses.size) { + battle.andWhere('battle_pokemon_id', 'in', [...battleBosses]) + } + if (battleForms.size) { + battle.andWhere('battle_pokemon_form', 'in', [...battleForms]) + } + if (battleLevels.size) { + battle.andWhere('battle_level', 'in', [...battleLevels]) + } + } else { + battle.andWhere('battle_level', onlyBattleTier) } }) - - if (battleBosses.size) { - query.andWhere('battle_pokemon_id', 'in', [...battleBosses]) - } - if (battleForms.size) { - query.andWhere('battle_pokemon_form', 'in', [...battleForms]) - } - if (battleLevels.size) { - query.andWhere('battle_level', 'in', [...battleLevels]) - } - } else { - query.andWhere('battle_level', onlyBattleTier) - } + if (onlyGmaxStationed) station.orWhere('total_stationed_gmax', '>', 0) + }) } } diff --git a/server/src/ui/drawer.js b/server/src/ui/drawer.js index 473decc8f..876210c9d 100644 --- a/server/src/ui/drawer.js +++ b/server/src/ui/drawer.js @@ -68,6 +68,7 @@ function drawer(req, perms) { ? { allStations: perms.stations || BLOCKED, maxBattles: perms.dynamax || BLOCKED, + gmaxStationed: perms.dynamax || BLOCKED, } : BLOCKED, pokemon: diff --git a/src/pages/map/hooks/usePermCheck.js b/src/pages/map/hooks/usePermCheck.js index 6d75ef882..ee1ec54b1 100644 --- a/src/pages/map/hooks/usePermCheck.js +++ b/src/pages/map/hooks/usePermCheck.js @@ -56,7 +56,8 @@ export function usePermCheck(category) { case 'stations': if ( (filters?.allStations && perms?.stations) || - (filters?.maxBattles && perms?.dynamax) + (filters?.maxBattles && perms?.dynamax) || + (filters?.gmaxStationed && perms?.dynamax) ) { return true } diff --git a/src/services/queries/index.js b/src/services/queries/index.js index 9b39d015b..c0bd1eaa9 100644 --- a/src/services/queries/index.js +++ b/src/services/queries/index.js @@ -144,7 +144,7 @@ export class Query { static stations(filters) { const { perms } = useMemory.getState().auth let query = 'GET_ALL_STATIONS' - if (filters.maxBattles && perms.dynamax) { + if ((filters.maxBattles || filters.gmaxStationed) && perms.dynamax) { query += '_BATTLE' } return stationIndex[query] diff --git a/src/services/queries/station.js b/src/services/queries/station.js index fdf426ded..d54555e20 100644 --- a/src/services/queries/station.js +++ b/src/services/queries/station.js @@ -11,8 +11,6 @@ const core = gql` updated start_time end_time - total_stationed_pokemon - total_stationed_gmax } ` @@ -31,6 +29,8 @@ const battle = gql` battle_pokemon_bread_mode battle_pokemon_move_1 battle_pokemon_move_2 + total_stationed_pokemon + total_stationed_gmax } ` From be85da22ad64d06c7fd02e1384b4b0478a8925ec Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 18 Nov 2024 15:33:15 -0800 Subject: [PATCH 5/7] fix: no pokemon icon marker if it is not available --- src/features/station/useStationMarker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/station/useStationMarker.js b/src/features/station/useStationMarker.js index 3f9bfd84f..97fbd9270 100644 --- a/src/features/station/useStationMarker.js +++ b/src/features/station/useStationMarker.js @@ -48,7 +48,7 @@ export function useStationMarker({ }, basicEqualFn) const [stationMod, battleMod] = Icons.getModifiers('station', 'dynamax') const opacity = useOpacity('stations')(end_time) - const isActive = start_time < Date.now() / 1000 + const isActive = !!battle_pokemon_id && start_time < Date.now() / 1000 return divIcon({ popupAnchor: [ From 437f6b78daf848f9a0adc96b61577d428dab0b1e Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 18 Nov 2024 15:36:36 -0800 Subject: [PATCH 6/7] fix: add en translation --- packages/locales/lib/human/en.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/locales/lib/human/en.json b/packages/locales/lib/human/en.json index a6ae482c1..fbda09d08 100644 --- a/packages/locales/lib/human/en.json +++ b/packages/locales/lib/human/en.json @@ -794,6 +794,7 @@ "stations_filters": "Power Spots Filter Settings", "stations_options": "Power Spot Options", "all_stations": "All Power Spots", + "gmax_stationed": "Gigantamax Placed", "search_battles": "Search Max Battles", "started": "Started", "ended": "Ended", From 5a7a72aef1012b5504766a322f2046710482b296 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 18 Nov 2024 17:36:11 -0800 Subject: [PATCH 7/7] feat: support db without gmax count --- packages/types/lib/server.d.ts | 1 + server/src/models/Station.js | 113 ++++++++++++++++++------------- server/src/services/DbManager.js | 3 + 3 files changed, 71 insertions(+), 46 deletions(-) diff --git a/packages/types/lib/server.d.ts b/packages/types/lib/server.d.ts index 6ee4cdc94..76659e940 100644 --- a/packages/types/lib/server.d.ts +++ b/packages/types/lib/server.d.ts @@ -45,6 +45,7 @@ export interface DbContext { hasShowcaseData: boolean hasShowcaseForm: boolean hasShowcaseType: boolean + hasStationedGmax: boolean } export interface ExpressUser extends User { diff --git a/server/src/models/Station.js b/server/src/models/Station.js index 838cca0d5..53081b74d 100644 --- a/server/src/models/Station.js +++ b/server/src/models/Station.js @@ -19,7 +19,7 @@ class Station extends Model { * @param {import("@rm/types").DbContext} ctx * @returns {Promise} */ - static async getAll(perms, args, { isMad }) { + static async getAll(perms, args, { isMad, hasStationedGmax }) { const { areaRestrictions } = perms const { stationUpdateLimit } = config.getSafe('api') const { @@ -67,49 +67,53 @@ class Station extends Model { 'battle_pokemon_move_1', 'battle_pokemon_move_2', 'total_stationed_pokemon', - 'total_stationed_gmax', + ) + select.push( + hasStationedGmax ? 'total_stationed_gmax' : 'stationed_pokemon', ) if (!onlyAllStations) { query.whereNotNull('battle_pokemon_id').andWhere('battle_end', '>', ts) query.andWhere((station) => { - station.where((battle) => { - if (onlyBattleTier === 'all') { - const battleBosses = new Set() - const battleForms = new Set() - const battleLevels = new Set() + if (hasStationedGmax || !onlyGmaxStationed) + station.where((battle) => { + if (onlyBattleTier === 'all') { + const battleBosses = new Set() + const battleForms = new Set() + const battleLevels = new Set() - Object.keys(args.filters).forEach((key) => { - switch (key.charAt(0)) { - case 'o': - break - case 'j': - battleLevels.add(key.slice(1)) - break - default: - { - const [id, form] = key.split('-') - if (id) battleBosses.add(id) - if (form) battleForms.add(form) - } - break + Object.keys(args.filters).forEach((key) => { + switch (key.charAt(0)) { + case 'o': + break + case 'j': + battleLevels.add(key.slice(1)) + break + default: + { + const [id, form] = key.split('-') + if (id) battleBosses.add(id) + if (form) battleForms.add(form) + } + break + } + }) + if (battleBosses.size) { + battle.andWhere('battle_pokemon_id', 'in', [...battleBosses]) } - }) - if (battleBosses.size) { - battle.andWhere('battle_pokemon_id', 'in', [...battleBosses]) - } - if (battleForms.size) { - battle.andWhere('battle_pokemon_form', 'in', [...battleForms]) - } - if (battleLevels.size) { - battle.andWhere('battle_level', 'in', [...battleLevels]) + if (battleForms.size) { + battle.andWhere('battle_pokemon_form', 'in', [...battleForms]) + } + if (battleLevels.size) { + battle.andWhere('battle_level', 'in', [...battleLevels]) + } + } else { + battle.andWhere('battle_level', onlyBattleTier) } - } else { - battle.andWhere('battle_level', onlyBattleTier) - } - }) - if (onlyGmaxStationed) station.orWhere('total_stationed_gmax', '>', 0) + }) + if (hasStationedGmax && onlyGmaxStationed) + station.orWhere('total_stationed_gmax', '>', 0) }) } } @@ -121,17 +125,6 @@ class Station extends Model { const results = await query.select(select) return results - .filter( - (station) => - onlyAllStations || - !perms.dynamax || - args.filters[`j${station.battle_level}`] || - args.filters[ - `${station.battle_pokemon_id}-${station.battle_pokemon_form}` - ] || - onlyBattleTier === 'all' || - onlyBattleTier === station.battle_level, - ) .map((station) => { if (station.is_battle_available && station.battle_pokemon_id === null) { station.is_battle_available = false @@ -139,8 +132,36 @@ class Station extends Model { if (station.total_stationed_pokemon === null) { station.total_stationed_pokemon = 0 } + if ( + station.stationed_pokemon && + (station.total_stationed_gmax === undefined || + station.total_stationed_gmax === null) + ) { + const list = + typeof station.stationed_pokemon === 'string' + ? JSON.parse(station.stationed_pokemon) + : station.stationed_pokemon || [] + let count = 0 + if (list) + for (let i = 0; i < list.length; ++i) + if (list[i].bread_mode === 2 || list[i].bread_mode === 3) ++count + station.total_stationed_gmax = count + } return station }) + .filter( + (station) => + onlyAllStations || + (perms.dynamax && + ((onlyMaxBattles && + (args.filters[`j${station.battle_level}`] || + args.filters[ + `${station.battle_pokemon_id}-${station.battle_pokemon_form}` + ] || + onlyBattleTier === 'all' || + onlyBattleTier === station.battle_level)) || + (onlyGmaxStationed && station.total_stationed_gmax))), + ) } /** diff --git a/server/src/services/DbManager.js b/server/src/services/DbManager.js index 8149f4f78..539cf936e 100644 --- a/server/src/services/DbManager.js +++ b/server/src/services/DbManager.js @@ -155,6 +155,8 @@ class DbManager extends Logger { 'showcase_pokemon_form_id' in columns, 'showcase_pokemon_type_id' in columns, ]) + const hasStationedGmax = + 'total_stationed_gmax' in (await schema('station').columnInfo()) const [hasLayerColumn] = isMad ? await schema('trs_quest') .columnInfo() @@ -200,6 +202,7 @@ class DbManager extends Logger { hasShowcaseData, hasShowcaseForm, hasShowcaseType, + hasStationedGmax, } }