From 4b6cc38f5dac5d047d9bb8645eb987484268e1a7 Mon Sep 17 00:00:00 2001 From: laynester Date: Wed, 9 Nov 2022 06:12:54 -0500 Subject: [PATCH 1/2] start game center, missing queue window n such --- src/api/utils/ColorUtils.ts | 7 + src/assets/images/gamecenter/selectedIcon.png | Bin 0 -> 248 bytes src/assets/styles/icons.scss | 202 +++++++++--------- .../game-center/GameCenterView.scss | 44 ++++ src/components/game-center/GameCenterView.tsx | 50 +++++ .../game-center/views/GameListView.tsx | 32 +++ .../game-center/views/GameStageView.tsx | 47 ++++ src/components/game-center/views/GameView.tsx | 58 +++++ src/components/index.scss | 53 ++--- src/components/main/MainView.tsx | 2 + src/components/toolbar/ToolbarView.tsx | 3 +- src/hooks/game-center/index.ts | 1 + src/hooks/game-center/useGameCenter.ts | 83 +++++++ src/hooks/index.ts | 1 + 14 files changed, 458 insertions(+), 125 deletions(-) create mode 100644 src/assets/images/gamecenter/selectedIcon.png create mode 100644 src/components/game-center/GameCenterView.scss create mode 100644 src/components/game-center/GameCenterView.tsx create mode 100644 src/components/game-center/views/GameListView.tsx create mode 100644 src/components/game-center/views/GameStageView.tsx create mode 100644 src/components/game-center/views/GameView.tsx create mode 100644 src/hooks/game-center/index.ts create mode 100644 src/hooks/game-center/useGameCenter.ts diff --git a/src/api/utils/ColorUtils.ts b/src/api/utils/ColorUtils.ts index 9377255e..100bcc5b 100644 --- a/src/api/utils/ColorUtils.ts +++ b/src/api/utils/ColorUtils.ts @@ -23,4 +23,11 @@ export class ColorUtils { return parseInt(color.replace('#', ''), 16); } + + public static uintHexColor(color: number): string + { + const realColor = color >>>0; + + return ColorUtils.makeColorHex(realColor.toString(16).substring(2)); + } } diff --git a/src/assets/images/gamecenter/selectedIcon.png b/src/assets/images/gamecenter/selectedIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..718e48b8b3cca422701cf4cf2d0b0872e3fa5d9b GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^!63}R1|%PEvIde2`#oJ8Ln>~)y}OaO!GOor@%?@i zo`wxM$y^uqnyp;tF;jkG$%~*8=WQ)rnVcf$g5mCD! zsd6Uw%ohjS6T6)kl%Du>{ChyV-88M9))^ZOH!TtQ$g-yI?| div { + color: inherit; + } + } + + .gameList-container { + min-height: 107px; + + .game-icon { + width: 83px; + height: 83px; + background-position: center; + background-repeat: no-repeat; + + &.selected { + position: relative; + &::after { + content: ""; + background-image: url("../../assets/images/gamecenter/selectedIcon.png"); + width: 83px; + height: 83px; + position: absolute; + inset: 0; + } + } + } + } +} diff --git a/src/components/game-center/GameCenterView.tsx b/src/components/game-center/GameCenterView.tsx new file mode 100644 index 00000000..f0955ae6 --- /dev/null +++ b/src/components/game-center/GameCenterView.tsx @@ -0,0 +1,50 @@ +import { ILinkEventTracker } from '@nitrots/nitro-renderer'; +import { useEffect } from 'react'; +import { AddEventLinkTracker, RemoveLinkEventTracker } from '../../api'; +import { Flex } from '../../common'; +import { useGameCenter } from '../../hooks'; +import { GameListView } from './views/GameListView'; +import { GameStageView } from './views/GameStageView'; +import { GameView } from './views/GameView'; + +export const GameCenterView = () => +{ + const{ isVisible, setIsVisible, games, accountStatus } = useGameCenter(); + + useEffect(() => + { + const toggleGameCenter = () => + { + setIsVisible(prev => !prev); + } + + const linkTracker: ILinkEventTracker = { + linkReceived: (url: string) => + { + const value = url.split('/'); + + switch(value[1]) + { + case 'toggle': + toggleGameCenter(); + break; + } + }, + eventUrlPrefix: 'games/' + }; + + AddEventLinkTracker(linkTracker); + + return () => RemoveLinkEventTracker(linkTracker); + }, [ ]); + + if(!isVisible || !games || !accountStatus) return; + + return + + + + + + +} diff --git a/src/components/game-center/views/GameListView.tsx b/src/components/game-center/views/GameListView.tsx new file mode 100644 index 00000000..1211bc75 --- /dev/null +++ b/src/components/game-center/views/GameListView.tsx @@ -0,0 +1,32 @@ +import { GameConfigurationData } from '@nitrots/nitro-renderer'; +import { LocalizeText } from '../../../api'; +import { Base, Flex } from '../../../common'; +import { useGameCenter } from '../../../hooks'; + +export const GameListView = () => +{ + const { games,selectedGame, setSelectedGame } = useGameCenter(); + + const getClasses = (game: GameConfigurationData) => + { + let classes = [ 'game-icon' ]; + + if(selectedGame === game) classes.push('selected'); + + return classes.join(' '); + } + + const getIconImage = (game: GameConfigurationData): string => + { + return `url(${ game.assetUrl }${ game.gameNameId }_icon.png)` + } + + return + { LocalizeText('gamecenter.game_list_title') } + + { games && games.map((game,index) => + setSelectedGame(game) } style={ { backgroundImage: getIconImage(game) } }/> + ) } + + +} diff --git a/src/components/game-center/views/GameStageView.tsx b/src/components/game-center/views/GameStageView.tsx new file mode 100644 index 00000000..0a26fea4 --- /dev/null +++ b/src/components/game-center/views/GameStageView.tsx @@ -0,0 +1,47 @@ +import { Game2ExitGameMessageComposer } from '@nitrots/nitro-renderer'; +import { useEffect, useRef, useState } from 'react'; +import { SendMessageComposer } from '../../../api'; +import { Base } from '../../../common'; +import { useGameCenter } from '../../../hooks'; + +export const GameStageView = () => +{ + const { gameURL,setGameURL } = useGameCenter(); + const [ loadTimes, setLoadTimes ] = useState(0); + const ref = useRef(); + + useEffect(()=> + { + if(!ref || ref && !ref.current) return; + + setLoadTimes(0); + + let frame: HTMLIFrameElement = document.createElement('iframe'); + + frame.src = gameURL; + frame.classList.add('game-center-stage'); + frame.classList.add('h-100'); + + frame.onload = () => + { + setLoadTimes(prev => prev += 1) + } + + ref.current.innerHTML = ''; + ref.current.appendChild(frame); + + },[ ref, gameURL ]); + + useEffect(()=> + { + if(loadTimes > 1) + { + setGameURL(null); + SendMessageComposer(new Game2ExitGameMessageComposer()); + } + },[ loadTimes,setGameURL ]) + + if(!gameURL) return null; + + return +} diff --git a/src/components/game-center/views/GameView.tsx b/src/components/game-center/views/GameView.tsx new file mode 100644 index 00000000..a9d641f7 --- /dev/null +++ b/src/components/game-center/views/GameView.tsx @@ -0,0 +1,58 @@ +import { Game2GetAccountGameStatusMessageComposer, GetGameStatusMessageComposer, JoinQueueMessageComposer } from '@nitrots/nitro-renderer'; +import { useEffect } from 'react'; +import { ColorUtils, LocalizeText, SendMessageComposer } from '../../../api'; +import { Base, Button, Flex, LayoutItemCountView, Text } from '../../../common'; +import { useGameCenter } from '../../../hooks'; + +export const GameView = () => +{ + const { selectedGame, accountStatus } = useGameCenter(); + + useEffect(()=> + { + if(selectedGame) + { + SendMessageComposer(new GetGameStatusMessageComposer(selectedGame.gameId)); + SendMessageComposer(new Game2GetAccountGameStatusMessageComposer(selectedGame.gameId)); + } + },[ selectedGame ]) + + const getBgColour = (): string => + { + return ColorUtils.uintHexColor(selectedGame.bgColor) + } + + const getBgImage = (): string => + { + return `url(${ selectedGame.assetUrl }${ selectedGame.gameNameId }_theme.png)` + } + + const getColor = () => + { + return ColorUtils.uintHexColor(selectedGame.textColor); + } + + const onPlay = () => + { + SendMessageComposer(new JoinQueueMessageComposer(selectedGame.gameId)); + } + + return + + { LocalizeText(`gamecenter.${ selectedGame.gameNameId }.description_title`) } + + { (accountStatus.hasUnlimitedGames || accountStatus.freeGamesLeft > 0) && <> + + } + { LocalizeText(`gamecenter.${ selectedGame.gameNameId }.description_content`) } + + + + + + +} diff --git a/src/components/index.scss b/src/components/index.scss index 5cea1b3b..5f4c0268 100644 --- a/src/components/index.scss +++ b/src/components/index.scss @@ -1,26 +1,27 @@ -@import './achievements/AchievementsView'; -@import './avatar-editor/AvatarEditorView'; -@import './camera/CameraWidgetView'; -@import './campaign/CampaignView'; -@import './catalog/CatalogView'; -@import './chat-history/ChatHistoryView'; -@import './floorplan-editor/FloorplanEditorView'; -@import './friends/FriendsView'; -@import './groups/GroupView'; -@import './guide-tool/GuideToolView'; -@import './hc-center/HcCenterView'; -@import './help/HelpView'; -@import './hotel-view/HotelView'; -@import './inventory/InventoryView'; -@import './loading/LoadingView'; -@import './mod-tools/ModToolsView'; -@import './navigator/NavigatorView'; -@import './nitropedia/NitropediaView'; -@import './notification-center/NotificationCenterView'; -@import './purse/PurseView'; -@import './right-side/RightSideView'; -@import './room/RoomView'; -@import './toolbar/ToolbarView'; -@import './user-profile/UserProfileVew'; -@import './user-settings/UserSettingsView'; -@import './wired/WiredView'; +@import "./achievements/AchievementsView"; +@import "./avatar-editor/AvatarEditorView"; +@import "./camera/CameraWidgetView"; +@import "./campaign/CampaignView"; +@import "./catalog/CatalogView"; +@import "./chat-history/ChatHistoryView"; +@import "./floorplan-editor/FloorplanEditorView"; +@import "./friends/FriendsView"; +@import "./groups/GroupView"; +@import "./guide-tool/GuideToolView"; +@import "./hc-center/HcCenterView"; +@import "./help/HelpView"; +@import "./hotel-view/HotelView"; +@import "./inventory/InventoryView"; +@import "./loading/LoadingView"; +@import "./mod-tools/ModToolsView"; +@import "./navigator/NavigatorView"; +@import "./nitropedia/NitropediaView"; +@import "./notification-center/NotificationCenterView"; +@import "./purse/PurseView"; +@import "./right-side/RightSideView"; +@import "./room/RoomView"; +@import "./toolbar/ToolbarView"; +@import "./user-profile/UserProfileVew"; +@import "./user-settings/UserSettingsView"; +@import "./wired/WiredView"; +@import "./game-center/GameCenterView.scss"; diff --git a/src/components/main/MainView.tsx b/src/components/main/MainView.tsx index 3dec4d05..f54ad251 100644 --- a/src/components/main/MainView.tsx +++ b/src/components/main/MainView.tsx @@ -11,6 +11,7 @@ import { CatalogView } from '../catalog/CatalogView'; import { ChatHistoryView } from '../chat-history/ChatHistoryView'; import { FloorplanEditorView } from '../floorplan-editor/FloorplanEditorView'; import { FriendsView } from '../friends/FriendsView'; +import { GameCenterView } from '../game-center/GameCenterView'; import { GroupsView } from '../groups/GroupsView'; import { GuideToolView } from '../guide-tool/GuideToolView'; import { HcCenterView } from '../hc-center/HcCenterView'; @@ -105,6 +106,7 @@ export const MainView: FC<{}> = props => + ); } diff --git a/src/components/toolbar/ToolbarView.tsx b/src/components/toolbar/ToolbarView.tsx index 5b7081bd..0efab76f 100644 --- a/src/components/toolbar/ToolbarView.tsx +++ b/src/components/toolbar/ToolbarView.tsx @@ -1,6 +1,6 @@ import { Dispose, DropBounce, EaseOut, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, Wait } from '@nitrots/nitro-renderer'; import { FC, useState } from 'react'; -import { CreateLinkEvent, GetSessionDataManager, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api'; +import { CreateLinkEvent, GetConfiguration, GetSessionDataManager, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api'; import { Base, Flex, LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common'; import { useAchievements, useFriends, useInventoryUnseenTracker, useMessageEvent, useMessenger, useRoomEngineEvent, useSessionInfo } from '../../hooks'; import { ToolbarMeView } from './ToolbarMeView'; @@ -81,6 +81,7 @@ export const ToolbarView: FC<{ isInRoom: boolean }> = props => { !isInRoom && CreateLinkEvent('navigator/goto/home') } /> } CreateLinkEvent('navigator/toggle') } /> + { GetConfiguration('game.center.enabled') && CreateLinkEvent('games/toggle') } /> } CreateLinkEvent('catalog/toggle') } /> CreateLinkEvent('inventory/toggle') }> { (getFullCount > 0) && diff --git a/src/hooks/game-center/index.ts b/src/hooks/game-center/index.ts new file mode 100644 index 00000000..59f04720 --- /dev/null +++ b/src/hooks/game-center/index.ts @@ -0,0 +1 @@ +export * from './useGameCenter'; diff --git a/src/hooks/game-center/useGameCenter.ts b/src/hooks/game-center/useGameCenter.ts new file mode 100644 index 00000000..0b9dbcb6 --- /dev/null +++ b/src/hooks/game-center/useGameCenter.ts @@ -0,0 +1,83 @@ +import { Game2AccountGameStatusMessageEvent, Game2AccountGameStatusMessageParser, GameConfigurationData, GameListMessageEvent, GameStatusMessageEvent, GetGameListMessageComposer, LoadGameUrlEvent } from '@nitrots/nitro-renderer'; +import { useEffect, useState } from 'react'; +import { useBetween } from 'use-between'; +import { SendMessageComposer, VisitDesktop } from '../../api'; +import { useMessageEvent } from '../events'; + +const useGameCenterState = () => +{ + const [ isVisible, setIsVisible ] = useState(false); + const [ games, setGames ] = useState(null); + const [ selectedGame, setSelectedGame ] = useState(null); + const [ accountStatus, setAccountStatus ] = useState(null); + const [ gameOffline, setGameOffline ] = useState(false); + const [ gameURL, setGameURL ] = useState(null); + + useMessageEvent(GameListMessageEvent, event => + { + let parser = event.getParser(); + + if(!parser || parser && !parser.games.length) return; + + setSelectedGame(parser.games[0]); + + setGames(parser.games); + }); + + useMessageEvent(Game2AccountGameStatusMessageEvent, event => + { + let parser = event.getParser(); + + if(!parser) return; + + setAccountStatus(parser); + }); + + useMessageEvent(GameStatusMessageEvent, event => + { + let parser = event.getParser(); + + if(!parser) return; + + setGameOffline(parser.isInMaintenance); + }) + + useMessageEvent(LoadGameUrlEvent, event => + { + let parser = event.getParser(); + + if(!parser) return; + + switch(parser.gameTypeId) + { + case 2: + return console.log('snowwar') + default: + return setGameURL(parser.url); + } + }); + + useEffect(()=> + { + if(isVisible) + { + SendMessageComposer(new GetGameListMessageComposer()); + VisitDesktop(); + } + else + { + // dispose or wtv + } + },[ isVisible ]); + + return { + isVisible, setIsVisible, + games, + accountStatus, + selectedGame, setSelectedGame, + gameOffline, + gameURL, setGameURL + } +} + +export const useGameCenter = () => useBetween(useGameCenterState); diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 91a23d23..a5515749 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -6,6 +6,7 @@ export * from './events'; export * from './events/core'; export * from './events/nitro'; export * from './friends'; +export * from './game-center'; export * from './groups'; export * from './help'; export * from './inventory'; From 1d27eb2699c98302dce0d7fe77fa2a6f26ff73b9 Mon Sep 17 00:00:00 2001 From: laynester Date: Wed, 9 Nov 2022 06:13:08 -0500 Subject: [PATCH 2/2] add to ui config --- public/ui-config.json.example | 1 + 1 file changed, 1 insertion(+) diff --git a/public/ui-config.json.example b/public/ui-config.json.example index 80b6970a..c9e4a5c3 100644 --- a/public/ui-config.json.example +++ b/public/ui-config.json.example @@ -21,6 +21,7 @@ "wired.action.chat.max.length": 100, "wired.action.kick.from.room.max.length": 100, "wired.action.mute.user.max.length": 100, + "game.center.enabled": false, "navigator.room.models": [ { "clubLevel": 0, "tileSize": 104, "name": "a" }, { "clubLevel": 0, "tileSize": 94, "name": "b" },